I'm having an issue with part of my tooltip text for this multiple line chart. It finds the name correctly, but when I try to access the y-value of the line, it's coming back as undefined.
The data structure looks like this in the console:
I need the value from the "arrests:" piece to show in the tooltip. Right now it says undefined.
Here's my code. Tooltip bit is at the end.
<div id="graph">
<div id="tooltip" class="hidden">
<p id="value">value</p>
</div>
</div>
<script type="text/javascript">
var w = 700
h = 500
var margin = {top: 20, right: 140, bottom: 130, left: 100},
width = w - margin.left - margin.right,
height = h - margin.top - margin.bottom;
var parseDate = d3.time.format("%Y").parse;
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.ordinal()
.range([ "#43736C", "#29403C", "#f4b400", '#000'])
//"#29403C", "#463573", "#f4b400", "#43736C", "#43736C", "#f4b400" ]);
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.year); })
.y(function(d) {return y(d.arrests); });
var svg = d3.select("#graph").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("https://spreadsheets.google.com/tq?key=1DNo1v8lYRzzZA6kPdQ77HrREhzkW1nDwktNQm2MXSio&tqx=out:csv", function(error, data) {
if (error) throw error;
color.domain(d3.keys(data[0]).filter(function(key) {return key !== "year"; }));
data.forEach(function(d) {
d.year = parseDate(d.year);
});
var populations = color.domain().map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {year: d.year, arrests: +d[name]};
})
};
});
var populations = populations.filter(function(d){
return d.name!== "";
});
console.log(populations);
x.domain(d3.extent(data, function(d) {return d.year; }));
y.domain([0, 15000]);
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("class", "yLabel")
.attr("transform", "rotate(-90)")
.attr("y", 0)
.attr("dy", "-6em")
.style("text-anchor", "end")
.text("Number of arrests");
var pop = svg.selectAll(".pop")
.data(populations)
.enter().append("g")
.attr("class", "pop");
pop.append("path")
.attr("class", "line")
.attr("d", function(d) { return line(d.values); })
.style("stroke", function(d) {return color(d.name); });
var legend = svg.selectAll(".legend")
.data(populations.slice())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) {return "translate(0,"+ i * 20 + ")"});
legend.append("rect")
.data(populations)
.attr("x", width)
.attr("width", 18)
.attr("height", 18)
.style("fill", function(d) {return color(d.name);});
legend.append("text")
.attr("x", w - 220)
.attr("y", 9)
.attr("dy", ".35em")
.style("text-align", "left")
.text(function(d) {return d.name});
svg.selectAll("path")
.on("mouseover", function(d) {
var xPosition = d3.event.pageX;
var yPosition = d3.event.pageY;
console.log(d.values);
d3.select("#tooltip")
.style("left", xPosition + "px")
.style("top", yPosition + "px")
.select("#value")
.text(d.name + " " + d.values.arrests);
d3.select("#tooltip").classed("hidden", false);
})
.on("mouseout", function(){
d3.select("#tooltip").classed("hidden", true);
});
});
It looks as though your problem is that your mouseover behavior is on the path. The data for the path is the entire series, even if you're thinking of it as though you're mousing over just one year. So the value of d
is not what you expect it to be. d.values
is the entire array of data for each year for that series (e.g. Misdemeanor).
Instead, you should add invisible point markers for each place where a year intersects the line for each series and put the tooltip behavior on those -- the answer to this SO question -- d3.js tooltips on path -- may help.