Graphique à barres avec valeurs négatives

je dois créer un diagramme à barres d3 qui peut avoir des valeurs négatives. Idéalement, la position de l'axe zéro devrait être calculée sur la base de l'étendue des données, mais je me contenterais d'une solution qui suppose une étendue symétrique positive et négative, c'est-à-dire qu'elle serait toujours au milieu du graphique.

voici un exemple de ce que j'aimerais accomplir.

Bar chart with negative values

25
demandé sur khaledh 2012-04-12 20:04:10

1 réponses

OK, disons que vous avez un tableau de nombres comme ensemble de données, et cela inclut quelques valeurs positives et négatives:

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

vous aurez besoin de deux échelles pour construire un diagramme à barres. Vous avez besoin d'une échelle quantitative (typiquement linéaire) pour calculer les positions des barres le long du xl'axe, et un second échelle ordinale pour calculer les positions des barres le long du ol'axe.

pour l'échelle quantitative, généralement, vous devez calculer le domaine de vos données, qui est basé sur la valeur minimum et maximum. Une façon facile de le faire est via d3.mesure:

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

Vous pouvez aussi nice l'échelle arrondit légèrement l'étendue. Comme autre exemple, parfois vous voulez que la valeur zéro soit centrée au milieu de la toile, auquel cas vous voulez prendre la plus grande des valeurs minimum et maximum:

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

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

alternativement, vous pouvez coder n'importe quel domaine que vous voulez.

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

pour le ol'axe, vous aurez envie d'utiliser rangeRoundBands pour diviser l'espace vertical en bandes pour chaque barre. Cela vous permet également de spécifier la quantité de remplissage entre les barres. Souvent une échelle ordinale est utilisé avec certaines données d'identification, comme un nom ou un identifiant unique. Toutefois, vous pouvez également utiliser des échelles ordinales en conjonction avec l'index des données:

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

Maintenant que vous avez vos deux scales, vous pouvez créer les éléments rect pour afficher les barres. La seule partie délicate est que dans SVG, les rects sont positionnés (le x et y attributs) basés sur leur coin supérieur gauche. Nous avons donc besoin d'utiliser le x et o-échelles pour calculer la position du coin supérieur gauche, et qui dépend de la valeur associée est positif ou négatif: si la valeur est positive, alors la valeur de données détermine le bord droit de la barre, tandis que si c'est négatif, c' détermine le bord gauche de la barre. D'où les conditionnels ici:

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

Enfin, vous pouvez ajouter un axe pour afficher les marques de graduation sur le dessus. Vous pouvez également calculer un style de remplissage (ou même un gradient) pour modifier la différenciation de l'apparence des valeurs positives et négatives. Mettre tous ensemble:

53
répondu mbostock 2012-04-12 16:28:08