javascript - Set D3 line stroke according to deviation -
here sample of data:
x var min max 045 53.4 55 60 046 52.2 51 60 047 52.7 52 60 048 53.1 53 60 049 49.0 54 60 050 50.4 55 60 051 51.1 56 60 052 52.3 51 60 053 54.6 52 60 054 55.1 53 60 055 51.5 53 60 056 53.6 54 60 057 52.3 55 60
i want plot var against x color of line should black if var inside [min,max] , red if outside.
plotting line if ok cannot change color. tried:
<!doctype html> <meta charset="utf-8"> <style> body { margin: auto; width: 960px; } text { font: 10px sans-serif; } .axis path, .axis line { fill: none; stroke: #000; shape-rendering: crispedges; } .x.axis path { display: none; } .line { fill: none; stroke: #000000; stroke-width: 1.5px; } </style> <body> <script src="lib/vendor/d3/d3.min.js"></script> <script> var margin = {top: 20, right: 20, bottom: 30, left: 50}, width = 960 - margin.left - margin.right, height = 500 - margin.top - margin.bottom; var x = d3.scale.linear() .range([0, width]); var y = d3.scale.linear() .range([height, 0]); var xaxis = d3.svg.axis() .scale(x) .orient("bottom"); var yaxis = d3.svg.axis() .scale(y) .orient("left"); var line = d3.svg.line() .interpolate("basis") .x(function(d) { return x(d.x); }) .y(function(d) { return y(d.var); }) .style('stroke', function(d) { return (d.var>d.min && d.var<d.max) ? 0 : d3.rgb('#ee0000'); }); var svg = d3.select("body").append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); d3.tsv("smidata.tsv", function(error, data) { if (error) throw error; x.domain([data[0].x, data[data.length - 1].x]); y.domain(d3.extent(data, function(d) { return d.var; })); svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xaxis); svg.append("g") .attr("class", "y axis") .call(yaxis) .append("text") .attr("transform", "rotate(-90)") .attr("y", 6) .attr("dy", ".71em") .style("text-anchor", "end") .text("measurement"); svg.append("path") .datum(data) .attr("class", "line") .attr("d", line); }); </script> </body>
but style not function here.
thanks!
edit
i figured how link provided. still rough though. if more simple solution exist, welcome.
<!doctype html> <meta charset="utf-8"> <style> body { margin: auto; width: 960px; } text { font: 10px sans-serif; } svg { width: 100%; height: 20em; } g.axis line, g.axis path { shape-rendering: crispedges; fill: none; stroke: black; } g.plot line { stroke-width: 2; } </style> <body> <script src="lib/vendor/d3/d3.min.js"></script> <script> function update(data) { lines = lines.data(data); xscale.domain([data[0].x, data[data.length - 1].x]); var inter = d3.extent(data, function(d) { return d.var; }); yscale.domain([0,100]); lines.enter().append("line"); lines.each(function (d, i) { var elem = data[i]; //plotting value current point //find next point var nextelem; if (i+1 == data.length) { // there no next value, // repeat point end of line //(line have 0 length) nextelem = elem; } else { nextelem = data[i+1]; } d3.select(this) .attr( //set coordinates: { x1: xscale(elem.x), y1: yscale(elem.var), x2: xscale(nextelem.x), y2: yscale(nextelem.var) } ) //set styles individual line segments .style("stroke", (elem.var > elem.min && elem.var < elem.max) ? "black" : "red"); }); } //*** initialization ***// var svg = d3.select("body").append("svg"); var margin = { top: 20, right: 20, bottom: 30, left: 50 }, width = 960 - margin.left - margin.right, height = 500 - margin.top - margin.bottom; var xscale = d3.scale.linear() .range([0, width]); var yscale = d3.scale.linear() .range([height, 0]); var xaxis = d3.svg.axis() .scale(xscale) .orient("bottom"); var yaxis = d3.svg.axis() .scale(yscale) .orient("left"); svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xaxis); svg.append("g") .attr("class", "y axis") .call(yaxis) .append("text") .attr("transform", "rotate(-90)") .attr("y", 6) .attr("dy", ".71em") .style("text-anchor", "end") .text("measurement"); var lines = svg.append("g").attr("class", "plot").selectall("line"); d3.tsv("smidata.tsv", function (error, data) { if (error) throw error; update(data); }); </script> </body>
for styling, use style function in every path
element.
edit:
i sorry; misunderstood question. think best option prepare accordingly data first, can use api properly. instance, following method job:
var data = [ {x: 45, variance: 53.4, min: 55, max: 60}, {x: 46, variance: 52.2, min: 51, max: 60}, {x: 47, variance: 52.7, min: 52, max: 60}, {x: 48, variance: 53.1, min: 53, max: 60}, {x: 49, variance: 49.0, min: 54, max: 60}, {x: 50, variance: 50.4, min: 55, max: 60}, {x: 51, variance: 51.1, min: 56, max: 60}, {x: 52, variance: 52.3, min: 51, max: 60}, {x: 53, variance: 54.6, min: 52, max: 60}, {x: 54, variance: 55.1, min: 53, max: 60}, {x: 55, variance: 51.5, min: 53, max: 60}, {x: 56, variance: 53.6, min: 54, max: 60}, {x: 57, variance: 52.3, min: 55, max: 60} ]; var preparedata = function(data){ var result = []; data.foreach(function(d, i) { var x1,y1,x2,y2; // 0-length line if (i == data.length - 1) { x1 = x2 = d.x; y1 = y2 = d.variance; } else { x1 = d.x; x2 = data[i+1].x; y1 = d.variance; y2 = data[i+1].variance; } result.push({points: [{x: x1, y: y1}, {x: x2, y: y2}], variance: d.variance, min: d.min, max: d.max}); }); return result; } data = preparedata(data);
next, have work scales match interests. example, inferred following values fine:
var line = d3.svg.line() .interpolate("basis") .x(function(d) { return x(d.x); }) .y(function(d) { return y(d.y); }); xextents = d3.extent(data.map(function(d) { return d.points.map(function(d) { return d.x; }); })) var x = d3.scale.linear() .domain([d3.min(xextents[0]), d3.max(xextents[1])]) .range([0, width]); var y = d3.scale.linear() .domain([0, 100]) .range([height, 0]);
finally, drawing lines pretty simple:
var svg = d3.select('body').append('svg') .attr('width', width) .attr('height', height) .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')'); var lines = svg.selectall('.line') .data(data); lines .enter() .append('g') .append('path') .attr('class', 'line') .attr('d', function (d) { return line(d.points); }) .style('stroke', function(d) { return (d.variance > d.min && d.variance < d.max) ? "black" : "red"; });
i have created simple fiddle trying recreate such scenario, encourage in further questions can see have tried far , understand better want achieve.
Comments
Post a Comment