block by curran 2363e734c759bea987ad

Box Plot in Chiasm

Full Screen

A Box Plot in Chiasm.

Draws from

web counter

index.html

<!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>

boxPlot.js

// 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;
}

iris.csv

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

iris.json

{
  "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" }
  ]
}