Skip to content

Instantly share code, notes, and snippets.

@syntagmatic
Forked from syntagmatic/index.html
Created July 18, 2012 11:54
Show Gist options
  • Select an option

  • Save syntagmatic/3135763 to your computer and use it in GitHub Desktop.

Select an option

Save syntagmatic/3135763 to your computer and use it in GitHub Desktop.

Revisions

  1. syntagmatic revised this gist Jul 18, 2012. 3 changed files with 363 additions and 99 deletions.
    176 changes: 135 additions & 41 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -2,23 +2,30 @@
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
    <title>Canvas Parallel Coordinates</title>
    <title>Parallel Coordinates</title>
    <style type="text/css">
    html {
    margin: 0;
    width: 100%;
    height: 100%;
    }
    body {
    font-family: sans-serif;
    font-size: 12px;
    font-size: 13px;
    line-height: 1.4em;
    background: #f9f9f9;
    color: #777;
    margin: 30px 0 0 0;
    overflow: hidden;
    color: #333;
    width: 100%;
    height: 100%;
    }

    body.dark {
    background: #090909;
    color: #ccc;
    background: #070707;
    color: #e3e3e3;
    }

    #wrap {
    padding: 0 14px;
    }

    svg {
    @@ -35,81 +42,168 @@
    position: relative;
    }

    .brush .extent {
    fill: rgba(0,0,0,0.12);
    stroke: rgba(255,255,255,0.6);
    .brush rect.extent {
    fill: rgba(255,255,255,0.4);
    stroke: rgba(55,55,55,0.4);
    shape-rendering: crisp-edges;
    }

    .dark .brush .extent {
    fill: rgba(255,255,255,0.12);
    stroke: rgba(0,0,0,0.5);
    .dark .brush rect.extent {
    fill: rgba(0,0,0,0.4);
    stroke: rgba(200,200,200,0.5);
    }

    .resize rect {
    fill: none;
    }

    .background {
    fill: rgba(255,255,255,0.4);
    stroke: rgba(255,255,255,0.8);
    }
    .dark .background {
    fill: rgba(0,0,0,0.4);
    stroke: rgba(0,0,0,0.8);
    }

    .axis g {
    pointer-events: none;
    }

    .axis line, .axis path {
    display: none;
    fill: none;
    stroke: #222;
    stroke: rgba(180,180,180,1);
    shape-rendering: crispEdges;
    }

    .axis .tick {
    width: 200px;
    }

    .axis text {
    fill: #222;
    text-shadow: 1px 1px 1px #fff, -1px -1px 1px #fff;
    font-weight: bold;
    text-anchor: middle;
    font-size: 12px;
    text-shadow: 0 1px 1px #fff, 1px 0 1px #fff, 0 -1px 1px #fff, -1px 0 1px #fff;
    }

    .axis text.label {
    fill: #444;
    font-size: 14px;
    font-size: 13px;
    font-weight: bold;
    cursor: move;
    }

    .dark .axis text {
    fill: #f2f2f2;
    text-shadow: 0 1px 0 #000, 1px 0 0 #000;
    text-shadow: 0 1px 0 #000, 1px 0 0 #000, 0 -1px 0 #000, -1px 0 0 #000;
    }

    .dark .axis text.label {
    fill: #ddd;
    }

    .axis g,
    .axis path {
    display: none;
    .quarter, .half {
    float: left;
    }

    .quarter {
    width: 23%;
    margin: 0 1%;
    }

    .half {
    width: 48%;
    margin: 0 1%;
    }

    h3 {
    margin: 0.9em 0 0.6em;
    }

    p {
    margin: 0.6em 0;
    }

    #food-list {
    position: absolute;
    left: 220px;
    width: 740px;
    overflow-x: hidden;
    overflow-y: auto;
    height: 400px;
    background: #f8f8f8;
    }
    #legend {
    text-align: right;
    overflow-y: auto;
    height: 400px;
    }
    .dark #food-list {
    background: #0b0b0b;
    }
    #food-list span {
    .color-block {
    display: inline-block;
    height: 6px;
    width: 6px;
    margin: 2px 4px;
    }
    #rendered-bar,
    #selected-bar {
    width:0%;
    background: rgba(120,120,120,0.6);
    font-weight: bold;
    border-right: 1px solid rgba(120,120,120,1);
    }
    .fillbar {
    border:1px solid rgba(120,120,120,0.5);
    }
    </style>
    </head>
    <body>
    <div id="chart">
    <canvas id="foreground"></canvas>
    <svg></svg>
    </div>
    <div id="wrap">
    <div id="chart">
    <canvas id="foreground"></canvas>
    <svg></svg>
    <div class="quarter">
    <h3>Legend</h3>
    <p id="legend">
    </p>
    </div>
    <div class="quarter" id="controls">
    <h3>Controls</h3>
    <p>
    Drag vertically along an axis to brush<br/>
    Tap the axis background to remove its brush<br/>
    Drag labels horizontally to reorder axes<br/>
    </p>

    <h3>Rendering Progress</h3>
    <strong id="data-count"></strong> entries, <strong id="selected-count"></strong> selected, <strong id="rendered-count"></strong> rendered
    <p>
    <div class="fillbar"><div id="selected-bar"><div id="rendered-bar">&nbsp;</div></div></div><br/>
    Opacity set at <strong id="opacity"></strong> to reduce overplotting<br/>
    </p>

    <h3>Filters</h3>
    <p>
    Click this button to rescale the axes for selected data, and remove unselected data.
    </p>
    <button id="keep-data">Keep Selected</button><br/>

    <h3>Appearance</h3>
    <button id="hide-ticks">Hide Ticks</button>
    <button id="show-ticks">Show Ticks</button><br/>
    <button id="hide-brush">Hide Brush Area</button>
    <button id="show-brush">Show Brush Area</button><br/>
    <button id="dark-theme">Dark</button>
    <button id="light-theme">Light</button>
    </div>
    <div class="half">
    <h3>Random sample of 30 entries</h3>
    <p id="food-list">
    </p>
    </div>
    <pre id="food-list"></pre>
    <p>
    Rendered: <strong id="rendered-count"></strong><br/>
    Selected: <strong id="selected-count"></strong><br/>
    Opacity: <strong id="opacity"></strong><br/>
    <button id="hide-ticks">Hide Ticks</button>
    <button id="show-ticks">Show Ticks</button><br/>
    <button id="dark-theme">Dark</button>
    <button id="light-theme">Light</button>
    </p>
    <p>
    Drag along a vertical axis to brush<br/>
    Tap the axis to remove its brush
    </p>
    </div>
    </body>
    <script src="http://mbostock.github.com/d3/d3.v2.js"></script>
    276 changes: 219 additions & 57 deletions parallel.js
    Original file line number Diff line number Diff line change
    @@ -7,18 +7,28 @@ window.requestAnimFrame = window.requestAnimationFrame ||
    function( callback ){
    window.setTimeout(callback, 1000 / 60);
    };
    d3.select("#hide-ticks").on("click", hideTicks);
    d3.select("#show-ticks").on("click", showTicks);
    d3.select("#hide-brush").on("click", hideBrush);
    d3.select("#show-brush").on("click", showBrush);

    function hideTicks() {
    d3.selectAll(".axis g").style("display", "none");
    d3.selectAll(".axis path").style("display", "none");
    };

    d3.select("#hide-ticks")
    .on("click", function() {
    d3.selectAll(".axis g").style("display", "none");
    d3.selectAll(".axis path").style("display", "none");
    });
    function showTicks() {
    d3.selectAll(".axis g").style("display", null);
    d3.selectAll(".axis path").style("display", null);
    };

    d3.select("#show-ticks")
    .on("click", function() {
    d3.selectAll(".axis g").style("display", "block");
    d3.selectAll(".axis path").style("display", "block");
    });
    function hideBrush() {
    d3.selectAll(".background").style("visibility", "hidden");
    };

    function showBrush() {
    d3.selectAll(".background").style("visibility", null);
    };

    d3.select("#dark-theme")
    .on("click", function() {
    @@ -30,18 +40,19 @@ d3.select("#light-theme")
    d3.select("body").attr("class", null);
    });

    var width = document.body.offsetWidth,
    height = document.body.offsetHeight;
    var width = document.body.clientWidth,
    height = d3.max([document.body.clientHeight-500, 240]);

    var m = [60, 0, 10, 0],
    var m = [40, 0, 10, 0],
    w = width - m[1] - m[3],
    h = 350 - m[0] - m[2];
    h = height - m[0] - m[2];

    var xscale = d3.scale.ordinal().rangePoints([0, w], 1),
    yscale = {};
    yscale = {},
    dragging = {};

    var line = d3.svg.line(),
    axis = d3.svg.axis().orient("left"),
    axis = d3.svg.axis().orient("left").ticks(1+height/50),
    foreground,
    dimensions,
    n_dimensions,
    @@ -75,8 +86,22 @@ var colors = {
    "Restaurant Foods": [204,70,41]
    };

    var legend = d3.select("#legend")
    .selectAll(".row")
    .data(d3.keys(colors).sort())
    .enter().append("div")
    .attr("class", "row");

    legend
    .append("span")
    .text(function(d,i) { return d});

    legend
    .append("span")
    .style("background", function(d,i) { return color(d,0.85)})
    .attr("class", "color-block");

    d3.select("#chart")
    .style("width", (w + m[1] + m[3]) + "px")
    .style("height", (h + m[0] + m[2]) + "px")

    d3.selectAll("canvas")
    @@ -98,7 +123,6 @@ var svg = d3.select("svg")
    .attr("transform", "translate(" + m[3] + "," + m[0] + ")");

    d3.csv("nutrients.csv", function(data) {

    // Convert quantitative scales to floats
    data = data.map(function(d) {
    for (var k in d) {
    @@ -113,7 +137,7 @@ d3.csv("nutrients.csv", function(data) {
    return d != "name" && d != "group" && d != "id" &&(yscale[d] = d3.scale.linear()
    .domain(d3.extent(data, function(p) { return +p[d]; }))
    .range([h, 0]));
    }));
    }).sort());

    n_dimensions = dimensions.length;

    @@ -125,72 +149,211 @@ d3.csv("nutrients.csv", function(data) {
    .data(dimensions)
    .enter().append("svg:g")
    .attr("class", "dimension")
    .attr("transform", function(d) { return "translate(" + xscale(d) + ")"; });
    .attr("transform", function(d) { return "translate(" + xscale(d) + ")"; })
    .call(d3.behavior.drag()
    .on("dragstart", function(d) {
    dragging[d] = this.__origin__ = xscale(d);
    })
    .on("drag", function(d) {
    dragging[d] = Math.min(w, Math.max(0, this.__origin__ += d3.event.dx));
    dimensions.sort(function(a, b) { return position(a) - position(b); });
    xscale.domain(dimensions);
    g.attr("transform", function(d) { return "translate(" + position(d) + ")"; });
    brush_count++;
    })
    .on("dragend", function(d) {
    brush();
    delete this.__origin__;
    delete dragging[d];
    d3.select(this).transition().attr("transform", "translate(" + xscale(d) + ")");
    }))

    // Add and store a brush for each axis.
    g.append("svg:g")
    .attr("class", "brush")
    .each(function(d) { d3.select(this).call(yscale[d].brush = d3.svg.brush().y(yscale[d]).on("brush", brush)); })
    .selectAll("rect")
    .style("visibility", null)
    .attr("x", -15)
    .attr("width", 30)
    .attr("rx", 0)
    .attr("ry", 0);

    // Add an axis and title.
    g.append("svg:g")
    .attr("class", "axis")
    .attr("transform", "translate(10,0)")
    .each(function(d) { d3.select(this).call(axis.scale(yscale[d])); })
    .append("svg:text")
    .attr("text-anchor", "left")
    .attr("y", -8)
    .attr("x", -4)
    .attr("transform", "rotate(-19)")
    .attr("text-anchor", "middle")
    .attr("y", -16)
    .attr("x", -12)
    .attr("class", "label")
    .text(String);

    // Add and store a brush for each axis.
    g.append("svg:g")
    .attr("class", "brush")
    .each(function(d) { d3.select(this).call(yscale[d].brush = d3.svg.brush().y(yscale[d]).on("brush", brush)); })
    .selectAll("rect")
    .attr("x", -16)
    .attr("width", 32)
    .attr("rx", 3)
    .attr("ry", 3);

    // Handles a brush event, toggling the display of foreground lines.
    function brush() {
    brush_count++;
    var actives = dimensions.filter(function(p) { return !yscale[p].brush.empty(); }),
    extents = actives.map(function(p) { return yscale[p].brush.extent(); });

    // hack to hide ticks beyond extent
    var b = d3.selectAll('.dimension')[0]
    .forEach(function(element, i) {
    var dimension = d3.select(element).data()[0];
    if (_.include(actives, dimension)) {
    var extent = extents[actives.indexOf(dimension)];
    d3.select(element)
    .selectAll('text')
    .style('display', function() {
    var value = d3.select(this).text();
    return extent[0] <= value && value <= extent[1] ? null : "none"
    });
    } else {
    d3.select(element)
    .selectAll('text')
    .style('display', null);
    }
    d3.select(element)
    .selectAll('.label')
    .style('display', null);
    });
    ;

    // Get lines within extents
    var selected = [];
    data.map(function(d) {
    return actives.every(function(p, i) {
    return extents[i][0] <= d[p] && d[p] <= extents[i][1];
    return actives.every(function(p, dimension) {
    return extents[dimension][0] <= d[p] && d[p] <= extents[dimension][1];
    }) ? selected.push(d) : null;
    });

    // Render selected lines
    paths(selected, foreground, brush_count);
    }

    function paths(data, ctx, count) {
    var n = data.length,
    function actives() {
    var actives = dimensions.filter(function(p) { return !yscale[p].brush.empty(); }),
    extents = actives.map(function(p) { return yscale[p].brush.extent(); });

    // Get lines within extents
    var selected = [];
    data.map(function(d) {
    return actives.every(function(p, i) {
    return extents[i][0] <= d[p] && d[p] <= extents[i][1];
    }) ? selected.push(d) : null;
    });

    return selected;
    };

    window.onresize = function() {
    width = document.body.clientWidth,
    height = d3.max([document.body.clientHeight-500, 220]);

    w = width - m[1] - m[3],
    h = height - m[0] - m[2];

    d3.select("#chart")
    .style("height", (h + m[0] + m[2]) + "px")

    d3.selectAll("canvas")
    .attr("width", w)
    .attr("height", h)
    .style("padding", m.join("px ") + "px");

    d3.select("svg")
    .attr("width", w + m[1] + m[3])
    .attr("height", h + m[0] + m[2])
    .select("g")
    .attr("transform", "translate(" + m[3] + "," + m[0] + ")");

    xscale = d3.scale.ordinal().rangePoints([0, w], 1).domain(dimensions);
    dimensions.forEach(function(d) {
    yscale[d].range([h, 0]);
    });

    d3.selectAll(".dimension")
    .attr("transform", function(d) { return "translate(" + xscale(d) + ")"; })
    // update brush placement
    d3.selectAll(".brush")
    .each(function(d) { d3.select(this).call(yscale[d].brush = d3.svg.brush().y(yscale[d]).on("brush", brush)); })
    brush_count++;

    // update axis placement
    axis = axis.ticks(1+height/50),
    d3.selectAll(".axis")
    .each(function(d) { d3.select(this).call(axis.scale(yscale[d])); });

    // render data
    brush();
    };

    // Remove all but selected from the dataset
    d3.select("#keep-data")
    .on("click", function() {
    data = actives();

    dimensions.forEach(function(d,i) {
    yscale[d] = d3.scale.linear()
    .domain(d3.extent(data, function(p) { return +p[d]; }))
    .range([h, 0]);
    });

    // update brushes
    d3.selectAll(".brush")
    .each(function(d) { d3.select(this).call(yscale[d].brush = d3.svg.brush().y(yscale[d]).on("brush", brush)); })
    brush_count++;

    showTicks();

    // update axes
    d3.selectAll(".axis")
    .each(function(d,i) {
    d3.select(this)
    .transition()
    .ease(d3.ease('linear'))
    .duration(320)
    .delay(60*i)
    .call(axis.scale(yscale[d]));
    });

    // Render selected data
    paths(data, foreground, brush_count);
    });

    function paths(selected, ctx, count) {
    var n = selected.length,
    i = 0,
    opacity = d3.min([2/Math.pow(n,0.37),1]);

    d3.select("#data-count").text(data.length);
    d3.select("#selected-count").text(n);
    d3.select("#selected-bar").style("width", (100*n/data.length) + "%");
    d3.select("#opacity").text((""+opacity).slice(0,6));

    data = _.shuffle(data);
    shuffled_data = _.shuffle(selected);

    // data table
    // data table, sorted by first column
    var foodText = "";
    data.slice(0,10).forEach(function(d) {
    foodText += "<span style='background:" + color(d.group,0.85) + "'></span>" + d.name + "<br/>";
    shuffled_data.slice(0,30).sort(function(a,b) {
    var col = d3.keys(a)[0];
    return a[col] < b[col] ? -1 : 1;
    })
    .forEach(function(d) {
    foodText += "<span class='color-block' style='background:" + color(d.group,0.85) + "'></span>" + d.name + "<br/>";
    });
    d3.select("#food-list").html(foodText);

    ctx.clearRect(0,0,w+1,h+1);
    function render() {
    var max = d3.min([i+12, n]);
    data.slice(i,max).forEach(function(d) {
    shuffled_data.slice(i,max).forEach(function(d) {
    path(d, foreground, color(d.group,opacity));
    });
    i = max;
    d3.select("#rendered-count").text(i);
    d3.select("#rendered-bar").style("width", (100*i/n) + "%");
    };

    // render all lines until finished or a new brush event
    @@ -205,26 +368,25 @@ d3.csv("nutrients.csv", function(data) {

    function path(d, ctx, color) {
    if (color) ctx.strokeStyle = color;
    var x = xscale(0)-15;
    y = yscale[dimensions[0]](d[dimensions[0]]); // left edge
    ctx.beginPath();
    var x0 = xscale(0)/2,
    y0 = yscale[dimensions[0]](d[dimensions[0]]); // left edge
    ctx.moveTo(x0,y0);
    ctx.moveTo(x,y);
    dimensions.map(function(p,i) {
    var x = xscale(p),
    y = yscale[p](d[p]);
    var cp1x = x - 0.85*(x-x0);
    var cp1y = y0;
    var cp2x = x - 0.15*(x-x0);
    var cp2y = y;
    ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
    x0 = x;
    y0 = y;
    x = xscale(p),
    y = yscale[p](d[p]);
    ctx.lineTo(x, y);
    });
    ctx.lineTo(w-xscale(0)/2,y0); // right edge
    ctx.lineTo(x+15, y); // right edge
    ctx.stroke();
    };

    function color(d,a) {
    var c = colors[d];
    return ["hsla(",c[0],",",c[1],"%,",c[2],"%,",a,")"].join("");
    };
    };

    function position(d) {
    var v = dragging[d];
    return v == null ? xscale(d) : v;
    }
    10 changes: 9 additions & 1 deletion readme.MD
    Original file line number Diff line number Diff line change
    @@ -1 +1,9 @@
    This is an experiment in extending the left and right edges of parallel coordinates. Compare to [cycled parallel coordinates](http://bl.ocks.org/2499006)
    Improvements:
    -------------

    * Scale to window size and resizes
    * Axis reordering by dragging labels
    * Rendering progress bar
    * Keep selected button removes unselected data
    * Alphabetized random sample
    * Brushed axes only show tick numbers within extent
  2. syntagmatic revised this gist Jul 2, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion parallel.js
    Original file line number Diff line number Diff line change
    @@ -35,7 +35,7 @@ var width = document.body.offsetWidth,

    var m = [60, 0, 10, 0],
    w = width - m[1] - m[3],
    h = 370 - m[0] - m[2];
    h = 350 - m[0] - m[2];

    var xscale = d3.scale.ordinal().rangePoints([0, w], 1),
    yscale = {};
  3. syntagmatic revised this gist Jul 2, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion parallel.js
    Original file line number Diff line number Diff line change
    @@ -35,7 +35,7 @@ var width = document.body.offsetWidth,

    var m = [60, 0, 10, 0],
    w = width - m[1] - m[3],
    h = 400 - m[0] - m[2];
    h = 370 - m[0] - m[2];

    var xscale = d3.scale.ordinal().rangePoints([0, w], 1),
    yscale = {};
  4. syntagmatic revised this gist Jun 21, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion parallel.js
    Original file line number Diff line number Diff line change
    @@ -35,7 +35,7 @@ var width = document.body.offsetWidth,

    var m = [60, 0, 10, 0],
    w = width - m[1] - m[3],
    h = 290 - m[0] - m[2];
    h = 400 - m[0] - m[2];

    var xscale = d3.scale.ordinal().rangePoints([0, w], 1),
    yscale = {};
  5. syntagmatic revised this gist Apr 26, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion parallel.js
    Original file line number Diff line number Diff line change
    @@ -220,7 +220,7 @@ function path(d, ctx, color) {
    x0 = x;
    y0 = y;
    });
    ctx.lineTo(w,y0-xscale(0)/2); // right edge
    ctx.lineTo(w-xscale(0)/2,y0); // right edge
    ctx.stroke();
    };

  6. syntagmatic revised this gist Apr 26, 2012. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions parallel.js
    Original file line number Diff line number Diff line change
    @@ -206,7 +206,7 @@ d3.csv("nutrients.csv", function(data) {
    function path(d, ctx, color) {
    if (color) ctx.strokeStyle = color;
    ctx.beginPath();
    var x0 = 0,
    var x0 = xscale(0)/2,
    y0 = yscale[dimensions[0]](d[dimensions[0]]); // left edge
    ctx.moveTo(x0,y0);
    dimensions.map(function(p,i) {
    @@ -220,7 +220,7 @@ function path(d, ctx, color) {
    x0 = x;
    y0 = y;
    });
    ctx.lineTo(w,y0); // right edge
    ctx.lineTo(w,y0-xscale(0)/2); // right edge
    ctx.stroke();
    };

  7. syntagmatic revised this gist Apr 26, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion parallel.js
    Original file line number Diff line number Diff line change
    @@ -206,7 +206,7 @@ d3.csv("nutrients.csv", function(data) {
    function path(d, ctx, color) {
    if (color) ctx.strokeStyle = color;
    ctx.beginPath();
    var x0 = xscale(0)/3,
    var x0 = 0,
    y0 = yscale[dimensions[0]](d[dimensions[0]]); // left edge
    ctx.moveTo(x0,y0);
    dimensions.map(function(p,i) {
  8. syntagmatic revised this gist Apr 26, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion parallel.js
    Original file line number Diff line number Diff line change
    @@ -206,7 +206,7 @@ d3.csv("nutrients.csv", function(data) {
    function path(d, ctx, color) {
    if (color) ctx.strokeStyle = color;
    ctx.beginPath();
    var x0 = xscale(0)/2,
    var x0 = xscale(0)/3,
    y0 = yscale[dimensions[0]](d[dimensions[0]]); // left edge
    ctx.moveTo(x0,y0);
    dimensions.map(function(p,i) {
  9. syntagmatic revised this gist Apr 26, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion parallel.js
    Original file line number Diff line number Diff line change
    @@ -206,7 +206,7 @@ d3.csv("nutrients.csv", function(data) {
    function path(d, ctx, color) {
    if (color) ctx.strokeStyle = color;
    ctx.beginPath();
    var x0 = 0,
    var x0 = xscale(0)/2,
    y0 = yscale[dimensions[0]](d[dimensions[0]]); // left edge
    ctx.moveTo(x0,y0);
    dimensions.map(function(p,i) {
  10. syntagmatic revised this gist Apr 26, 2012. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions readme.MD
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    This is an experiment in extending the left and right edges of parallel coordinates. Compare to [cycled parallel coordinates](http://bl.ocks.org/2499006)
  11. syntagmatic revised this gist Apr 26, 2012. 1 changed file with 2 additions and 3 deletions.
    5 changes: 2 additions & 3 deletions parallel.js
    Original file line number Diff line number Diff line change
    @@ -207,8 +207,7 @@ function path(d, ctx, color) {
    if (color) ctx.strokeStyle = color;
    ctx.beginPath();
    var x0 = 0,
    y0 = (yscale[dimensions[n_dimensions-1]](d[dimensions[n_dimensions-1]]) +
    yscale[dimensions[0]](d[dimensions[0]]))/2; // begin cycle
    y0 = yscale[dimensions[0]](d[dimensions[0]]); // left edge
    ctx.moveTo(x0,y0);
    dimensions.map(function(p,i) {
    var x = xscale(p),
    @@ -221,7 +220,7 @@ function path(d, ctx, color) {
    x0 = x;
    y0 = y;
    });
    ctx.lineTo(w,(yscale[dimensions[0]](d[dimensions[0]])+y0)/2); // end cycle
    ctx.lineTo(w,y0); // right edge
    ctx.stroke();
    };

  12. syntagmatic revised this gist Apr 26, 2012. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions parallel.js
    Original file line number Diff line number Diff line change
    @@ -208,7 +208,7 @@ function path(d, ctx, color) {
    ctx.beginPath();
    var x0 = 0,
    y0 = (yscale[dimensions[n_dimensions-1]](d[dimensions[n_dimensions-1]]) +
    yscale[dimensions[0]](d[dimensions[0]]))/2; // begin torus
    yscale[dimensions[0]](d[dimensions[0]]))/2; // begin cycle
    ctx.moveTo(x0,y0);
    dimensions.map(function(p,i) {
    var x = xscale(p),
    @@ -221,7 +221,7 @@ function path(d, ctx, color) {
    x0 = x;
    y0 = y;
    });
    ctx.lineTo(w,(yscale[dimensions[0]](d[dimensions[0]])+y0)/2); // end torus
    ctx.lineTo(w,(yscale[dimensions[0]](d[dimensions[0]])+y0)/2); // end cycle
    ctx.stroke();
    };

  13. syntagmatic revised this gist Apr 26, 2012. 1 changed file with 2 additions and 5 deletions.
    7 changes: 2 additions & 5 deletions parallel.js
    Original file line number Diff line number Diff line change
    @@ -208,23 +208,20 @@ function path(d, ctx, color) {
    ctx.beginPath();
    var x0 = 0,
    y0 = (yscale[dimensions[n_dimensions-1]](d[dimensions[n_dimensions-1]]) +
    yscale[dimensions[0]](d[dimensions[0]]))/2; // begin torus
    yscale[dimensions[0]](d[dimensions[0]]))/2; // begin torus
    ctx.moveTo(x0,y0);
    dimensions.map(function(p,i) {
    var x = xscale(p),
    y = yscale[p](d[p]);

    var cp1x = x - 0.85*(x-x0);
    var cp1y = y0;
    var cp2x = x - 0.15*(x-x0);
    var cp2y = y;
    ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);


    x0 = x;
    y0 = y;
    });
    ctx.lineTo(w,(yscale[dimensions[0]](d[dimensions[0]])+y0)/2)
    ctx.lineTo(w,(yscale[dimensions[0]](d[dimensions[0]])+y0)/2); // end torus
    ctx.stroke();
    };

  14. syntagmatic revised this gist Apr 26, 2012. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion parallel.js
    Original file line number Diff line number Diff line change
    @@ -207,7 +207,8 @@ function path(d, ctx, color) {
    if (color) ctx.strokeStyle = color;
    ctx.beginPath();
    var x0 = 0,
    y0 = (yscale[dimensions[n_dimensions-1]](d[dimensions[n_dimensions-1]])+y)/2; // begin torus
    y0 = (yscale[dimensions[n_dimensions-1]](d[dimensions[n_dimensions-1]]) +
    yscale[dimensions[0]](d[dimensions[0]]))/2; // begin torus
    ctx.moveTo(x0,y0);
    dimensions.map(function(p,i) {
    var x = xscale(p),
  15. syntagmatic revised this gist Apr 26, 2012. 1 changed file with 11 additions and 17 deletions.
    28 changes: 11 additions & 17 deletions parallel.js
    Original file line number Diff line number Diff line change
    @@ -207,29 +207,23 @@ function path(d, ctx, color) {
    if (color) ctx.strokeStyle = color;
    ctx.beginPath();
    var x0 = 0,
    y0 = 0;
    y0 = (yscale[dimensions[n_dimensions-1]](d[dimensions[n_dimensions-1]])+y)/2; // begin torus
    ctx.moveTo(x0,y0);
    dimensions.map(function(p,i) {
    var x = xscale(p),
    y = yscale[p](d[p]);
    if (i == 0) {
    // beginning line
    // ctx.moveTo(0,y);
    ctx.moveTo(0,(yscale[dimensions[n_dimensions-1]](d[dimensions[n_dimensions-1]])+y)/2);
    ctx.lineTo(x,y);
    } else {
    // intermediate line
    var cp1x = x - 0.85*(x-x0);
    var cp1y = y0;
    var cp2x = x - 0.15*(x-x0);
    var cp2y = y;
    ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
    }
    if ( i == n_dimensions-1 ) {
    ctx.lineTo(w,(yscale[dimensions[0]](d[dimensions[0]])+y)/2)
    }

    var cp1x = x - 0.85*(x-x0);
    var cp1y = y0;
    var cp2x = x - 0.15*(x-x0);
    var cp2y = y;
    ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);


    x0 = x;
    y0 = y;
    });
    ctx.lineTo(w,(yscale[dimensions[0]](d[dimensions[0]])+y0)/2)
    ctx.stroke();
    };

  16. syntagmatic revised this gist Apr 26, 2012. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -13,6 +13,7 @@
    background: #f9f9f9;
    color: #777;
    margin: 30px 0 0 0;
    overflow: hidden;
    }

    body.dark {
  17. syntagmatic revised this gist Apr 26, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion parallel.js
    Original file line number Diff line number Diff line change
    @@ -225,7 +225,7 @@ function path(d, ctx, color) {
    ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
    }
    if ( i == n_dimensions-1 ) {
    ctx.lineTo(0,(yscale[dimensions[0]](d[dimensions[0]])+y)/2)
    ctx.lineTo(w,(yscale[dimensions[0]](d[dimensions[0]])+y)/2)
    }
    x0 = x;
    y0 = y;
  18. syntagmatic revised this gist Apr 26, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion parallel.js
    Original file line number Diff line number Diff line change
    @@ -225,7 +225,7 @@ function path(d, ctx, color) {
    ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
    }
    if ( i == n_dimensions-1 ) {
    ctx.lineTo(w,y);
    ctx.lineTo(0,(yscale[dimensions[0]](d[dimensions[0]])+y)/2)
    }
    x0 = x;
    y0 = y;
  19. syntagmatic revised this gist Apr 26, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion parallel.js
    Original file line number Diff line number Diff line change
    @@ -214,7 +214,7 @@ function path(d, ctx, color) {
    if (i == 0) {
    // beginning line
    // ctx.moveTo(0,y);
    ctx.moveTo(0,(yscale[n_dimensions-1](d[n_dimensions-1])+y)/2);
    ctx.moveTo(0,(yscale[dimensions[n_dimensions-1]](d[dimensions[n_dimensions-1]])+y)/2);
    ctx.lineTo(x,y);
    } else {
    // intermediate line
  20. syntagmatic revised this gist Apr 26, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion parallel.js
    Original file line number Diff line number Diff line change
    @@ -214,7 +214,7 @@ function path(d, ctx, color) {
    if (i == 0) {
    // beginning line
    // ctx.moveTo(0,y);
    ctx.moveTo(0,(yscale[n_dimensions](d[n_dimensions])+y)/2);
    ctx.moveTo(0,(yscale[n_dimensions-1](d[n_dimensions-1])+y)/2);
    ctx.lineTo(x,y);
    } else {
    // intermediate line
  21. syntagmatic revised this gist Apr 26, 2012. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions parallel.js
    Original file line number Diff line number Diff line change
    @@ -32,7 +32,7 @@ d3.select("#light-theme")

    var width = document.body.offsetWidth,
    height = document.body.offsetHeight;
    console.log(width, document.body.clientWidth);

    var m = [60, 0, 10, 0],
    w = width - m[1] - m[3],
    h = 290 - m[0] - m[2];
    @@ -214,7 +214,7 @@ function path(d, ctx, color) {
    if (i == 0) {
    // beginning line
    // ctx.moveTo(0,y);
    ctx.moveTo(0,(yscale[n_dimensions](d[n_dimensions]+y)/2);
    ctx.moveTo(0,(yscale[n_dimensions](d[n_dimensions])+y)/2);
    ctx.lineTo(x,y);
    } else {
    // intermediate line
  22. syntagmatic revised this gist Apr 26, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion parallel.js
    Original file line number Diff line number Diff line change
    @@ -214,7 +214,7 @@ function path(d, ctx, color) {
    if (i == 0) {
    // beginning line
    // ctx.moveTo(0,y);
    console.log(xscale(p))
    ctx.moveTo(0,(yscale[n_dimensions](d[n_dimensions]+y)/2);
    ctx.lineTo(x,y);
    } else {
    // intermediate line
  23. syntagmatic revised this gist Apr 26, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion parallel.js
    Original file line number Diff line number Diff line change
    @@ -214,7 +214,7 @@ function path(d, ctx, color) {
    if (i == 0) {
    // beginning line
    // ctx.moveTo(0,y);
    console.log(p);
    console.log(xscale(p))
    ctx.lineTo(x,y);
    } else {
    // intermediate line
  24. syntagmatic revised this gist Apr 26, 2012. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion parallel.js
    Original file line number Diff line number Diff line change
    @@ -213,7 +213,8 @@ function path(d, ctx, color) {
    y = yscale[p](d[p]);
    if (i == 0) {
    // beginning line
    ctx.moveTo(0,y);
    // ctx.moveTo(0,y);
    console.log(p);
    ctx.lineTo(x,y);
    } else {
    // intermediate line
  25. syntagmatic revised this gist Apr 26, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion parallel.js
    Original file line number Diff line number Diff line change
    @@ -32,7 +32,7 @@ d3.select("#light-theme")

    var width = document.body.offsetWidth,
    height = document.body.offsetHeight;

    console.log(width, document.body.clientWidth);
    var m = [60, 0, 10, 0],
    w = width - m[1] - m[3],
    h = 290 - m[0] - m[2];
  26. syntagmatic revised this gist Apr 26, 2012. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -4,6 +4,9 @@
    <meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
    <title>Canvas Parallel Coordinates</title>
    <style type="text/css">
    html {
    margin: 0;
    }
    body {
    font-family: sans-serif;
    font-size: 12px;
  27. syntagmatic revised this gist Apr 26, 2012. 1 changed file with 1 addition and 5 deletions.
    6 changes: 1 addition & 5 deletions parallel.js
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,3 @@
    (function() {

    // shim layer with setTimeout fallback
    window.requestAnimFrame = window.requestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    @@ -237,6 +235,4 @@ function path(d, ctx, color) {
    function color(d,a) {
    var c = colors[d];
    return ["hsla(",c[0],",",c[1],"%,",c[2],"%,",a,")"].join("");
    };

    })();
    };
  28. syntagmatic revised this gist Apr 26, 2012. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion parallel.js
    Original file line number Diff line number Diff line change
    @@ -239,4 +239,4 @@ function color(d,a) {
    return ["hsla(",c[0],",",c[1],"%,",c[2],"%,",a,")"].join("");
    };

    });
    })();
  29. syntagmatic revised this gist Apr 26, 2012. 1 changed file with 7 additions and 4 deletions.
    11 changes: 7 additions & 4 deletions parallel.js
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,5 @@
    (function() {

    // shim layer with setTimeout fallback
    window.requestAnimFrame = window.requestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    @@ -29,10 +31,9 @@ d3.select("#light-theme")
    .on("click", function() {
    d3.select("body").attr("class", null);
    });
    console.log(document.body.offsetWidth);

    var width = parseInt(d3.select('#wrap').style('width').replace("px","")),
    height = parseInt(d3.select('#wrap').style('height').replace("px",""));
    var width = document.body.offsetWidth,
    height = document.body.offsetHeight;

    var m = [60, 0, 10, 0],
    w = width - m[1] - m[3],
    @@ -236,4 +237,6 @@ function path(d, ctx, color) {
    function color(d,a) {
    var c = colors[d];
    return ["hsla(",c[0],",",c[1],"%,",c[2],"%,",a,")"].join("");
    };
    };

    });
  30. syntagmatic revised this gist Apr 26, 2012. 1 changed file with 1 addition and 0 deletions.
    1 change: 1 addition & 0 deletions parallel.js
    Original file line number Diff line number Diff line change
    @@ -29,6 +29,7 @@ d3.select("#light-theme")
    .on("click", function() {
    d3.select("body").attr("class", null);
    });
    console.log(document.body.offsetWidth);

    var width = parseInt(d3.select('#wrap').style('width').replace("px","")),
    height = parseInt(d3.select('#wrap').style('height').replace("px",""));