2012-03-13 6 views
6

Soy nuevo en D3 y juego con un diagrama de dispersión. No puedo hacer que d3.max (datos) funcione correctamente al configurar el dominio.¿Por qué el dominio no usa d3.max (datos) en D3?

que tienen la siguiente configuración de un conjunto de datos al azar:

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

Y entonces lo siguiente para configurar mis coordenadas:

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

Esto pone a los 40 puntos en una sola línea, horizontal. Si reemplazo d3.max (datos) con '5', entonces es una diagonal (aunque desde la parte superior izquierda hacia la parte inferior derecha, todavía estoy luchando para voltear las coordenadas y). ¿Por qué no está funcionando el d3.max (datos) como se esperaba?

Respuesta

9

d3.max() espera una matriz de números, no de objetos. Los elementos de data tienen una estructura interna de clave-valor y no hay forma de que d3.max() sepa qué tomar al máximo. Puede usar algo como jQuery's $.map para obtener los elementos de los objetos que desea y luego tomar el máximo, p.

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

Editar:

Como se señaló en el comentario anterior, que ni siquiera es necesario jQuery para esto, como .map() es un método de matrices nativas. El código se convierte entonces simplemente

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

o incluso más simple (y para los navegadores que no implementan Array.map()), utilizando el segundo argumento opcional de d3.max que le indica cómo acceder a los valores dentro de la matriz

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

No necesita jQuery para el mapa; es un método Array nativo: 'd3.max (data.map (function (d) {return d.y;}))'. 'd3.max()' toma un descriptor de acceso opcional como segundo argumento, por lo que también puede hacer 'd3.max (data, function (d) {return d.y;})' –

3

d3.max La documentación de la API se puede encontrar here.

# d3. max (array [, de acceso])

devuelve el valor máximo de la matriz dada usando orden natural. Si la matriz está vacía, devuelve indefinido. Se puede especificar una función de acceso opcional , que es equivalente a llamar a array.map (acceso) antes de calcular el valor máximo. A diferencia del Math.max incorporado, este método ignora los valores indefinidos; esto es útil para calcular el dominio de una escala, mientras que solo se considera la región definida de los datos . Además, los elementos se comparan usando el orden natural más bien que el orden numérico. Por ejemplo, el máximo de [ "20", "3"] es "3", mientras que el máximo de [20, 3] es 20.

La aplicación de esta información a la pregunta original, obtenemos:

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

Si termina usando muchas funciones de acceso, puede hacer una fábrica.

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

Estaba teniendo un problema similar relacionado con una matriz asociativa. Mis datos se veían como los siguientes: [{"year_decided": 1982, "total": 0}, {"year_decided": "1983", "Total": "847"}, ...}]

Simply pasando el parseInt antes de devolver el valor trabajado.

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