Создание демографической пирамиды с помощью D3.js
-
21-12-2019 - |
Вопрос
Мне нужно создать классическую демографическую пирамиду с помощью D3.js.Что-то похожее на это изображение:
Я нашел несколько примеров, которые выглядят действительно хорошо (этот и этот), но они более сложны, чем я ищу.Кто-нибудь знает хороший ПРОСТОЙ пример, на который я могу посмотреть?Есть какой-нибудь совет, как начать это делать?Должен ли я просто построить две гистограммы рядом друг с другом, по одной для каждой половой группы?
Решение
Ключ к созданию такой визуализации — потратить достаточно времени на предварительную настройку макета, прежде чем вы приступите к рисованию.
Есть несколько ключевых измерений, которые вы захотите использовать, чтобы значительно облегчить себе жизнь, когда придет время создавать шкалы и оси для вашей диаграммы.Затем вы можете использовать <g>
элементы с переводами, чтобы в каждом «разделе» вашей диаграммы можно было работать в локальных координатах.
Цель состоит в том, чтобы создать две зеркальные области, подобные этой:
Это позволит вам использовать одни и те же масштабы для измерений x и y в двух регионах.
Чтобы определить эти области, вы можете сначала установить некоторые значения для полей внутри вашего SVG, а затем создать группу, которая будет находиться внутри этих полей.Это обычная практика в визуализациях d3, и если вы еще с ней не знакомы, сейчас самое время поучиться.Обычно это выглядит примерно так:
var width = 400,
height = 300;
var margin = {
top: 20,
right: 10
bottom: 40,
left: 10
};
var svg = d3.select('body').append('svg')
.attr('width', margin.left + width + margin.right)
.attr('height', margin.top + height + margin.bottom)
.append('g')
.attr('class', 'inner-region')
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
Это хорошая практика, которой следует следовать, поскольку она позволяет вам оставить место в вашем svg-документе для отметок осей, меток и заголовков без необходимости учитывать это пространство при позиционировании частей самой визуализации.Позже, если вы обнаружите, что вам нужно больше места, вы можете просто изменить одно значение в верхней части кода, а не переставлять всю диаграмму.
Другие важные точки — это координаты X двух осей Y.Другими словами, точки, в которых численность населения равна нулю для мужчин и женщин (показаны красными линиями ниже).Это будет заданное расстояние от центральной линии вашей внутренней области (показано синей линией ниже):
Вы можете добавить свойство среднего поля к созданному ранее объекту поля, чтобы ссылаться на это значение:
margin.middle = 28;
Вам понадобится создать переменные для хранения положений двух красных линий выше.А пока давайте позвоним им pointA
(координата x нулевой линии для мужского населения) и pointB
(соответствующая точка для женского населения).
var regionWidth = (width/2) - margin.middle;
var pointA = regionWidth,
pointB = width - regionWidth;
Как только вы настроите эти точки, все станет намного проще, поскольку вы можете просто подключить эти значения к преобразованию SVG, чтобы перевести создаваемые вами объекты в эти позиции.
Самой сложной частью будут две центральные оси Y, которые имеют один набор меток.Для этого вам нужно хорошо разбираться в том, как d3.svg.axis()
создает свои текстовые метки и определяет, какими свойствами можно манипулировать.Для этого нужно знать четыре важных свойства:
axis.orient(direction)
указывает направление, в котором указывают галочки, выходящие из оси.В данном случае это будет немного сбивать с толку, поскольку мы хотим, чтобы отметки были направлены к центру, поэтому левая ось будет иметь.orient('right')
и правая ось будет иметь.orient('left')
axis.tickSize(inner,outer)
устанавливает длину (в единицах SVG) делений, выходящих из оси.«Внешние» метки — это метки на конечных точках оси, их можно установить на0
в данном случае потому, что мы используем порядковую шкалу с диапазонами диапазонов, поэтому конечные точки не представляют значения.Выберите небольшое значение для внутренних тиков, в этом примере я буду использовать4
.axis.tickPadding(padding)
устанавливает, насколько далеко от конца галочки размещается текстовая привязка текста метки.Мы хотим разместить текстовую привязку в центре изображения, прямо между двумя осями.Поскольку мы уже знаем среднее поле (расстояние от центральной линии до каждой оси) и знаемtickSize
(длина делений), мы можем разместить их в центре, взяв разницу этих двух значений:.tickPadding(margin.middle - 4)
.axis.tickFormat(format)
определяет формат меток делений.Для него можно установить пустую строку, чтобы удалить метки делений с одной из осей, чтобы не происходило перекрытия:.tickFormat('')
Итак, две оси Y можно определить следующим образом:
var yAxisLeft = d3.svg.axis()
.scale(yScale)
.orient('right')
.tickSize(4,0)
.tickPadding(margin.middle - 4);
var yAxisRight = d3.svg.axis()
.scale(yScale)
.orient('left')
.tickSize(4,0)
.tickFormat('');
Затем, рисуя левую ось Y, выберите ее <text>
элементы и установите текстовый якорь как middle
поэтому они будут сосредоточены вокруг якоря:
.call(yAxisLeft)
.selectAll('text')
.style('text-anchor', 'middle');
ЗДЕСЬ — это простой пример всей диаграммы с использованием некоторых надуманных данных.Я постарался прокомментировать как можно больше общей структуры, чтобы было легче понять.Я также сделал translation(x,y)
функция, позволяющая облегчить определение координат x и y каждого перевода, чем при использовании конкатенации строк.Вы можете найти его определение внизу скрипта.
Надеюсь, это поможет. Если у вас возникнут вопросы по поводу деталей, дайте мне знать.