D3 mouseover text positioning - javascript

I am writing a code for D3 multiline chart. The 2 lines appear properly along with the tooltip for which I am using focus element on mouseover. here is the code:
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.value); })
.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.uv); });
var valueline3 = d3.svg.line()
// .interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.tv); });
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 + ")");
tmp = null;
// Get the data
var data = [{"uv":"1904","date":"1434391200000","tv":"1000"},{"uv":"5174","date":"1434393900000","tv":"334"},{"uv":"4840","date":"1434394200000","tv":"3432"},{"uv":"11237","date":"1434394500000","tv":"3243"},{"uv":"14456","date":"1434394800000","tv":"1223"},{"uv":"5363","date":"1434397500000","tv":"554"},{"uv":"11641","date":"1434397800000","tv":"3244"},{"uv":"11414","date":"1434398100000","tv":"6767"},{"uv":"13041","date":"1434398400000","tv":"76765"},{"uv":"12111","date":"1434402300000","tv":"5546"},{"uv":"368","date":"1434402600000","tv":"6767"},{"uv":"14476","date":"1434402900000","tv":"5464"},{"uv":"6357","date":"1434403200000","tv":"4323"},{"uv":"1037","date":"1434403500000","tv":"6565"}];
var flatData = [];
data.forEach(function(d) {
d.date = d.date;
// d.california_energy_production = +d.california_energy_production;
d.uv = +d.uv;
d.tv = +d.tv
flatData.push({date: d.date, value: d.uv, key: "uv"});
flatData.push({date: d.date, value: d.tv, key: "tv"});
});
// 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.uv, d.tv); })]);
// Add the valueline path.
// svg.append("path")
// .attr("class", "line")
// .attr("d", valueline1(data));
svg.append("path")
.attr("class", "line uv")
.style("stroke","blue")
.attr("d", valueline2(data));
svg.append("path")
.attr("class", "line tv")
.style("stroke","yellow")
.attr("d", valueline3(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")
.attr("transform", "translate(-100,-100)");
focus.append("circle")
.attr("r", 4.5);
focus.append("text");
svg.append("text")
// .attr("class", "sources")
.attr("transform", "translate(" + (width+3) + "," + y(10) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "#898989");
svg.append("text")
// .attr("class", "sources")
.attr("transform", "translate(" + (width+3) + "," + y(10) + ")")
.attr("text-anchor", "start")
.style("fill", "#898989");
var voronoiGroup = svg.append("g")
.attr("class", "voronoi");
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);
function mouseover(d) {
console.log(d);
d3.select("."+d.key).classed("line-hover", true);
focus.attr("transform", "translate(" + x(d.date) + "," + y(d.value) + ")");
focus.style("position: absoloute");
focus.attrb("x","20px");
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 case the text on mouseover is appearing around the focus element circle. What I want is that the mouseover text should be positioned in an absolute position inside the chart, say, in top left corner of the chart and not near the focus circle. Can this be done with focus element?

I got it to work. Instead of appending the focus text with the info, I am appending the svg text. I added one id attribute to this svg text and on mouse out, I'm removing the svg id.

Related

D3: Add data value labels to multi line graph

I am using this multiline graph but so far have failed to generate data value labels on every tick (for every day).
<script>
var margin = {top: 30, right: 40, bottom: 30, left: 50},
width = 600 - margin.left - margin.right,
height = 270 - margin.top - margin.bottom;
var parseDate = d3.time.format("%d-%m-%y").parse;
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(7);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(7);
var valueline = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.sev3); });
var valueline2 = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.sev4); });
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 + ")");
// Get the data
d3.csv("data.tsv", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
d.sev3 = +d.sev3;
d.sev4 = +d.sev4;
});
// 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.sev3, d.sev4); })]);
svg.append("path") // Add the valueline path.
.attr("class", "line")
.attr("d", valueline(data));
svg.append("path") // Add the valueline2 path.
.attr("class", "line")
.style("stroke", "red")
.attr("d", valueline2(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);
svg.append("text")
.attr("transform", "translate(" + (width+3) + "," + y(data[0].sev4) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "red")
.text("Sev4");
svg.append("text")
.attr("transform", "translate(" + (width+3) + "," + y(data[0].sev3) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "steelblue")
.text("Sev3");
});
</script>
Data.tsv
date,sev3,sev4
20-02-15,0,0
19-02-15,0,0
18-02-15,0,0
17-02-15,481,200
16-02-15,691,200
15-02-15,296,200
14-02-15,307,200
The code above gives this:
And THIS is what i am trying to accomplish
I understand that i must use .append("text") and position the text at about the same x,y coords as the data point and pull the value from the data to feed into the "text" but i am having difficulties in integrating that concept.
I suspect that the selection would occur with valueline.append ? I have looked at a HEAP of examples, i dont thing a linegraph with data value labels exists, if it does please point me to it :)
Any thoughts ?
Your text will not be visible, as it is located outside the boundaries of your svg: you added a group that is translated of margin.left, and the put your x at width+3, which means located at width+3+margin.left of the left border of your svg.
Try replacing your append text with something like:
svg.append("text")
.attr("transform", "translate(" + (width/2) + "," + y(data[0].sev4) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "red")
.text("Sev4");
svg.append("text")
.attr("transform", "translate(" + (width/2) + "," + y(data[0].sev3) + ")")
.attr("dy", ".35em")
.attr("text-anchor", "start")
.style("fill", "steelblue")
.text("Sev3");
I did not test it, so I cannot guarantee, but your code seems fine, that's the only thing I see.
Result of this add:
EDIT
After your clarifications, here is a plunk: http://plnkr.co/edit/lDlseqUQQXgoFwTK5Aop?p=preview
The part you will be interested in is:
svg.append('g')
.classed('labels-group', true)
.selectAll('text')
.data(data)
.enter()
.append('text')
.classed('label', true)
.attr({
'x': function(d, i) {
return x(d.date);
},
'y': function(d, i) {
return y(d.sev3);
}
})
.text(function(d, i) {
return d.sev3;
});
This will draw your labels. Is it the result you try to achieve?

zoomable d3 line chart has disappearing data

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.

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