Reputation: 177
Can anyone help? My data is being filtered by values chosen from two dropdown lists - then nested/rolled up to get the mean value per day for these same values. I am getting a "problem parsing d error" for the code below. Although both filter and nest functions are returning the correct data - the problem occurs when I try to apply this data to the line graph to update it?
d3.select("#parameterType").on("change", function()
{
d3.select("#dateTimeTaken").on("change", function()
{
var selectedParameter = document.getElementById("parameterType").value;
var selectedMonth = document.getElementById("dateTimeTaken").value;
//filter data by selected parameter and month
var selectedData = data.filter(function(d) {
return d.parameterType == selectedParameter &&
+d.dateTimeTaken.getMonth() == (selectedMonth - 1);});
console.log(selectedData);//returning correct data
//get average reading for each day within selected month
var newdata = d3.nest()
.key(function(d) {return d3.time.day(d.dateTimeTaken);})
.sortKeys(d3.ascending)
.rollup(function(d)
{
return {
mean: d3.mean(selectedData, function(d) {return +d.reading;})};
})
.entries(selectedData);
console.log(newdata);//returning correct data
//UPDATE GRAPH
//not returning correct max values?
x.domain(d3.extent(newdata, function(d) { return d.key; }));
y.domain([0, d3.max(newdata, function(d) { return d.values; })]);
svg.select("path.line")
.attr( "d", line(newdata));
svg.select(".x.axis")
.transition()
.duration(750)
.ease("linear")
.call(xAxis);
svg.select(".y.axis")
.transition()
.duration(750)
.ease("linear")
.call(yAxis);
Upvotes: 1
Views: 570
Reputation: 34288
In the code that you posted, there are two problems which cause the said issue. Both the problems appear to stem from a misunderstanding of how data is nested and rolled up in D3.
var newdata = d3.nest()
.key(function(d) {return d.dateTimeTaken;})
.sortKeys(d3.ascending)
.entries(data);
This converts an object of the following kind:
var data = [{
parameterType: 'a',
dateTimeTaken: '2013-01-01 12:00:00',
reading: 100
}, {
parameterType: 'a',
dateTimeTaken: '2013-01-02 12:00:01',
reading: 101
}];
to:
[
{
"key": "2013-01-01 12:00:00",
"values": [
{
"parameterType": "a",
"dateTimeTaken": "2013-01-01 12:00:00",
"reading": 100
}
]
},
{
"key": "2013-01-02 12:00:01",
"values": [
{
"parameterType": "a",
"dateTimeTaken": "2013-01-02 12:00:01",
"reading": 101
}
]
}
]
The values
field is an array which accumulates the original data entries together.
rollup then takes as argument the array which would have been values
, calculates an aggregate metric from these (mean
in your case) and puts it in place of the array in the key values
.
Your rollup
function:
//AVERAGE READING FOR EACH DAY WITHIN SELECTED MONTH FOR SELECTED PARAMETER
// ...
.rollup(function(d) {
return {mean:d3.mean(selectedData, function(d) {return +d.reading;})};})
ignores the argument completely. I think it should read:
.rollup(function(d) {
return {mean:d3.mean(d, function(d_) {return +d_.reading;})};})
Now the resulting array would like:
[
{
"key": "2013-01-01 12:00:00",
"values": {
"mean": 100
}
},
{
"key": "2013-01-02 12:00:01",
"values": {
"mean": 101
}
}
]
Note that the values
key has yet another object inside it which contains the mean
. You calculate the range for the y
axis as:
y.domain([0, d3.max(newdata, function(d) { return d.values; })]);
The reason why the maximum values are incorrect is because you are asking d3 to calculate the maximum over objects
in values
. The result of such an operation is ill defined. Instead, you should ask for maximum over values.mean
:
y.domain([0, d3.max(newdata, function(d) { return d.values.mean; })]);
This works and produces the correct result as shown in this jsFiddle: http://jsfiddle.net/XLNeP/
That was about how to make the nesting and rollupus work correctly. Now to address a few other problems. Your line
variable has the following accessors:
var line = d3.svg.line()
.x(function(d) { return x(d.dateTimeTaken); })
.y(function(d) { return y(d.reading); });
This works perfectly for the time you call:
svg.append("path")
.attr("class", "line")
.attr("d", line(data));
However, newdata
is of the form shown above, which has key
and values
at the top level and not dateTimeTaken
or reading
. Hence you would be better off using the selectedData
which is just data
filtered and preserves the data structure. However, if you want to draw a different line (e.g., with the mean
) then you should define a new d3.svg.line()
line generator with different accessors.
Upvotes: 2