Визуализация данных в браузере с помощью D3.js



    Михаил Дунаев ( war_hol )


    С визуализацией данных и с различными диаграммами мы сталкиваемся каждый день, это какие-то Google Analitics, Интернет-банки, это Excel и т.д.



    На самом деле графики преследуют человечество всю нашу историю. Одна из первых визуализаций данных — это Х век н.э. Неизвестный астроном изобразил с помощью диаграмм движение небесных тел:




    Следующая интересная работа — это движение пятен по солнцу, XVII век:



    Тут уже виден некоторый таймлайн, он появляется от зарождения инфографики.



    Следующий. В XVIII веке появились такие устройства, которые позволяли делать механический таймлайн, т.е. прокручивая ручки слева и справа, вы можете разворачивать свиток в левую и правую сторону, и смотреть, узнавая историю из этого документа. Эдакая альтернатива книге:



    В это же время появляется такой прекрасный экземпляр визуализации данных:



    Это история человеческих империй. Тоже таймлайн, первый качественный цветной таймлайн, который появился у людей.

    А это самая известная историческая инфографика:



    На ней показывается движение войск Наполеона от Франции до Москвы и обратно. Соответственно, бежевый цвет — это движение до Москвы, черный цвет — это движение обратно. Толщина линий показывает количество войск у Наполеона. Обозначены специально реки и можем увидеть, как при переходе через реку Наполеон потерял часть своего войска. Такой вид представления данных, который позволяет нам наглядно «видеть» историю.

    Это уже наше время:



    Это визуализация, которая показывает места рождений и смерти носителей культуры — синим цветом обозначено место, где человек родился, красным — где он умер. Это ребята собрали всех исторических каких-то важных деятелей для культуры, ученых, артистов. И видно, что процесс урбанизации происходил во все время существования человечества, т.е. с самых ранних времен, люди-носители культуры стремились в культурные центры, и при всем при этом рождались на окраинах. Т.е. как сейчас со всей России люди едут в Москву. Это началось не сейчас, это было всегда.



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

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



    Вот хороший пример, как можно красиво представить классический график:



    Это уже не Excel. Это количество смертей в войне в Ираке — «New York Times» с помощью таких кровоподтеков показывает бар чарт. Во-первых, это красиво, во-вторых, сразу наглядно, сколько и когда людей погибало.

    Точно так же мои бывшие коллеги из студии инфографики «РИА Новости» что-то тут изобразили:



    Видно, как это красиво. Т.е. если мы не ограничиваемся графиками из Excel, то у нас сразу начинает получаться красиво и модно.

    Еще хороший пример:



    Это Флоренс Найтингейл, основательница медицинского движения в XIX веке изобразила причины смертей в английской армии. Видите, XIX век, а уже какая красивая графика.

    А это уже наше время, количество и популярность онлайн игр:



    И мой любимый пример, это мой жесткий диск:



    Этот вид графика называется treemap. Есть программа для Mac ОС и Windows, которая показывает нам площадь каждого прямоугольника — размер файла. Это все файлы на моем жестком диске. Видно, что зеленый — это сериальчик, который я смотрю, красный — это папка Applications, синий — это swap-файлы… Когда вы видите свой жесткий диск в таком виде, вы сразу можете понять, куда делось ваше место, какой файл много места занимает, — очень удобно и наглядно.

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

    Вот хороший пример на D3, в нем совмещены сразу несколько типов диаграмм и результат, конечно, фантастический:



    На самом деле, инфографика и визуализация данных под веб имеет очень короткую историю. Все началось в 90-х годах с программы «Macromedia Director».



    Это предвестник flash’а, на ней начали появляться первые какие-то типы визуализации данных под веб. Естественно, после «Macromedia Director» пришла нам в помощь «Adobe Flash Platform», она была прекрасной. На самом деле визуализировать данные, стоить графики на flash’е — не придумать лучше инструмента.



    «РИА Новости» использовала flash как основной инструмент для инфографики. Два года назад они полностью отказались от flash’а, а до этого времени использовали, потому что удобно.

    Естественно, на смену пришли эти трое парней — html, javascript, css:



    И привели за собой svg и WebGL, которые позволили нам делать под веб почти все то же самое, что мы могли делать на flash’е.



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



    Эта библиотека начала свое развитие в 2010-ом году, она последние пять лет динамично развивается, в последнее время, правда, не так сильно, но это, скорее, связано с тем, что ход как бы устоялся и новых фич не так много нужно придумывать. Мы можем увидеть, что 37 тыс. звездочек и почти 10 тыс. форков говорят о том, что библиотека действительно хороша. Она входит в 20-ку самых популярных библиотек на JavaScript для Github.



    Вот хороший пример. Использование непосредственно библиотеки D3 в наше время. «New York Times» не важно, что показывают, а важно то, как они это показывают:



    Здесь очень хорошо виден дата-драйвинг подход — каждый DOM элемент хранит в себе какой-то элемент, часть данных, и мы каждый раз, когда выбираем тот или иной способ отображения, просто говорим, как нам надо эти данные отобразить. Эти данные хранятся в элементе, и можно посмотреть, как D3 красиво делает анимацию, как это все работает качественно, быстро и, главное, что в продакшне нет никаких проблем.

    Вот тоже хороший пример, тоже D3:



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

    Или же третий пример:



    Это «Tokyo Wind Speed». Вы можете прямо сейчас найти и посмотреть в реальном времени — визуализируется скорость ветра в Токио. Очень красиво, каждый раз вы можете посмотреть, где, как, зачем… Очень популярный сервис. У нас Gismeteo не знаю, скоро ли до такого додумается.

    Или же вот тоже пример:



    Это тоже «New York Times». Визуализация, которая управляется с помощью скролла, т.е. в момент, когда я снимал этот ролик, я скроллил мышкой. Страница статическая, но меняются графики — все наглядно, красиво и быстро. Это способ, который позволяет нам уйти от тупых Excel-табличек, от обычных графиков и сделать какой-то проект, который имеет большой «вау» эффект — тот эффект, когда пользователь смотрит и думает: «Вау, как это круто!».

    Что же у нас в России? В России все тоже достаточно хорошо.

    Расскажу про несколько своих проектов, и как они собираются. Проект мы начинаем каждый раз примерно вот с такого вот Excel-файла:



    Редактор дает какие-то данные, и мы вместе с редактором начинаем решать, что мы хотим с этими данными делать.

    Что это за данные? Это численность населения России в разные годы, которая разбита по возрастам, т.е. по оси Y — разные года, по оси Х — возраст. Соответственно, на пересечении — сколько людей того или иного возраста проживало в России в разные годы. В конечном итоге мы хотим получить диаграмму, где по оси Х будет показываться возраст, а по оси Y — население.



    В разные цвета будем «красить» мужское и женское население. Уже даже на статическом слайде, не на интерактивном, мы можем разглядеть какую-то историю. Главное, зачем заниматься визуализацией данных — это показать людям историю, которую они не могут увидеть в Excel-таблицах. Здесь мы уже видим, такую штуку как «эхо войны»:



    Видите этот провал? Это дети, которые не родились во время Второй мировой войны, и соответственно, бэби-бум — это дети, которые родились после Второй мировой войны.

    Также на этой диаграмме мы пометили возраст трудоспособного населения, т.е. от 16 до 55-60 лет, и посчитали, сколько на одного пенсионера приходится работоспособного населения:



    Это на самом деле очень важные цифры. Я покажу, зачем они.



    Мы видим, что в 1990-ом году приходилось на одного пенсионера три работающих человека. Еще мы добавили таймлайн, который вы можете таскать влево и вправо, чтобы менять год:



    Работает это так: мы нажимаем на кнопку «Play», и года начинают меняться, D3 анимирует наши графики. Мы видим, как «Эхо войны» ползет, уходит на пенсию, и что у нас сейчас примерно три работающих человека на одного пенсионера. Но что происходит за этим? За этим происходит такая интересная штука: дети, которые родились во время бэби-бума, уходят на пенсию и количество пенсионеров в России резко возрастает, а количество работающих на людей на одного пенсионера резко падает. Фактически у нас такая ситуация в стране, что каждый работающий человек получает зарплату за себя и за одного пенсионера. Вы понимаете, что у нас получается, что в 2025-м году будет меньше двух человек на одного пенсионера, и это будет реальный пенсионный кризис?

    Это такая штука, которая показывает нам, как из данных можно получить историю. Для журналистики это очень важно.

    А сначала это была просто «каша» из цифр:



    Следующий проект. Мы в открытых источниках нашли информацию о депутатах Государственной Думы:



    Все депутаты Государственной Думы всех шести созывов. Мы видим имя, фамилию депутата, партийную принадлежность и годы — когда он пришел в Госдуму и когда он из Госдумы ушел.

    Что мы можем с этими данными сделать? Мы попробуем их визуализировать. Первым делом мы возьмем первый созыв, «покрасим» всех депутатов в цвет, соответствующий их партийной принадлежности, и построим от меньшей партии к большей:



    Уже красиво, но что-то не то, истории никакой нет. Давайте дальше. Визуализируем все шесть созывов:



    Это достаточно просто сделать. Шесть созывов Госдумы. Мы видим, как появилась «Единая Россия», и как КПРФ теряет свои позиции из-за этого.

    Тоже очень интересно, но чего-то истории никакой нет. Давайте добавим историю.

    Мы знаем, что депутаты переходили от одного созыва в другой. Давайте прочертим линии, если депутат перешел из I-го созыва, например, во II-ой, и получается у нас такая диаграмма, уже красиво:



    Мы видим, как депутаты переходили из созыва в созыв, что, действительно, каждый созыв — это не какие-то новые депутаты, это старые депутаты из прошлых созывов.

    Добавим в эту схему немного интерактива, и получится такая штука, когда мы можем выделять отдельные партии, мы можем тыкать в каждого депутата, и мы можем проследить историю какого-то депутата. Историю КПРФ, допустим, посмотреть, как люди переходили из одной партии в другую. Мы сможем увидеть людей, которые пропускали какие-то созывы, — их линия обходит какой-то конкретный созыв.



    Уже очень интересно, пользователь может зайти на сайт, потыкать… Это работает, это вектор, это svg, это работает хорошо даже на медленных браузерах. На самом деле мы изначально хотели делать png-подложки, отрендерить их на быстром браузере, а потом, когда я увидел, как это хорошо работает в сыром виде в svg, решили оставить так, и я нисколько не жалею.

    Какие истории мы можем здесь найти? Здесь мы можем найти депутатов, которые были во всех шести созывах, т.е. людей «с историей».



    И мы можем увидеть, что большая часть таких депутатов из КПРФ. КПРФ «держит» своих людей, никуда их не пускает, потому что, наверное, новых нет.



    Точно так же мы можем выделить всех депутатов, которые пропускали какие-то созывы. Тоже интересно, но не понятно, зачем.

    А вот мой любимый слайд — депутаты, которые меняли свою политическую принадлежность четыре и более раз:



    Это люди, которые находятся в Госдуме не по политическим соображениям, а по каким-то иным. Потому что человек не может четыре раза поменять свои политические убеждения. Хотя, кто знает…

    Больше примеров вы можете найти на сайте Майка Бостока (это автор библиотеки D3):



    Надо сказать, что Майк Босток — большой фанат примеров, он их собирает в огромном количестве, и вы прокручиваете страницу с примерами, а они все не кончаются и не кончаются. Я ни разу не докручивал до «дна», потому что их там столько… И примеры есть на каждый день. Примеры с кодом, и все хорошо написано, т.е. можете найти все, что вам понадобиться.

    Итак, немного кода.



    D3 библиотека — как любая другая библиотека для работы с DOM элементами. Начинается все с selector’ов. Селекторы работают d3.select(«div») или d3.selectAll(«div»). Можно выделить либо только первый элемент, либо все. Используется W3C селектор API, либо Sizzle.

    Sizzle — это селектор engine, который использует jQuery, т.е. если у вас параллельно подключен jQuery, то селекторы будут работать быстрее, либо вы можете просто подключить Sizzle отдельно.

    Точно так же, как в D3, работает Chaining, вы по очереди можете вызывать методы.



    Давайте сделаем какой-то проект, посмотрим, как он делается, от начала до конца. Вернемся к моим любимым депутатам. Почему я так люблю депутатов? Не из-за того, что я какой-то политически активный чувак, просто Госдума в России — это прекрасный источник данных, потому что все данные про депутатов открыты, и мы можем про каждого депутата на сайте Госдумы узнать его имя, партийную принадлежность, зарплату, недвижимость в России, зарплату и недвижимость жены, машины — его и жены… Мы можем про каждого депутата узнать все вдоль и поперек.

    Как пример, мы можем узнать количество выступлений депутата, количество законопроектов, который этот депутат привнес в Госдуму. Очень хороший пример:



    Давайте сделаем такое предположение, что чем больше депутат зарабатывает, тем меньше он выступает. И проверим, так ли это, или нет.



    Внесем в наш svg таким образом каждого депутата. Каждый депутат будет отображаться с помощью квадратика. Еще покрасим каждого депутата в цвет его партии. Представим, что мы распарсили сайт Госдумы.



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



    D3 подключается как обычная библиотека.



    Первое, что мы делаем, — нам надо эти данные загрузить. Всем, кто знаком с jQuery, тем все понятно. d3.json('datajson) и callback, который обрабатывает ошибку и возвращает объект Json для работы.



    Следующее, что нам надо создать, — это svg в нашем DOM дереве, мы пишем d3.select('body'), append('svg'), ничего нового.



    Точно так же нам нужно задать дополнительные атрибуты ширины и высоты — attr('width'), attr('height'). Все просто, понятно, знакомо.



    И мы видим, что после выполнения этого кода у нас появляется svg элемент с нужными нам атрибутами.



    Следующее, что мы делаем, это очень важно. Что такое библиотека D3? Главная задача D3 — это data binding. Это когда вы привязываете данные к вашим DOM элементам. Это тип приложения, называемый data-driven приложение, которым управляют с помощью поступающих данных. Что нам надо сделать? Нам надо наши данные привязать к прямоугольникам. Мы делаем svg.selectAll('rect'), в ответ нам возвращается пустой массив, потому что svg мы только что создали, rect’ов там нет, и мы по отношению к нашему пустому D3 массиву делаем такую странную манипуляцию.



    Так работает D3, и когда вы начинаете с ним очень долго работать, этот путь становится очевидным. Мы с помощью метода .data присваиваем этому пустому массиву наши данные json.deputates. И получается такая схема:



    Когда у нас есть готовый проект, у нас каждому DOM элементу соответствует какой-то элемент данных, и они вместе связаны. В нашем проекте, сейчас что есть?



    У нас есть данные, но для каждого из них не назначено никакого DOM элемента.



    И мы делаем следующее.



    Мы используем метод .enter(), он возвращает нам элементы данных, для которых не назначен никакой DOM элемент. Нам возвращаются все данные, у которых нет DOM элемента, и он как бы итерирует по этим элементам. Для них мы вызываем метод append('rect'). Т.е. мы говорим: «Для каждого элемента данных, для которого нет DOM элемента, назначь новый элемент rect». Он, мало того, что его назначит, свяжет их вместе, он его еще и отрисует в нашем DOM дереве.



    Смотрите, у нас уже внутри svg появилось 3 элемента <rect>. На самом деле, это самая важная часть библиотеки D3.



    Если вы понимаете эту часть, если вы понимаете, как она работает, все остальное работает очень просто. И точно так же для каждого rect, мы зададим width и height.

    В чем смысл этого всего? Зачем мы это все делали?



    Если мы сейчас на это посмотрим, то увидим на экране один маленький черный прямоугольник 10x10 пикселей, который состоит из трех — один на другом. Нам надо изменить у каждого координаты (X, Y), в зависимости от зарплат депутата и в зависимости от количества его речей.



    И мы берем метод .attr и передаем первый атрибут 'x', а потом передаем функцию, в которой будет передано два параметра: d — это элемент данных, который соответствует этому DOM элементу, а второй — это итерационный номер. Итерационный номер почти никогда не нужен, но элемент данных нам нужен всегда, и мы возвращаем в этой функции обработанные данные таким образом, которые должны привязаться к нашему атрибуту 'x'.

    Есть небольшая напоминалка, как выглядят наши элементы данных. Т.е. к 'x' мы привязываем количество speeches, количество речей.



    Точно так же мы поступаем с координатой Y — к ней мы привязываем размер зарплаты нашего депутата и делим ее на 10 000. Я взял 10 тыс. абстрактно, потому что, понимаете, зарплаты у депутатов такие, что ни в один экран никогда не влезут. И вот у нас получаются в браузере три наших волшебных квадратика, которые мы нарисовали с помощью D3. Ништяк, очень красиво.



    Дальше. Естественно, нам это не нравится. А если мы добавим немного цвета? Мы «покрасим» депутатов в цвет их партии, добавим атрибут fill и в функцию на основании того, в какой он партии, вернем тот или иной цвет.



    Все элементарно. Такая штука у нас получилась.



    Давайте представим, что мы все-таки нормально написали скрипт на Python’е, обошли весь сайт Госдумы, все оттуда сохранили и вот, что получилось:



    Это реальная инфографика, основанная на реальных данных, как раз то, что мы с вами делали. И мы видим, что по оси Х у нас зарплата, по оси Y у нас количество выступлений. Эта шкала не честная, мы не видим, но это логарифмическая шкала, здесь от 0 до первого значения так, т.е. она растянута, и мы видим, что зависимость есть. Чем депутат больше зарабатывает, тем меньше у него речей. Т.е. есть, конечно, какие-то странные люди, но большая часть депутатов, которые выступают в Госдуме, зарабатывают не так уж и много, а та часть, которая много зарабатывает, они как раз сидят и молчат. Поймал мыша, ешь не спеша…

    Это базовое представление D3, все остальное мелочи.



    Анимация производится с помощью метода .transition(), т.е. изначально мы назначаем какой-то стиль, вызываем метод .transition() и следующий стиль. Если мы это запустим, то наш body плавно, по дефолту в течение одной секунды покрасится из одного цвета в другой.



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



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

    Покажу свои самые любимые. Вот допустим, Streamgraph:



    Он показывает в форме потока различные данные, тут они рандомно меняются. Это снятый ролик с браузера, это работает везде и вот так. Т.е. это работает быстро, качественно, и мне очень нравится. Я как человек, который перешел во фронтенд из флеша, который любит вектор, графику, что все это так хорошо работает, мне это очень понравилось.



    Или, допустим, такой лэйаут, который математически вы запаритесь обсчитывать, как вам надо соединять все потоки, потому что они непросто сужаются, а они соединяются в группки, и вы можете натяжение это контролировать. В D3 это есть по дефолту.



    Или мой любимый Treemap. Посмотрите, как красиво с easing перестраиваются treemap онлайн в прямом режиме.

    Итого: быстро, просто и главное, что красиво.



    Контакты


    » war_hol
    » Блог компании Rambler&Co

    Этот доклад — расшифровка одного из лучших выступлений на профессиональной конференции фронтенд-разработчиков FrontendConf.

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

    Ну и главная новость — мы начали подготовку весеннего фестиваля "Российские интернет-технологии", в который входит восемь конференций, включая FrontendConf.
    Метки:
    Конференции Олега Бунина (Онтико) 82,29
    Конференции Олега Бунина
    Поделиться публикацией
    Комментарии 11
    • –1
      А где ящик с усами?
      ИМХО, король всех графиков.
      • 0
        А еще есть DC.js, т.е. Crossfilter для удобной работы с самими данными.
        • +1
          Прекрасную инфографику от РИА в статье отрейскелили так, что смотреть без слез нельзя.
          • 0

            И даже ссылки не потрудились привести, хотя в тексте постоянно мелькает «посмотрите сюда и увидите это...» Куда сюда-то, блин?

          • 0
            Спасибо за статью, на хабре про неё не очень много рассказывают, хотя библиотека очень мощная, имел с ней небольшой опыт.
            • 0

              Очень интересная статья, data science на JS =). Небольшое замечание, хотелось бы код видеть как код, а не как скришоты.

              • 0
                «Стоимость размещения предвыборного агитационного материала» довольно вырвиглазная, как мне кажется. И непонятно, что ей хотели сказать. Что в прайм-тайм дороже? Какая неожиданность.
                • 0
                  Отличная статья, все описано идеально.
                  Жаль только, что не привели примеры с использованием шаблонов обычных Bar/line графиков, чтоб можно было сразу попробовать без заглядывания в документацию.
                  • 0
                    По поводу карты ветров
                    https://earth.nullschool.net/#current/wind/surface/level/
                    Кликабельно, можно покрутить, изменить масштаб, узнать данные в конкретной точке.
                    • 0
                      хоть и TL DR, но так много красивых картинок, что яростно плюсую!
                      • 0
                        Выборку данных рекомендуют сохранять, разделяя selectAll и команды enter/exit.
                        Хороший туториал тут

                        Спасибо за статью

                        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                        Самое читаемое