Skip to content

Instantly share code, notes, and snippets.

@curran
Last active February 28, 2018 14:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save curran/2363e734c759bea987ad to your computer and use it in GitHub Desktop.
Save curran/2363e734c759bea987ad to your computer and use it in GitHub Desktop.
Box Plot in Chiasm
license: mit
// This is an example Chaism plugin that uses D3 to make a box plot.
// Draws from this Box Plot example http://bl.ocks.org/mbostock/4061502
function BoxPlot() {
var my = ChiasmComponent({
margin: {
left: 30,
top: 30,
right: 30,
bottom: 30
},
xColumn: Model.None,
yColumn: Model.None,
fill: "white",
stroke: "black",
strokeWidth: "1px"
});
var xScale = d3.scale.ordinal();
var yScale = d3.scale.linear();
var rScale = d3.scale.sqrt();
var g = d3.select(my.initSVG()).append("g");
// Respond to changes in size and margin.
// Inspired by D3 margin convention from http://bl.ocks.org/mbostock/3019563
my.when(["box", "margin"], function(box, margin){
my.innerBox = {
width: box.width - margin.left - margin.right,
height: box.height - margin.top - margin.bottom
};
g.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
});
my.when(["data", "xColumn", "yColumn"], function (data, xColumn, yColumn){
if(xColumn !== Model.None && yColumn !== Model.None){
var getX = function (d){ return d[xColumn]; };
var getY = function (d){ return d[yColumn]; };
my.boxPlotData = d3.nest().key(getX).entries(data)
.map(function (d){
var sorted = d.values.map(getY).sort();
d.quartileData = quartiles(sorted);
d.whiskerData = [sorted[0], sorted[sorted.length - 1]];
return d;
});
}
});
function quartiles(d) {
return [
d3.quantile(d, .25),
d3.quantile(d, .5),
d3.quantile(d, .75)
];
}
my.when(["boxPlotData", "innerBox", "xColumn"], function (boxPlotData, innerBox, xColumn){
if(xColumn !== Model.None){
// The key here corresponds to the unique values in the X column.
xScale
.domain(boxPlotData.map(function (d){ return d.key; }))
.rangeBands([0, innerBox.width], 0.5);
}
});
my.when(["data", "innerBox", "yColumn"], function (data, innerBox, yColumn){
if(yColumn !== Model.None){
yScale
.domain(d3.extent(data, function (d){ return d[yColumn]; }))
.range([innerBox.height, 0]);
}
});
my.when([ "boxPlotData", "fill", "stroke", "strokeWidth" ],
function (boxPlotData, fill, stroke, strokeWidth){
// The center lines that span the whiskers.
var center = g.selectAll("line.center").data(boxPlotData);
center.enter().append("line").attr("class", "center");
center.exit().remove();
center
.attr("x1", function (d){ return xScale(d.key) + (xScale.rangeBand() / 2); })
.attr("x2", function (d){ return xScale(d.key) + (xScale.rangeBand() / 2); })
.attr("y1", function (d){ return yScale(d.whiskerData[0]); })
.attr("y2", function (d){ return yScale(d.whiskerData[1]); })
.style("stroke", stroke)
.style("stroke-width", strokeWidth);
// The top whiskers.
var whiskerTop = g.selectAll("line.whisker-top").data(boxPlotData);
whiskerTop.enter().append("line").attr("class", "whisker-top");
whiskerTop.exit().remove();
whiskerTop
.attr("x1", function (d){ return xScale(d.key); })
.attr("x2", function (d){ return xScale(d.key) + xScale.rangeBand(); })
.attr("y1", function (d){ return yScale(d.whiskerData[0]); })
.attr("y2", function (d){ return yScale(d.whiskerData[0]); })
.style("stroke", stroke)
.style("stroke-width", strokeWidth);
// The bottom whiskers.
var whiskerBottom = g.selectAll("line.whisker-bottom").data(boxPlotData);
whiskerBottom.enter().append("line").attr("class", "whisker-bottom");
whiskerBottom.exit().remove();
whiskerBottom
.attr("x1", function (d){ return xScale(d.key); })
.attr("x2", function (d){ return xScale(d.key) + xScale.rangeBand(); })
.attr("y1", function (d){ return yScale(d.whiskerData[1]); })
.attr("y2", function (d){ return yScale(d.whiskerData[1]); })
.style("stroke", stroke)
.style("stroke-width", strokeWidth);
// The box that shows the upper and lower quartiles.
var boxRect = g.selectAll("rect.box").data(boxPlotData);
boxRect.enter().append("rect").attr("class", "box");
boxRect.exit().remove();
boxRect
.attr("x", function (d){ return xScale(d.key); })
.attr("width", xScale.rangeBand())
.attr("y", function (d){ return yScale(d.quartileData[2]); })
.attr("height", function (d){ return yScale(d.quartileData[0]) - yScale(d.quartileData[2]); })
.style("stroke", stroke)
.style("stroke-width", strokeWidth)
.style("fill", fill);
// The horizontal line inside the box that shows the median.
var median = g.selectAll("line.median").data(boxPlotData);
median.enter().append("line").attr("class", "median");
median.exit().remove();
median
.attr("x1", function (d){ return xScale(d.key) })
.attr("x2", function (d){ return xScale(d.key) + xScale.rangeBand(); })
.attr("y1", function (d){ return yScale(d.quartileData[1]); })
.attr("y2", function (d){ return yScale(d.quartileData[1]); })
.style("stroke", stroke)
.style("stroke-width", strokeWidth);
});
return my;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Box Plot</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
<!-- A functional reactive model library. github.com/curran/model -->
<script src="https://curran.github.io/model/cdn/model-v0.2.4.js"></script>
<!-- Chiasm core and plugins. github.com/chiasm-project -->
<script src="https://chiasm-project.github.io/chiasm/chiasm-v0.2.0.js"></script>
<script src="https://chiasm-project.github.io/chiasm-component/chiasm-component-v0.2.1.js"></script>
<script src="https://chiasm-project.github.io/chiasm-layout/chiasm-layout-v0.2.2.js"></script>
<script src="https://chiasm-project.github.io/chiasm-links/chiasm-links-v0.2.0.js"></script>
<script src="https://chiasm-project.github.io/chiasm-dataset-loader/chiasm-dataset-loader-v0.3.1.js"></script>
<script src="boxPlot.js"></script>
<style>
body {
background-color: black;
}
/* Make the chart container fill the page using CSS. */
#chiasm-container {
background-color: white;
position: fixed;
left: 20px;
right: 20px;
top: 20px;
bottom: 20px;
}
</style>
</head>
<body>
<div id="chiasm-container"></div>
<script>
var chiasm = Chiasm();
chiasm.plugins.layout = ChiasmLayout;
chiasm.plugins.links = ChiasmLinks;
chiasm.plugins.dsvDataset = ChiasmDatasetLoader;
chiasm.plugins.boxPlot = BoxPlot;
chiasm.setConfig({
"layout": {
"plugin": "layout",
"state": {
"containerSelector": "#chiasm-container",
"layout": "boxPlot"
}
},
"boxPlotData": {
"plugin": "dsvDataset",
"state": {
"path": "iris"
}
},
"boxPlot": {
"plugin": "boxPlot",
"state": {
"xColumn": "class",
"yColumn": "petal_length"
}
},
"links": {
"plugin": "links",
"state": {
"bindings": [
"boxPlotData.data -> boxPlot.data"
]
}
}
});
</script>
</body>
</html>
sepal_length sepal_width petal_length petal_width class
5.1 3.5 1.4 0.2 setosa
4.9 3.0 1.4 0.2 setosa
4.7 3.2 1.3 0.2 setosa
4.6 3.1 1.5 0.2 setosa
5.0 3.6 1.4 0.2 setosa
5.4 3.9 1.7 0.4 setosa
4.6 3.4 1.4 0.3 setosa
5.0 3.4 1.5 0.2 setosa
4.4 2.9 1.4 0.2 setosa
4.9 3.1 1.5 0.1 setosa
5.4 3.7 1.5 0.2 setosa
4.8 3.4 1.6 0.2 setosa
4.8 3.0 1.4 0.1 setosa
4.3 3.0 1.1 0.1 setosa
5.8 4.0 1.2 0.2 setosa
5.7 4.4 1.5 0.4 setosa
5.4 3.9 1.3 0.4 setosa
5.1 3.5 1.4 0.3 setosa
5.7 3.8 1.7 0.3 setosa
5.1 3.8 1.5 0.3 setosa
5.4 3.4 1.7 0.2 setosa
5.1 3.7 1.5 0.4 setosa
4.6 3.6 1.0 0.2 setosa
5.1 3.3 1.7 0.5 setosa
4.8 3.4 1.9 0.2 setosa
5.0 3.0 1.6 0.2 setosa
5.0 3.4 1.6 0.4 setosa
5.2 3.5 1.5 0.2 setosa
5.2 3.4 1.4 0.2 setosa
4.7 3.2 1.6 0.2 setosa
4.8 3.1 1.6 0.2 setosa
5.4 3.4 1.5 0.4 setosa
5.2 4.1 1.5 0.1 setosa
5.5 4.2 1.4 0.2 setosa
4.9 3.1 1.5 0.1 setosa
5.0 3.2 1.2 0.2 setosa
5.5 3.5 1.3 0.2 setosa
4.9 3.1 1.5 0.1 setosa
4.4 3.0 1.3 0.2 setosa
5.1 3.4 1.5 0.2 setosa
5.0 3.5 1.3 0.3 setosa
4.5 2.3 1.3 0.3 setosa
4.4 3.2 1.3 0.2 setosa
5.0 3.5 1.6 0.6 setosa
5.1 3.8 1.9 0.4 setosa
4.8 3.0 1.4 0.3 setosa
5.1 3.8 1.6 0.2 setosa
4.6 3.2 1.4 0.2 setosa
5.3 3.7 1.5 0.2 setosa
5.0 3.3 1.4 0.2 setosa
7.0 3.2 4.7 1.4 versicolor
6.4 3.2 4.5 1.5 versicolor
6.9 3.1 4.9 1.5 versicolor
5.5 2.3 4.0 1.3 versicolor
6.5 2.8 4.6 1.5 versicolor
5.7 2.8 4.5 1.3 versicolor
6.3 3.3 4.7 1.6 versicolor
4.9 2.4 3.3 1.0 versicolor
6.6 2.9 4.6 1.3 versicolor
5.2 2.7 3.9 1.4 versicolor
5.0 2.0 3.5 1.0 versicolor
5.9 3.0 4.2 1.5 versicolor
6.0 2.2 4.0 1.0 versicolor
6.1 2.9 4.7 1.4 versicolor
5.6 2.9 3.6 1.3 versicolor
6.7 3.1 4.4 1.4 versicolor
5.6 3.0 4.5 1.5 versicolor
5.8 2.7 4.1 1.0 versicolor
6.2 2.2 4.5 1.5 versicolor
5.6 2.5 3.9 1.1 versicolor
5.9 3.2 4.8 1.8 versicolor
6.1 2.8 4.0 1.3 versicolor
6.3 2.5 4.9 1.5 versicolor
6.1 2.8 4.7 1.2 versicolor
6.4 2.9 4.3 1.3 versicolor
6.6 3.0 4.4 1.4 versicolor
6.8 2.8 4.8 1.4 versicolor
6.7 3.0 5.0 1.7 versicolor
6.0 2.9 4.5 1.5 versicolor
5.7 2.6 3.5 1.0 versicolor
5.5 2.4 3.8 1.1 versicolor
5.5 2.4 3.7 1.0 versicolor
5.8 2.7 3.9 1.2 versicolor
6.0 2.7 5.1 1.6 versicolor
5.4 3.0 4.5 1.5 versicolor
6.0 3.4 4.5 1.6 versicolor
6.7 3.1 4.7 1.5 versicolor
6.3 2.3 4.4 1.3 versicolor
5.6 3.0 4.1 1.3 versicolor
5.5 2.5 4.0 1.3 versicolor
5.5 2.6 4.4 1.2 versicolor
6.1 3.0 4.6 1.4 versicolor
5.8 2.6 4.0 1.2 versicolor
5.0 2.3 3.3 1.0 versicolor
5.6 2.7 4.2 1.3 versicolor
5.7 3.0 4.2 1.2 versicolor
5.7 2.9 4.2 1.3 versicolor
6.2 2.9 4.3 1.3 versicolor
5.1 2.5 3.0 1.1 versicolor
5.7 2.8 4.1 1.3 versicolor
6.3 3.3 6.0 2.5 virginica
5.8 2.7 5.1 1.9 virginica
7.1 3.0 5.9 2.1 virginica
6.3 2.9 5.6 1.8 virginica
6.5 3.0 5.8 2.2 virginica
7.6 3.0 6.6 2.1 virginica
4.9 2.5 4.5 1.7 virginica
7.3 2.9 6.3 1.8 virginica
6.7 2.5 5.8 1.8 virginica
7.2 3.6 6.1 2.5 virginica
6.5 3.2 5.1 2.0 virginica
6.4 2.7 5.3 1.9 virginica
6.8 3.0 5.5 2.1 virginica
5.7 2.5 5.0 2.0 virginica
5.8 2.8 5.1 2.4 virginica
6.4 3.2 5.3 2.3 virginica
6.5 3.0 5.5 1.8 virginica
7.7 3.8 6.7 2.2 virginica
7.7 2.6 6.9 2.3 virginica
6.0 2.2 5.0 1.5 virginica
6.9 3.2 5.7 2.3 virginica
5.6 2.8 4.9 2.0 virginica
7.7 2.8 6.7 2.0 virginica
6.3 2.7 4.9 1.8 virginica
6.7 3.3 5.7 2.1 virginica
7.2 3.2 6.0 1.8 virginica
6.2 2.8 4.8 1.8 virginica
6.1 3.0 4.9 1.8 virginica
6.4 2.8 5.6 2.1 virginica
7.2 3.0 5.8 1.6 virginica
7.4 2.8 6.1 1.9 virginica
7.9 3.8 6.4 2.0 virginica
6.4 2.8 5.6 2.2 virginica
6.3 2.8 5.1 1.5 virginica
6.1 2.6 5.6 1.4 virginica
7.7 3.0 6.1 2.3 virginica
6.3 3.4 5.6 2.4 virginica
6.4 3.1 5.5 1.8 virginica
6.0 3.0 4.8 1.8 virginica
6.9 3.1 5.4 2.1 virginica
6.7 3.1 5.6 2.4 virginica
6.9 3.1 5.1 2.3 virginica
5.8 2.7 5.1 1.9 virginica
6.8 3.2 5.9 2.3 virginica
6.7 3.3 5.7 2.5 virginica
6.7 3.0 5.2 2.3 virginica
6.3 2.5 5.0 1.9 virginica
6.5 3.0 5.2 2.0 virginica
6.2 3.4 5.4 2.3 virginica
5.9 3.0 5.1 1.8 virginica
{
"columns": [
{ "name": "sepal_length", "type": "number" },
{ "name": "sepal_width", "type": "number" },
{ "name": "petal_length", "type": "number" },
{ "name": "petal_width", "type": "number" },
{ "name": "class", "type": "string" }
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment