d3 line chart runs off the chart when threshold values are applied - javascript

I am new to d3 and working with line chart, where i want to view the chart between the threshold values Fiddler. The chart works fine with y.domain([min,max]), since i want to view the chart with my own threshold values the line runs off the chart, i've no idea why this is happening. Any help is much appreciated.

If you want to avoid the lines bleeding over the graph area, what you might want is using a clip-path. I tweaked your code a little bit and added the clip path to it.
svg.append("clipPath")
.attr("id", "clip-path")
.append("rect")
.attr("width", width)
.attr("height", height);
svg.append("path") // Add the valueline path.
.attr("d", valueline(data))
.attr("clip-path", "url(#clip-path)");
Here is the JSFiddle link for the same: http://jsfiddle.net/vxo1qsf9/2/
Please let me know if this is what you are looking for. :)

The reason why you get a broken graph is that, the values after 26 April is less than 75 which is the minimum you have defined. So the graph is actually drawing, but you can't see the lines because it is below the svg area you defined.
Here is my 2 cents.
Just update the data with correct values. So that you can view the data at the end.
{
date: "1-May-12",
close: "90.13"
}
or
Just update the min value to the minimum expected value.
var thresholdValues = {
minValue: 50,
maxValue: 100
};
This is what I did and seems it works fine. Here is the fiddle link for the same http://jsfiddle.net/vxo1qsf9/1/
If you want to automatically find the minimum and maximum value from data, use d3's native function d3.extent(), which returns an array containing min and max value of that array or you can also try finding min and max separately by using d3.min() and d3.max().
Here is the documentation link for d3 array methods.
Hope this helps! :)

Related

How to format array of values to form a distribution for google-charts histogram?

