zoomable d3 line chart has disappearing data - javascript

I'm trying to add a zoom ability to a historical line chart I've built using a custom data object. I've been using http://codepen.io/brantwills/pen/igsoc/ as a template. The chart is rendered but when I try zooming there are two errors:
Error: Invalid value for path attribute d=""
Uncaught TypeError: undefined is not a function (in the last transform, translate of the last part of the zoomed function)
JSFiddle: http://jsfiddle.net/dshamis317/sFp6Q/
This is what my code looks like:
function renderHistoricalData(data) {
var parseDate = d3.time.format("%Y%m%d").parse;
data.forEach(function(d) { d.date = parseDate(d.date); });
// data.sort(function(a,b) { return a.date - b.date; });
var margin = {top: 20, right: 80, bottom: 30, left: 50},
width = 1200 - margin.left - margin.right,
height = 450 - margin.top - margin.bottom;
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.category10();
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var zoom = d3.behavior.zoom()
.x(x)
.y(y)
.scaleExtent([1, 10])
.on("zoom", zoomed);
var line = d3.svg.line()
.interpolate("basis")
// .defined(function(d) { return d.y!=0; })
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.sentiment); });
var svg = d3.select("#historical_chart").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 + ")");
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "date"; }));
var sites = color.domain().map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {date: d.date, sentiment: +d[name]};
})
};
});
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([
d3.min(sites, function(c) { return d3.min(c.values, function(v) { return v.sentiment; }); }),
d3.max(sites, function(c) { return d3.max(c.values, function(v) { return v.sentiment; }); })
]);
var site = svg.selectAll(".site")
.data(sites)
.enter().append("g")
.attr("class", "site");
site.append("path")
.attr("class", "line")
.attr("d", function(d) { return line(d.values); })
.style("stroke", function(d) { return color(d.name); });
site.append("text")
.attr("transform", function(d) {
var val = d.values[d.values.length-1];
return "translate(" + x(val.date) + "," + y(val.sentiment) + ")";
})
.attr("x", 3)
.attr("dy", ".35em")
.style("text-anchor", "start")
.text(function(d) { return d.name; });
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Sentiment (%)");
function zoomed() {
svg.select(".x.axis").call(xAxis);
svg.select(".y.axis").call(yAxis);
svg.selectAll('path.line').attr('d', line);
sites.selectAll('.site').attr("transform", function(d) {
return "translate(" + x(d.date) + "," + y(d.sentiment) + ")"; }
);
}
}
Thank you!

Alright, let's walk through each thing.
To start with, in zoomed, the last transform doesn't need to be there. In the original, it's there to move the circles, which you don't have.
Also important, your edit on path.line sets d to the wrong function. If you look at what you're setting d to when you first make it, it should be the same, as a general rule of thumb, so it should be function(d) { return line(d.values); }, not just line.
Now, for the actual reason it's disappearing.
Your scale extent is calculated based off the original domain. However, you don't set the domain until AFTER you call scaleExtent, which means your scaling is all based on the default. It's not actually disappearing, it's being compressed to the left hand side of the graph. If you remove your x axis, you'll see the colored smear of all your data flattened against the side.
Move all your domain calculations to above where you build your scale, and it'll be fine.
To make things a bit more concrete:
function renderHistoricalData(data) {
var parseDate = d3.time.format("%Y%m%d").parse;
data.forEach(function(d) { d.date = parseDate(d.date); });
// data.sort(function(a,b) { return a.date - b.date; });
var margin = {top: 20, right: 80, bottom: 30, left: 50},
width = 1200 - margin.left - margin.right,
height = 450 - margin.top - margin.bottom;
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.category10();
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "date"; }));
var sites = color.domain().map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {date: d.date, sentiment: +d[name]};
})
};
});
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([
d3.min(sites, function(c) { return d3.min(c.values, function(v) { return v.sentiment; }); }),
d3.max(sites, function(c) { return d3.max(c.values, function(v) { return v.sentiment; }); })
]);
var zoom = d3.behavior.zoom()
.x(x)
.y(y)
.scaleExtent([1, 10])
.on("zoom", zoomed);
var line = d3.svg.line()
.interpolate("basis")
// .defined(function(d) { return d.y!=0; })
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.sentiment); });
var svg = d3.select("#historical_chart").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 + ")");
var site = svg.selectAll(".site")
.data(sites)
.enter().append("g")
.attr("class", "site");
site.append("path")
.attr("class", "line")
.attr("d", function(d) { return line(d.values); })
.style("stroke", function(d) { return color(d.name); });
site.append("text")
.attr("transform", function(d) {
var val = d.values[d.values.length-1];
return "translate(" + x(val.date) + "," + y(val.sentiment) + ")";
})
.attr("x", 3)
.attr("dy", ".35em")
.style("text-anchor", "start")
.text(function(d) { return d.name; });
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Sentiment (%)");
function zoomed() {
svg.select(".x.axis").call(xAxis);
svg.select(".y.axis").call(yAxis);
svg.selectAll('path.line').attr('d', function(d) { return line(d.values); });
}
}
If you want to text to move, you can give it an easily identifiable class, and then update it in zoomed.
Giving it a class:
site.append("text")
.attr("class", "lineLabel")
Updating it in zoomed:
svg.selectAll(".lineLabel")
.attr("transform", function(d) {
var val = d.values[d.values.length-1];
return "translate(" + x(val.date) + "," + y(val.sentiment) + ")";
});
This will just make it follow the ends of the lines, but you can modify whatever attributes you like to get the wanted effects.

Related

d3 v4 error: "Unexpected value parsing width attribute." in grouped bar chart

I am trying to create a d3 (version 4) grouped bar chart with my own data, based on Mike Bostock's great example. I had to change all d3 v3 outdated functions to the new v4 ones (e.g. d3.scale.ordinal -> d3.scaleOrdinal) but then I got errors relating to the 'width' and 'x' attributes of the rect bars:
'Unexpected value 0,0,900 parsing width attribute.'
'Unexpected value 0,900 parsing x attribute.'
here is the relevant part of the code:
var x0 = d3.scaleBand()
.range([0, width])
.round(true);
var x1 = d3.scaleOrdinal();
var y = d3.scaleLinear()
.range([height, 0]);
var xAxis = d3.axisBottom()
.scale(x0);
var yAxis = d3.axisLeft()
.scale(y);
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("myData.csv", function(error, data) {
if (error) throw error;
var yearNames = d3.keys(data[0]).filter(function(key) { return key !== "Unit"; });
data.forEach(function(d) {
d.years = yearNames.map(function(name) { return {name: name, value: +d[name]}; });
});
x0.domain(data.map(function(d) { return d.Unit; }));
x1.domain(yearNames).range([0, x0.range()]);
y.domain([0, d3.max(data, function(d) { return d3.max(d.years, 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", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Population");
var unit = svg.selectAll(".unit")
.data(data)
.enter().append("g")
.attr("class", "unit")
.attr("transform", function(d) { return "translate(" + x0(d.Unit) + ",0)"; });
unit.selectAll("rect")
.data(function(d) { return d.years; })
.enter().append("rect")
.attr("width", x1.range())
.attr("x", function(d) { return x1(d.name); })
.attr("y", function(d) { return y(d.value); })
.attr("height", function(d) { return height - y(d.value); })
.style("fill", function(d) { return color(d.name); });
});
and here is the csv data:
Unit,2012,2013
Comp,54.13809524,52.25
Edu,20.39642857,18.75
Bus,16.3,18.5
SoW,16.08,7
Pharm,45,59
Agr,150.3,122.51
Soc,105.2,112.72
Nat,264.86,277.73
Hum,61.73174603,52.91
Law,14.5,22.33
Dent,27.5,11.5
Med,149.1,147.33
Vet,15,19
Jew,1,0.25
Bra,2.5,4
Most of your problems come from an incorrect usage of .range(). For example here:
x1.domain(yearNames).range([0, x0.range()]);
and here:
.attr("width", x1.range())
.range return an array, which is not what you want.
Further, you probably don't want x1 to be a scaleOrdinal but rather a scaleBand. I'd set it up like this:
x0.domain(data.map(function(d) {
return d.Unit;
}));
// set a sane bar width
var barWidth = x0.bandwidth() / yearNames.length,
barPadding = barWidth * 0.3;
// set up x1 as a scaleBand with padding
x1.domain(yearNames).range([barPadding , x0.bandwidth() - barPadding]);
y.domain([0, d3.max(data, function(d) {
return d3.max(d.years, function(d) {
return d.value;
});
})]);
Running code here.

d3 text all over the place and not in the right places

I'm trying to build a linechart based off of the example at http://bl.ocks.org/mbostock/3884955. I'm not using temperatures but rather value levels from 0-1 that I call sentiments.
I'm not using a tsv file either, but rather rendering JSON in real time through an AJAX call where my data object is an array with objects in it:
[{date: '20140716', ESPN.com: 0.4, SI.com: 0.5})]
There are typically multiple dates in an array and at least 6-7 websites (they're included in every object).
The code looks like this:
function renderHistoricalData(array) {
var data = array;
var margin = {top: 20, right: 80, bottom: 30, left: 50},
width = 1200 - margin.left - margin.right,
height = 450 - margin.top - margin.bottom;
var parseDate = d3.time.format("%Y%m%d").parse;
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.category10();
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var line = d3.svg.line()
.interpolate("basis")
.defined(function(d) { return d.y!=0; })
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.sentiment); });
var svg = d3.select("#historical_chart").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 + ")");
data.forEach(function(d) {
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "date"; }));
d.date = parseDate(d.date);
var sites = color.domain().map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {date: d.date, sentiment: +d[name]};
})
};
});
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([
d3.min(sites, function(c) { return d3.min(c.values, function(v) { return v.sentiment; }); }),
d3.max(sites, function(c) { return d3.max(c.values, function(v) { return v.sentiment; }); })
]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Sentiment (%)");
var site = svg.selectAll(".site")
.data(sites)
.enter().append("g")
.attr("class", "site");
site.append("path")
.attr("class", "line")
.attr("d", function(d) { return line(d.values); })
.style("stroke", function(d) { return color(d.name); });
site.append("text")
.datum(function(d) { return {name: d.name, value: d.values[d.values.length - 1]}; })
.attr("transform", function(d) { return "translate(" + x(d.value.date) + "," + y(d.value.sentiment) + ")"; })
.attr("x", 3)
.attr("dy", ".35em")
// .style("text-anchor", "inherit")
.text(function(d) { return d.name; });
});
}
This results in something that looks like:
http://imgur.com/hFTItGp
Any ideas? I'd greatly appreciate your help. Thanks!
The root cause of the problem is that in the code
{name: d.name, value: d.values[d.values.length - 1]}
you're assuming that values are sorted by date, latest date last. In your data, the opposite is the case -- the latest date is first. Therefore, your text appears at the beginning of the x axis. To fix, simply sort your data.
I've fixed this and a few other things here.

Multiple Line Graph Labels - D3.js

I am trying to replicate the Multi-Series Line Chart example but I am unable to get the labels to show up at the end of the line or at all for that matter. The code is basically all the same as the example but a few words changed. The dataset is of county population and is formatted the same as in the example, earliest date at the top of the list and most recent date at the bottom of the list.
Anyone see anything I'm missing??
var margin = {top: 20, right: 80, bottom: 30, left: 50},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var parseDate = d3.time.format("%Y%m%d").parse;
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.category10();
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var line = d3.svg.line()
.interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.population); });
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("historicalpopulationTest.csv", function(error, data) {
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "date"; }));
data.forEach(function(d) {
d.date = parseDate(d.date);
});
var counties = color.domain().map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {date: d.date, population: +d[name]};
})
};
});
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([
d3.min(counties, function(c) { return d3.min(c.values, function(v) { return v.population; }); }),
d3.max(counties, function(c) { return d3.max(c.values, function(v) { return v.population; }); })
]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.append("text")
.attr("x", width)
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Year");
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("Population");
var county = svg.selectAll(".county")
.data(counties)
.enter().append("g")
.attr("class", "county");
county.append("path")
.attr("class", "line")
.attr("d", function(d) { return line(d.values); })
.style("stroke", function(d) { return color(d.name); });
county.append("text")
.datum(function(d) { return {name: d.name, value: d.values[d.values.length - 1]}; })
.attr("transform", function(d) { return "translate(" + x(d.value.date) + "," + y(d.value.population) + ")"; })
.attr("x", width)
.attr("dy", ".35em")
.text(function(d) { return d.name; });
});
Graph looks like this
I think your problem is in the following code
county.append("text")
.datum(function(d) { return {name: d.name, value: d.values[d.values.length - 1]}; })
.attr("transform", function(d) { return "translate(" + x(d.value.date) + "," + y(d.value.population) + ")"; })
.attr("x", width)
.attr("dy", ".35em")
.text(function(d) { return d.name; });
I haven't run your code, but it looks like you are translating the text to the end of the line and then moving the x position an additional 'width' number of pixels.
Try changing .attr("x", width) to .attr("x", 3)

Error parsing with multiline graph in D3

