2012-04-12 21 views
24

Ho bisogno di creare un grafico a barre d3 che può avere valori negativi. Idealmente, la posizione zero dell'asse dovrebbe essere calcolata in base all'estensione dei dati, ma mi accontento di una soluzione che presuppone un'estensione simmetrica positiva e negativa, vale a dire che sarebbe sempre nel mezzo del grafico.Grafico a barre con valori negativi

Ecco un esempio di ciò che mi piacerebbe ottenere.

Bar chart with negative values

risposta

52

OK, diciamo che si dispone di una serie di numeri come set di dati, e questo include alcuni valori positivi e negativi:

var data = [-15, -20, -22, -18, 2, 6, -26, -18]; 

Ti consigliamo due scale per la costruzione di un grafico a barre . Occorrono una scala quantitativa (tipicamente un linear scale) per calcolare le posizioni della barra lungo le x -axis, ed una seconda ordinal scale di calcolare le posizioni della barra lungo le y -axis.

Per la scala quantitativa, in genere è necessario calcolare il dominio dei dati, che si basa sul valore minimo e massimo. Un modo semplice per farlo è tramite d3.extent:

var x = d3.scale.linear() 
    .domain(d3.extent(data)) 
    .range([0, width]); 

Si potrebbe anche voler nice la scala per arrotondare un po 'il punto. Come altro esempio, a volte si desidera che il valore zero a essere centrata nel mezzo della tela, nel qual caso si vorrà prendere il maggiore tra il valore minimo e massimo:

var x0 = Math.max(-d3.min(data), d3.max(data)); 

var x = d3.scale.linear() 
    .domain([-x0, x0]) 
    .range([0, width]) 
    .nice(); 

In alternativa, si può hard-code qualsiasi dominio tu voglia.

var x = d3.scale.linear() 
    .domain([-30, 30]) 
    .range([0, width]); 

Per i y -axis, ti consigliamo di utilizzare rangeRoundBands per dividere lo spazio verticale in bande per ogni barra. Ciò consente anche di specificare la quantità di padding tra le barre. Spesso una scala ordinale viene utilizzata con alcuni dati identificativi, come un nome o un ID univoco. Tuttavia, è anche possibile utilizzare le scale ordinali in combinazione con l'indice i propri dati:

var y = d3.scale.ordinal() 
    .domain(d3.range(data.length)) 
    .rangeRoundBands([0, height], .2); 

Ora che hai la tua due scale, è possibile creare gli elementi rect per visualizzare le barre. L'unica parte delicata è che in SVG, i rects sono posizionati (gli attributi x e in base all'angolo in alto a sinistra. Quindi abbiamo bisogno di usare il x - e y - scale per calcolare la posizione dell'angolo in alto a sinistra e che dipende dal fatto che il valore associato sia positivo o negativo: se il valore è positivo, allora il valore dei dati determina il lato destro della barra, mentre se è negativo determina il bordo sinistro della barra. Da qui i condizionali qui:

svg.selectAll(".bar") 
    .data(data) 
    .enter().append("rect") 
    .attr("class", "bar") 
    .attr("x", function(d, i) { return x(Math.min(0, d)); }) 
    .attr("y", function(d, i) { return y(i); }) 
    .attr("width", function(d, i) { return Math.abs(x(d) - x(0)); }) 
    .attr("height", y.rangeBand()); 

Infine, è possibile aggiungere un asse per visualizzare i segni di graduazione sulla parte superiore. Potresti anche calcolare uno stile di riempimento (o anche un gradiente) per alterare la differenziazione dell'aspetto dei valori positivi e negativi. Mettere tutto insieme:

Problemi correlati