Adding tooltips to line graph data points AFTER lines animate - javascript
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.
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]}) };
d3js scatter plot auto update doesnt work
Need some help figuring out how to auto update 3djs scatter plot. The code looks fine ,however, when the update function is running the graph gets updated but the scatter plot remains at place. I'm using svg.selectAll(".dot").remove() in order to remove the outdated ones but unable to find a way to added them back. I found a few solutions online but none of them worked for my code. Any help would be much appreciated. thanks DB structure: dtg | temperature 2016-03-02 09:14:00 23 2016-03-02 09:10:00 22 Code: <script> // Set the dimensions of the canvas / graph var margin = {top: 30, right: 20, bottom: 30, left: 40}, width = 400 - margin.left - margin.right, height = 200 - margin.top - margin.bottom; // Parse the date / time var parseDate = d3.time.format("%Y-%m-%d %H:%M:%S").parse; var formatTime = d3.time.format("%e %B %X"); // Set the ranges var x = d3.time.scale().range([0, width]); var y = d3.scale.linear().range([height, 0]); // Define the axes var xAxis = d3.svg.axis().scale(x) .orient("bottom").ticks(5); var yAxis = d3.svg.axis().scale(y) .orient("left").ticks(5); // Define the line var valueline = d3.svg.line() .x(function(d) { return x(d.dtg); }) .y(function(d) { return y(d.temperature); }); var div = d3.select("#chart1").append("div") .attr("class", "tooltip") .style("opacity", 0); // Adds the svg canvas var svg = d3.select("#chart1") .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 + ")"); function make_x_axis() { return d3.svg.axis() .scale(x) .orient("bottom") .ticks(10) } function make_y_axis() { return d3.svg.axis() .scale(y) .orient("left") .ticks(10) } // Get the data d3.json("2301data.php", function(error, data) { data.forEach(function(d) { d.dtg = parseDate(d.dtg); d.temperature = +d.temperature; }); // Scale the range of the data x.domain(d3.extent(data, function(d) { return d.dtg; })); y.domain([0, 60]); // // y.domain([0, d3.max(data, function(d) { return d.temperature; })]); // Add the valueline path. svg.append("path") .attr("class", "line") .attr("d", valueline(data)); // draw the scatterplot svg.selectAll(".dot") .data(data) .enter().append("circle") .attr("class", "dot") .filter(function(d) { return d.temperature > 30 }) .style("fill", "red") .attr("r", 3.5) .attr("cx", function(d) { return x(d.dtg); }) .attr("cy", function(d) { return y(d.temperature); }) // Tooltip stuff after this .on("mouseover", function(d) { div.transition() .duration(500) .style("opacity", 0); div.transition() .duration(200) .style("opacity", .9); div .html( d.temperature + "C" + "<br>" + formatTime(d.dtg)) .style("left", (d3.event.pageX + 8) + "px") .style("top", (d3.event.pageY - 18) + "px");}) .on("mouseout", function(d) { div.transition() .duration(500) .style("opacity", 0); }); // Add the X Axis svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .style("font-size", "14px") .call(xAxis); // Add the Y Axis svg.append("g") .attr("class", "y axis") .style("font-size", "14px") .call(yAxis); // Draw the grid 1 svg.append("g") .attr("class", "grid") .attr("transform", "translate(0," + height + ")") .call(make_x_axis() .tickSize(-height, 0, 0) .tickFormat("") ) // Draw the grid 2 svg.append("g") .attr("class", "grid") .call(make_y_axis() .tickSize(-width, 0, 0) .tickFormat("") ) // Addon 3 // text label for the graph svg.append("text") .attr("x", (width / 2)) .attr("y", 0 - (margin.top / 2)) .attr("text-anchor", "middle") .style("font-size", "14px") .style("text-decoration", "underline") .style('fill', 'white') //.attr("class", "shadow") // using text css .text("2301 Temperature read in the past 24h\n"); }); var inter = setInterval(function() { updateData(); }, 5000); // ** Update data section (Called from the onclick) function updateData() { // Get the data again d3.json("2301data.php", function(error, data) { data.forEach(function(d) { d.dtg = parseDate(d.dtg); d.temperature = +d.temperature; //d.hum = +d.hum; // Addon 9 part 3 }); // Scale the range of the data again x.domain(d3.extent(data, function(d) { return d.dtg; })); y.domain([0, 60]); var svg = d3.select("#chart1").transition(); // Make the changes svg.selectAll(".dot").remove(); //remove old dots svg.select(".line").duration(750).attr("d", valueline(data)); svg.select("x.axis").duration(750).call(xAxis); svg.select("y.axis").duration(750).call(yAxis); //update the scatterplot svg.selectAll(".dotUpdate") .data(data) .attr("class", "dotUpdate") .enter().append("circle") .filter(function(d) { return d.temperature > 30 }) .style("fill", "red") .attr("r", 3.5) .attr("cx", function(d) { return x(d.dtg); }) .attr("cy", function(d) { return y(d.temperature); }); }); } </script>
The first thing I did wrong was using the wrong d3js.. the following line has to be replaced <script src="http://d3js.org/d3.v3.min.js"></script> With the following or else svg.selectAll would not work. <script type="text/javascript" src="http://d3js.org/d3.v3.js"></script> Now, as far as the scatter plots update goes. I'm now using the code below which works fine with some databases. In my case it still does not work well and I'll be posting it as a sepearte question as stakoverflow guidlines requsts.. // ** Update data section (Called from the onclick) function updateData() { // Get the data again data = d3.json("2301data.php", function(error, data) { data.forEach(function(d) { d.dtg = parseDate(d.dtg); d.temperature = +d.temperature; // d.hum = +d.hum; // Addon 9 part 3 }); // Scale the range of the data again x.domain(d3.extent(data, function(d) { return d.dtg; })); y.domain([0, 60]); // Addon 9 part 4 var svg = d3.select("#chart1") var circle = svg.selectAll("circle").data(data) svg.select(".x.axis") // change the x axis .transition() .duration(750) .call(xAxis); svg.select(".y.axis") // change the y axis .transition() .duration(750) .call(yAxis); svg.select(".line") // change the line .transition() .duration(750) .attr("d", valueline(data)); circle.transition() .duration(750) .attr("cx", function(d) { return x(d.dtg); }) // enter new circles circle.enter() .append("circle") .filter(function(d) { return d.temperature > 30 }) .style("fill", "red") .attr("r", 3.5) .attr("cx", function(d) { return x(d.dtg); }) // remove old circles circle.exit().remove() }); }
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!
Animate lines in a line graph with D3.js
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.