Skip to content

Instantly share code, notes, and snippets.

@mattbrehmer
Last active August 25, 2016 20:50
Show Gist options
  • Save mattbrehmer/12ea86353bc807df2187 to your computer and use it in GitHub Desktop.
Save mattbrehmer/12ea86353bc807df2187 to your computer and use it in GitHub Desktop.
Simple Box Plot w/ Point Hover
//initialize the dimensions
var margin = {top: 10, right: 10, bottom: 10, left: 10},
width = 800 - margin.left - margin.right,
height = 100 - margin.top - margin.bottom,
padding = 20
midline = (height - padding) / 2;
//initialize the x scale
var xScale = d3.scale.linear()
.range([padding, width - padding]);
//initialize the x axis
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom");
//initialize boxplot statistics
var data = [],
outliers = [],
minVal = Infinity,
lowerWhisker = Infinity,
q1Val = Infinity,
medianVal = 0,
q3Val = -Infinity,
iqr = 0,
upperWhisker = -Infinity,
maxVal = -Infinity;
d3.csv("data.csv", type, function(error,csv) { // load the data
data = csv.map(function(d) {
return d.value;
});
data = data.sort(d3.ascending);
//calculate the boxplot statistics
minVal = data[0],
q1Val = d3.quantile(data, .25),
medianVal = d3.quantile(data, .5),
q3Val = d3.quantile(data, .75),
iqr = q3Val - q1Val,
maxVal = data[data.length - 1];
// lowerWhisker = d3.max([minVal, q1Val - iqr])
// upperWhisker = d3.min([maxVal, q3Val + iqr]);
var index = 0;
//search for the lower whisker, the mininmum value within q1Val - 1.5*iqr
while (index < data.length && lowerWhisker == Infinity) {
if (data[index] >= (q1Val - 1.5*iqr))
lowerWhisker = data[index];
else
outliers.push(data[index]);
index++;
}
index = data.length-1; // reset index to end of array
//search for the upper whisker, the maximum value within q1Val + 1.5*iqr
while (index >= 0 && upperWhisker == -Infinity) {
if (data[index] <= (q3Val + 1.5*iqr))
upperWhisker = data[index];
else
outliers.push(data[index]);
index--;
}
//map the domain to the x scale +10%
xScale.domain([0,maxVal*1.10]);
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
//append the axis
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0, " + (height - padding) + ")")
.call(xAxis);
//draw verical line for lowerWhisker
svg.append("line")
.attr("class", "whisker")
.attr("x1", xScale(lowerWhisker))
.attr("x2", xScale(lowerWhisker))
.attr("stroke", "black")
.attr("y1", midline - 10)
.attr("y2", midline + 10);
//draw vertical line for upperWhisker
svg.append("line")
.attr("class", "whisker")
.attr("x1", xScale(upperWhisker))
.attr("x2", xScale(upperWhisker))
.attr("stroke", "black")
.attr("y1", midline - 10)
.attr("y2", midline + 10);
//draw horizontal line from lowerWhisker to upperWhisker
svg.append("line")
.attr("class", "whisker")
.attr("x1", xScale(lowerWhisker))
.attr("x2", xScale(upperWhisker))
.attr("stroke", "black")
.attr("y1", midline)
.attr("y2", midline);
//draw rect for iqr
svg.append("rect")
.attr("class", "box")
.attr("stroke", "black")
.attr("fill", "white")
.attr("x", xScale(q1Val))
.attr("y", padding)
.attr("width", xScale(iqr) - padding)
.attr("height", 20);
//draw vertical line at median
svg.append("line")
.attr("class", "median")
.attr("stroke", "black")
.attr("x1", xScale(medianVal))
.attr("x2", xScale(medianVal))
.attr("y1", midline - 10)
.attr("y2", midline + 10);
//draw data as points
svg.selectAll("circle")
.data(csv)
.enter()
.append("circle")
.attr("r", 2.5)
.attr("class", function(d) {
if (d.value < lowerWhisker || d.value > upperWhisker)
return "outlier";
else
return "point";
})
.attr("cy", function(d) {
return random_jitter();
})
.attr("cx", function(d) {
return xScale(d.value);
})
.append("title")
.text(function(d) {
return "Date: " + d.date + "; value: " + d.value;
});
});
function random_jitter() {
if (Math.round(Math.random() * 1) == 0)
var seed = -5;
else
var seed = 5;
return midline + Math.floor((Math.random() * seed) + 1);
}
function type(d) {
d.value = +d.value; // coerce to number
return d;
}
date value
Jan 2000 64.56
Feb 2000 68.87
Mar 2000 67
Apr 2000 55.19
May 2000 48.31
Jun 2000 36.31
Jul 2000 30.12
Aug 2000 41.5
Sep 2000 38.44
Oct 2000 36.62
Nov 2000 24.69
Dec 2000 15.56
Jan 2001 17.31
Feb 2001 10.19
Mar 2001 10.23
Apr 2001 15.78
May 2001 16.69
Jun 2001 14.15
Jul 2001 12.49
Aug 2001 8.94
Sep 2001 5.97
Oct 2001 6.98
Nov 2001 11.32
Dec 2001 10.82
Jan 2002 14.19
Feb 2002 14.1
Mar 2002 14.3
Apr 2002 16.69
May 2002 18.23
Jun 2002 16.25
Jul 2002 14.45
Aug 2002 14.94
Sep 2002 15.93
Oct 2002 19.36
Nov 2002 23.35
Dec 2002 18.89
Jan 2003 21.85
Feb 2003 22.01
Mar 2003 26.03
Apr 2003 28.69
May 2003 35.89
Jun 2003 36.32
Jul 2003 41.64
Aug 2003 46.32
Sep 2003 48.43
Oct 2003 54.43
Nov 2003 53.97
Dec 2003 52.62
Jan 2004 50.4
Feb 2004 43.01
Mar 2004 43.28
Apr 2004 43.6
May 2004 48.5
Jun 2004 54.4
Jul 2004 38.92
Aug 2004 38.14
Sep 2004 40.86
Oct 2004 34.13
Nov 2004 39.68
Dec 2004 44.29
Jan 2005 43.22
Feb 2005 35.18
Mar 2005 34.27
Apr 2005 32.36
May 2005 35.51
Jun 2005 33.09
Jul 2005 45.15
Aug 2005 42.7
Sep 2005 45.3
Oct 2005 39.86
Nov 2005 48.46
Dec 2005 47.15
Jan 2006 44.82
Feb 2006 37.44
Mar 2006 36.53
Apr 2006 35.21
May 2006 34.61
Jun 2006 38.68
Jul 2006 26.89
Aug 2006 30.83
Sep 2006 32.12
Oct 2006 38.09
Nov 2006 40.34
Dec 2006 39.46
Jan 2007 37.67
Feb 2007 39.14
Mar 2007 39.79
Apr 2007 61.33
May 2007 69.14
Jun 2007 68.41
Jul 2007 78.54
Aug 2007 79.91
Sep 2007 93.15
Oct 2007 89.15
Nov 2007 90.56
Dec 2007 92.64
Jan 2008 77.7
Feb 2008 64.47
Mar 2008 71.3
Apr 2008 78.63
May 2008 81.62
Jun 2008 73.33
Jul 2008 76.34
Aug 2008 80.81
Sep 2008 72.76
Oct 2008 57.24
Nov 2008 42.7
Dec 2008 51.28
Jan 2009 58.82
Feb 2009 64.79
Mar 2009 73.44
Apr 2009 80.52
May 2009 77.99
Jun 2009 83.66
Jul 2009 85.76
Aug 2009 81.19
Sep 2009 93.36
Oct 2009 118.81
Nov 2009 135.91
Dec 2009 134.52
Jan 2010 125.41
Feb 2010 118.4
Mar 2010 128.82
<!DOCTYPE html>
<link rel = "stylesheet" type="text/css" href="style.css" />
<style type="text/css"></style>
<html>
<body>
<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
<script type="text/javascript" src="boxplot.js"></script>
</body>
</html>
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org>
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}
.whisker line,
.median line,
.box rect, {
fill: #fff;
stroke: #000;
stroke-width: 1px;
shape-rendering: crispEdges;
}
circle {
fill: black;
stroke: none;
shape-rendering: crispEdges;
}
circle:hover {
fill: orange;
stroke: orange;
opacity: 1;
}
.outlier {
stroke: black;
stroke-width: 2px;
}
.point {
opacity: 0.25;
}
.axis path {
fill: none;
stroke: black;
stroke-width: 1px;
shape-rendering: crispEdges;
}
.axis line {
fill: none;
stroke: black;
stroke-width: 1px;
shape-rendering: crispEdges;
}
.axis text {
font-size: 10px;
}
Copy link

ghost commented Aug 25, 2016

you have written the example for single box, what should be the position of y1 and y2 if there are multiple boxes. I am facing this issue because I have implemented the same code for mutiple data. But i am not able to figure out how to set the position based on the tick marks and the scale is an ordinal scale.

Copy link

ghost commented Aug 25, 2016

Could you please help me in this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment