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

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

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

Bar chart with negative values

Ответы на вопрос(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]);

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

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

Теперь, когда у вас есть две шкалы, вы можете создать прямоугольные элементы для отображения полос. Одна сложная часть заключается в том, что в 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());

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

Bar Chart with Negative Values

Ваш ответ на вопрос