I'm trying to create a multiline graph using D3, and I keep running across the same error
Error: Problem parsing d="MNaN,450LNaN,0LNaN,450LNaN,450LNaN,0LNaN,0"
Which seems to occur when I try to graph my line:
city.append("path")
.attr("class", "line")
.attr("d", function(d) { return line(d.values); })
.style("stroke", function(d) { return color(d.name); });
I'm trying to graph a single line at the moment with the following data set:
{"name":"application_active_users","values":[{"value":0,"end_time":"2013-06-14T11:00:00.000Z"},{"value":1,"end_time":"2013-06-15T11:00:00.000Z"},{"value":0,"end_time":"2013-06-16T11:00:00.000Z"},{"value":0,"end_time":"2013-06-17T11:00:00.000Z"},{"value":1,"end_time":"2013-06-18T11:00:00.000Z"},{"value":1,"end_time":"2013-06-19T11:00:00.000Z"}]}
I'm assuming something is wrong with my datasource. Does anyone see an immediate issue with how my datasource is set up?
Here is a portion of the D3 code. The entire code is here http://jsfiddle.net/hy4Hz/.
var payload;
var storedMetrics = [];
var metricCount = 1;
var graphData = [];
var margin = {
top: 20,
right: 20,
bottom: 30,
left: 50
},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
//var parseDate = d3.time.format("%Y-%m-%d").parse;
//var parseDate = d3.time.format("%Y-%m-%dT%H:%M:%SZ").parse;
var parseDate = d3.time.format("%Y-%m-%dT%H:%M:%S").parse;
var color = d3.scale.category10();
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.end_time);
})
.y(function (d) {
return y(d.value);
});
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 + ")");
x.domain(d3.extent(
data, function (d) {
return d.end_time;
}));
y.domain([
d3.min(metrics, function (c) {
return d3.min(c.values, function (v) {
return v.value;
});
}),
d3.max(metrics, function (c) {
return d3.max(c.values, function (v) {
return v.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", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Temperature (ºF)");
var city = svg.selectAll(".city")
.data(metrics)
.enter().append("g")
.attr("class", "city");
city.append("path")
.attr("class", "line")
.attr("d", function (d) {
return line(d.values);
})
.style("stroke", function (d) {
return color(d.name);
});
city.append("text")
.datum(function (d) {
return {
name: d.name,
value: d.values[d.values.length - 1]
};
})
.attr("transform", function (d) {
return "translate(" + x(d.value.end_time) + "," + y(d.value.value) + ")";
})
.attr("x", 3)
.attr("dy", ".35em")
.text(function (d) {
return d.name;
});
It looks like your x.domain() might not be set up correctly. The first argument to d3.extent should be data.values.

Error parsing D3 d=""repeated two times

I'm working from this code sample on Chained Transitions http://bl.ocks.org/mbostock/3903818
I've set up my own code to parse a csv file instead of a tsv. However when I switch from the New to Existing view I get the error Error parsing D3 d=""repeated two times in the Javascript console. Not sure if it is the data for each function that is causing the errors. Code is below:
var margin = {top: 20, right: 50, bottom: 30, left: 60},
width = 878 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var parseDate = d3.time.format("%Y%d%m").parse;
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.category10();
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var line = d3.svg.line()
.interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.price); });
var tooltip = d3.select("body")
.append("div")
.style("position", "absolute")
.style("z-index", "10")
.style("visibility", "hidden")
.text("a simple tooltip");
var svg = d3.select("#chart").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 + ")")
//Add grid lines
function make_X_axis() {
return d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(6)
}
function make_Y_axis() {
return d3.svg.axis()
.scale(y)
.orient("left")
.ticks(9)
}
//Parse data
d3.csv("data/newdata2.csv", function(error, data) {
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "date"; }));
data.forEach(function(d) {
d.date = parseDate(d.date);
d["New"] = +d["New"];
d["Existing"] = +d["Existing"];
});
var homes = color.domain().map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {date: d.date, price: +d[name]};
})
};
});
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([
d3.min(homes, function(c) { return d3.min(c.values, function(v) { return v.price; }); }),
d3.max(homes, function(c) { return d3.max(c.values, function(v) { return v.price; }); })
]);
svg.append("g")
.attr("class", "grid")
.attr("transform", "translate(0," + height + ")")
.call(make_X_axis()
.tickSize(-height, 0, 0)
.tickFormat("")
)
svg.append("g")
.attr("class", "grid")
.call(make_Y_axis()
.tickSize(-width, 0, 0)
.tickFormat("")
)
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("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Thousands($)");
var city = svg.selectAll(".city")
.data(homes)
.enter().append("g")
.attr("class", "city");
city.append("path")
.attr("class", "line")
.attr("d", function(d) { return line(d.values); })
.style("stroke", function(d) { return color(d.name); });
city.append("text")
.datum(function(d) { return {name: d.name, value: d.values[d.values.length - 1]}; })
.attr("transform", function(d) { return "translate(" + x(d.value.date) + "," + y(d.value.price) + ")"; })
.attr("x", 3)
.attr("dy", ".35em")
.text(function(d) { return d.name; });
d3.selectAll("input").on("change", change);
var timeout = setTimeout(function() {
d3.select("input[value=\"Existing\"]").property("checked", true).each(change);
}, 2000);
function change() {
clearTimeout(timeout);
city = this.value;
// First transition the line & label to the new city.
var t0 = svg.transition().duration(750);
t0.selectAll(".line").attr("d", line);
t0.selectAll(".label").attr("transform", transform).text(city);
// Then transition the y-axis.
y.domain(d3.extent(data, function(d) { return d[city]; }));
var t1 = t0.transition();
t1.selectAll(".line").attr("d", line);
t1.selectAll(".label").attr("transform", transform);
t1.selectAll(".y.axis").call(yAxis);
}
function transform(d) {
return "translate(" + x(d.date) + "," + y(d[city]) + ")";
}
});
In the code where you create the line, you are referencing d.values as the data to draw the path with:
city.append("path")
.attr("class", "line")
.attr("d", function(d) { return line(d.values); })
.style("stroke", function(d) { return color(d.name); });
However, in the change handler, you simply call (twice)
t0.selectAll(".line").attr("d", line);
Making the two bits of code consistent should fix the issue, i.e. change the two calls in the change function to
t0.selectAll(".line").attr("d", function(d) { return line(d.values); });

Categories

Resources