How to enter data from several variables into one chart using d3? - javascript

It is quite easy to enter data in d3 as long as all of the data are in one file or in one variable like this:
svg.selectAll("path").data(datavariable).enter()
.append("path")
....
I need to enter data stored in separate variables into one graph. I tried
svg.selectAll("path").data(datavariable1).enter()
.append("path")
....
svg.selectAll("path").data(datavariable2).enter()
.append("path")
....
It doesn't seem to work. I also tried svg.selectAll("path1")... and svg.selectAll("path.datavariable1")..., but it just plots the second path over the first using the same data (datavariable1). Does anyone know how to get data from two variables to work on one graph at the same time?

I figured it out with the help of Nixie's comment. This is what worked for me. For the paths I didn't need to svg.selectAll anything. line1 and line2 get the data from data variables:
var line1 = d3.line()
.x(function(d,i) { return x(datavariable1[i].xvalue); })
.y(function(d,i) { return y(datavariable1[i].yvalue); });
var line2 = d3.line()
.x(function(d,i) { return x(datavariable2[i].xvalue); })
.y(function(d,i) { return y(datavariable2[i].yvalue); });
Then I just appended SVG as follows:
svg.append("path")
.attr("class", "line")
.attr("d", line1(datavariable1))
svg.append("path")
.attr("class", "line")
.attr("d", line2(datavariable2))
Answer in Nixie's comment to my question wouldn't work in my case because path has to stay path for the line graph, but it works for a dot graph. Hopefully this helps someone who might run into similar issue.

Related

d3.js: Multiple Series Line Chart

