var keys = ["HIP","Vmag","B-V","RA","DE","Plx","pmRA","pmDE","e_Plx"] // shim layer with setTimeout fallback window.requestAnimFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function( callback ){ window.setTimeout(callback, 1000 / 60); }; d3.select("#hide-ticks") .on("click", function() { d3.selectAll(".axis g").style("display", "none"); d3.selectAll(".axis path").style("display", "none"); }); d3.select("#show-ticks") .on("click", function() { d3.selectAll(".axis g").style("display", "block"); d3.selectAll(".axis path").style("display", "block"); }); var width = document.body.offsetWidth, height = document.body.offsetHeight; var m = [30, 0, 10, 0], w = width - m[1] - m[3], h = 290 - m[0] - m[2]; var xscale = d3.scale.ordinal().rangePoints([0, w], 1), yscale = {}; var line = d3.svg.line(), axis = d3.svg.axis().orient("left"), foreground, scatter, dimensions, n_dimensions, brush_count = 0; d3.select("#chart") .style("width", (w + m[1] + m[3]) + "px") .style("height", (h + m[0] + m[2]) + "px") d3.selectAll("#chart canvas") .attr("width", w) .attr("height", h) .style("padding", m.join("px ") + "px"); foreground = document.getElementById('foreground').getContext('2d'); scatterplot = document.getElementById('scatterplot').getContext('2d'); foreground.strokeStyle = "rgba(0,100,160,0.1)"; foreground.lineWidth = 1.3; // avoid weird subpixel effects foreground.globalCompositeOperation = "lighter"; scatterplot.globalCompositeOperation = "lighter"; foreground.fillText("Loading...",w/2,h/2); var svg = d3.select("svg") .attr("width", w + m[1] + m[3]) .attr("height", h + m[0] + m[2]) .append("svg:g") .attr("transform", "translate(" + m[3] + "," + m[0] + ")"); d3.csv("HIP_star.csv", function(data) { // Convert quantitative scales to floats data = data.map(function(d) { for (var k in d) { d[k] = parseFloat(d[k]) || 0; }; return d; }); // Extract the list of dimensions and create a scale for each. xscale.domain(dimensions = keys.filter(function(d) { var scale = (yscale[d] = d3.scale.linear() .domain(d3.extent(data, function(p) { return +p[d]; }))); if (d == "Vmag") return scale.range([0, h]); return scale.range([h, 0]); })); n_dimensions = dimensions.length; // Render full foreground paths(data, foreground, brush_count); // Add a group element for each dimension. var g = svg.selectAll(".dimension") .data(dimensions) .enter().append("svg:g") .attr("class", "dimension") .attr("transform", function(d) { return "translate(" + xscale(d) + ")"; }); // Add an axis and title. g.append("svg:g") .attr("class", "axis") .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("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(); }); // 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; }); // Render selected lines paths(selected, foreground, brush_count); } function paths(data, ctx, count) { var n = data.length, i = 0, opacity = d3.min([1.5/Math.pow(n,0.5),1]); d3.select("#selected-count").text(n); d3.select("#opacity").text((""+opacity).slice(0,6)); data = _.shuffle(data); var foodText = ""; data.slice(0,10).forEach(function(d) { foodText += "HIP " + d.HIP + "
"; }); d3.select("#food-list").html(foodText); ctx.clearRect(0,0,w+1,h+1); scatterplot.clearRect(0,0,290,290); function render() { var max = d3.min([i+12, n]); data.slice(i,max).forEach(function(d) { path(d, foreground, color(d,opacity)); circle(d, scatterplot, color(d,0.5)); }); i = max; d3.select("#rendered-count").text(i); }; // render all lines until finished or a new brush event (function animloop(){ if (i >= n || count < brush_count) return; requestAnimFrame(animloop); render(); })(); }; }); function path(d, ctx, color) { if (color) ctx.strokeStyle = color; ctx.beginPath(); ctx.moveTo(xscale(0),yscale[dimensions[0]](d[dimensions[0]])); dimensions.map(function(p,i) { ctx.lineTo(xscale(p),yscale[p](d[p])); }); ctx.stroke(); }; function circle(d,ctx,color) { if (color) ctx.fillStyle = color; ctx.beginPath(); ctx.arc(290-yscale['B-V'](d['B-V']),yscale['Vmag'](d['Vmag']),1,0,2*Math.PI) ctx.closePath(); ctx.fill(); }; function color(d,a) { return "hsla(" + (Math.max(100-50*d['B-V'],0)) + "," + (65*d['B-V']) + "%," + 50 +"%," + a + ")"; };