I'm trying to make a plot with multiple lines on it from a JSON blob that looks like:
{"2007": [{"val":10, "mon":10}, {"val":20, "mon":11}, {"val":40, "mon":12}, ...],
"2008": [{"val":20, "mon":8}, {"val":20, "mon":9}, {"val":40, "mon":10}, ...],
...
"2012": [{"val":40, "mon":8}, {"val":50, "mon":9}, {"val":60, "mon":10}, ...]
}
The data is basically monthly totals for each year, with some years not having data for some months. I can't figure out exactly how to parse the data in d3 though. I tried various ways such as
var line = d3.svg.line()
.interpolate("basis")
.x(function(d) { return x(d.mon); })
.y(function(d) { return y(d.val); });
svg.selectAll(".line")
.data(series)
.enter().append("path")
.attr("class", "line")
.attr("d", line);
But I can't seem to get the data into the SVG line. Any suggestions? Is there a better way to structure the JSON?
I'm trying to make a plot with multiple lines on it from a JSON blob that looks like:
{"2007": [{"val":10, "mon":10}, {"val":20, "mon":11}, {"val":40, "mon":12}, ...],
"2008": [{"val":20, "mon":8}, {"val":20, "mon":9}, {"val":40, "mon":10}, ...],
...
"2012": [{"val":40, "mon":8}, {"val":50, "mon":9}, {"val":60, "mon":10}, ...]
}
The data is basically monthly totals for each year, with some years not having data for some months. I can't figure out exactly how to parse the data in d3 though. I tried various ways such as
var line = d3.svg.line()
.interpolate("basis")
.x(function(d) { return x(d.mon); })
.y(function(d) { return y(d.val); });
svg.selectAll(".line")
.data(series)
.enter().append("path")
.attr("class", "line")
.attr("d", line);
But I can't seem to get the data into the SVG line. Any suggestions? Is there a better way to structure the JSON?
Share Improve this question asked Jan 13, 2013 at 22:08 reptilicusreptilicus 10.4k6 gold badges58 silver badges80 bronze badges 2- Where do the multiple lines e in? Are you trying to make one line per year? – nrabinowitz Commented Jan 13, 2013 at 22:14
- Yup, want one line for each year. – reptilicus Commented Jan 13, 2013 at 22:36
2 Answers
Reset to default 4Here's what worked out in case anyone else runs across this problem. The trick is to pass a function that returns the values in the associative array in the "d" attribute of the path element.
entries = d3.entries(data);
var colors = d3.scale.category20()
.domain(d3.keys(data));
var line = d3.svg.line()
.interpolate("basis")
.x(function(d) { return x(d.month) })
.y(function(d) { return y(d.value) });
svg1.selectAll(".line")
.data(entries)
.enter().append("path")
.attr("class", "line")
// function(d), not just line function
.attr("d", function(d){ return line(d.value); })
.attr("stroke", function(d) { return colors(d.key) });
Some help from this answer too: Using nested data with javascript D3 problem
My guess is that the biggest problem here is that you're starting with an object, not an array. d3.data
takes an array, not an object, so you might need your data set up like:
[
[{"val":10, "mon":10}, {"val":20, "mon":11}, {"val":40, "mon":12}, ...],
[{"val":20, "mon":8}, {"val":20, "mon":9}, {"val":40, "mon":10}, ...],
...
]
If you need to convert your current data to this format, look at d3.entries
, which will give you an array with your key as well as your array of points:
[
{
key: "2008",
value: [{"val":10, "mon":10}, {"val":20, "mon":11}, {"val":40, "mon":12}, ...]
},
{
key: "2008",
value: [{"val":20, "mon":8}, {"val":20, "mon":9}, {"val":40, "mon":10}, ...]
},
...
]
See this fiddle for a simple-case version of your graph, using the first data format above: http://jsfiddle/nrabinowitz/kmmyc/