With this code as a starting point: https://bl.ocks.org/d3noob/15e4f2a49d0d25468e76ab6717cd95e7 I'm attempting to make a simple line graph with multiple data series. Per #wasserholz suggestion, I've added a complete MVP: https://github.com/djmcmath/d3-fail-mvp
The data parsing portion seems to be working correctly, in that I'm creating a map with 5 elements, each of which is a "sailing date" and array of values associated with that date. This is the variable named "group_by_sailing_date".
The axes appear to be reasonable: For the X-axis, I'm taking the "since_midnight" value, pulling the extents, and formatting it as a time. The Y-axis, similarly, is just the extents of the "margin" value. I get this -- so far so good:
Next, I want to add some lines to my chart. My thinking is that I iterate through the map, and for each of the map elements, I add the element as data to a series. What I get is a gigantic "Nothing Happens" though. No lines, no errors, just "Gosh, your data looks great, but I'm going to ignore it."
//line generator?
var valueline = d3.line()
.x(function(d) { return x(d.since_midnight); })
.y(function(d) { return y(d.margin); });
group_by_sailing_date.forEach(function (s) {
svg_summ.append("path")
.data(s)
.attr("stroke", "steelblue")
.attr("stroke-width", "3px")
.attr("d", valueline);
});
I feel like I'm missing something really fundamental here, but I'm drawing a complete blank (pun intended, ha ha ha). Help?
Following the rules of selection within d3.js (https://bost.ocks.org/mike/selection/) the code should look something like this:
svg_summ.selectAll("path")
.data(group_by_sailing_date)
.enter()
.append("path")
.attr("stroke", "steelblue")
.attr("fill", "none")
.attr("stroke-width", "1px")
.attr("d", (d) => valueline(d));
Ok, I've made it work, but I don't know why. I removed the .data(s) line, and changed "valueline" to "valueline(s)". No idea why this works. Technically, it's all good, but I'd be thrilled if someone could help me understand what this code actually means.
group_by_sailing_date.forEach(function (s) {
svg_summ.append("path")
.attr("stroke", "steelblue")
.attr("fill", "none")
.attr("stroke-width", "1px")
.attr("d", valueline(s));
});

Why would a string of methods need to be separated?

I'm implementing a reactive line chart in meteor.js based on this example line chart. In the code that I lifted for that chart, I have the following block, which works fine.
var paths = svg.selectAll("path.line")
.data([dataset]);
paths
.enter()
.append("path")
.attr("class", "line")
.attr('d', line);
paths
.attr('d', line);
paths
.exit()
.remove();
However, when I try writing something like the following, the axes still show, but the path does not render. Why the heck could that be?
var paths = svg.selectAll("path.line")
.data([dataset])
.enter()
.append("path")
.attr("class", "line")
.attr('d', line)
.exit()
.remove();
It's because you're calling the functions on different objects. D3 returns update, enter, and exit selections from calls to .data() -- this is what you're storing in paths in the first code block. Then you get the enter, update, and exit selections and handle them.
In the second code block, you're calling .enter() you're handling the enter selection afterwards. That is, all the code after the .enter() is being applied to the enter selection and not to the other selections as well as before.
So the .exit().remove() is being called on the newly-appended path elements (which should give you an error) instead of the return value of .data() as in the first block of code.

Missing Initial Step from Step Plot D3.js

This is an issue that I have not discovered a clean fix for.
Within my step plot below:
http://jsfiddle.net/q47r3pyk/7/
You can see that I have a vertical blue line at the start of the chart.
This is because I added an additional x-value and y-value so that the first step will show up in the step plot.
If you look at
http://jsfiddle.net/q47r3pyk/8/
where I remove the first dummy entry with
x-value of "12-Jul-14"
y-value of 0
The first step of my step plot will have a width of zero.
Is there a recommended approach within d3.js for having the first step show without losing the last step by using step-after? or a fix for removing the vertical blue line that shows up with my hack of adding a dummy value?
Step is specified in
var line = d3.svg.line()
.x(function (d) {
return x(d.x);
})
.y(function (d) {
return y(+d.y);
})
.interpolate("step-after");
You could clip the path using SVG clip-path:
svg.append("clipPath").attr("id", "canvasClip")
.append("rect")
.attr("height", height)
.attr("width", width)
Then reference the clip-path on your line:
svg.append("path")
.datum(formatted_data)
.attr("class", "line")
.attr("d", line)
.attr("clip-path", "url(#canvasClip)")
Here's the fiddle, it seems to work fine:
http://jsfiddle.net/q47r3pyk/11/
But, ultimately, I think this is a case where the interpolator is acting as it should, and you really shouldn't be thinking about how to subvert it but rather whether it's the right interpolator for your data. In this case, I'd say no, and suggest you use "step" as your interpolator instead of "step-before" or "step-after". I think that would give you the result you're looking for and lines up well with your interactivity.
Is this help?
I have tried several times, i think it is the best result i have got, hope it helps!
x.domain(d3.extent(x_axis, function (d) {
return parseDate(d);
})).nice(x_axis.length);
fiddle

D3 Select <g> Element and Modify Fill

I have used D3 to make a map of the US and filled in the colors
var map = d3.select("#map").append("svg")
.attr("width", svgWidth)
.attr("height", svgHeight);
d3.json("us.json", function (error, us) {
map.append("g")
.selectAll("path")
.data(topojson.feature(us, us.objects.states).features)
.enter().append("path")
.attr("d", path)
.style("stroke", function (d) { return "#000000"; } )
.style("fill", function (d) { return gradient(Math.random()); } )
};
Now, I want to change the color of each state but rather than removing the map and then re-adding it, I would like to transition the colors.
I have tried:
d3.selectAll("#map").selectAll("g").selectAll("path")
But then trying to loop through the elements of this array does not help.
What am I doing wrong?
EDIT:
The code I am using to try and change the colors of each state (each path variable) is...
d3.select(this).transition().style("fill", gradient(Math.random()));
I do not believe the problem has to do with the code above - it's the code I am trying to use to select the paths/states that is giving me trouble.
I have also tried
d3.selectAll("path").attr("fill", function (d) { ... });
But, that too, did not do anything. :(
As Lars said in the comments, since I used "style" before, I have to do it again [instead of using attr as I was before].
Selecting the data as I did (d3.selectAll("path")) is the correct way to select the states.

d3 Multi Series Chart with Incorrect Values

I'm trying to implement the d3 multi-series line chart example at http://bl.ocks.org/mbostock/3884955.
But I'm having a problem when using my own data - as the lines don't seem to match the legend/ values in the JSON data. For example at 10:00, the "high" line should be measuring 3512 "threats" on the y-axis.
city.append("path")
.attr("class", "line")
.attr("d", function(d) { return line(d.values); }) // Problem here?
.style("stroke", function(d) { return color(d.name); });
Please take a look at this js fiddle:- http://jsfiddle.net/Ca8Uj/
Many thanks.
You're seeing this behaviour because you're using the basis interpolation on your lines, which smooths out peaks (ie the line is not guaranteed to go through each point).
If you change to:
var line = d3.svg.line()
.interpolate("linear")
You should see the correct values. Alternatively to get a smooth-ish line that shows correct exact y-values you could use monotone. To experiment with interpolations, have a look at: http://bl.ocks.org/mbostock/4342190

Categories

Resources