I have 1000 values in no particular order but I'd like to format them into a normal distribution to plot on a histogram using google-charts.
I've tried using d3.js and I got it working just based off some examples but it looks extremely ugly and I don't have enough time to learn d3 in and out to get the results I want. Google-charts visual format are great.
The problem is google-charts expects data in a format where each value has a name along with headers. So when I organized it into this:
'dsSample1': [
['price', 'number'],
['price', 11386.057139142767],
['price', 27659.397260273952],
['price', 44159.39726027395],
...
from
'dsSample2': [
11386.057139142767,
27659.397260273952,
44159.39726027395,
28026.04112639835,
...
google charts works, but I get the following:
This is as close as I've come to getting it working in d3: https://jsfiddle.net/0jtrq17x/1/. It works but it's extremely ugly.
I've managed to arrange the array data into bins using some d3 code but it is imcompatible with google-charts and I don't know to make it compatible, and also don't know how to format the data so it plays nice with google-charts histogram
this code
var values = this.hypo.dsSample2.map(x => {
return x + 128608.42487322348
})
var max = d3.max(values)
var min = d3.min(values)
var x = d3.scale.linear()
.domain([min, max])
.range([0, 800]);
var histGenerator = d3.layout.histogram()
.bins(x.ticks(100))
(values)
this.data1 = histGenerator
returns this array transformation
My problem is I don't know how to massage my array of data so I can get something like this in google-charts:
there are two data formats for the google charts version.
a single series format, with the names,
or a multi-series format, with just the numbers.
it is ok to use the multi-series format with a single series.
so, assigning names is not required.
but you will have to convert each value to its own array.
'dsSample1': [
[11386.057139142767],
[27659.397260273952],
[44159.39726027395],
...
from
'dsSample2': [
11386.057139142767,
27659.397260273952,
44159.39726027395,
...
you can use the map method to format the data.
dsSample.map(function (value) {
return [value];
});
see following fiddle...
https://jsfiddle.net/x684f1vs/
I know you have decided against D3, but since your question is still tagged with d3.js, I will post an answer using D3 anyways :)
I have made an updated JSFiddle, with an adaption of your code:
https://jsfiddle.net/w7r80cfo/1/
In short, to manipulate this histogram, look to the following lines:
1038 and 1039 to change the dimensions (width and height respectively) of the visualization. The values given are in pixels.
1049 to change the number of buckets for you histogram. Currently it is set to 100.
1083 to change the width of the individual bars. Currently, I've set it to 0.25 of the space calculated for each bar. If you e.g. change 0.25 to 1 the bars will be so wide, they will be drawn right next to each other.
1085 to change the color of the bars. Currently they are given a darker shade of red the higher number of values they represent. If you want e.g. just blue, change the line to .attr("fill", "steelblue")
Play around with these values and see if you can get to a chart that is close to what you want.
To elaborate a bit on the changes I've made, they consist mainly of the following:
Line 1038: lowered the width to 600.
Line 1073: updated to position the visualization correctly:
.attr('transform', `translate(${margin.left},${margin.top})`);
Line 1083: lowered the width of the bars by multiplying by 0.25:
.attr("width", (x(data[0].dx) - x(0)) * 0.25)
Other than that I have removed the following code to remove the text labels, as they indeed made the chart look messy:
bar.append("text")
.attr("dy", ".75em")
.attr("y", -12)
.attr("x", (x(data[0].dx) - x(0)) / 2)
.attr("text-anchor", "middle")
.text(function(d) { return "$" + d3.format(",.2f")(d.x); });
Besides this, I have added an y axis and changed the way the axes are drawn in order to make them look a bit nicer. I can go into detail about these changes, but I think they are of lesser interest to your goal.
Hope this helps!

D3 Persistent Path d expected number error during transition

Sorry for the lengthy post, but I just wanted to share all of the trouble shooting and progress I made up until this point. This error has been persistent for over a week.
I have a line chart supplemented with three buttons representing three days of data. I have the buttons mapped to three .txt files and a d3 event listener:
var fileMap = {
'Day 1':'2018-05-17.txt',
'Day 2':'2018-05-18.txt',
'Day 3':'2018-05-19.txt'
}
d3.selectAll('.button').on('click', function(d) {
var dayValue = this.innerHTML;
var thisFile = fileMap[dayValue];
createChart(thisFile);
});
So the idea is you can click the button and the graph will update itself. I kept running into trouble while implementing the .transition() call. I ended up using this, which works:
before calling the main createGraph function, I have a variable that counts how many times we create a graph:
var graphCount = 0;
Then within the scope of the createGraph function I have a counter:
graphCount +=1;
Then I have the logic necessary to draw the graph (initial state) or simply transition (if already drawn):
if (graphCount>1) {
xScale.domain(d3.extent(data, function(d) {return (d.date)}));
yScale.domain(d3.extent(data, function(d) {return (d.y2)}));
d3.selectAll(".line")
.data([data])
.transition() // change the line
.duration(750)
.attr("d", graphLine);
d3.selectAll("g.y.axis").transition() // change the y axis
.duration(750)
.call(yAxis);
} else {
svg.append('path')
.attr('transform', 'translate(' + margins.left + ',' + margins.top + ')')
.datum(data)
.attr('class', 'line')
.attr('d', graphLine);
var yAxisNodes = svg.append('g')
.attr('class', 'y axis')
.attr('transform', 'translate(' + margins.left + ',' + margins.top + ')')
.call(yAxis);
}
Maybe it's not the most elegant way to handle update functionality. I admit it seems a little crude, but at least it does work.
Red Flags:
X Axis: First off, the x axis isn't visible in my graph, but that's by design. I have a tooltip that shows the x axis value, but I have omiited the tooltip for simplicity.
The X axis is a time dimension, the .txts use unix time, which I convert using new Date(((split[0]*300)+rawTime)*1000). Meaning that instead of hour:minutes (as I originally wanted) all my d.dates are full fledged dates. Here is an example slice:
data[0]->Object->date: Thu May 17 2018 09:35:00 ….
I have a few timeFormat variables as well, but oddly when I try to call d3.time.format("%H:%M") the graph isn't drawn. So in my code they are not called. Since I don't need a visible x axis, I have let this go. The graph works fine when I don't use timeFormat and use the full fledged date from new Date().
The problem: Whenever a button is clicked, the graph updates successfully -- new data is read from the respective .txt but for some reason I'm getting over 40 errors reading:
Error: attribute d: Expected number, "12342542342352452, Nan".
Which makes no sense because the graph is plotted fine. As noted earlier, the unix dates have all been successfully parsed into javascript date objects. I passed the data to the console to examine just to be safe, and yes, it seems there are no parsing errors. All the dates and all the y axis values are there.
I'm not sure what to do, since a few button clicks will result in the log showing 100+ errors. I don't think that's good for browswer stability, but on the other hand, the graph appears to work just fine.
Question: Why am I getting 40+ errors in the log? My data set is around 80 observations long. I noticed it only throws errors during transitions. The initial graph creation doesn't have any errors.
Please, please make the errors go awayyyy.
I have a very minimal example here:
https://plnkr.co/edit/Zq9Yd6Hf7mlTlegMXiIG
Hunches
I also thought it could be the xAxis itself. But I passed
d3.extent(data, function(d) {return d.date
into the console log, and everything checked out again. Very strange.
The errors are due only to an empty last row in the txt files, giving you a last object like this in the arrays:
{y2: NaN, date: Wed May 16 2018 23:35:00}
Of course, you're not getting anywhere with that NaN.
Solution: remove those empty rows. After that your arrays have the correct number of objects (77 versus 78 in the running code you linked)
Here is the updated Plunker: https://plnkr.co/edit/XdOcqsdCG3kXw8cvja9y?p=preview
PS: regarding that graphCount and your supposition...
Maybe it's not the most elegant way to handle update functionality.
Yes, it's certainly not the best way. There is a much better approach: the famous enter-update-exit pattern! Get rid of that awkward counter and the if...else statement!

D3: gauge chart with growing arc

I want to achieve something like a growing arc which indicates 5 levels (see picture). My data has only an integer value which is between 1-5. You can ignore the icon in the middle for now. Is there any possibility to achieve something like that in d3? I couldn't find any example for this. Moreover I tried it with a cut off pie (donut) chart approach, but I couldn't make the growing arc... I would appreciate any help! Thanks for that.
You can do this with d3 without dependency on external images, SVG sprites or anything in the DOM — just d3.js.
Here's a working fiddle. The implementation is explained below.
But also, here's a more advanced fiddle that animates a clip-path over the growing arc. Check out its predecessor to see how the mask looks without clipping.
First, you need to represent the graphics as an array of data that you bind to with d3. Specifically, you need a color and a "line command" (the string you assign to d as in <path d="...">. Something like this:
var segmentData = [
{ color:"#ED6000", cmd:"M42.6,115.3c5.2,1.5,11,2.4,16.8,2.4c1.1,0,2.7,0,3.7-0.1v-2.2c-7,0-13.1-1.3-18.8-3.6L42.6,115.3z" },
{ color:"#EF7D00", cmd:"M25.7,99.3c4.3,4.7,9.5,8.6,15.3,11.3l-1.4,3.8c-6.9-2.4-13.2-6.1-18.6-10.8L25.7,99.3z" },
{ color:"#F4A300", cmd:"M23.7,97c-5.2-6.4-8.8-14-10.3-22.4L2.9,75.7c2.9,10,8.5,18.9,15.8,25.9L23.7,97z" },
{ color:"#F7BC00", cmd:"M13,71.5c-0.2-2-0.4-4-0.4-6c0-10.7,3.4-20.6,9.2-28.8L9.4,28.3c-5.6,9-8.9,19.6-8.9,30.9 c0,4.6,0.6,9.1,1.6,13.5L13,71.5z" },
{ color:"#FFCF36", cmd:"M63,15.7V0.8c-1-0.1-2.5-0.1-3.7-0.1c-19.9,0-37.5,9.9-48.1,25l12.7,8.6C33.1,23,46,15.7,63,15.7z" }
];
Then you need an empty <svg> and probably a <g> within it, into which to draw the graphics:
var svg = d3.select("body").append("svg")
.attr("width", 125)
.attr("height", 125);
var gauge = svg.append("g");
Then you use d3 binding to create the segments:
var segments = gauge.selectAll(".segment")
.data(segmentData);
segments.enter()
.append("path")
.attr("fill", function(d) { return d.color; })
.attr("d", function(d) { return d.cmd; });
This just creates the graphic, but doesn't color it based on an integer value. For that, you can define an update function:
function update(value) {
segments
.transition()
.attr("fill", function(d, i) {
return i < value ? d.color : "#ccc";
})
}
Calling update(4) will color all but the last segment. Calling update(0) color none (leaving all of them gray).
In the fiddle, there's also a tick() function that calls update with a new value on a setTimeout basis, but that's just for demo.
Finally, if you wish, you can wrap all that code up and create a reusable component by following the advice in [this article].(http://bost.ocks.org/mike/chart/)
since it is relatively simple picture, I'd use a sprite, with 5 variations.
That would be much easier than using d3 and gives the same result.
(you could use some online tool like http://spritepad.wearekiss.com/ )
If you want to mimic duolingo progress images you can just simply copy their solution with own images. They are using sprites as this one: http://d7mj4aqfscim2.cloudfront.net/images/skill-strength-sprite2.svg not the d3.js approach. This will save you a lot of time and effort.

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.js line and area graph - want to add a extra line defined by two points and representing a threshold/minimum value (for ease of viewing)

I have a working d3.js visualization that shows data return rates as a composite line and area graph (http://anf.ucsd.edu/tools/data_return_rates/).
The x-axis is time, the y-axis is percent data return rates. You can click various buttons at the top of the visualization to switch between datasets (just parsed JSON files).
In addition to the raw data plot, I want to add a simple line that defines the minimum data return rate required (85%). This is purely a visual aid to help users determine if the data return rates are above this minimum/threshold value. I calculate the x-values (time) for this 'minima'-line (only two points) using the d3.min() and d3.max() methods on the dataset. The y-values are just integers (85):
var min_data_return = [
{
"readable_time": d3.min(data, function(d) { return d.readable_time; }),
"value": 85
},
{
"readable_time": d3.max(data, function(d) { return d.readable_time; }),
"value": 85
}
]
(I do some other transformations to make sure everything plots okay)
Now, before I wanted this minima line added to the visualization, I just did the following to create the area and line plot, which worked:
svg.select("path.area").data([data]);
svg.select("path.line").data([data]);
There is some other plotting code later in the script:
svg.select("path.area").attr("d", area);
svg.select("path.line").attr("d", line);
All the d3.js examples I have read say that to create multiple lines, you just need to make your data array have all the datasets you want to plot, so in my example above, this:
svg.select("path.line").data([data]);
Becomes:
svg.select("path.line").data([data, min_data_return]);
And this should work. However, it doesn't. I see the data set line plotted as before, but not the min_data_return line.
Any ideas what I am doing wrong?
Gist here: https://gist.github.com/2662793
In the Gist, look at lines 133 - 140 (search for the commented string OPTION). These are the only lines that are relevant to getting this working. I put the whole script into the Gist for completeness.
Thanks in advance!
Instead of trying to draw both the reference line and the data line together, consider drawing them separately:
svg.append("svg:path")
.attr("class", "minline")
.attr("clip-path", "url(#clip)");
...
svg.select("path.minline").data([min_data_return]);
...
svg.select("path.minline").attr("d", line);
JSfiddle here with full example: http://jsfiddle.net/qAHC2/6/

Categories

Resources