Reputation: 4052
I'm new to D3 and playing around with a scatterplot. I cannot get d3.max(data) to work correctly in setting up domain!
I have the following setting up a random dataset:
var data = [];
for (i=0; i < 40; i++){
data.push({"x": i/40, "y": i/8, "a": Math.floor(Math.random() * 3), "x2": Math.random()});
}
And then the following to set my coordinates:
var x = d3.scale.linear().domain([0, 1]).range([0 + margin, w-margin]),
y = d3.scale.linear().domain([0, d3.max(data)]).range([0 + margin, h-margin]),
c = d3.scale.linear().domain([0, 3]).range(["hsl(100,50%,50%)", "rgb(350, 50%, 50%)"]).interpolate(d3.interpolateHsl);
This puts all 40 points in a single, horizontal line. If I replace d3.max(data) with '5' then it is a diagonal (albeit from the upper left to the bottom right, I'm still struggling to flip y-coordinates). Why isn't d3.max(data) working as expected?
Upvotes: 6
Views: 12370
Reputation: 75
I was having a similar issue dealing with an associative array. My data looked like the following: [{"year_decided":1982,"total":0},{"year_decided":"1983","Total":"847"},...}]
Simply passing parseInt before returning the value worked.
var yScale = d3.scale.linear()
.domain([0, d3.max(query,function(d){ return parseInt(d["Total"]); }) ])
.range([0,h]);
Upvotes: 0
Reputation: 109242
d3.max()
expects an array of numbers, not of objects. The elements of data
have an internal key-value structure and there is no way for d3.max()
to know what to take the maximum of. You can use something like jQuery's $.map
to get the elements of the objects you want and then take the max, e.g.
var maxy = d3.max($.map(data, function(d) { return d.y; }));
Edit:
As pointed out in the comment below, you don't even need JQuery for this, as .map()
is a native Array method. The code then becomes simply
var maxy = d3.max(data.map(function(d) { return d.y; }));
or even simpler (and for those browsers that don't implement Array.map()
), using the optional second argument of d3.max
that tells it how to access values within the array
var maxy = d3.max(data, function(d) { return d.y; });
Upvotes: 10
Reputation: 9759
d3.max
API documentation can be found here.
# d3.max(array[, accessor])
Returns the maximum value in the given array using natural order. If the array is empty, returns undefined. An optional accessor function may be specified, which is equivalent to calling array.map(accessor) before computing the maximum value. Unlike the built-in Math.max, this method ignores undefined values; this is useful for computing the domain of a scale while only considering the defined region of the data. In addition, elements are compared using natural order rather than numeric order. For example, the maximum of ["20", "3"] is "3", while the maximum of [20, 3] is 20.
Applying this information to the original question we get:
function accessor(o){
return o.y;
}
var y = d3.scale.linear()
.domain([0, d3.max(data, accessor)])
.range([0 + margin, h-margin]);
If you end up using many accessor functions you can just make a factory.
function accessor(key) {
return function (o) {
return o[key];
};
}
var x = d3.scale.linear()
.domain([0, d3.max(data, accessor('x'))])
.range([...]),
y = d3.scale.linear()
.domain([0, d3.max(data, accessor('y'))])
.range([...]);
Upvotes: 4