2012-03-13 2 views
6

Я новичок в D3 и играю с рассеянным экраном. Я не могу заставить d3.max (данные) работать правильно при настройке домена!Почему домен не использует d3.max (данные) в D3?

У меня есть следующие настройки случайного набора данных:

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()}); 
     } 

И затем следующее, чтобы установить мои координаты:

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); 

Это ставит все 40 точек в одной горизонтальной линии. Если я заменил d3.max (данные) на «5», то это диагональ (хотя и с верхнего левого угла вправо справа, я все еще пытаюсь перевернуть y-координаты). Почему d3.max (данные) работают как ожидалось?

ответ

9

d3.max() ожидает массив чисел, а не объектов. Элементы data имеют внутреннюю структуру ключевых значений, и нет никакого способа для d3.max() знать, что взять максимум. Вы можете использовать что-то вроде jQuery's $.map, чтобы получить элементы требуемых объектов, а затем взять максимум, например.

var maxy = d3.max($.map(data, function(d) { return d.y; })); 

Edit:

Как было отмечено в комментарии ниже, вы даже не нужно JQuery для этого, как .map() является нативный метод массива. Код становится просто

var maxy = d3.max(data.map(function(d) { return d.y; })); 

или даже проще (и для тех браузеров, которые не реализуют Array.map()), используя необязательный второй аргумент d3.max, который говорит, что, как получить доступ к значениям в массиве

var maxy = d3.max(data, function(d) { return d.y; }); 
+27

Для карты вам не нужен jQuery; это собственный метод Array: 'd3.max (data.map (function (d) {return d.y;})). 'd3.max()' принимает дополнительный аксессор в качестве второго аргумента, так что вы также можете сделать 'd3.max (data, function (d) {return d.y;})' –

3

d3.max Документация по API может быть найдена here.

# d3. макс (массив [, аксессор])

Возвращает максимальное значение в данном массиве, используя естественный порядок. Если массив пуст, возвращается неопределенный. Может быть указана необязательная функция доступа , что эквивалентно вызову array.map (accessor) перед вычислением максимального значения. В отличие от встроенного Math.max этот метод игнорирует неопределенные значения; это полезно для вычисления области масштаба, но только с учетом области, в которой находятся данные . Кроме того, элементы сравниваются с использованием естественного порядка, а не , чем числовой порядок. Например, максимальное значение [ "20", "3"] является "3", а максимум [20, 3] 20.

Применяя эту информацию к первоначальному вопросу мы получаем:

function accessor(o){ 
    return o.y; 
} 
var y = d3.scale.linear() 
     .domain([0, d3.max(data, accessor)]) 
     .range([0 + margin, h-margin]); 

Если вы в конечном итоге используете многие функции доступа, вы можете просто сделать завод.

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([...]); 
0

У меня была аналогичная проблема, связанная с ассоциативным массивом. Мои данные выглядели следующим образом: [{«year_decided»: 1982, «total»: 0}, {«year_decided»: «1983», «Total»: «847»}, ...}]

Просто передавая parseInt перед возвратом обработанного значения.

var yScale = d3.scale.linear() 
    .domain([0, d3.max(query,function(d){ return parseInt(d["Total"]); }) ]) 
    .range([0,h]);