2012-03-13 13 views
6

Sono nuovo di D3 e sto giocando con un grafico a dispersione. Non riesco a far sì che d3.max (data) funzioni correttamente nell'impostazione del dominio!Perché il dominio non utilizza d3.max (dati) in D3?

Ho la seguente creazione di un set di dati casuali:

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

E poi la seguente per impostare le mie coordinate:

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

Questo mette tutti i 40 punti in una sola riga, orizzontale. Se sostituisco d3.max (data) con '5', allora è una diagonale (anche se in alto a sinistra in basso a destra, sto ancora lottando per capovolgere le coordinate y). Perché d3.max (dati) non funziona come previsto?

risposta

9

d3.max() prevede una matrice di numeri, non di oggetti. Gli elementi di data hanno una struttura di valori-chiave interna e non è possibile per d3.max() sapere cosa prendere al massimo. Puoi usare qualcosa come jQuery's $.map per ottenere gli elementi degli oggetti che desideri e poi prendere il massimo, ad es.

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

Edit:

Come sottolineato nel commento qui sotto, non è nemmeno necessario JQuery per questo, come .map() è un metodo array nativo. Il codice diventa allora semplicemente

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

o ancora più semplice (e per quei browser che non implementano Array.map()), utilizzando il secondo argomento opzionale di d3.max che gli dice come accedere valori all'interno dell'array

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

Non è necessario jQuery per la mappa; è un metodo array nativo: 'd3.max (data.map (function (d) {return d.y;}))'. 'd3.max()' accetta un accessor opzionale come secondo argomento, quindi potresti anche fare 'd3.max (data, function (d) {return d.y;})' –

3

d3.max È disponibile la documentazione API here.

# d3. max (matrice [, di accesso])

restituisce il valore massimo nell'array specificato utilizzando ordine naturale. Se l'array è vuoto, restituisce undefined. È possibile specificare una funzione di accesso opzionale , che equivale a chiamare array.map (accessor) prima di calcolare il valore massimo. A differenza del Math.max integrato, questo metodo ignora i valori non definiti; questo è utile per calcolare il dominio di una scala considerando solo la regione definita dei dati . Inoltre, gli elementi vengono confrontati utilizzando l'ordine naturale piuttosto rispetto all'ordine numerico. Ad esempio, il massimo di [ "20", "3"] è "3", mentre il massimo di [20, 3] è 20.

Applicando queste informazioni alla domanda iniziale otteniamo:

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

Se si finisce per utilizzare molte funzioni di accesso, è sufficiente creare una fabbrica.

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

Avevo un problema simile relativo a un array associativo. I miei dati sono stati i seguenti: [{"year_decided": 1982, "totale": 0}, {"anno_decidato": "1983", "Totale": "847"}, ...}]

Semplicemente passare parseInt prima di restituire il valore lavorato.

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