Я использую D3 уже несколько лет в таких проектах, как 100 компаний и Михмихи, я также писал туториалы по таким вещам, как как рисовать карты. Тем не менее, я никогда не писал введение в D3, потому что трудно передать его великолепие, не просто используя его. Итак, давайте начнем.

Документы, управляемые данными

Прежде всего, D3 — это функциональный набор инструментов для визуализации данных, который привязывает данные к визуальным элементам. Используя связанные данные, атрибуты и внешний вид элементов можно определить с помощью утилит и функций. В этом сила D3; он не ориентирован на визуализацию, он ориентирован на данные и функции для использования этих данных.

Примечание. D3 может использовать любой элемент объектной модели документа (DOM), например элементы SVG или HTML. В этом руководстве будет использоваться D3 с HTML и CSS (вместо SVG), так как с ними знакомо больше разработчиков.

Связывание данных

Давайте привяжем часть данных к элементу body:

d3.select('body').datum('red')

Строка «красный» теперь привязана к телу.

Теперь давайте извлечем эти данные:

d3.select('body').datum() // 'red'

Что может быть за данные? Любой элемент Javascript, например объекты, строки, массивы и т. д. D3 просто запоминает отношения между элементом и данными, чтобы их можно было использовать позже.

Вы можете использовать D3 для установки атрибутов элемента, к которому вы привязали данные:

// changes the body's CSS color to red
d3.select('body').style('color',
  function(datum){
    // datum == 'red'
    return datum
  }
)

Вы также можете связать многие функции, предлагаемые D3, для более удобного использования:

// changes the CSS background-color to 'blue'
d3.select('body')
.datum('blue')
.style('background-color',
  function(datum){
    // datum == 'blue'
    return datum
  }
)

Если у вас много данных, вы можете выбрать несколько элементов с помощью selectAll и привязать их к этим элементам с помощью функции данных.

Примечание. Многие функции в D3 возвращают Selection, включая данные selectAll и select

// Selection of all p elements
p = d3.selectAll('p')
// bind data to the first 5 p elements
p.data(['red','green','blue','black','white'])
// changes the CSS background-color to bound datum
p.style('background-color',
  function(datum){
    return datum
  }
)

D3 также помогает, если у вас больше (или меньше) данных, чем существующих элементов. Функции ввода и выхода используются с добавлением и удалением соответственно, чтобы вы могли создавать и уничтожать элементы.

Примечание: функция данных возвращает ограниченный выбор только элементов, которые могут быть привязаны к данным.

// Selection of all p elements in body
p = d3.select('body').selectAll('p')
// bind data to the first 5 p elements, get restricted Selection
pdata = p.data(['red','green','blue','black','white'])
// add p elements if they don't already exist
pdata.enter().append('p')
// remove p elements if there are too many
pdata.exit().remove()

Создание функций

Привязка данных к элементам с помощью D3 — это круто, но знаете, что действительно круто? Функции! В D3 есть огромный набор функций высшего порядка (функций, возвращающих функции), которые позволяют легко создавать полезные инструменты для управления данными.

В частности, моя любимая функция в D3 — Весы.

В следующем примере я буду использовать шкалу Сковилла того, насколько остротой отличается перец для нашего примера. Вот некоторые данные (shu расшифровывается как Scoville Heat Unit):

data = [
  { name: 'Pimento', shu: 100},
  { name: 'Anaheim', shu: 2500},
  { name: 'Jalapeno', shu: 10000},
  { name: 'Cayenne', shu: 50000},
  { name: 'Habanero', shu: 350000},
  { name: 'Ghost', shu: 1500000}
]

Квантовать весы

Я начну с создания функции для описания этих данных такими словами, как средний и горячий. Для этого от 0 до 1 500 000 SHU необходимо преобразовать в слова, используя Шкалу квантования, которая имеет непрерывный домен (вход) и дискретный диапазон (выход).

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

logscale = d3.scale.log()
.domain([1,1500000])
.range([0,1])

Эта шкала создает функцию, которая принимает число от 1 до 1 500 000 и возвращает число от 0 до 1 на логарифмической кривой.

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

Теперь давайте определим список слов, используя шкалу квантования:

