Столбчатая диаграмма в D3.js строится на основе сопоставления дискретных категорий с количественными значениями и визуального кодирования этих значений через длину или высоту прямоугольных элементов. Базовая идея заключается в том, что каждая категория отображается отдельной полосой, а значение определяет размер этой полосы вдоль выбранной оси.
Для построения столбчатых диаграмм используется массив объектов, где каждый элемент содержит категорию и числовое значение.
const data = [
{ name: "A", value: 30 },
{ name: "B", value: 80 },
{ name: "C", value: 45 },
{ name: "D", value: 60 }
];
Категориальная переменная name используется для оси X
(или Y в горизонтальном варианте), а value определяет длину
столбца.
Визуализация строится внутри SVG-элемента, который задаёт область рисования.
const width = 600;
const height = 400;
const svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
SVG выступает базовым холстом, на котором размещаются прямоугольники, оси и подписи.
Для преобразования данных в координаты используются шкалы. В столбчатых диаграммах ключевую роль играет комбинация категориальной и линейной шкалы.
const xScale = d3.scaleBand()
.domain(data.map(d => d.name))
.range([0, width])
.padding(0.1);
const yScale = d3.scaleLinear()
.domain([0, d3.max(data, d => d.value)])
.nice()
.range([height, 0]);
Ключевые моменты:
scaleBand распределяет категории равномерно по
оси.padding управляет расстоянием между столбцами.scaleLinear отвечает за количественное масштабирование
значений.Вертикальная ориентация предполагает, что столбцы растут снизу вверх.
svg.selectAll(".bar")
.data(data)
.enter()
.append("rect")
.attr("class", "bar")
.attr("x", d => xScale(d.name))
.attr("y", d => yScale(d.value))
.attr("width", xScale.bandwidth())
.attr("height", d => height - yScale(d.value))
.attr("fill", "steelblue");
Каждый прямоугольник определяется четырьмя параметрами:
x — положение по горизонтали через категориальную
шкалуy — верхняя точка столбцаwidth — ширина полосыheight — разница между базовой линией и значениемОсь Y инвертирована, поскольку SVG-координаты начинаются сверху.
Оси повышают читаемость визуализации.
const xAxis = d3.axisBottom(xScale);
const yAxis = d3.axisLeft(yScale);
svg.append("g")
.attr("transform", `translate(0, ${height})`)
.call(xAxis);
svg.append("g")
.call(yAxis);
Ось X размещается внизу, а ось Y — слева.
Горизонтальная ориентация меняет роли осей: значения откладываются по горизонтали, а категории — по вертикали.
const yScale = d3.scaleBand()
.domain(data.map(d => d.name))
.range([0, height])
.padding(0.1);
const xScale = d3.scaleLinear()
.domain([0, d3.max(data, d => d.value)])
.nice()
.range([0, width]);
svg.selectAll(".bar")
.data(data)
.enter()
.append("rect")
.attr("class", "bar")
.attr("y", d => yScale(d.name))
.attr("x", 0)
.attr("height", yScale.bandwidth())
.attr("width", d => xScale(d.value))
.attr("fill", "tomato");
В горизонтальной диаграмме:
Вертикальная диаграмма:
Горизонтальная диаграмма:
Добавление отступов между столбцами управляется через
paddingInner и paddingOuter:
d3.scaleBand()
.paddingInner(0.2)
.paddingOuter(0.1);
Сетка помогает визуально сопоставлять значения:
const yGrid = d3.axisLeft(yScale)
.tickSize(-width)
.tickFormat("");
svg.append("g")
.call(yGrid);
Цвет может зависеть от значения или категории:
.attr("fill", d => d.value > 50 ? "green" : "gray");
Или через шкалу:
const colorScale = d3.scaleSequential()
.domain([0, d3.max(data, d => d.value)])
.interpolator(d3.interpolateBlues);
Плавные переходы усиливают восприятие динамики:
svg.selectAll(".bar")
.data(data)
.transition()
.duration(800)
.attr("height", d => height - yScale(d.value))
.attr("y", d => yScale(d.value));
Для горизонтальной версии аналогично изменяется
width.
Механизм связывания данных с DOM-элементами:
const bars = svg.selectAll(".bar")
.data(data);
bars.enter()
.append("rect")
.merge(bars)
.transition()
.attr("width", d => xScale(d.value));
bars.exit().remove();
Для динамической подстройки под контейнер используется вычисление размеров:
const width = parseInt(d3.select("#chart").style("width"));
И пересчёт шкал при изменении размеров контейнера позволяет сохранять пропорции.
Подписи значений добавляются через текстовые элементы:
svg.selectAll(".label")
.data(data)
.enter()
.append("text")
.attr("x", d => xScale(d.name) + xScale.bandwidth() / 2)
.attr("y", d => yScale(d.value) - 5)
.attr("text-anchor", "middle")
.text(d => d.value);
В горизонтальной диаграмме подписи обычно размещаются внутри или справа от столбца.
range у шкалscaleBanddata.sort((a, b) => b.value - a.value);
Позволяет упорядочить столбцы по убыванию.
data.filter(d => d.value > 40);
Используется для динамического уменьшения количества отображаемых элементов.
Для составных диаграмм применяется вложенная структура данных и несколько шкал.
Оси автоматически пересчитываются при изменении шкал:
svg.select(".x-axis")
.transition()
.call(xAxis);
Это критично при анимации или интерактивной фильтрации данных.
При большом количестве элементов применяются:
join вместо
enter/update/exitsvg.selectAll(".bar")
.data(data)
.join("rect")
Столбчатая диаграмма в D3 строится как система преобразований:
данные → шкалы → координаты → SVG-элементы → оси → интеракции
Вертикальная и горизонтальная ориентации отличаются только перестановкой ролей осей и соответствующей перестройкой вычислений координат, сохраняя общую структуру визуализации неизменной.