Here is the important part of my code. For some reasons, there is a problem with the "errorBars2". It always returns this error:
Invalid value for <path> attribute d="M40.5,NaNL40.5,NaNZ"
I spent now hours on searching for the mistake but I can't find it! Could somebody explain me what's the problem with the "errorBars2"?
In errorBarArea2 you have written for
.y0(function (d) {
return y0(+d.top_after + +d.moe3);
})
but in the JSON structure it is not available change it to +d.moe3_after
and you have written
.y1(function (d) {
return y0(+d.low_after - +d.moe4);
})
but in the JSON structure it is not available change it to +d.moe4_after
So the final code is
var errorBarArea2 = d3.svg.area()
.x(function (d) {
return x3(d.name) +x3.rangeBand()/2;
})
.y0(function (d) {
return y0(+d.top_after + +d.moe3_after);
})
.y1(function (d) {
return y0(+d.low_after - +d.moe4_after);
})
Tell me if this works.
var errorBarArea2 = d3.svg.area()
.x(function (d) {
return x3(d.name) +x3.rangeBand()/2;
})
.y0(function (d) {
return y2(d.top_after + +d.moe3);
})
.y1(function (d) {
return y2(d.low_after - +d.moe4);
})
Related
I'm trying to plot a dc choropleth , but somehow the legend is not showing up.
Here is the sample fiddle :
http://jsfiddle.net/susram/9VJHe/56/
usChart
.width(1200)
.height(500)
.dimension(state_dim)
.group(latest_mean_sqft_per_state)
//.colors(d3.scale.quantize().range(["#E2F2FF", "#C4E4FF", "#9ED2FF", "#81C5FF", "#6BBAFF", "#51AEFF", "#36A2FF", "#1E96FF", "#0089FF", "#0061B5"]))
.colors(d3.scale.quantize().range(["#fff7fb","#ece2f0","#d0d1e6","#a6bddb","#67a9cf","#3690c0","#02818a","#016c59","#014636"]))
//.colors(d3.scale.quantize().range(d3.schemeBlues()(9)))
.colorDomain([0, 500])
//.colorAccessor(function (d) { /*console.log(d);*/ return d? usChart.colors(d.avg_psft) : '#ccc'; })
.colorAccessor(function (d) { /*console.log(d);*/ return d.avg_psft; })
.overlayGeoJson(statesJson.features, "state", function (d) {
return d.properties.name;
})
.valueAccessor(function(kv) {
console.log(kv);
return kv.value;
})
.title(function (d) {
return "State: " + d.key + "\nAverage Price per SqFt: " + numberFormat(d.value.avg_psft ? d.value.avg_psft : 0) + "M";
})
.legend(dc.legend().x(1300).y(80).itemHeight(13).gap(5));
Why is the legend showing up as 0x0 ?
I've been trying to get the legend to work with geoChoroplethCharts as well and unfortunately legend support appears to not have been implemented yet in dc. There are a few functions (legendables, legendHighlight, legendReset, legendToggle, ect...) that were defined in the dc base-mixin and would need to be extended before legend support would work.
For an example take a look at the source for pieChart:
https://github.com/dc-js/dc.js/blob/develop/src/pie-chart.js
Versus the soruce for geoChoroplethChart:
https://github.com/dc-js/dc.js/blob/develop/src/geo-choropleth-chart.js
You'll notice at the bottom of the pieChart source that the related legend functions were extended. I belive something similar would need to be done for the geoChoroplethChart source code.
EDIT:
I worked off your jsfiddle and was able to get a bare bones label to display on the geoChoroplethChart: http://jsfiddle.net/Lx3x929v/2/
usChart.legendables = function () {
return usChart.group().all().map(function (d, i) {
var legendable = {name: d.key, data: d.value, others: d.others,
chart: usChart};
legendable.color = usChart.colorCalculator()(d.value);
return legendable;
});
};
Here is my modification —for a continuous map— from #MarcTifrea 's solution and comment.
chart.legendables = function () {
var domain = chart.colorDomain();
return domain.map(function (d, i) {
var legendable = {name: parseFloat((Math.round(domain[i] * 100000) /100000).toPrecision(2)) , chart: chart};
if (i==1) legendable.name += ' unit'; // add the unit only in second(last) legend item
legendable.color = chart.colorCalculator()(domain[i]);
return legendable;
});
};
chart.legend(
dc.legend()
.x(width/4)
.y(height*4/5)
.itemHeight(height/30)
// .itemWidth(width/25)
.gap(5)
// .horizontal(1)
// .autoItemWidth(1)
);
I would like to load a dc dataTable with dimensional data that has been grouped and filtered. Is this possible? I am assuming it is but the examples I have seen so far have simple groups coded at the time of table construction and I can't get it to work any other way!
var facts = crossfilter(data);
var testTable = dc.dataTable('#testtable');
var providerDim = facts.dimension(function (d) {
if (d.report_by_3 !== null) {
return d.report_by_3;
}
});
var MH003Group = providerDim.group().reduceSum(function (d) {
if (d.indicator_code === 'MH003') {
return (d.observed / d.expected);
} else {
return null;
}
});
var MH003Group2 = {
all: function () {
return MH003Group.all().filter(function (d) {
return d.value !== null;
});
}
};
dataTable.width(960)
.height(8000)
.dimension(providerDim)
// .group(MH003Group2)
.group(function (d) {
return 'data';
})
.size(10)
.columns([function (d) {return d.indicator_code;},
function (d) {return d.report_by_1;},
function (d) {return d.report_by_3;},
function (d) {return (d.observed / d.expected);}
]);
.sortBy(function (d) {return d.report_by_1;})
.order(d3.ascending);
In the code above I would like to display filtered rows in the dimension using the pre-defined grouping rather than all the rows of data in the dimension which is what is currently happening.
I'm having some trouble with the exit().remove() function in a stacked area chart I am creating.
JSFiddle here: Link
I have functionality where the user can enable/disable the data in the chart by clicking on the legend rectangle/color. I know that the data is being updated based on console messages and the Y axis changing scale, but the data in the chart does not change. For instance if the user deselects the Failed category the orange layer should disappear and the Failed and Passed layers should re-adjust.
The issue appears to be in lines 214 to 234 in the fiddle, specifically where I am calling exit().remove():
// filter the data
var updatedData = dataSeries.filter(function(d) {
if(d.vis === "1"){
return d;
}
else {
return null;
}
});
stack.values(function(d) { return d.values; });
layer = stack(updatedData);
main_layer.selectAll(".layer")
.data(layer);
main_layer
.attr("d", function(d) { return main_area(d.values); });
main_layer.exit().remove();
The error I am getting is Object [object Array] has no method exit I have tried changing the selectAll to just a select, but that also produces the same error. Thanks in advance.
I finally got this working. The code below updates the layers correctly:
// filter the data
var updatedData = dataSeries.filter(function(d) {
if(d.vis === "1"){
return d;
}
else {
return null;
}
});
stack(updatedData);
var sel = main_layer.select(".layer");
sel
.attr("class", function(d) { return d.key + " layer"; })
.style("fill", function(d, i) {
if(d.vis === "1") {
return z(i);
}
else return null;
})
.attr("d", function(d) {
if(d.vis === "1") {
return main_area(d.values);
}
else return null;
});
Using D3, how can I find the maximum value in an object where all the values are arrays of floats?
var data = {
"point1": {
"level1": [...],
"level2": [...]
},
...
};
I read Mike's answer on finding the max of a nested array, but I'm not sure what to do here since this is an object of arrays.
Currently I'm doing this, which is awful:
var c1Max = d3.max(data.point1.level1, function(d) { return d.value; });
var c2Max = d3.max(data.point1.level2, function(d) { return d.value; });
var c3Max = d3.max(data.point2.level1, function(d) { return d.value; });
var c4Max = d3.max(data.point2.level2, function(d) { return d.value; });
var c5Max = d3.max(data.point3.level1, function(d) { return d.value; });
var c6Max = d3.max(data.point3.level2, function(d) { return d.value; });
var max = d3.max([c1Max, c2Max, c3Max, c4Max, c5Max, c6Max]);
Maybe I should iterate over all the keys? Or maybe I could flatten the data object somehow? Or maybe there's a nicer way.
You can use d3.entries to convert the object into something you can iterate over:
var max = d3.max(d3.entries(data), function(d) {
return d3.max(d3.entries(d.value), function(e) {
return d3.max(e.value);
});
});
In this particular case (keys not required) you can of course also use d3.values, which makes the above code a bit shorter.
To make it work with the structure in your jsfiddle, you need this code:
var max1 = d3.max(d3.entries(data), function(d) {
return d3.max(d3.entries(d.value), function(e) {
return d3.max(e.value, function(f) { return f.value; });
});
});
I'm new to D3 and working on a modified version of Chained Transitions: http://bl.ocks.org/mbostock/3903818.
However one problem I'm running into is forcing the y-axis to start at 0. Normally this would be simple fix with changing the y domain and range properties when declaring your other variables but in the context of the transition function, I'm running into issues. Here is the code: http://jsfiddle.net/maureenlinke/DCc6g/
I believe the issue is here:
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([
d3.min(homes, function(c) { return d3.min(c.values, function(v) { return v.price; }); }),
d3.max(homes, function(c) { return d3.max(c.values, function(v) { return v.price; }); })
]);
Thanks,
Maureen
You just need to fix the domain:
var maxPrice = d3.max(homes, function(c) {
return d3.max(c.values, function(v) { return v.price; });
});
y.domain([0, maxPrice]);
The d3.extent function returns the min/max range of the data in the form of an array [min, max].
Normally, you would code the following:
y.domain( d3.extent(homes, function(d) { return d.price; }) );
So the following should work:
var yRange = d3.extent(homes, function(d) { return d.price; });
y.domain( [0, yRange[1] ); // Force the min to 0