I'm a D3.js newbie and I'm learning how to play around with data.
Let's say I have an object with names as keys, and each key has an array of numbers like this:
var userdata = { 'John' : [0, 1, 3, 9, 8, 7], 'Harry': [0, 10, 7, 1, 1, 11], 'Steve': [3, 1, 4, 4, 4, 17], 'Adam' : [4, 77, 2, 13, 11, 13] };
For each user, I would like to append an SVG object and then plot the line with the array of values for that user.
So here is my assumption of how that would look based on tutorials, but I know it is incorrect. This is to show my limited knowledge and give better understanding of what I'm doing:
First I should create the line
var line = d3.svg.line().interpolate('basis');
Then I want to bind the data to my body and append an svg element for each key:
d3.select('body') .selectAll('svg') .data(userdata) .enter() .append('svg') .append(line) .x(function(d, i) { return i; }) .y(function(d) { return d[i]; });
So am I close??
enter() function creates the initial join of the data with our DOM elements. Thus selecting only the elements that were not in the DOM yet. merge() function will select the DOM elements that did not exist in the DOM before and the ones that did. exit() function will select the DOM elements that are left from the join.
d3 append() append() - Appends a new element with the specified name as the last child of each element in the current selection, returning a new selection containing the appended elements.
datum(data) will bind the entirety of data to every single element in the selection.
Here's another example similar to mbeasley's: http://jsfiddle.net/2N2rt/15/ which adds axis, colors, and flips the chart right side up. First, I massaged your data just a little bit. Works the best if you have an array of values and I used keys to make getting to the name
and values
properties easier.
var data = [ {name: 'John', values: [0,1,3,9, 8, 7]}, {name: 'Harry', values: [0, 10, 7, 1, 1, 11]}, {name: 'Steve', values: [3, 1, 4, 4, 4, 17]}, {name: 'Adam', values: [4, 77, 2, 13, 11, 13]} ];
Generally in d3
you set up the chart like this which determines the size of the actual graph and the surrounding margins.
var margin = {top: 20, right: 80, bottom: 30, left: 50}, width = 640 - margin.left - margin.right, height = 380 - margin.top - margin.bottom;
Then you can create your scales based on your data. Though you don't have to create them, they make positioning elements on the chart much easier by converting values to points. The domain
is the min and max values that your data has, while the range
is the min and max values of the size of your graph. Note that the range
for the y axis
gets reversed which puts (0,0) in the bottom left hand corner (usually 0 for the y axis is at the top).
var x = d3.scale.linear() .domain([0, d3.max(data, function(d) { return d.values.length - 1; })]) .range([0, width]); var y = d3.scale.linear() .domain([d3.min(data, function(d) { return d3.min(d.values); }), d3.max(data, function(d) { return d3.max(d.values); })]) .range([height, 0]);
d3
has a couple of features for automatically creating color scales for you. Just set it up with the keys that you want to use and the number of colors (I think there are 10 and 20 color options).
var color = d3.scale.category10() .domain(d3.keys(data[0]).filter(function(key) { return key === "name"; }));
Here we use our scales to setup the x and y axis. There are lots of different options for the axes. TickFormat is handy to change how the ticks look, d3.format
has lots of different options so that you rarely have to create a custom formatter.
var xAxis = d3.svg.axis() .scale(x) .tickFormat(d3.format('d')) .orient("bottom"); var yAxis = d3.svg.axis() .scale(y) .orient("left");
Here we create a reusable function that knows how to draw a line. We'll pass each datapoint for each person into the line function later on. Note that d
holds the current set of values that we are graphing and i
is the index of the current values within our original data array.
var line = d3.svg.line() .interpolate("basis") .x(function(d, i) { return x(i); }) .y(function(d, i) { return y(d); });
Finally we can start adding things to our chart, first creating and positioning the main svg element.
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 + ")");
Then appending each axis.
svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis); svg.append("g") .attr("class", "y axis") .call(yAxis);
We append a group (g
) for each person and associate the data with the group. We'll use this data when we draw the lines. We provide a class
so that we can style the chart later if we want to.
var people = svg.selectAll(".people") .data(data) .enter().append("g") .attr("class", "people");
Then finally draw the lines for each person.
people.append("path") .attr("class", "line") .attr("d", function(d) { return line(d.values); }) .style("stroke", function(d) { return color(d.name); });
I used your data to answer another question about drawing a grid when you have negative values. You can see that graph at http://jsfiddle.net/2y3er/2/.
I'd say you're going in the right direction. Here's what I would do (but know that there isn't just one way to do this):
// your user data var userdata = { 'John' : [0, 1, 3, 9, 8, 7], 'Harry': [0, 10, 7, 1, 1, 11], 'Steve': [3, 1, 4, 4, 4, 17], 'Adam' : [4, 77, 2, 13, 11, 13] }; // add your main SVG block var svg = d3.select('body') .append('svg') .attr('width', 400) .attr('height', 200) .attr('id', 'chart'); // add an SVG group element for each user var series = svg.selectAll('g.series') .data(d3.keys(userdata)) .enter() .append('g') .attr('class', 'series'); // create your line generator var line = d3.svg.line() .interpolate('basis') .x(function(d, i) { return i*40; // *40 just to increase the chart size }) .y(function(d) { return d*3; // *3 for the same reason }); // add a line for each user using your SVG grouping var lineSVG = series.selectAll('.line') .data(d3.keys(userdata)) .enter() .append('svg:path') .attr('d', function(d) { return line(userdata[d]); }) .attr('class','line');
Here's a demo of the above code.
I also highly recommend that you read this article, as it really helps solidify the way that d3 works.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With