Missing Initial Step from Step Plot D3.js - javascript

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

Related

Adapting nvd3 linePlusBarChart to a histogram with cumulative percentage line?

I was looking for options to build histograms, and before I tried to do it in barebones d3, I found nvd3's linePlusBarChart desirable, although the given example wasn't designed for histograms with a cumulative percentage line.
With community help, I managed to get such a chart done in d3. I then went to try to adapt it and got this far.
It seems for some reason, I get 2 charts, a mini preview at the bottom with the larger chart at top, and the line has circular points, that are too big on the large chart. How do I get it to be just one chart, no points on line (or at least very small points), and make it match more like the basic d3 version?
Any suggestions?
I'm not sure if using nvd3 (look/feel) is a requirement for you, but it sounds like you're trying to replicate the d3 histogram example "...make it match more like the basic d3 version?".
If you're fine with a pure d3 version take a look at this fiddle which make small changes to this histogram example.
First, we add a cumulative property to the result of the d3 histogram function
data.forEach(function(d,i){
if(i === 0){
d.cum = d.y
}else{
d.cum = d.y + data[i-1].cum
}
})
Next we create a y scale for the cumulative line
var yc = d3.scale.linear()
.domain([0, d3.max(data, function(d) { return d.cum; })])
.range([height, 0]);
Then, declare a line function to make use of our new cum property and yc scale
var line = d3.svg.line()
.x(function(d) { return x(d.x); })
.y(function(d) { return yc(d.cum); });
And finally draw the cumulative line
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
Regarding the nvd3 example you posted, you can set the chart's 'focusEnable' to false to get rid of the bottom chart.
var chart = nv.models.linePlusBarChart()
.margin({top: m.top, right: m.right, bottom: m.bottom, left: m.left})
.x(function(d,i) { return i })
.y(function(d,i) {return d[1] })
.focusEnable(false)
;
The other issues (big dots and shaded region around line) are css related. Adding nvd3's css file should solve them. See this fiddle.
Hope this helps.

Add points (x,y) to a d3 multi-line graph with time scale x-axis

I'm currently attempting to build a a multi-line graph with a d3.time.scale() for the x-axis.
I'm trying to add circles to each point on lines of the graph, but have been unsuccessful thus far.
When I do something like:
.attr('cx', function(d){ return x(d.price) })
I get a negative number.
I was thinking of setting up another scale (pointsScale) to handle this but have been largely unsuccessful.
What am I doing wrong?
Please refer to my JSBin for the code.
You're running into a few issues here:
Since you made the x-axis a time-scale, I'm guessing that you actually want price to be the y variable, while date is the x variable. That's why x(d.price) is negative - d3 is trying to interpret the prices as dates, which doesn't end up making much sense. So replace your line of code above with this: .attr('cy', function(d){ return y(d.price) })
In order to actually have circles be visible, they need to have three parameters set: cx, cy, and r. Since d3 already knows that your x axis is a time scale, you can set cx with .attr('cx', function(d){ return x(d.date) }). You can make r be whatever radius you want for the circles. Just choose one, or it will default to 0 and you won't be able to see the circles. .attr('r', 4), for instance, would set the radius to a perfectly visible value of 4.
You're drawing the circles before you draw the lines. As a result, the lines get drawn over the circles and it looks kind of weird. So move the circle code to after the line code if you want to avoid that.
Putting it all together, this is roughly what the code to create your circles should look like, and it should go after you declare var paths:
var circles = company.selectAll('circle')
.data(function(d){ return d.values; })
.enter().append('circle')
.attr('cy', function(d){
return y(d.price);}) //Price is the y variable, not the x
.attr('cx', function(d){
return x(d.date);}) //You also need an x variable
.attr('r',4); //And a radius - otherwise your circles have
//radius 0 and you can't see them!
Updated jsbin:
http://jsbin.com/gorukojoxu/edit?html,console,output

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

Drawing multiple sets of multiple lines on a d3.js chart

I have a d3 chart that displays two lines showing a country's imports and exports over time. It works fine, and uses the modular style described in 'Developing a D3.js Edge' so that I could quite easily draw multiple charts on the same page.
However, I now want to pass in data for two countries and draw imports and exports lines for both of them. After a day of experimentation, and getting closer to making it work, I can't figure out how to do this with what I have. I've successfully drawn multi-line charts with d3 before, but can't see how to get there from here.
You can view what I have here: http://bl.ocks.org/philgyford/af4933f298301df47854 (or the gist)
I realise there's a lot of code. I've marked with "Hello" the point in script.js where the lines are drawn. I can't work out how to draw those lines once for each country, as opposed to just for the first one, which is what it's doing now.
I'm guessing that where I'm applying data() isn't correct for this usage, but I'm stumped.
UPDATE: I've put a simpler version on jsfiddle: http://jsfiddle.net/philgyford/RCgaL/
The key to achieving what you want are nested selections. You first bind the entire data to the SVG element, then add a group for each group in the data (each country), and finally get the values for each line from the data bound to the group. In code, it looks like this (I've simplified the real code here):
var svg = d3.select(this)
.selectAll('svg')
.data([data]);
var g = svg.enter().append('svg').append('g');
var inner = g.selectAll("g.lines").data(function(d) { return d; });
inner.enter().append("g").attr("class", "lines");
inner.selectAll("path.line.imports").data(function(d) { return [d.values]; })
.enter().append("path").attr('class', 'line imports')
.attr("d", function(d) { return imports_line(d); });
The structure generated by this looks like svg > g > g.lines > path.line.imports. I've omitted the code for the export line here -- that would be below g.lines as well. Your data consists of a list of key-value pairs with a list as value. This is mirrored by the SVG structure -- each g.lines corresponds to a key-value pair and each path to the value list.
Complete demo here.
The point is that you're thinking to imperative. That's why you have so much code. I really can't put it better than Mike Bostock, you have to start Thinking with Joins:
svg.append("circle")
.attr("cx", d.x)
.attr("cy", d.y)
.attr("r", 2.5);
But that’s just a single circle, and you want many circles: one for each data point. Before you bust out a for loop and brute-force it, consider this mystifying sequence from one of D3’s examples.
Here data is an array of JSON objects with x and y properties, such as: [{"x": 1.0, "y": 1.1}, {"x": 2.0, "y": 2.5}, …].
svg.selectAll("circle")
.data(data)
.enter().append("circle")
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.attr("r", 2.5);
I'll leave translating this example to the "from one line to many lines" as an excerxise.

Categories

Resources