Animate lines in a line graph with D3.js - javascript
I have my line graph, with 2 lines.
Data to draw my line graph is pulled from a .csv file.
Can anyone explain how I could start off with an empty graph, and when I click a button,
my lines animate across the graph?
Thanks in advance!!
var button=d3.select("#button");
var margin = {top: 30, right: 20, bottom: 50, left: 60},
width = 700 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
var parseDate = d3.time.format("%d-%b-%y").parse;
//treats value passed to it as a time/date
//OUTPUT RANGE
var x = d3.time.scale()
.range([0, width]);
//OUTPUT RANGE
var y = d3.scale.linear()
.range([height, 0]);
var xAxis = d3.svg.axis().scale(x)
.orient("bottom")
.ticks(5);
var yAxis = d3.svg.axis().scale(y)
.orient("left")
.ticks(5);
//assigns coordinates for each piece of data
var valueline = d3.svg.line()
.interpolate("linear")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.close); });
//second line data
var valueline2 = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.open); });
//create area for 'area' below line
var area = d3.svg.area()
.x(function(d) { return x(d.date); })
.y0(height)
.y1(function(d) { return y(d.close); });
//creates area to draw graph
var svg = d3.select("body")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
//groups content
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
function make_x_axis() {
return d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(5)
}
function make_y_axis() {
return d3.svg.axis()
.scale(y)
.orient("left")
.ticks(30)
}
// csv callback function
d3.csv("myData2.csv", function(data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
//+ operator sets any 'close' values to nuneric
d.close = +d.close;
d.open = +d.open;
});
//INPUT DOMAINS
//.extent() returns min and max values of argument
x.domain(d3.extent(data, function(d) { return d.date; }));
//returns max of whichever set of data is bigger
y.domain([0, d3.max(data, function(d) { return Math.max(d.close, d.open); })]);
//draws lines
//passes the valueline array to path object
svg.append("path") // Add the valueline path.
.attr("class", "line")
//adds dashed line
.style("stroke-dasharray", ("5, 9")) // <== This line here!!
.attr("d", valueline(data));
button.on("click", function() {
svg.append("path") // Add the valueline2 path.
.attr("class", "line2")
.transition()
.attr("d", valueline2(data));
})
svg.append("g") // Add the X Axis
.attr("class", "x axis")
//moves x axis to bottom of graph
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
//text label for x-axis
svg.append("text") // text label for the x axis
.attr("transform", "translate(" + (width / 2) + " ," + (height + margin.bottom - 5 ) + ")")
.style("text-anchor", "middle")
.text("Date");
svg.append("g") // Add the Y Axis
.attr("class", "y axis")
.call(yAxis);
//text label for y-axis
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0 - margin.left)
.attr("x",0 - (height / 2))
//adds extra left padding as original y pos = 0
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Value");
//adding a title to the graph
svg.append("text")
.attr("x", (width / 2))
.attr("y", 0 - (margin.top / 2))
.attr("text-anchor", "middle")
.style("font-size", "16px")
.style("text-decoration", "underline")
.text("Me Graph Larry");
//draw x axis grid
svg.append("g")
.attr("class", "grid")
.attr("transform", "translate(0," + height + ")")
.call(make_x_axis()
.tickSize(-height, 0, 0)
.tickFormat("")
)
//draw y axis grid
svg.append("g")
.attr("class", "grid")
.call(make_y_axis()
.tickSize(-width, 0, 0)
.tickFormat("")
)
});<!--d3.csv close-->
You need to setup a reasonable start value for the animation:
var startvalueline2 = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(0); })
button.on("click", function() {
svg.append("path") // Add the valueline2 path.
.attr("class", "line2")
.attr("d", startvalueline2(data)); // set starting position
.transition()
.attr("d", valueline2(data)); // set end position
});
You might also have a look at Mike's path transitions page. To see how to implement smooth (non-wobbly) animations when using svg:path.
Related
How to dynamically create append svg line using d3js?
I am attempting to draw markers to a zoomable / pannable graph. My current version is available at https://jsfiddle.net/n2enn80o/ raw = {"l2":[-58,-44,-31,-21,-17,-16,-16,-15,-15,-14,-13,-12,-11,-10,-9,-7,-5,-3,-1,2,4,8,11,14,17,20,24,28,32,37,41,46,51,56,60,64,69,73,77,82,84,87,87,87,87,85,82,77,73,66,60,53,46,39,33,26,20,13,8,4,-1,-6,-10,-14,-16,-19,-22,-25,-26,-27,-28,-29,-30,-31,-31,-32,-32,-32,-32,-31,-31,-31,-31,-31,-30,-31,-30,-30,-30,-30,-29,-28,-27,-27,-27,-27,-27,-26,-26,-26,-26,-26,-26,-26,-26,-25,-25,-25,-25,-25,-25,-25,-25,-25,-24,-24,-24,-25,-25,-24,-23,-23,-23,-23,-23,-23,-23,-23,-23,-22,-22,-22,-22,-22,-22,-21,-21,-21,-21,-20,-20,-20,-20,-19,-18,-16,-13,-10,-6,-2,1,4,7,9,12,14,16,16,16,15,13,9,6,2,-1,-4,-7,-10,-11,-12,-14,-15,-16,-17,-18,-19,-19,-20,-20,-20,-20,-20,-20,-20,-24,-32,-45,-54,-50,-25,25,97,182,252,270,220,126,35,-25,-53,-65,-71,-70,-60,-46,-32,-22,-18,-16,-16,-15,-14,-13,-13,-12,-11,-10,-8,-7,-5,-3,-1,1,4,7,10,14,17,21,24,28,32,36,40,45,50,55,59,64,69,72,77,81,84,87,88,88,87,84,82,77,73,67,61,54,47,39,33,26,20,14,9,4,-1,-6,-9,-13,-16,-19,-22,-24,-26,-28,-29,-29,-30,-30,-31,-32,-32,-32,-31,-31,-32,-31,-31,-31,-31,-30,-30,-29,-29,-29,-29,-28,-28,-27,-27,-28,-28,-26,-26,-26,-26,-26,-26,-26,-26,-25,-25,-25,-25,-25,-25,-26,-26,-25,-24,-24,-24,-24,-24,-24,-24,-23,-23,-23,-23,-23,-23,-23,-24,-22,-22,-22,-22,-22,-22,-22,-21,-22,-20,-20,-20,-20,-20,-19,-18,-16,-13,-10,-8,-3,0,4,7,9,11,13,15,16,16,16,14,11,6,2,-2,-4,-7,-9,-11,-12,-14,-16,-17,-18,-19,-19,-19,-19,-20,-20,-20,-20,-20,-20,-23,-30,-43,-54,-53,-30,17,88,172,245,271,230,138,45,-19,-50,-63,-70,-70,-61,-48,-34,-23,-18,-17,-16,-16,-15,-14,-13,-13,-11,-10,-8,-7,-5,-3,-1,1,4,7,9,13,16,20,23,27,31,36,40,44,49,54,59,63,68,73,76,81,83,86,88,87,87,85,82,78,73,68,62,55,48,40,33,27,20,14,9,4,0,-5,-9,-13,-16,-19,-22,-24,-26,-28,-29,-29,-29,-30,-31,-31,-32,-31,-32,-32,-32,-32], "startts":1357714800000,"marker1":[50,100]}; var data =[]; for(var i=0;i<raw.l2.length;i++) { var marker = Number.NaN; for(var j=0;j<raw.marker1.length;j++) { if(i==raw.marker1[j]) { marker=i; break; } } var obj = {"date":raw.startts+(1/244.140625*1000)*i, "value":raw.l2[i]/75,"marker":marker} data.push(obj) } margin = { top: 20, right: 20, bottom: 20, left: 45 }; width = 1800 - margin.left - margin.right; height = 600 - margin.top - margin.bottom; var x = d3.time.scale() .domain(d3.extent(data, function (d) { return d.date; })) .range([0, width]); var y = d3.scale.linear() .domain(d3.extent(data, function (d) { return d.value; })) .range([height, 0]); var line = d3.svg.line() .x(function (d) { return x(d.date); }) .y(function (d) { return y(d.value); }); var zoom = d3.behavior.zoom() .x(x) .y(y) .on("zoom", zoomed); svg = d3.select('#chart') .append("svg:svg") .attr('width', width + margin.left + margin.right) .attr('height', height + margin.top + margin.bottom) .append("svg:g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")") .call(zoom); svg.append("svg:rect") .attr("width", width) .attr("height", height) .attr("class", "plot"); var make_x_axis = function () { return d3.svg.axis() .scale(x) .orient("bottom") .ticks(5); }; var make_y_axis = function () { return d3.svg.axis() .scale(y) .orient("left") .ticks(5); }; var xAxis = d3.svg.axis() .scale(x) .orient("bottom") .ticks(5); svg.append("svg:g") .attr("class", "x axis") .attr("transform", "translate(0, " + height + ")") .call(xAxis); var yAxis = d3.svg.axis() .scale(y) .orient("left") .ticks(5); svg.append("g") .attr("class", "y axis") .call(yAxis); var marker = svg.append("line") .attr("x1",100) .attr("y1", 0) .attr("x2",100) .attr("y2", height) .attr("class", "marker") svg.append("text") .attr("x", 100) .attr("y", 0) .attr("dy", ".35em") .attr("dx", 5) .attr("class", "marker-text") .text(function(d) { return "test"; }); svg.append("g") .attr("class", "x grid") .attr("transform", "translate(0," + height + ")") .call(make_x_axis() .tickSize(-height, 0, 0) .tickFormat("")); svg.append("g") .attr("class", "y grid") .call(make_y_axis() .tickSize(-width, 0, 0) .tickFormat("")); var clip = svg.append("svg:clipPath") .attr("id", "clip") .append("svg:rect") .attr("x", 0) .attr("y", 0) .attr("width", width) .attr("height", height); var chartBody = svg.append("g") .attr("clip-path", "url(#clip)"); chartBody.append("svg:path") .datum(data) .attr("class", "line") .attr("d", line); function zoomed() { console.log(d3.event.translate); console.log(d3.event.scale); svg.select(".x.axis").call(xAxis); svg.select(".y.axis").call(yAxis); svg.select(".x.grid") .call(make_x_axis() .tickSize(-height, 0, 0) .tickFormat("")); svg.select(".y.grid") .call(make_y_axis() .tickSize(-width, 0, 0) .tickFormat("")); svg.select(".line") .attr("class", "line") .attr("d", line); } I have been able to add static lines to my d3 plot in the example, what i am trying to achieve is to make the marker line along with the text "test" to be moving along with the graph. What I have tried is to use a d3.svg.line() with a line generator, but it ends up not getting the reference to d. Another version I have attempted is to create a function as below but that does not get the reference of d, and draws the line at zero. Here i attempted to draw the line if and only if the marker tag was present in the data. By default when populating the data i have ensured that it has Number.NaN when i dont need to draw the marker. var marker = svg.append("line") .attr("x1",function(d) { if(d.marker!=Number.NaN) return x(d.date); }) .attr("y1", 0) .attr("x2",function(d) { if(d.marker!=Number.NaN) return x(d.date); }) .attr("y2", height) .attr("class", "marker")
I have made a couple of small changes, as per my reply to your question. Inside your zoom handler zoomed() you need to change the x1 & x2 attributes of marker, and the x attr of markerText. This function fires on each zoom event to move stuff around or redraw stuff according to your zoom, and your axes. raw = {"l2":[-58,-44,-31,-21,-17,-16,-16,-15,-15,-14,-13,-12,-11,-10,-9,-7,-5,-3,-1,2,4,8,11,14,17,20,24,28,32,37,41,46,51,56,60,64,69,73,77,82,84,87,87,87,87,85,82,77,73,66,60,53,46,39,33,26,20,13,8,4,-1,-6,-10,-14,-16,-19,-22,-25,-26,-27,-28,-29,-30,-31,-31,-32,-32,-32,-32,-31,-31,-31,-31,-31,-30,-31,-30,-30,-30,-30,-29,-28,-27,-27,-27,-27,-27,-26,-26,-26,-26,-26,-26,-26,-26,-25,-25,-25,-25,-25,-25,-25,-25,-25,-24,-24,-24,-25,-25,-24,-23,-23,-23,-23,-23,-23,-23,-23,-23,-22,-22,-22,-22,-22,-22,-21,-21,-21,-21,-20,-20,-20,-20,-19,-18,-16,-13,-10,-6,-2,1,4,7,9,12,14,16,16,16,15,13,9,6,2,-1,-4,-7,-10,-11,-12,-14,-15,-16,-17,-18,-19,-19,-20,-20,-20,-20,-20,-20,-20,-24,-32,-45,-54,-50,-25,25,97,182,252,270,220,126,35,-25,-53,-65,-71,-70,-60,-46,-32,-22,-18,-16,-16,-15,-14,-13,-13,-12,-11,-10,-8,-7,-5,-3,-1,1,4,7,10,14,17,21,24,28,32,36,40,45,50,55,59,64,69,72,77,81,84,87,88,88,87,84,82,77,73,67,61,54,47,39,33,26,20,14,9,4,-1,-6,-9,-13,-16,-19,-22,-24,-26,-28,-29,-29,-30,-30,-31,-32,-32,-32,-31,-31,-32,-31,-31,-31,-31,-30,-30,-29,-29,-29,-29,-28,-28,-27,-27,-28,-28,-26,-26,-26,-26,-26,-26,-26,-26,-25,-25,-25,-25,-25,-25,-26,-26,-25,-24,-24,-24,-24,-24,-24,-24,-23,-23,-23,-23,-23,-23,-23,-24,-22,-22,-22,-22,-22,-22,-22,-21,-22,-20,-20,-20,-20,-20,-19,-18,-16,-13,-10,-8,-3,0,4,7,9,11,13,15,16,16,16,14,11,6,2,-2,-4,-7,-9,-11,-12,-14,-16,-17,-18,-19,-19,-19,-19,-20,-20,-20,-20,-20,-20,-23,-30,-43,-54,-53,-30,17,88,172,245,271,230,138,45,-19,-50,-63,-70,-70,-61,-48,-34,-23,-18,-17,-16,-16,-15,-14,-13,-13,-11,-10,-8,-7,-5,-3,-1,1,4,7,9,13,16,20,23,27,31,36,40,44,49,54,59,63,68,73,76,81,83,86,88,87,87,85,82,78,73,68,62,55,48,40,33,27,20,14,9,4,0,-5,-9,-13,-16,-19,-22,-24,-26,-28,-29,-29,-29,-30,-31,-31,-32,-31,-32,-32,-32,-32], "startts":1357714800000,"marker1":[50,100]}; var data =[]; for(var i=0;i<raw.l2.length;i++) { var marker = Number.NaN; for(var j=0;j<raw.marker1.length;j++) { if(i==raw.marker1[j]) { marker=i; break; } } var obj = {"date":raw.startts+(1/244.140625*1000)*i, "value":raw.l2[i]/75,"marker":marker} data.push(obj) } margin = { top: 20, right: 20, bottom: 20, left: 45 }; width = 1800 - margin.left - margin.right; height = 600 - margin.top - margin.bottom; var x = d3.time.scale() .domain(d3.extent(data, function (d) { return d.date; })) .range([0, width]); var y = d3.scale.linear() .domain(d3.extent(data, function (d) { return d.value; })) .range([height, 0]); var line = d3.svg.line() .x(function (d) { return x(d.date); }) .y(function (d) { return y(d.value); }); var zoom = d3.behavior.zoom() .x(x) .y(y) .on("zoom", zoomed); svg = d3.select('#chart') .append("svg:svg") .attr('width', width + margin.left + margin.right) .attr('height', height + margin.top + margin.bottom) .append("svg:g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")") .call(zoom); svg.append("svg:rect") .attr("width", width) .attr("height", height) .attr("class", "plot"); var make_x_axis = function () { return d3.svg.axis() .scale(x) .orient("bottom") .ticks(5); }; var make_y_axis = function () { return d3.svg.axis() .scale(y) .orient("left") .ticks(5); }; var xAxis = d3.svg.axis() .scale(x) .orient("bottom") .ticks(5); svg.append("svg:g") .attr("class", "x axis") .attr("transform", "translate(0, " + height + ")") .call(xAxis); var yAxis = d3.svg.axis() .scale(y) .orient("left") .ticks(5); svg.append("g") .attr("class", "y axis") .call(yAxis); svg.append("g") .attr("class", "x grid") .attr("transform", "translate(0," + height + ")") .call(make_x_axis() .tickSize(-height, 0, 0) .tickFormat("")); svg.append("g") .attr("class", "y grid") .call(make_y_axis() .tickSize(-width, 0, 0) .tickFormat("")); // Moved this after you append your grids var marker = svg.append("line") .attr("x1",100) .attr("y1", 0) .attr("x2",100) .attr("y2", height) .attr("class", "marker") // Moved this after you append your grids & saved it to a var for later use var markerText = svg.append("text") .attr("x", 100) .attr("y", 0) .attr("dy", ".35em") .attr("dx", 5) .attr("class", "marker-text") .text(function(d) { return "test"; }); var clip = svg.append("svg:clipPath") .attr("id", "clip") .append("svg:rect") .attr("x", 0) .attr("y", 0) .attr("width", width) .attr("height", height); var chartBody = svg.append("g") .attr("clip-path", "url(#clip)"); chartBody.append("svg:path") .datum(data) .attr("class", "line") .attr("d", line); function zoomed() { console.log(d3.event.translate); console.log(d3.event.scale); svg.select(".x.axis").call(xAxis); svg.select(".y.axis").call(yAxis); svg.select(".x.grid") .call(make_x_axis() .tickSize(-height, 0, 0) .tickFormat("")); svg.select(".y.grid") .call(make_y_axis() .tickSize(-width, 0, 0) .tickFormat("")); svg.select(".line") .attr("class", "line") .attr("d", line); // Position at the start time according to your x scale. x(val) // It's not clear from your question where you want to position it var markerPos = x(raw.startts); // Move marker to position marker.attr("x1", markerPos ).attr("x2", markerPos ); // Move marker text to position markerText.attr("x", markerPos ); } Fiddle: https://jsfiddle.net/kqnLfkvw/1/
This can be solved by using d3 axis. A working example is available at https://jsfiddle.net/3gww76s0/ var make_x_marker = function (scale=1, transform=[0,0]) { console.log(transform) var markers =[]; var markerLabels={}; for (i=0; i<raw.marker1.length; i++) { var value=transform[0]+scale*(1/244.140625*1000)*raw.marker1[i]; markers.push(value) markerLabels[value]="A"+Math.floor(Math.random()*26); } return d3.svg.axis() .orient("top") .tickValues(markers) .tickSize(height-15) .tickFormat(function(d){return markerLabels[d]}) };
Plotting a line graph along with Bar graph in d3js. Issue with Date
I'm learning d3js using various examples found online. I've been trying to plot a chart with dual Y axis and an X-axis. The Y axis on the left side would plot a bar chart against the X-axis and the Y-axis on the right side would plot a line chart against X-axis. The Bar graph plots as exactly as required but the line graph does not. The X-axis is date (2015-10-15 04:10). Following this example. The code I wrote var margin = {top: 50, right: 50, bottom: 100, left: 50}, width = 900 - margin.left - margin.right, height = 500 - margin.top - margin.bottom; var parseDate = d3.time.format("%m/%d/%Y %H:%M:%S").parse; var x = d3.scale.ordinal().rangeRoundBands([0, width], .05); var yTxnVol = d3.scale.linear().range([height, 0]); var yResTime = d3.scale.linear().range([height, 0]); var xAxis = d3.svg.axis() .scale(x) .orient("bottom") var yAxis = d3.svg.axis() .scale(yTxnVol) .orient("left") var yAxis2 = d3.svg.axis() .scale(yResTime) .orient("right") .ticks(10); var svg = d3.selectAll("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.csv("../res/data.csv", function(error, data) { data.forEach(function(d) { d.AVRG_RESP_TIME = +d.AVRG_RESP_TIME; d.TXN_VOL = +d.TXN_VOL; }); x.domain(data.map(function(d) { return d.TYM; })); yTxnVol.domain([0, d3.max(data, function(d) { return d.TXN_VOL+50; })]); yResTime.domain([0, d3.max(data, function(d) { return d.AVRG_RESP_TIME+50; })]); var minDate = d3.min(data, function(d){return d.TYM}); var maxDate = d3.max(data, function(d){ return d.TYM}); var xScale = d3.time.scale().range([0,width]);//.domain([minDate, maxDate]); xScale.domain(d3.extent(data, function(d) { return new Date(d.TYM); })); svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis) .selectAll("text") .style("text-anchor", "end") .attr("dx", "-.8em") .attr("dy", "-.55em") .attr("transform", "rotate(-90)" ); svg.append("g") .attr("class", "y axis") .call(yAxis) svg.append("g") .attr("class","y axis") .attr("transform","translate("+width+ ", 0)") .call(yAxis2) svg.selectAll("bar") .data(data) .enter().append("rect") .attr("class", "yhover") .attr("x", function(d) { return x(d.TYM); }) .attr("width", x.rangeBand()) .attr("y", function(d) { return yTxnVol(d.TXN_VOL); }) .attr("height", function(d) { return height - yTxnVol(d.TXN_VOL); }) var line = d3.svg.line() .x(function(d) { return xScale(new Date(d.TYM));}) .y(function(d) { return d.AVRG_RESP_TIME; }); svg.append("path") .datum(data) .attr("class", "line") .attr("d", line); }); The Output Trying to make this to a meaningful line graph. Got NaN error while formatting the dates. Could someone help me to make this a proper line graph ? The csv data sample TYM, AVRG_RESP_TIME, TXN_VOL 2015-10-15 04:00:00, 12, 170 2015-10-15 04:10:00, 18, 220 2015-10-15 04:20:00, 28, 251 2015-10-15 05:00:00, 19, 100
First, fix your csv file. It is improperly formatted and should not have spaces after the comma. Second, You are trying to mix an ordinal scale and a time scale for you xAxis. This isn't going to work. For your use case, just stick with time. Here's a reworking of your code with explanatory comments: <!DOCTYPE html> <html> <head> <script data-require="d3#3.5.3" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script> </head> <body> <script> var margin = { top: 50, right: 50, bottom: 100, left: 50 }, width = 900 - margin.left - margin.right, height = 500 - margin.top - margin.bottom; var parseDate = d3.time.format("%Y-%m-%d %H:%M:%S").parse; // x scale should be time and only time var x = d3.time.scale().range([0, width]); var yTxnVol = d3.scale.linear().range([height, 0]); var yResTime = d3.scale.linear().range([height, 0]); var xAxis = d3.svg.axis() .scale(x) .orient("bottom") var yAxis = d3.svg.axis() .scale(yTxnVol) .orient("left") var yAxis2 = d3.svg.axis() .scale(yResTime) .orient("right") .ticks(10); var svg = d3.selectAll("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.csv("data.csv", function(error, data) { var data = [{"TYM":"2015-10-15 04:00:00","AVRG_RESP_TIME":"12","TXN_VOL":"170"},{"TYM":"2015-10-15 04:10:00","AVRG_RESP_TIME":"18","TXN_VOL":"220"},{"TYM":"2015-10-15 04:20:00","AVRG_RESP_TIME":"28","TXN_VOL":"251"},{"TYM":"2015-10-15 05:00:00","AVRG_RESP_TIME":"19","TXN_VOL":"100"}]; // just make TYM a date and keep it as a date data.forEach(function(d) { d.TYM = parseDate(d.TYM); d.AVRG_RESP_TIME = +d.AVRG_RESP_TIME; d.TXN_VOL = +d.TXN_VOL; }); // get our min and max date in milliseconds // set a padding around our domain of 15% var minDate = d3.min(data, function(d){ return d.TYM; }).getTime(); var maxDate = d3.max(data, function(d){ return d.TYM; }).getTime(); var padDate = (maxDate - minDate) * .15; x.domain([new Date(minDate - padDate), new Date(maxDate + padDate)]); yTxnVol.domain([0, d3.max(data, function(d) { return d.TXN_VOL + 50; })]); yResTime.domain([0, d3.max(data, function(d) { return d.AVRG_RESP_TIME + 50; })]); // set an intelligent bar width var barWidth = (width / x.ticks().length) - 20; svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis) .selectAll("text") .style("text-anchor", "end") .attr("dx", "-.8em") .attr("dy", "-.55em") .attr("transform", "rotate(-90)"); svg.append("g") .attr("class", "y axis") .call(yAxis) svg.append("g") .attr("class", "y axis") .attr("transform", "translate(" + width + ", 0)") .call(yAxis2) svg.selectAll("bar") .data(data) .enter().append("rect") .attr("class", "yhover") .attr("x", function(d) { // center bar on time return x(d.TYM) - (barWidth / 2); }) .attr("width", barWidth) .attr("y", function(d) { return yTxnVol(d.TXN_VOL); }) .attr("height", function(d) { return height - yTxnVol(d.TXN_VOL); }) .style("fill","orange"); var line = d3.svg.line() .x(function(d) { return x(d.TYM); }) .y(function(d) { return d.AVRG_RESP_TIME; }); svg.append("path") .datum(data) .attr("class", "line") .attr("d", line) .style("fill","none") .style("stroke","steelblue") .style("stoke-width","3px"); // }); </script> </body> </html>
The issue with the line graph filling with black was due to improper css. The new css property. .line { fill: none; stroke: darkgreen; stroke-width: 2.5px; } For the dates I formatted it to (%Y-%m-%d %H:%M) format and it worked.
how to left align ticks in d3 bar chart
i created a stacked bar graph. on the y axis side i have ticks with varying lengths. what i am trying to accomplish is to align the text in the tick to the left. this is my example:http://jsfiddle.net/2khbceut/2/ html <title>Diverging Stacked Bar Chart with D3.js</title> <body> <div id="figure" align="center" style="margin-bottom: 50px;"></div> </body> javascript $(document).ready(getTopolegy()); function getTopolegy(){ var data = null; var links = parseTopology(data); createChart(links); } function parseTopology(data){ var links=[{1:5,2:5,3:10,N:20,link_name: "Link CHGIL21CRS-SFXCA21CRS"}, {1:5,2:5,3:10,N:20,link_name: "Link NYCNY21CRS-NYCNY22CRS"}]; return links; } function jsonNameToId(name){ switch (allocated_priority) { case "allocated_priority": return 1; case "allocated_default": return 2; case "spare_capacity": return 3; case "total": return "N"; default: return 999; } } function createChart(data){ var margin = {top: 50, right: 20, bottom: 10, left: 210}, width = 1000 - margin.left - margin.right, height = 100 - margin.top - margin.bottom; var y = d3.scale.ordinal() .rangeRoundBands([0, height], .3); var x = d3.scale.linear() .rangeRound([0, width]); var color = d3.scale.ordinal() .range(["#cccccc", "#92c6db", "#086fad"]); var xAxis = d3.svg.axis() .scale(x) .orient("top"); var yAxis = d3.svg.axis() .scale(y) .orient("left") var svg = d3.select("#figure").append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .attr("id", "d3-plot") .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); color.domain(["Allocated Priority %", "Allocated Default %", "Spare Capacity %"]); // d3.csv("js/raw_data.csv", function(error, data) { data.forEach(function(d) { d["Allocated Priority %"] = +d[1]*100/d.N; d["Allocated Default %"] = +d[2]*100/d.N; d["Spare Capacity %"] = +d[3]*100/d.N; var x0 = 0; var idx = 0; d.boxes = color.domain().map(function(name) { return {name: name, x0: x0, x1: x0 += +d[name], N: +d.N, n: +d[idx += 1]}; }); }); var min_val = d3.min(data, function(d) { return d.boxes["0"].x0; }); var max_val = d3.max(data, function(d) { return d.boxes["2"].x1; }); x.domain([min_val, max_val]).nice(); y.domain(data.map(function(d) { return d.link_name; })); svg.append("g") .attr("class", "x axis") .call(xAxis); svg.append("g") .attr("class", "y axis") .call(yAxis) var vakken = svg.selectAll(".Link") .data(data) .enter().append("g") .attr("class", "bar") .attr("transform", function(d) { return "translate(0," + y(d.link_name) + ")"; }); var bars = vakken.selectAll("rect") .data(function(d) { return d.boxes; }) .enter().append("g").attr("class", "subbar"); bars.append("rect") .attr("height", y.rangeBand()) .attr("x", function(d) { return x(d.x0); }) .attr("width", function(d) { return x(d.x1) - x(d.x0); }) .style("fill", function(d) { return color(d.name); }); bars.append("text") .attr("x", function(d) { return x(d.x0); }) .attr("y", y.rangeBand()/2) .attr("dy", "0.5em") .attr("dx", "0.5em") .style("font" ,"10px sans-serif") .style("text-anchor", "begin") .text(function(d) { return d.n !== 0 && (d.x1-d.x0)>3 ? d.n : "" }); vakken.insert("rect",":first-child") .attr("height", y.rangeBand()) .attr("x", "1") .attr("width", width) .attr("fill-opacity", "0.5") .style("fill", "#F5F5F5") .attr("class", function(d,index) { return index%2==0 ? "even" : "uneven"; }); svg.append("g") .attr("class", "y axis") .append("line") .attr("x1", x(0)) .attr("x2", x(0)) .attr("y2", height); var startp = svg.append("g").attr("class", "legendbox").attr("id", "mylegendbox"); // this is not nice, we should calculate the bounding box and use that var legend_tabs = [0, 150, 300]; var legend = startp.selectAll(".legend") .data(color.domain().slice()) .enter().append("g") .attr("class", "legend") .attr("transform", function(d, i) { return "translate(" + legend_tabs[i] + ",-45)"; }); legend.append("rect") .attr("x", 0) .attr("width", 18) .attr("height", 18) .style("fill", color); legend.append("text") .attr("x", 22) .attr("y", 9) .attr("dy", ".35em") .style("text-anchor", "begin") .style("font" ,"10px sans-serif") .text(function(d) { return d; }); d3.selectAll(".axis path") .style("fill", "none") .style("stroke", "#000") .style("shape-rendering", "crispEdges") d3.selectAll(".axis line") .style("fill", "none") .style("stroke", "#000") .style("shape-rendering", "crispEdges") var movesize = width/2 - startp.node().getBBox().width/2; d3.selectAll(".legendbox").attr("transform", "translate(" + movesize + ",0)"); // }); } as can be seen the current positioning of the tick text is to the right. i tried the following idea: svg.append("g") .attr("class", "y axis") .call(yAxis) .selectAll("text") .style("text-anchor", "start"); but it did not position the ticks in the desired alignment. any ideas?
You can make the Y axis right-oriented, which will have the effect of positioning all the labels to the right of the axis, left-aligning them: var yAxis = d3.svg.axis() .scale(y) .orient("right")// <- 1st step At that point the labels would disappear, because they'll get covered up by the bars of the graph. But then you can shift all those left-aligned labels some constant distance in the negative X direction, such that they're back on the left side of the Y axis, but still left-aligned the way you wanted. tickPadding() is a way to shift them: var yAxis = d3.svg.axis() .scale(y) .orient("right") .tickPadding(-180) Here's your example, modified with the above: http://jsfiddle.net/2khbceut/3/ Maybe hardcoding the -180 is ok for you. If you need that amount to be dynamic, you can compute it using getBBox() on each text element of the axis and taking the maximum width to be the negative offset.
You can set the text-anchor to "start" and adjust the x position with translate, I added the code below in the chart model "boxPlotChart.js" g.select('.nv-y.nv-axis').selectAll('.tick').selectAll('text') .style('text-anchor','start') .attr('transform', function(d,i,j) { return 'translate(-14,0)' }); g.select('.nv-y.nv-axis').selectAll('.nv-axisMaxMin').selectAll('text') .style('text-anchor','start') .attr('transform', function(d,i,j) { return 'translate(-16,0)' });
Path not showing d3 (binding issue?)
I've been working on a project using fake data and sketches I've found online to create a line graph. However, I can't display paths with a JSON file containing numerical data. This is not the final data but I'm using the field "Id" as numerical value. I should be able to see a diagonal line, but nothing shows on the graph. <body> <script> var margin = {top: 20, right: 30, bottom: 30, left: 50}, width = 900 - margin.left - margin.right, height = 500 - margin.top - margin.bottom, a = 3.779528*5, f = width/height, ticksX = 1+ (width/a), ticksY = 1+ (height/a*f) c = 1 + (width/a*10); var x = d3.scale.linear() .domain([194, 2229]) .range([0, width]); var y = d3.scale.linear() .domain([194, 2229]) .range([height, 0]); var xAxis = d3.svg.axis() .scale(x) .tickSize(-height) .tickPadding(10) .tickSubdivide(true) .ticks(ticksX) .orient("bottom"); var yAxis = d3.svg.axis() .scale(y) .tickPadding(10) .tickSize(-width) .tickSubdivide(true) .ticks(ticksY) .orient("left"); var zoom = d3.behavior.zoom() .x(x) //.y(y) .scaleExtent([1, 10]) .on("zoom", zoomed); var svg = d3.select("body").append("svg") .call(zoom) .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); d3.json("pacientes.json", function(error, data) { data.forEach(function(d) { d.Id = +d.Id; d.Edad = +d.Edad; console.log(d.Id); }); x.domain(d3.extent(data, function(d) { return d.Id; })); y.domain(d3.extent(data, function(d) { return d.Id; })); svg.append("clipPath") .attr("id", "clip") .append("rect") .attr("width", width) .attr("height", height); var line = d3.svg.line() .interpolate("linear") .x(function(d) { return x(d.Id); }) .y(function(d) { return y(d.Edad); }); svg.selectAll('svg-path') .data(data) .enter() .append("path") .attr("x", function(d) { return x(d.Id); }) .attr("y", function(d) { return x(d.Id); }) .style("stroke-width", 10) .attr("class", "line") .attr("clip-path", "url(#clip)") .attr('stroke', 'blue') .attr("d", line); svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis); svg.append("g") .attr("class", "y axis") .call(yAxis); svg.append("g") .attr("class", "y axis") .append("text") .attr("class", "axis-label") .attr("transform", "rotate(-90)") .attr("y", (-margin.left) + 10) .attr("x", -height/2) .text('mV'); }); // closing line function zoomed() { svg.select(".x.axis").call(xAxis); svg.select(".y.axis").call(yAxis); svg.selectAll('path.line').attr('d', line); ); } </script> </body> </html> I'm pretty convinced that my error is here svg.selectAll('svg-path') .data(data) .enter() .append("path") .attr("x", function(d) { return x(d.Id); }) .attr("y", function(d) { return x(d.Id); }) .style("stroke-width", 10) .attr("class", "line") .attr("clip-path", "url(#clip)") .attr('stroke', 'blue') .attr("d", line); The data is being loaded correctly and the SVGs are being created (as you can see from the pictures). Any help will be appreciated. I did not add the CSS, but it should be a blue line. Thank you!
Adding tooltips to line graph data points AFTER lines animate
I have a basic line graph with two lines. When I click a button, one of the two lines will draw on the graph. I use stroke-dasharray to draw the lines. Would anyone know how I could add tooltips to my lines? Does using stroke-dasharray make it harder? Heres my code. var button=d3.select("#button"); //defines canvas (area in which graph is placed) var margin = {top: 30, right: 20, bottom: 50, left: 60}, width = 800 - margin.left - margin.right, height = 700 - margin.top - margin.bottom; var parseDate = d3.time.format("%d-%b-%y").parse; //OUTPUT RANGE var x = d3.time.scale() .range([0, width]); //OUTPUT RANGE var y = d3.scale.linear() .range([height, 0]); var xAxis = d3.svg.axis().scale(x) .orient("bottom") .ticks(5); var yAxis = d3.svg.axis().scale(y) .orient("left") .ticks(5); //assigns coordinates for each piece of data var valueline = d3.svg.line() .interpolate("interpolation") .x(function(d) { return x(d.date); }) .y(function(d) { return y(d.close); }); //second line data var valueline2 = d3.svg.line() .x(function(d) { return x(d.date); }) .y(function(d) { return y(d.open); }); //create area for 'area' below line var area = d3.svg.area() .x(function(d) { return x(d.date); }) .y0(height) .y1(function(d) { return y(d.close); }); //creates area to draw graph var svg = d3.select("body") .append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) //groups content .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); function make_x_axis() { return d3.svg.axis() .scale(x) .orient("bottom") .ticks(5) } function make_y_axis() { return d3.svg.axis() .scale(y) .orient("left") .ticks(30) } // csv callback function d3.csv("myData3.csv", function(data) { data.forEach(function(d) { d.date = parseDate(d.date); d.close = +d.close; d.open = +d.open; }); //INPUT DOMAINS //.extent() returns min and max values of argument x.domain(d3.extent(data, function(d) { return d.date; })); //returns max of whichever set of data is bigger y.domain([0, d3.max(data, function(d) { return Math.max(d.close, d.open); })]); d3.select("#button1").on("click", function(){ var path = svg.append("path") // Add the valueline path. .attr("class", "line") .attr("d", valueline(data)) .attr("stroke", "steelblue") .attr("stroke-width", "5") .attr("fill", "none"); var totalLength = path.node().getTotalLength(); path .attr("stroke-dasharray", totalLength + "30" * 30) .attr("stroke-dashoffset", totalLength) .transition() .duration(2000) .ease("linear") .attr("stroke-dashoffset", 0); }) d3.select("#button2").on("click", function(){ var path2 = svg.append("path") // Add the valueline path. .attr("class", "line2") .attr("d", valueline2(data)) .attr("stroke", "steelblue") .attr("stroke-width", "5") .attr("fill", "none"); var totalLength = path2.node().getTotalLength(); path2 .attr("stroke-dasharray", totalLength + "30" * 30) .attr("stroke-dashoffset", totalLength) .transition() .duration(2000) .ease("linear") .attr("stroke-dashoffset", 0) }) svg.append("g") // Add the X Axis .attr("class", "x axis") //moves x axis to bottom of graph .attr("transform", "translate(0," + height + ")") .call(xAxis); //text label for x-axis svg.append("text") // text label for the x axis .attr("transform", "translate(" + (width / 2) + " ," + (height + margin.bottom - 5 ) + ")") .style("text-anchor", "middle") .text("Date"); svg.append("g") // Add the Y Axis .attr("class", "y axis") .call(yAxis); //text label for y-axis svg.append("text") .attr("transform", "rotate(-90)") .attr("y", 0 - margin.left) .attr("x",0 - (height / 2)) //adds extra left padding as original y pos = 0 .attr("dy", "1em") .style("text-anchor", "middle") .text("Value"); //adding a title to the graph svg.append("text") .attr("x", (width / 2)) .attr("y", 0 - (margin.top / 2)) .attr("text-anchor", "middle") .style("font-size", "16px") .style("text-decoration", "underline") .text("Graph"); //draw x axis grid svg.append("g") .attr("class", "grid") .attr("transform", "translate(0," + height + ")") .call(make_x_axis() .tickSize(-height, 0, 0) .tickFormat("") ) //draw y axis grid svg.append("g") .attr("class", "grid") .call(make_y_axis() .tickSize(-width, 0, 0) .tickFormat("") ) });<!--d3.csv close--> Thanks in advance!
The easiest way to add a tooltip is to append an svg:title element to the elements you want to have a tooltip for. It will be displayed by the browser automatically when you hover over the element. It works for all kinds of elements as well. So your code would need to look something like var path = svg.append("path") // Add the valueline path. .attr("class", "line") .attr("d", valueline(data)) .attr("stroke", "steelblue") .attr("stroke-width", "5") .attr("fill", "none") .append("title").text("whatever"); If you need more sophisticated functionality, you could try for example tipsy, which works in a similar way.