Подтвердить что ты не робот

Гистограмма с отрицательными значениями

Мне нужно создать диаграмму d3, которая может иметь отрицательные значения. В идеале нулевая позиция оси должна рассчитываться на основе объема данных, но я бы согласился на решение, которое предполагает симметричную положительную и отрицательную степень, т.е. Что он всегда будет посреди диаграммы.

Вот пример того, что я хотел бы достичь.

Bar chart with negative values

4b9b3361

Ответ 1

ОК, скажем, у вас есть массив чисел в качестве вашего набора данных, и это включает в себя некоторые положительные и отрицательные значения:

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

Вы хотите, чтобы две шкалы построили гистограмму. Вам нужен один количественный масштаб (обычно линейный масштаб), чтобы вычислить позиции столбца вдоль оси x и второй порядковый номер масштаб, чтобы вычислить позиции столбцов вдоль оси y.

Для количественного масштаба вам обычно необходимо вычислить домен ваших данных, который основан на минимальном и максимальном значении. Легкий способ сделать это через d3.extent:

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

Вы также можете захотеть nice масштаб в несколько раз. В качестве другого примера иногда вам нужно, чтобы нулевое значение было центрировано в середине холста, и в этом случае вам нужно взять большее минимальное и максимальное значение:

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

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

В качестве альтернативы вы можете жестко запрограммировать любой домен, который вы хотите.

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

Для оси y вы хотите использовать rangeRoundBands, чтобы разделить вертикальное пространство на полосы для каждого бара. Это также позволяет указать количество отступов между столбцами. Часто используется порядковая шкала с некоторыми идентифицирующими данными, такими как имя или уникальный идентификатор. Тем не менее, вы также можете использовать порядковые шкалы в сочетании с индексом данных:

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

Теперь, когда у вас есть ваши две шкалы, вы можете создать элементы rect, чтобы отображать столбцы. Одна сложная часть заключается в том, что в SVG позиционируются прямоугольники (атрибуты x и y) в зависимости от их верхнего левого угла. Поэтому нам нужно использовать x- и y-шкалы для вычисления положения левого верхнего угла, и это зависит от того, является ли связанное значение положительным или отрицательным: если значение положительное, то значение данных определяет правый край от бара, а если он отрицательный, он определяет левый край панели. Отсюда и условные обозначения:

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

Наконец, вы можете добавить ось для отображения меток сверху. Вы также можете вычислить стиль заполнения (или даже градиент), чтобы изменить дифференцирование появления положительных и отрицательных значений. Объединяя все это: