Scatter plot matrix

by Eamonn Maguire

HTML

<h3>Patients</h3>

<div id="scatter-matrix-canvas"></div>
<pre>
Blood Glucose,Cholesterol,HDL Ratio,LDL...

CSS

pre {
    display:none;
}
svg .foreground path {
    fill: none;
    stroke: #F15A29;
    stroke-opacity: .7;
}
.axis path, .axis line {
    fill: none;
    stroke:black;
    shape-rendering: crispEdges;
}
.brush .extent {
    fill-opacity: .1;
    stroke: #fff;
    shape-rendering: crispEdges;
}
#scatter-matrix-canvas svg .axis {
    shape-rendering: crispEdges;
}
#scatter-matrix-canvas svg .axis line {
    stroke: #ddd;
    stroke-width: .5px;
}
#scatter-matrix-canvas svg .axis path {
    display: none;
}
#scatter-matrix-canvas svg rect.extent {
    fill: #2c3e50;
    fill-opacity: .125;
    stroke: #fff;
}
#scatter-matrix-canvas svg rect.frame {
    fill: white;
    fill-opacity: .7;
    stroke: #aaa;
}
#scatter-matrix-canvas svg circle {
    fill: #ccc;
    fill-opacity: .8;
}
#scatter-matrix-canvas svg .legend circle {
    fill-opacity: 1;
}
#scatter-matrix-canvas svg .legend text {
    font-size: 18px;
    font-style: oblique;
}
#scatter-matrix-canvas svg .cell text {
    pointer-events: none;
}
#scatter-matrix-canvas svg .Patient1 {
    fill: #1abc9c;
}
#scatter-matrix-canvas svg .Patient2 {
    fill: #f39c12;
}

JavaScript

/**
 * Created by eamonnmaguire on 12/11/15.
 * Usage: scatter_plot_matrix.render_from_file("#scatter-matrix-canvas", "assets/data/patients-1.csv",
 ["Blood Glucose","Cholesterol", "HDL Ratio", "LDL Ratio"], "patient", {"width": 1280, "height": 500});
 */

var scatter_plot_matrix = (function () {
    var x = {}, y = {};
    var size = 140,
        padding = 5;
    var data;
    var svg;
    var cell;
    var key;

    var brushstart = function (p) {
        if (brush.data !== p) {
            cell.call(brush.clear());
            brush.x(x[p.x]).y(y[p.y]).data = p;
        }
    };

    // Highlight the selected circles.
    var dobrush = function (p) {
        var e = brush.extent();
        svg.selectAll(".cell circle").attr("class", function (d) {
            return e[0][0] <= d[p.x] && d[p.x] <= e[1][0] && e[0][1] <= d[p.y] && d[p.y] <= e[1][1] ? d[key] : null;
        });
    };

    // If the brush is empty, select all circles.
    var brushend = function () {
        if (brush.empty()) svg.selectAll(".cell circle").attr("class", function (d) {
            return d[key];
        });
    };

    var cross = function (a, b) {
        var c = [],
            n = a.length,
            m = b.length,
            i, j;
        for (i = -1; ++i < n;) for (j = -1; ++j < m;) c.push({
            x: a[i],
            i: i,
            y: b[j],
            j: j
        });
        return c;
    };

    // Brush.
    var brush = d3.svg.brush()
        .on("brushstart", brushstart)
        .on("brush", dobrush)
        .on("brushend", brushend);

    var plot = function (p) {
        var cell = d3.select(this);

        // Plot frame.
        cell.append("svg:rect")
            .attr("class", "frame")
            .attr("x", padding / 2)
            .attr("y", padding / 2)
            .attr("width", size - padding)
            .attr("height", size - padding);

        // Plot dots.
        cell.selectAll("circle")
            .data(data)
           ...