qscale = d3.scale.quantize()
.domain([0,1])
.range(['nothing', 'mild','medium','hot'
,'burning','scorching','hellfire'])

Эта функция принимает число от 0 до 1 и возвращает элемент из предоставленного списка слов. Например, qscale(0) вернет «ничего», а qscale(1) вернет «адский огонь».

Чтобы быть полезной, необходима функция, которая объединяет и отображает предоставленные данные:

textscale = function(datum){
  return qscale(
    logscale(datum.shu)
  )
}

Текстовая шкала возьмет объект перца и вернет слово, соответствующее его остроте. Для проверки результатов карта может быть использована:

data.map(textscale)
// ["medium", "hot", "burning", "scorching", "hellfire", "hellfire"]

Линейные шкалы

В некоторых местах используется несколько значков, отображающих, насколько что-то горячо, например. от 0 до 4 чили. Для этого можно использовать Линейную шкалу:

linearscale = d3.scale.linear()
.domain([0,1])
.range([0,4])

Эта шкала принимает число от 0 до 1 и возвращает число от 0 до 4 на линейной линии, например. linearscale(.5) возвращает 2. Однако она может возвращать нецелые числа, поэтому при создании функции отображения она должна округлять выходные данные.

chiliscale = function(datum){
  return Math.round(
    linearscale(
      logscale(datum.shu)
     )
  )
}
data.map(chiliscale)
// [1, 2, 3, 3, 4, 4]

Цветовые шкалы

Еще один способ визуализировать остроту перца — использовать цвет. Одной из лучших особенностей D3 является то, что он позволяет использовать шестнадцатеричные цвета в диапазонах функций масштабирования. Вот как вы можете использовать линейную шкалу для определения цвета:

colorscale = d3.scale.linear()
.domain([0,1])
.range(['#FFF', '#933'])

Эта шкала принимает число от 0 до 1 и возвращает цвет от белого до красноватого. Опять же, необходима простая функция отображения:

burnscale = function(datum){
  return colorscale(
      logscale(datum.shu)
  )
}
data.map(burnscale)
// ["#debdbd", "#c78f8f", "#bd7b7b", "#b16464", "#a34848", "#993333"]

Добавление визуальных элементов

Используя инструменты, которые я обсуждал ранее, давайте создадим простую визуализацию для набора данных о перцах.

Сначала давайте создадим несколько div для наших перцев:

peppers = d3.select('.peppers').selectAll('div')
pepperssdata = peppers.data(data)
.enter().append('div').attr('class','pepper')

Примечание. Я добавил класс перец для некоторого стиля

Используя текстовую функцию, текст внутри div может быть установлен на имя перца:

pepperssdata.text(
  function(datum){
    return datum.name
  }
)

Добавляется div с классом how-spicy с текстом, назначенным функцией textscale:

pepperssdata.append('div').attr('class','how-spicy').text(
  function(datum){
    return 'is ' + textscale(datum)
  }
)

Цвет фона задается функцией Burnscale:

pepperssdata.style('background-color', burnscale)

Это самый сложный кусок кода, но он не содержит ничего такого, чего раньше не видели:

pepperssdata.append('div').attr('class','fire').selectAll('i')
.data(
  function(datum){
   return new Array(chiliscale(datum))
  }
)
.enter().append('i').attr('class','fa fa-fire')

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

Примечание. К сожалению, в Font Awesome нет значка чили (см. здесь)

Добавьте немного CSS и:

http://bl.ocks.org/grahamjenson/raw/9950335/

Просмотреть код здесь

Это не самая красивая, или очень полезная, или самая интересная визуализация в мире. Тем не менее, это хорошее начало для изучения D3.

Вывод

D3 — мощный инструмент, и этот пост лишь немного коснулся поверхности. Если вы хотите изучить D3, я рекомендую найти интересующие вас данные, а затем сделать для них небольшую визуализацию. D3 определенно является инструментом, который вы изучаете, используя его, так что идите и используйте его.

Читать далее

Время от времени я захожу в блоки и смотрю, что строит Майк Босток (создатель D3). Вы можете получить несколько удивительных примеров D3 оттуда.

Визуальное отображение количественной информации — Эдвард Тафте

Начало работы с D3 — Майк Дьюар