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

Я фанат D3.js. В прошлом у меня была возможность использовать его для создания нескольких библиотек диаграмм для компаний, ориентированных на данные, в том числе: Datameer dashboard, Plotly Micropolar, Boundary Firespray и Radio-Canada Moby. Многие библиотеки диаграмм построены на основе D3. Вот список из более чем 35.

Сегодня в Planet OS запускаем новейшую библиотеку - Cirrus.js. Так зачем я строю эту?

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

Джером Кукье написал отличный пост в блоге (как всегда), чтобы напомнить нам, почему мы любим D3 и как мы иногда используем его для удобства, не подвергая сомнению наши потребности и не оценивая альтернативы. Учитывая проблемы визуализации, которые мы планируем решать в Planet OS, мне показалось, что это хорошая возможность спросить себя, почему я использую D3 и чего я хочу, что нетривиально с D3.

Отделение от DOM

Как вы используете D3 с Canvas? Сообщество всегда находит творческие способы использования D3. Вот несколько примеров.

А что насчет WebGL? VML (с использованием Raphael, для IE7 +)? Всегда есть решение. Но мне нужна была простая абстракция, многоцелевой рендерер для SVG, Canvas и WebGL. Механизм абстрактного рендеринга просто не входит в сферу применения ядра D3. Итак, я изучил:

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

Затем мне потребовался чистый компонент оси HTML (например, более простое форматирование текста, работа на платформе без поддержки SVG), а для D3 нужен SVG. Это было легко, поскольку моей личной задачей с Moby было заставить его работать на чистом HTML. Даже пузырьковые диаграммы состоят из блоков div с закругленными углами, а линии - из блоков с вращением CSS. Компоненту оси HTML по-прежнему нужна DOM, но при необходимости было бы легко использовать мой простой многоцелевой рендерер.

Но на самом деле я хотел приблизить архитектуру к конвейеру datavis.

Пайплайн Datavis

Лучшие графические библиотеки и фреймворки (такие как ggplot и D3) вдохновлены Грамматикой графики и другими концептуальными фреймворками, чтобы формализовать, как перейти от пространства данных к пространству пикселей. Вот упрощенная (удобно наивная) версия, которую я использую в Cirrus.js: данные, масштаб, макет, атрибут, компонент, средство визуализации, взаимодействие. Я делюсь этой минимальной библиотекой диаграмм в качестве примера разделения задач, который, я уверен, хорошо масштабируется.

Данные

Давайте начнем с данных и оставим в стороне соображения по сбору, размещению и загрузке, которые я предпочитаю обрабатывать за пределами библиотеки диаграмм. Мне нравится использовать формат массива объектов.

var data1 = [
    {name: 'Sensor1', values: [
        {x: 'Fri May 01 2015 13:00:00 GMT-0400 (EDT)', y: 1},
        {x: 'Sat May 02 2015 13:00:00 GMT-0400 (EDT)', y: 2},
        {x: 'Mon May 04 2015 13:00:00 GMT-0400 (EDT)', y: 3},
        {x: 'Tue May 05 2015 13:00:00 GMT-0400 (EDT)', y: 8}
    ]},
    {name: 'Sensor2', values: [
        {x: 'Fri May 01 2015 13:00:00 GMT-0400 (EDT)', y: 1},
        {x: 'Sat May 02 2015 13:00:00 GMT-0400 (EDT)', y: 2},
        {x: 'Mon May 04 2015 13:00:00 GMT-0400 (EDT)', y: 3},
        {x: 'Tue May 05 2015 13:00:00 GMT-0400 (EDT)', y: 8}
    ]}
];

Наличие x и y в качестве ключей уже означает, что они будут отображаться по осям x и y. Если вам это не нравится, вы можете использовать другие ключи и сообщить диаграмме, используя keyX и keyY. Мне также нравятся функции преобразования данных для преобразования необработанных наборов данных в этот общий формат. Все это будет в файле data.js, где пока есть только валидатор данных. Другие функции могут заключаться в преобразовании форматов или типов данных, преобразовании, вычислении агрегатов, получении наборов данных и т. Д.

Масштаб

Когда у нас есть набор данных в согласованном формате, мы можем определить нужные нам масштабы. Я вижу два применения масштабов: преобразование данных (например, проецирование в масштаб журнала) и проецирование в пиксельное пространство. Обертывание модуля для обработки всех типов масштабов D3 может быть немного утомительным, особенно если вы хотите автоматически настроить правильный масштаб. Я хочу, чтобы в моих графиках отображалось время, числовое и категориальное. Эта работа будет помещена в файл scale.js.

Макет

Макет - это имя D3 для генераторов, которые вычисляют значения графического пространства из данных. Это графическое пространство не обязательно должно быть в пикселях. Это может быть индекс, некоторые нормализованные значения и т. Д. Одна вещь, которую я не совсем понимаю в инструментах D3, - это то, как каждый макет немного отличается в том, как он обрабатывает данные (см. Это отличное обсуждение). Кстати, лучшая книга по верстке IMO - D3.js in Action. Я немного ленив, поэтому свернул свой, как делал это до того, как использовал D3. Таким образом, у меня есть общий макет для простой / составной / процентной гистограммы и для простых / множественных / линейных диаграмм. Я также распространил концепцию компоновки на оси, легенды и другие компоненты. Все это будет в layout.js. Одно важное различие, которое я пытаюсь сделать, заключается в том, что макет - это ничто без диспетчера атрибутов, который преобразует это графическое пространство в графические атрибуты так, как этого хочет средство визуализации.

Атрибуты

Графические атрибуты, высота / ширина, x / y, цвет и т. Д. Представлены здесь в пиксельном пространстве, непосредственно используемом средством визуализации. В файле attribute.js есть генератор атрибутов для каждого графического элемента. В его обязанности входит разрешение макетов в соответствии с конфигурацией и соглашением об именах для использования с средством визуализации. Например, макет имеет координаты x и y каждой точки линейной диаграммы, но генератор атрибутов позаботится о преобразовании этой информации в путь, представляющий формы области.

Компоненты

В последнее время некоторые очень хорошие проекты пытаются рассматривать построение диаграмм как сборку набора компонентов, таких как Plottable.js и D4. Мне очень нравится подход. В моем случае компоненты в component.js отвечают за сборку этой графической части из сгенерированных атрибутов.

Средство визуализации

Абстрактное средство визуализации в renderer.js, на данный момент очень минимальное, является адаптером для механизмов визуализации, которые я хочу использовать, абстрагируя SVG и Canvas под общим API. В какой-то момент у меня был 2D WebGL, но после тестирования я решил, что мне нужна лучшая стратегия, чтобы максимально использовать ее.

Взаимодействие

Мне всегда было сложно реализовать взаимодействие. D3 решает эту проблему элегантно, используя «поведения». Концептуально было бы действительно неплохо иметь «Грамматику взаимодействия», чтобы мы могли описывать взаимодействия с пользователем так же легко, как мы можем описывать графику. В файле Interaction.js есть основные всплывающие подсказки. Его задача - привязать события и направить их к нужному компоненту.

Ядро, утилиты, автоматизация

Некоторые файлы не подходят для концептуального конвейера, но необходимы для поддержки реализации. Одним из примеров является automatic.js, в котором разрешаются все элементы конфигурации, помеченные как «auto» (например, определение размера диаграммы из контейнера, количества делений из размеров меток и т. Д.). В файле utils есть функции, например, для экспорта в png. Одним из важных файлов является core.js, который запускает работу и предоставляет API. Мне нравится иметь один файл, показывающий объект конфигурации, внешний и внутренний, а также методы диаграммы. Здесь же собирается трубопровод.

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

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

var pipeline = fy.utils.pipeline(
    fy.setupContainers,
    fy.setupScales,
    fy.setupBrush,
    fy.setupAxisY,
    fy.setupAxisX,
    fy.setupHovering,
    fy.setupStripes,
    fy.setupGeometries
);

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

Модульный D3

Экосистема D3 потрясающая, с множеством плагинов, инструментов разработки, примеров, встреч, репозиториев, документации, галерей, блогов, книг, новостных лент Twitter, справочных форумов, IRC. Так какая же следующая революция в мире D3? Не знаю, но у нас уже есть намеки, что это произойдет из-за большей модульности. Я лично надеюсь, что у меня будет лучшая экосистема плагинов, больше владения крошечными частями ядра D3 и инструментами, особенно компонентами, макетами и преобразователями данных.

Работа над диаграммами Cirrus.js помогла мне сосредоточиться на архитектуре конвейера datavis вместо того, чтобы просто «упаковывать диаграммы» или исследовать лучшие шаблоны проектирования для решения архитектурной проблемы. Я рад открыть исходный код сегодня, не для того, чтобы получить еще одну библиотеку диаграмм в уже переполненном списке, а для того, чтобы поделиться примером моего собственного способа реализации конвейера datavis и, надеюсь, для того, чтобы иметь возможность извлечь некоторые модули для участия в мой скромный путь к этой модульной революции.

Так что команда Planet OS рада поделиться Cirrus.js, чтобы поддержать обсуждение реализации конвейера datavis. Не стесняйтесь обращаться ко мне через обычные каналы, особенно чтобы сообщить мне, как вы отражаете конвейер данных в своей собственной архитектуре.

Крис Вио

@ D3visualization

Инженер по визуализации данных ОС Planet