D3 X-Value Mouseover Multiple Line Chart - d3.js
I am trying to create a X-value mouseoever event for all the valuelines in my line chart. However, I couldn't get each line highlighted and right now I have only one line with mouseover effect.
I would like to create a combination of this(http://bl.ocks.org/mbostock/8033015) and this (http://bl.ocks.org/mbostock/3902569). I have been struggling with this for days, any help would be greatly appreciated!!!
Here is my original code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv="Content-Language" content="en">
<title>Energy Production in California</title>
<style>
body { font: 14px avenir next;}
path {
stroke: #e5e5e5;
stroke-width: ;
fill: none;
}
.axis path,
.axis line {
fill: none;
stroke: grey;
stroke-width: 1;
shape-rendering: crispEdges;
}
/*.sources {
font-size:14px;
fill:#e5e5e5;
}
.sources:hover {
/* font-size:18px;*/
font-weight: 800;
fill:#853b62;
}*/
/*.graph-svg-component {
background-color:#e1e1e1;
}*/
div {
padding: 15px;
width:800px;
margin-left:auto;
margin-right:auto;
border:10px ;
}
.overlay {
fill: none;
pointer-events: all;
}
.focus circle {
fill: steelblue;
stroke: steelblue;
}
.line {
stroke: #e5e5e5;
/* stroke:white;*/
}
.line:hover {
stroke: #e769ab ;
stroke-width:2;
}
</style>
</head>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<div>
<script>
var margin = {top: 50, right: 140, bottom: 50, left: 80},
width = 1000 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom;
var parseDate = d3.time.format("%Y").parse,
bisectDate = d3.bisector(function(d) { return d.date; }).left,
formatValue = d3.format(",.2f");
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
var xAxis = d3.svg.axis().scale(x)
.orient("bottom").ticks(15);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(10);
var voronoi = d3.geom.voronoi()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.total_hydroelectric); })
.clipExtent([[-margin.left, -margin.top], [width + margin.right, height + margin.bottom]]);
// var valueline1 = d3.svg.line()
// .x(function(d) { return x(d.date); })
// .y(function(d) { return y(d.california_energy_production); });
var valueline2 = d3.svg.line()
// .interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.total_hydroelectric); });
var valueline3 = d3.svg.line()
// .interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.nuclear); });
var valueline4 = d3.svg.line()
// .interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.in_state_coal); });
var valueline5 = d3.svg.line()
// .interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.oil); });
var valueline6 = d3.svg.line()
// .interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.natural_gas ); });
var valueline7 = d3.svg.line()
// .interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.geothermal ); });
var valueline8 = d3.svg.line()
// .interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.biomass ); });
var valueline9 = d3.svg.line()
// .interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.wind ); });
var valueline10 = d3.svg.line()
// .interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.solar ); });
var valueline11 = d3.svg.line()
// .interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.other ); });
var valueline12 = d3.svg.line()
// .interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.direct_coal_imports ); });
var valueline13 = d3.svg.line()
// .interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.other_imports ); });
var svg = d3.select("body")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.attr("class", "graph-svg-component")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// Get the data
d3.csv("data_3.csv", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
// d.california_energy_production = +d.california_energy_production;
d.total_hydroelectric = +d.total_hydroelectric;
d.nuclear = +d.nuclear;
d.in_state_coal = +d.in_state_coal;
d.oil = +d.oil;
d.natural_gas = +d.natural_gas;
d.geothermal = +d.geothermal;
d.biomass = +d.biomass;
d.wind = +d.wind;
d.solar = +d.solar;
d.other = +d.other;
d.direct_coal_imports = +d.direct_coal_imports;
d.other_imports = +d.other_imports;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return Math.max( d.total_hydroelectric, d.nuclear,d.in_state_coal, d.oil, d.natural_gas, d.geothermal, d.biomass, d.wind, d.solar, d.other, d.direct_coal_imports, d.other_imports); })]);
// Add the valueline path.
// svg.append("path")
// .attr("class", "line")
// .attr("d", valueline1(data));
svg.append("path")
.attr("class", "line")
.attr("d", valueline2(data));
svg.append("path")
.attr("class", "line")
.attr("d", valueline3(data));
svg.append("path")
.attr("class", "line")
.attr("d", valueline4(data));
svg.append("path")
.attr("class", "line")
.attr("d", valueline5(data));
svg.append("path")
.attr("class", "line")
.attr("d", valueline6(data));
svg.append("path")
.attr("class", "line")
.attr("d", valueline7(data));
svg.append("path")
.attr("class", "line")
.attr("d", valueline8(data));
svg.append("path")
.attr("class", "line")
.attr("d", valueline9(data));
svg.append("path")
.attr("class", "line")
.attr("d", valueline10(data));
svg.append("path")
.attr("class", "line")
.attr("d", valueline11(data));
svg.append("path")
.attr("class", "line")
.attr("d", valueline12(data));
svg.append("path")
.attr("class", "line")
.attr("d", valueline13(data));
svg.append("g") // Add the X Axis
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g") // Add the Y Axis
.attr("class", "y axis")
.call(yAxis);
var focus = svg.append("g")
.attr("class", "focus")
.style("display", "none");
focus.append("circle")
.attr("r", 4.5);
focus.append("text")
.attr("x", 9)
.attr("dy", ".35em");
svg.append("rect")
.attr("class", "overlay")
.attr("width", width)
.attr("height", height)
.on("mouseover", function() { focus.style("display", null); })
.on("mouseout", function() { focus.style("display", "none"); })
.on("mousemove", mousemove);
function mousemove() {
var x0 = x.invert(d3.mouse(this)[0]),
i = bisectDate(data, x0, 1),
d0 = data[i - 1],
d1 = data[i],
d = x0 - d0.date > d1.date - x0 ? d1 : d0;
focus.attr("transform", "translate(" + x(d.date) + "," + y(d.total_hydroelectric) + ")");
focus.select("text").text(d.total_hydroelectric + " Gigawatt/Hours");
};
svg.append("text")
// .attr("class", "sources")
.attr("transform", "translate(" + (width+3) + "," + y(data[30].total_hydroelectric) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "#898989")
.text("Total Hydroelectric");
svg.append("text")
.attr("transform", "translate(" + (width+3) + "," + y(data[30].nuclear) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "#898989")
.text("Nuclear");
svg.append("text")
.attr("transform", "translate(" + (width+3) + "," + y(data[30].in_state_coal) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "#898989")
.text("In State Coal");
svg.append("text")
.attr("transform", "translate(" + (width+3) + "," + y(data[30].oil) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "#898989")
.text("Oil");
svg.append("text")
.attr("transform", "translate(" + (width+3) + "," + y(data[30].natural_gas) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "#898989")
.text("Natural Gas");
svg.append("text")
.attr("transform", "translate(" + (width+3) + "," + y(data[30].geothermal) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "#898989")
.text("Geotheral");
svg.append("text")
.attr("transform", "translate(" + (width+3) + "," + y(data[30].biomass) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "#898989")
.text("Biomass");
svg.append("text")
.attr("transform", "translate(" + (width+3) + "," + y(data[30].wind) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "#898989")
.text("Wind");
svg.append("text")
.attr("transform", "translate(" + (width+3) + "," + y(data[30].solar) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "#898989")
.text("Solar");
svg.append("text")
.attr("transform", "translate(" + (width+3) + "," + y(data[30].other) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "#898989")
.text("Other");
svg.append("text")
.attr("transform", "translate(" + (width+3) + "," + y(data[30].direct_coal_imports) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "#898989")
.text("Direct Coal Imports");
svg.append("text")
.attr("transform", "translate(" + (width+3) + "," + y(data[30].other_imports) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "#898989")
.text("Other Imports");
});
</script>
</div>
</body>
</html>
and here is my data.
date,california_energy_production,total_hydroelectric,nuclear,in_state_coal,oil,natural_gas,geothermal,biomass,wind,solar,other,direct_coal_imports,other_imports
1983,199609,59351,6738,563,6535,45486,7020,731,52,2,0,17001,56130
1984,211900,46880,13467,731,2632,58248,9272,1099,192,11,0,18080,61288
1985,210172,33898,18911,865,2790,69771,10957,1171,655,33,0,14112,57009
1985,211028,44478,28000,1033,3126,49260,13094,2063,1221,64,6,17588,51095
1987,220371,27140,32995,1163,2143,75437,14083,2461,1713,188,5,17544,45499
1988,232926,26692,35481,1791,8158,74221,14194,4092,1824,315,4,19243,46911
1989,238567,32742,33803,2479,9275,78916,15247,5204,2139,471,4,17223,41064
1990,252355,26092,36586,3692,4449,76082,16038,6644,2418,681,4,17710,61959
1991,242343,23244,37167,3050,523,75828,15566,7312,2669,719,0,20392,55873
1992,245535,22373,38622,3629,107,87032,16491,7362,2707,700,2,28806,37704
1993,242026,41595,36579,2549,2085,70715,15770,5760,2867,857,0,20358,42892
1994,256719,25626,38828,2655,1954,95025,15573,7173,3293,798,0,22440,43354
1995,256367,51665,36186,1136,489,78378,14267,5969,3182,793,0,16788,47514
1996,253621,47883,39753,2870,693,66711,13539,5557,3154,832,343,22590,49696
1997,230243,41400,37267,2276,143,74341,11950,5701,2739,810,896,22411,30310
1998,244577,48757,41715,2701,123,82052,12554,5266,2776,839,230,22570,24993
1999,243077,41627,40419,3602,55,84703,13251,5663,3433,838,0,22802,26685
2000,246876,42053,43533,3183,449,106878,13456,6086,3604,860,0,23877,2897
2001,267399,24988,33294,4041,379,116369,13525,5761,3242,836,38,23699,41227
2002,274444,31359,34353,4275,87,92752,13396,6196,3546,851,35,23653,63941
2003,280026,36341,35594,4269,103,94715,13329,6092,3316,759,108,23148,62253
2004,290211,34490,30241,4086,127,105358,13494,6080,4258,741,48,24504,66785
2005,289177,40263,36155,4283,148,97110,13292,6076,4084,660,24,24114,62967
2006,298454,48559,32036,4190,134,109316,13093,5861,4902,616,34,14452,65263
2007,304823,27105,35698,4217,103,120459,13029,5743,5570,668,15,14417,77799
2008,307448,24460,32482,3977,92,123036,12907,5927,5724,733,39,14463,83608
2009,299101,29220,31509,3735,67,117277,12907,6096,6249,851,20,13556,77615
2010,291310,34327,32214,3406,52,109916,12740,5960,6172,912,12,13119,72481
2011,293875,42731,36666,3120,36,91276,12685,5986,7598,1097,13,13032,79633
2012,302113,27459,18491,1580,90,121761,12733,6121,9242,1834,14,9716,93071
2013,296569,24098,17860,1018,38,120896,12485,6466,12694,4154,14,11824,85022
The key here is making the voronoi work correctly; after that it all falls into place. The way you started only used the total_hydroelectric data, but it needs to take into account all your data. The quickest way to do that, it to create a flat data structure of all the data:
var flatData = [];
data.forEach(function(d) {
d.date = parseDate(d.date);
// d.california_energy_production = +d.california_energy_production;
d.total_hydroelectric = +d.total_hydroelectric;
d.nuclear = +d.nuclear;
d.in_state_coal = +d.in_state_coal;
...
flatData.push({date: d.date, value: d.total_hydroelectric, key: "total_hydroelectric"});
flatData.push({date: d.date, value: d.nuclear, key: "nuclear"});
flatData.push({date: d.date, value: d.in_state_coal, key: "in_state_coal"});
...
});
Later:
voronoiGroup.selectAll("path")
.data(voronoi(flatData))
.enter().append("path")
.attr("d", function(d) { return "M" + d.join("L") + "Z"; })
.datum(function(d) { return d.point; })
.on("mouseover", mouseover)
.on("mouseout", mouseout);
And when you draw your lines add a class so you can find them later:
svg.append("path")
.attr("class", "line total_hydroelectric") // tag this as hydro
.attr("d", valueline2(data));
Where mouseover/mouseout then becomes:
function mouseover(d) {
d3.select("."+d.key).classed("line-hover", true);
focus.attr("transform", "translate(" + x(d.date) + "," + y(d.value) + ")");
focus.select("text").text(d.date);
}
function mouseout(d) {
d3.select("."+d.key).classed("line-hover", false);
focus.attr("transform", "translate(-100,-100)");
}
In this way then the voronoi events also take care of your x-value point hover.
Here's an example putting it together.
Related
How can I highlight a part of a grouped chart when filter d3
I start with d3 using version 3. I created a grouped bar chart that looks like this: I added a drop-down list that contains all the genders (Woman (femme), Couple...). I'm blocked because I can't highlight the bars that correspond to a certain gender when I choose from the drop-down list. I found on the internet that I could use this code: d3.select('#inds') .on("change", function () { var sect = document.getElementById("inds"); var section = sect.options[sect.selectedIndex].value; //some code here }); the "Section" part contains my selected gender I would like that when I select, for example torque, that the bars corresponding to the torque remain in color and the others are in gray. This is the all code : source : https://bl.ocks.org/hydrosquall/7966e9c8e8414ffcd8b5 Highlight : https://bl.ocks.org/bricedev/0d95074b6d83a77dc3ad var margin = {top: 20, right: 20, bottom: 30, left: 40}, width = 600, height = 250 ; var x0 = d3.scale.ordinal() .rangeRoundBands([0, width], .1); var x1 = d3.scale.ordinal(); var y = d3.scale.linear() .range([height, 0]); var color = d3.scale.ordinal() .range(["#54E868", "#54CCE8", "#6395FF", "#50FFC5"]); var xAxis = d3.svg.axis() .scale(x0) .tickSize(0) .orient("bottom"); var yAxis = d3.svg.axis() .scale(y) .orient("left") 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.csv("../CSV/GenreOrigine.csv", function(error, data) { if (error) throw error; //Couples, Famille... var genreNames = d3.keys(data[0]).filter(function(key) { return key !== "Origine"; }); data.forEach(function(d) { //Valeur pour chacune des origines par rapport au genre d.genres = genreNames.map(function(name) { return {name: name, value: +d[name]}; }); }); x0.domain(data.map(function(d) { return d.Origine; })); x1.domain(genreNames).rangeRoundBands([0, x0.rangeBand()]); y.domain([0, d3.max(data, function(d) { return d3.max(d.genres, function(d) { return d.value; }); })]); 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", 0.3) .attr("dy", ".71em") .style("text-anchor", "end") .text("Nombre de personnes"); svg.select('.y').transition().duration(500).delay(1300).style('opacity','1'); var Origine = svg.selectAll(".Origine") .data(data) .enter().append("g") .attr("class", "g") .attr("transform", function(d) { return "translate(" + x0(d.Origine) + ",0)"; }); Origine.selectAll("rect") .data(function(d) { return d.genres; }) .enter().append("rect") .attr("width", x1.rangeBand()) .attr("x", function(d) { return x1(d.name); }) .style("fill", function(d) { return color(d.name) }) .attr("y", function(d) { return y(d.value); }) .attr("height", function(d) { return height - y(d.value); }) .on("mouseover", function(d) { d3.select(this).style("fill", d3.rgb(color(d.name)).darker(2)); }) .on("mouseout", function(d) { d3.select(this).style("fill", color(d.name)); }); Origine.selectAll("rect") .transition() .delay(function (d) {return Math.random()*1000;}) .duration(1000) var legend = svg.selectAll(".legend") .data(genreNames.slice().reverse()) .enter().append("g") .attr("class", "legend") .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; }); legend.append("rect") .attr("x", width - 18) .attr("width", 18) .attr("height", 18) .style("fill", color); legend.append("text") .attr("x", width - 24) .attr("y", 9) .attr("dy", ".35em") .style("text-anchor", "end") .text(function(d) { return d; }); d3.select('#inds') .on("change", function () { var sect = document.getElementById("inds"); var section = sect.options[sect.selectedIndex].value; //some code here }); });
You can select all the rect in the SVG and filter them in the function, so the code would look like: var sect = document.getElementById('inds'); var section = sect.options[sect.selectedIndex].value; if(section !== '') { d3.selectAll("rect") .attr('opacity', function(d) { if(d.name !== section) { return 0.2; } else { return 1; } }) } else { d3.selectAll('rect') .attr('opacity', 1) } In the example above, I changed the opacity attribute, but you can change fill with the same approach.
Rotate label text of bar chart by 90deg
How to rotate text of label of barchart in d3.js? I tried using .attr("transform", "rotate(-90)") but it rotates the entire column. csv file: date,value 2013-01,53 2013-02,165 2013-03,269 2013-04,344 2013-05,376 2013-06,410 2013-07,421 2013-08,405 2013-09,376 2013-10,359 2013-11,392 2013-12,433 2014-01,455 2014-02,478 code: <!DOCTYPE html> <html> <head> <script data-require="d3#4.0.0" data-semver="4.0.0" src="https://d3js.org/d3.v4.min.js"></script> </head> <body> <script> // Code goes here var margin = {top: 20, right: 20, bottom: 70, left: 40}, width = 600 - margin.left - margin.right, height = 300 - margin.top - margin.bottom; padding = -60; // space around the chart, not including labels // Parse the date / time var parseDate = d3.timeParse("%Y-%m"); var x = d3.scaleBand().rangeRound([0, width]).paddingInner(0.05); var y = d3.scaleLinear().range([height, 0]); var xAxis = d3.axisBottom(x) .tickFormat(d3.timeFormat("%Y-%m")); var yAxis = d3.axisLeft(y) .ticks(10); 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.csv("bar-data.csv", function(error, data) { data.forEach(function(d) { d.date = parseDate(d.date); d.value = +d.value; }); x.domain(data.map(function(d) { return d.date; })); y.domain([0, d3.max(data, function(d) { return d.value; })]); 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) .append("text") .attr("transform", "rotate(-90)") .attr("y", 6) .attr("dy", ".71em") .style("text-anchor", "end") .text("Value ($)"); svg.selectAll("bar") .data(data) .enter().append("rect") .style("fill", "steelblue") .attr("x", function(d) { return x(d.date); }) .attr("width", x.bandwidth()) .attr("y", function(d) { return y(d.value); }) .attr("height", function(d) { return height - y(d.value); }); svg.selectAll(".text") .data(data) .enter() .append("text") //.attr("transform", "rotate(-90)") .attr("x", (function(d) { return x(d.date); } )) .attr("width", x.bandwidth()) .attr("y", function(d) { return y(d.value); }) .attr("dy", ".75em") .text(function(d) { return d.value; }); svg.selectAll("text") .data(data) .enter() .append("text") .text(function(d) { return d.value; }) .attr("text-anchor", "middle") .attr("fill", "white") .attr("x", function(d, i) { return i * (width / data.length); }) .attr("y", function(d) { return height - (d * 4); }); }); // now add titles to the axes svg.append("text") .attr("text-anchor", "middle") // this makes it easy to centre the text as the transform is applied to the anchor .attr("transform", "translate("+ (padding/2) +","+(height/2)+")rotate(-90)") // text is drawn off the screen top left, move down and out and rotate .text("Value"); svg.append("text") .attr("text-anchor", "middle") // this makes it easy to centre the text as the transform is applied to the anchor .attr("transform", "translate("+ (width/2) +","+(height-(padding))+")") // centre below axis .text("Date"); </script> </body> </html>
What you see is actually the expected behaviour, since the rotate function of the transform attribute rotates all the elements around their origins, not around their centres. The easiest solution is passing the optional x and y arguments to rotate: .attr("transform", function(d) { return "rotate(-90," + x(d.date) + "," + y(d.value) + ")"; //x and y here ------------^------------------^ }) Here is your code with that change: <!DOCTYPE html> <html> <head> <script data-require="d3#4.0.0" data-semver="4.0.0" src="https://d3js.org/d3.v4.min.js"></script> </head> <body> <script> // Code goes here var csv = `date,value 2013-01,53 2013-02,165 2013-03,269 2013-04,344 2013-05,376 2013-06,410 2013-07,421 2013-08,405 2013-09,376 2013-10,359 2013-11,392 2013-12,433 2014-01,455 2014-02,478`; var margin = { top: 20, right: 20, bottom: 70, left: 40 }, width = 600 - margin.left - margin.right, height = 300 - margin.top - margin.bottom; padding = -60; // space around the chart, not including labels // Parse the date / time var parseDate = d3.timeParse("%Y-%m"); var x = d3.scaleBand().rangeRound([0, width]).paddingInner(0.05); var y = d3.scaleLinear().range([height, 0]); var xAxis = d3.axisBottom(x) .tickFormat(d3.timeFormat("%Y-%m")); var yAxis = d3.axisLeft(y) .ticks(10); 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 + ")"); var data = d3.csvParse(csv); data.forEach(function(d) { d.date = parseDate(d.date); d.value = +d.value; }); x.domain(data.map(function(d) { return d.date; })); y.domain([0, d3.max(data, function(d) { return d.value; })]); 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) .append("text") .attr("transform", "rotate(-90)") .attr("y", 6) .attr("dy", ".71em") .style("text-anchor", "end") .text("Value ($)"); svg.selectAll("bar") .data(data) .enter().append("rect") .style("fill", "steelblue") .attr("x", function(d) { return x(d.date); }) .attr("width", x.bandwidth()) .attr("y", function(d) { return y(d.value); }) .attr("height", function(d) { return height - y(d.value); }); svg.selectAll(".text") .data(data) .enter() .append("text") .attr("transform", function(d) { return "rotate(-90," + x(d.date) + "," + y(d.value) + ")"; }) .attr("x", (function(d) { return x(d.date); })) .attr("width", x.bandwidth()) .attr("y", function(d) { return y(d.value); }) .attr("dy", "1.3em") .attr("dx", "0.2em") .text(function(d) { return d.value; }); svg.selectAll("text") .data(data) .enter() .append("text") .text(function(d) { return d.value; }) .attr("text-anchor", "middle") .attr("fill", "white") .attr("x", function(d, i) { return i * (width / data.length); }) .attr("y", function(d) { return height - (d * 4); }); // now add titles to the axes svg.append("text") .attr("text-anchor", "middle") // this makes it easy to centre the text as the transform is applied to the anchor .attr("transform", "translate(" + (padding / 2) + "," + (height / 2) + ")rotate(-90)") // text is drawn off the screen top left, move down and out and rotate .text("Value"); svg.append("text") .attr("text-anchor", "middle") // this makes it easy to centre the text as the transform is applied to the anchor .attr("transform", "translate(" + (width / 2) + "," + (height - (padding)) + ")") // centre below axis .text("Date"); </script> </body> </html>
d3 brushing and mouse move coexist
im trying to update http://bl.ocks.org/d3noob/6eb506b129f585ce5c8a and add brushing into it(brushing displayed under the line graph) to make it look like https://www.google.com.hk/#q=s%26p+500 added coded to the first link: var brush = d3.svg.brush() .x(x) .on("brush", brushmove) .on("brushend", brushend); svg.append("g") .attr("class", "brush") .call(brush) .selectAll('rect') .attr('height', height); function brushmove() { var extent = brush.extent(); } function brushend() { x.domain(brush.extent()) console.log(brush.extent()); } The problem is that once i add brushing into it, there's a background formed behind the graph and i can't perform mouse events(mousemove) anymore. Is there a way to fix it to make it look like google? 1) brushing and mouse event coexist 2) brushing area under the curve var csv = date,close1, close2 26-Mar-12,606.98,58.13 27-Mar-12,614.48,53.98 28-Mar-12,617.62,67.00 29-Mar-12,609.86,89.70 30-Mar-12,599.55,99.00 2-Apr-12,618.63,130.28 3-Apr-12,629.32,166.70 4-Apr-12,624.31,234.98 5-Apr-12,633.68,345.44 9-Apr-12,636.23,443.34 10-Apr-12,628.44,543.70 11-Apr-12,626.20,580.13 12-Apr-12,622.77,605.23 13-Apr-12,605.23,626.20 16-Apr-12,580.13,628.44 17-Apr-12,543.70,636.23 18-Apr-12,443.34,633.68 19-Apr-12,345.44,624.31 20-Apr-12,234.98,629.32 23-Apr-12,166.70,618.63 24-Apr-12,130.28,599.55 25-Apr-12,99.00,609.86 26-Apr-12,89.70,617.62 27-Apr-12,67.00,614.48 30-Apr-12,53.98,606.98 1-May-12,58.13,503.15
Both the example you link to and the brush add a rect on top of the plot to capture mouse events. The key to making them coexist is to add the brush (and allow it to create its rect) and then use that rect to add the tooltip events. This way you only end up with one point-events rect: // add a g for the brush var context = svg.append("g"); // add the brush context.call(brush); // grab the brush's rect and add the tooltip events context.select(".background") .on("mouseover", function() { focus.style("display", null); }) .on("mouseout", function() { focus.style("display", "none"); }) .on("mousemove", mousemove); Full code: <!DOCTYPE html> <meta charset="utf-8"> <style> /* set the CSS */ body { font: 12px Arial; } path { stroke: steelblue; stroke-width: 2; fill: none; } .axis path, .axis line { fill: none; stroke: grey; stroke-width: 1; shape-rendering: crispEdges; } .extent { stroke: #fff; fill-opacity: .125; shape-rendering: crispEdges; } </style> <body> <!-- load the d3.js library --> <script src="http://d3js.org/d3.v3.min.js"></script> <script> // Set the dimensions of the canvas / graph var margin = { top: 30, right: 20, bottom: 30, left: 50 }, width = 600 - margin.left - margin.right, height = 270 - margin.top - margin.bottom; // Parse the date / time var parseDate = d3.time.format("%d-%b-%y").parse, formatDate = d3.time.format("%d-%b"), bisectDate = d3.bisector(function(d) { return d.date; }).left; // 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.date); }) .y(function(d) { return y(d.close); }); var area = d3.svg.area() .x(function(d) { return x(d.date); }) .y0(height) .y1(function(d) { return y(d.close); }); // Adds the svg canvas 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 + ")"); var defs = svg.append("defs"); var areaClip = defs.append("clipPath") .attr("id", "areaClip") .append("rect") .attr("x", width) .attr("y", 0) .attr("width", width) .attr("height", height); var lineSvg = svg.append("g"); var focus = svg.append("g") .style("display", "none"); var brush = d3.svg.brush() .x(x) .on("brush", function() { var s = brush.extent(), x1 = x(s[0]), x2 = x(s[1]); areaClip.attr('x', x1); areaClip.attr('width', x2 - x1); }) var csv = `date,close 26-Mar-12,606.98 27-Mar-12,614.48 28-Mar-12,617.62 29-Mar-12,609.86 30-Mar-12,599.55 2-Apr-12,618.63 3-Apr-12,629.32 4-Apr-12,624.31 5-Apr-12,633.68 9-Apr-12,636.23 10-Apr-12,628.44 11-Apr-12,626.20 12-Apr-12,622.77 13-Apr-12,605.23 16-Apr-12,580.13 17-Apr-12,543.70 18-Apr-12,443.34 19-Apr-12,345.44 20-Apr-12,234.98 23-Apr-12,166.70 24-Apr-12,130.28 25-Apr-12,99.00 26-Apr-12,89.70 27-Apr-12,67.00 30-Apr-12,53.98 1-May-12,58.13`; var data = d3.csv.parse(csv); data.forEach(function(d) { d.date = parseDate(d.date); d.close = +d.close; }); // Scale the range of the data x.domain(d3.extent(data, function(d) { return d.date; })); y.domain([0, d3.max(data, function(d) { return d.close+20; })]); // Add the valueline path. lineSvg.append("path") .attr("class", "line") .attr("d", valueline(data)); lineSvg.append("path") .attr("d", area(data)) .style("fill", "steelblue") .style("stroke", "none") .style("opacity", "0.5") .attr("clip-path", "url(#areaClip)") // Add the X Axis svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis); // Add the Y Axis svg.append("g") .attr("class", "y axis") .call(yAxis); // append the x line focus.append("line") .attr("class", "x") .style("stroke", "blue") .style("stroke-dasharray", "3,3") .style("opacity", 0.5) .attr("y1", 0) .attr("y2", height); // append the y line focus.append("line") .attr("class", "y") .style("stroke", "blue") .style("stroke-dasharray", "3,3") .style("opacity", 0.5) .attr("x1", width) .attr("x2", width); // append the circle at the intersection focus.append("circle") .attr("class", "y") .style("fill", "none") .style("stroke", "blue") .attr("r", 4); // place the value at the intersection focus.append("text") .attr("class", "y1") .style("stroke", "white") .style("stroke-width", "3.5px") .style("opacity", 0.8) .attr("dx", 8) .attr("dy", "-.3em"); focus.append("text") .attr("class", "y2") .attr("dx", 8) .attr("dy", "-.3em"); // place the date at the intersection focus.append("text") .attr("class", "y3") .style("stroke", "white") .style("stroke-width", "3.5px") .style("opacity", 0.8) .attr("dx", 8) .attr("dy", "1em"); focus.append("text") .attr("class", "y4") .attr("dx", 8) .attr("dy", "1em"); // append the rectangle to capture mouse var context = svg.append("g"); context.call(brush); context.selectAll(".resize").append("path") .attr("d", "M0,2V" + (height - 2)) .style("stroke", "black") context.select(".extent") .attr("height", height - 2) .attr("fill", "none"); context.select(".background") .attr("height", height) .on("mouseover.tooltip", function() { focus.style("display", null); }) .on("mouseout.tooltip", function() { focus.style("display", "none"); }) .on("mousemove.tooltip", mousemove); function mousemove() { var x0 = x.invert(d3.mouse(this)[0]), i = bisectDate(data, x0, 1), d0 = data[i - 1], d1 = data[i], d = x0 - d0.date > d1.date - x0 ? d1 : d0; focus.select("circle.y") .attr("transform", "translate(" + x(d.date) + "," + y(d.close) + ")"); focus.select("text.y1") .attr("transform", "translate(" + x(d.date) + "," + y(d.close) + ")") .text(d.close); focus.select("text.y2") .attr("transform", "translate(" + x(d.date) + "," + y(d.close) + ")") .text(d.close); focus.select("text.y3") .attr("transform", "translate(" + x(d.date) + "," + y(d.close) + ")") .text(formatDate(d.date)); focus.select("text.y4") .attr("transform", "translate(" + x(d.date) + "," + y(d.close) + ")") .text(formatDate(d.date)); focus.select(".x") .attr("transform", "translate(" + x(d.date) + "," + y(d.close) + ")") .attr("y2", height - y(d.close)); focus.select(".y") .attr("transform", "translate(" + width * -1 + "," + y(d.close) + ")") .attr("x2", width + width); } </script> </body>
D3 toggle stacked to grouped on multiple bar charts
I'm trying to run multiple "stacked-to-grouped" d3 bar charts on one page. I can get the charts to render, but have not been successful in getting the two charts to toggle between the options in unison. I'm guessing that this might have to do with calling the "change" function more than once (since I'm calling it in the rendering of both charts), but I'm not sure how to place it outside of the charts and enable it to have access to what it needs. Thought it might have something to do with "each", but I'm not sure. Here's a link to the jsfiddle that I've created: http://jsfiddle.net/1amsknh2/ And here's the js for the charts: $( document ).ready(function() { chart1(); }); function chart1(){ var stack = d3.layout.stack(), layers = [ [ {"x":0,"y":1.5,"y0":0,"name":"cat1","color":"#B7A4DB"}, {"x":1,"y":1.5,"y0":0,"name":"cat2","color":"#B7A4DB"}, {"x":2,"y":1.5,"y0":0,"name":"cat3","color":"#B7A4DB"} ], [ {"x":0,"y":2.5,"y0":1.5,"name":"cat1","color":"#85E6B5"}, {"x":1,"y":1.5,"y0":1.5,"name":"cat2","color":"#85E6B5"}, {"x":2,"y":1.0,"y0":1.5,"name":"cat3","color":"#85E6B5"} ] ]; n = 2, // number of layers m = layers.length, // number of samples per layer mb = ['cat1', 'cat2', 'cat3'] yGroupMax = d3.max(layers, function(layer) { return d3.max(layer, function(d) { return d.y; }); }), yStackMax = d3.max(layers, function(layer) { return d3.max(layer, function(d) { return d.y0 + d.y; }); }); var margin = {top: 40, right: 10, bottom: 20, left: 40}, width = 400 - margin.left - margin.right, height = 300 - margin.top - margin.bottom; var x = d3.scale.ordinal() .domain(mb) .rangeRoundBands([0, width], .08); var y = d3.scale.linear() .domain([0, yStackMax]) .range([height, 0]); var xAxis = d3.svg.axis() .scale(x) .tickSize(0) .tickPadding(6) .orient("bottom"); var yAxis = d3.svg.axis() .scale(y) .orient("left") .tickFormat(d3.format(".2s")); 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 + ")"); var layer = svg.selectAll(".layer") .data(layers) .enter().append("g") .attr("class", "layer"); // .style("fill", function(d) { return x(d.color); }); var rect = layer.selectAll("rect") .data(function(d) { return d; }) .enter().append("rect") .attr("x", function(d) { return x(d.name); }) .attr("y", height) .attr("width", x.rangeBand()) .attr("height", 0) .style("fill", function(d) { return d.color; }); rect.transition() .delay(function(d, i) { return i * 10; }) .attr("y", function(d) { return y(d.y0 + d.y); }) .attr("height", function(d) { return y(d.y0) - y(d.y0 + d.y); }) svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis); svg.select("g") .attr("class", "y axis") .call(yAxis) .append("text") .attr("transform", "rotate(-90)") // .attr("y", 6) .attr("dy", ".71em") // .style("text-anchor", "middle") .text("Amount"); d3.selectAll("input").on("change", change); var timeout = setTimeout(function() { d3.select("input[value=\"grouped\"]").property("checked", true).each(change); }, 2000); function change() { clearTimeout(timeout); console.log(1) if (this.value === "grouped") transitionGrouped(); else transitionStacked(); svg.select("g") .attr("class", "y axis") .call(yAxis) .append("text") .attr("transform", "rotate(-90)") // .attr("y", 6) .attr("dy", ".71em") // .style("text-anchor", "middle") .text("Contribution Amount"); } function transitionGrouped() { y.domain([0, yGroupMax]); rect.transition() .duration(500) .delay(function(d, i) { return i * 10; }) .attr("x", function(d, i, j) { return x(d.name) + x.rangeBand() / n * j; }) .attr("width", x.rangeBand() / n) .transition() .attr("y", function(d) { return y(d.y); }) .attr("height", function(d) { return height - y(d.y); }); } function transitionStacked() { y.domain([0, yStackMax]); rect.transition() .duration(500) .delay(function(d, i) { return i * 10; }) .attr("y", function(d) { return y(d.y0 + d.y); }) .attr("height", function(d) { return y(d.y0) - y(d.y0 + d.y); }) .transition() .attr("x", function(d) { return x(d.name); }) .attr("width", x.rangeBand()); } chart2(); } function chart2(){ var stack = d3.layout.stack(), layers = [ [ {"x":0,"y":0.5,"y0":0,"name":"cat1","color":"#B7A4DB"}, {"x":1,"y":1.5,"y0":0,"name":"cat2","color":"#B7A4DB"}, {"x":2,"y":1.0,"y0":0,"name":"cat3","color":"#B7A4DB"} ], [ {"x":0,"y":2.5,"y0":0.5,"name":"cat1","color":"#85E6B5"}, {"x":1,"y":1.5,"y0":1.5,"name":"cat2","color":"#85E6B5"}, {"x":2,"y":1.0,"y0":1.0,"name":"cat3","color":"#85E6B5"} ] ]; n = 2, // number of layers m = layers.length, // number of samples per layer mb = ['cat1', 'cat2', 'cat3'] yGroupMax = d3.max(layers, function(layer) { return d3.max(layer, function(d) { return d.y; }); }), yStackMax = d3.max(layers, function(layer) { return d3.max(layer, function(d) { return d.y0 + d.y; }); }); var margin = {top: 40, right: 10, bottom: 20, left: 40}, width = 400 - margin.left - margin.right, height = 300 - margin.top - margin.bottom; var x = d3.scale.ordinal() .domain(mb) .rangeRoundBands([0, width], .08); var y = d3.scale.linear() .domain([0, yStackMax]) .range([height, 0]); var xAxis = d3.svg.axis() .scale(x) .tickSize(0) .tickPadding(6) .orient("bottom"); var yAxis = d3.svg.axis() .scale(y) .orient("left") .tickFormat(d3.format(".2s")); var svg = d3.select("#chart2").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 + ")"); var layer = svg.selectAll(".layer") .data(layers) .enter().append("g") .attr("class", "layer"); var rect = layer.selectAll("rect") .data(function(d) { return d; }) .enter().append("rect") .attr("x", function(d) { return x(d.name); }) .attr("y", height) .attr("width", x.rangeBand()) .attr("height", 0) .style("fill", function(d) { return d.color; }); rect.transition() .delay(function(d, i) { return i * 10; }) .attr("y", function(d) { return y(d.y0 + d.y); }) .attr("height", function(d) { return y(d.y0) - y(d.y0 + d.y); }) svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis); svg.select("g") .attr("class", "y axis") .call(yAxis) .append("text") .attr("transform", "rotate(-90)") // .attr("y", 6) .attr("dy", ".71em") // .style("text-anchor", "middle") .text("Contribution Amount"); d3.selectAll("input").on("change", change); function change() { console.log(2); if (this.value === "grouped") transitionGrouped(); else transitionStacked(); svg.select("g") .attr("class", "y axis") .call(yAxis) .append("text") .attr("transform", "rotate(-90)") // .attr("y", 6) .attr("dy", ".71em") // .style("text-anchor", "middle") .text("Amount"); } function transitionGrouped() { y.domain([0, yGroupMax]); rect.transition() .duration(500) .delay(function(d, i) { return i * 10; }) .attr("x", function(d, i, j) { return x(d.name) + x.rangeBand() / n * j; }) .attr("width", x.rangeBand() / n) .transition() .attr("y", function(d) { return y(d.y); }) .attr("height", function(d) { return height - y(d.y); }); } function transitionStacked() { y.domain([0, yStackMax]); rect.transition() .duration(500) .delay(function(d, i) { return i * 10; }) .attr("y", function(d) { return y(d.y0 + d.y); }) .attr("height", function(d) { return y(d.y0) - y(d.y0 + d.y); }) .transition() .attr("x", function(d) { return x(d.name); }) .attr("width", x.rangeBand()); } }
After struggling here and there, finally I made one fiddle for you.check it once.I hope you are looking for this http://jsfiddle.net/jxbyf82u/ In this fiddle Observe these line d3.selectAll("input").on("change", change1); chart1.change1 = change1; and I'm calling this function from chart2()'s change() function by passing input value i.e. like below chart1.change1(this.value); If it is not what you are looking for, then ask what you want.Okay
d3.js line chart with negative numbers
I have a working d3.js line chart that renders linear numbers: http://jsfiddle.net/2g9VQ/ var probArray = ["1.0", "0.999999931839", "0.999816434171", "0.994147880224", "0.961785353466", "0.882923015661", "0.763731336472", "0.627901360001", "0.497594590727", "0.385100568858", "0.256161790111", "0.168894610653", "0.111773057", "0.0747467808441", "0.051065424573", "0.0355360834346", "0.0251527408762", "0.018097770"]; var imlArray = ["2.0", "4.0", "6.0", "8.0", "10.0", "12.0", "14.0", "16.0", "18.0", "20.0", "23.0", "26.0", "29.0", "32.0", "35.0", "38.0", "41.0", "44.0", "47.0", "50.0", "55.0", "60.0", "65.0", "70.0", "75.0", "80.0", "85.0", "90.0", "95.0", "100.0", "110.0", "120.0", "130.0", "140.0", "150.0", "160.0", "170.0", "180.0", "190.0", "200.0", "220.0", "240.0", "260.0", "280.0", "300.0"]; function log(n) { return Math.log(n) / Math.LN10; } var data = []; for(i=0; i<probArray.length; i++) { // without log values... data.push([parseFloat(imlArray[i]), parseFloat(probArray[i])]); // with log valuse... //data.push([log(parseFloat(imlArray[i])), log(parseFloat(probArray[i]))]); } console.log(data); var margin = {top: 20, right: 20, bottom: 50, left: 50}, width = 400 - margin.left - margin.right, height = 320 - margin.top - margin.bottom; var x = d3.time.scale().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() .x(function(d) { return x(d.x); }) .y(function(d) { return y(d.y); }); var svg = d3.select("#dialog").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 + ")"); var dataCallback = function(d) { d.x = +d[0]; d.y = +d[1]; }; data.forEach(dataCallback); x.domain(d3.extent(data, function(d) { return d.x; })); y.domain([0, d3.max(data, function(d) { return d.y; })]); svg.append("path") .data([data]) .attr("class", "line") .attr("d", line); svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis) .append("text") .attr("x", 160) .attr("y", 30) .attr("dy", ".71em") .style("text-anchor", "end") .text("Intensity measure type"); svg.append("g") .attr("class", "y axis") .call(yAxis) .append("text") .attr("transform", "rotate(-90)") .attr("y", -50) .attr("dy", ".71em") .style("text-anchor", "end") .text("Probabability of exceedance in "+invest_time+" years"); var legend = d3.select("#dialog").append("svg"); legend.append("text") .attr("x", 20) .attr("y", 7) .attr("dy", ".35em") .text("Location (Lon/Lat): "+lng+", "+lat); d3.select('#chart').on("click", function() { data.splice(0,1); data.push([5,5]); dataCallback(data[data.length - 1]); x.domain(d3.extent(data, function(d) { return d.x; })); y.domain([0, d3.max(data, function(d) { return d.y; })]); svg.selectAll("path").data([data]) .attr("d", line); }); But the chart fails to render when I change the points to a logarithmic scale: http://jsfiddle.net/Z3Yms/ var probArray = ["1.0", "0.999999931839", "0.999816434171", "0.994147880224", "0.961785353466", "0.882923015661", "0.763731336472", "0.627901360001", "0.497594590727", "0.385100568858", "0.256161790111", "0.168894610653", "0.111773057", "0.0747467808441", "0.051065424573", "0.0355360834346", "0.0251527408762", "0.018097770"]; var imlArray = ["2.0", "4.0", "6.0", "8.0", "10.0", "12.0", "14.0", "16.0", "18.0", "20.0", "23.0", "26.0", "29.0", "32.0", "35.0", "38.0", "41.0", "44.0", "47.0", "50.0", "55.0", "60.0", "65.0", "70.0", "75.0", "80.0", "85.0", "90.0", "95.0", "100.0", "110.0", "120.0", "130.0", "140.0", "150.0", "160.0", "170.0", "180.0", "190.0", "200.0", "220.0", "240.0", "260.0", "280.0", "300.0"]; function log(n) { return Math.log(n) / Math.LN10; } var data = []; for(i=0; i<probArray.length; i++) { // without log values... //data.push([parseFloat(imlArray[i]), parseFloat(probArray[i])]); // with log valuse... data.push([log(parseFloat(imlArray[i])), log(parseFloat(probArray[i]))]); } console.log(data); var margin = {top: 20, right: 20, bottom: 50, left: 50}, width = 400 - margin.left - margin.right, height = 320 - margin.top - margin.bottom; var x = d3.time.scale().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() .x(function(d) { return x(d.x); }) .y(function(d) { return y(d.y); }); var svg = d3.select("#dialog").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 + ")"); var dataCallback = function(d) { d.x = +d[0]; d.y = +d[1]; }; data.forEach(dataCallback); x.domain(d3.extent(data, function(d) { return d.x; })); y.domain([0, d3.max(data, function(d) { return d.y; })]); svg.append("path") .data([data]) .attr("class", "line") .attr("d", line); svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis) .append("text") .attr("x", 160) .attr("y", 30) .attr("dy", ".71em") .style("text-anchor", "end") .text("Intensity measure type"); svg.append("g") .attr("class", "y axis") .call(yAxis) .append("text") .attr("transform", "rotate(-90)") .attr("y", -50) .attr("dy", ".71em") .style("text-anchor", "end") .text("Probabability of exceedance in "+invest_time+" years"); var legend = d3.select("#dialog").append("svg"); legend.append("text") .attr("x", 20) .attr("y", 7) .attr("dy", ".35em") .text("Location (Lon/Lat): "+lng+", "+lat); d3.select('#chart').on("click", function() { data.splice(0,1); data.push([5,5]); dataCallback(data[data.length - 1]); x.domain(d3.extent(data, function(d) { return d.x; })); y.domain([0, d3.max(data, function(d) { return d.y; })]); svg.selectAll("path").data([data]) .attr("d", line); }); I believe this is due to the numbers becoming negative along the y axis.
You were setting the domain of the y axis as y.domain([0, d3.max(data, function(d) { return d.y; })]); which with the log values won't work because all values are less than 0. To fix, simply use y.domain(d3.extent(data, function(d) { return d.y; })); instead. You also might want to use a linear scale instead of a time scale for the x axis. Complete jsfiddle here.