Статьи

Создание визуализации данных в JavaScript с использованием Dimple и D3

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

В этой статье я проведу вас через создание визуализации данных, а именно отзывов автомобилей из США за январь 2015 года, с использованием библиотеки JavaScript dimple.js, созданной поверх D3.js.

Постановка цели

NHTSA / ODI предоставляют файл отзыва (который доступен через их веб-сайт ), содержащий все связанные с безопасностью и безопасностью кампании NHTSA с 1967 года. Наша цель — извлечь данные за определенный месяц (январь 2015 года) и создать планку график из него, изображающий общее количество отзывов транспортных средств производителем.

Смотреть визуализировать данные с D3.js
Проиллюстрируйте свои данные с помощью JavaScript

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

Вот чем мы закончим:

Димпл конечный результат

Вы можете увидеть (меньшую) живую демонстрацию в конце статьи или просмотреть оригинал на CodePen .

Работа с данными

Хранение только тех данных, которые нам нужны

Все файлы, упомянутые в этом разделе, можно найти в нашем репозитории GitHub .

Исходный файл FLAT_RCL.txt ( ссылка ) представляет собой файл значений, разделенных табуляцией, который содержит много данных — точнее, 109 682 записей. Существует сопроводительный файл RCL.txt ( ссылка ), который детализирует столбцы, относящиеся к этим данным.

Поскольку нас интересуют только данные за январь 2015 года, или, точнее, записи, для которых Record Creation Date является январь 2015 года, остальные записи могут быть удалены. Для этого я использую программу электронных таблиц OpenOffice Calc (хотя подойдет любое другое программное обеспечение для электронных таблиц). Результирующий файл RCL_January_2015.csv ( ссылка ) насчитывает только 201 запись.

Теперь нам нужно сократить столбцы до подмножества доступных, а именно:
Record Creation Date , производитель, Model , Model Year , Begin Date of Manufacturing , End Date of Manufacturing , Potential Number of Units Affected , Defect Summary Consequence Summary Corrective Summary . Затем мы можем добавить имена столбцов в первую строку полученного файла CSV, RCL_January_2015_clean.csv ( ссылка ).

Это дает нам необработанные данные, необходимые для нашей визуализации.

Создать структуру данных

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

Мы собираемся использовать структуру данных JSON для этой группировки.

Чтобы проиллюстрировать это, давайте обработаем первые три записи файла RCL_January_2015_clean.csv . Их можно сгруппировать в одну строку, утверждая, что J4500 от MCI 2013, 2014 и 2015 годов с одинаковыми годами производства имеют один и тот же дефект. Потенциальное количество затронутых единиц уже группирует эти три модели вместе в наборе данных.

Вот структура данных JSON, которую мы будем использовать:

 { "items": [ { "item": { "date": "", "models": [ "" ], "units": "", "defect": "", "consequence": "", "corrective": "" } } ] } 

После итерации этого процесса (и избежания двойных кавычек) у нас теперь есть CSV-файл RCL_January_2015_json.csv ( ссылка ). Для краткости наш рабочий пример покажет только первых трех создателей исходного файла (3 из 46).

Связывание данных с объектом D3

D3 обеспечивает встроенную поддержку форматов файлов данных, таких как CSV, TSV или JSON. Для извлечения файла выполняется Ajax-вызов, затем он анализируется и преобразуется в массив JavaScript. CSV-файл, который мы создали, можно получить с помощью следующего кода:

 d3.csv("RCL.csv", function (data) { // process the data }); 

Мы также можем определить массив JavaScript непосредственно в коде, что мы собираемся сделать здесь для целей нашей демонстрации CodePen. Структура данных была сохранена как можно ближе к массиву, который D3 создал бы из файла CSV.

 data = [ { 'Record creation date':'20150105', 'Maker':'MCI', 'Potential number of units affected':'109', 'JSON data': '{ "items":[ { "item": { "date":"January, 5 2015", "models":[ "J4500 (years 2013, 2014, 2015) ..." ], "units":"109", "defect":"...", "consequence":"...", "corrective":"..." } } ] }' }, ... ]; 

А теперь давайте окунемся!

 <div id="RecallsChart"></div> <div id="RecallDetails"></div> 

HTML- RecallsChart прост: два div, один для диаграммы ( RecallsChart ), другой для отображения дополнительной информации, если пользователь наводит курсор на одну из полос ( RecallDetails ).

 var svg = dimple.newSvg("#RecallsChart", 800, 560); var myChart = new dimple.chart(svg, data); myChart.setBounds(60, 30, 710, 355) 

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

 var x = myChart.addCategoryAxis("x", "Maker"); x.addOrderRule("Maker"); x.title = ''; 

Мы устанавливаем ось X диаграммы в поле Maker наших данных — мы используем метод addCategoryAxis поскольку создатели составляют категориальные данные. Мы упорядочиваем создателей в алфавитном порядке с addOrderRule метода addOrderRule и скрываем заголовок оси X (который был бы создателем), поскольку имена создателей не требуют пояснений.

 myChart.addLogAxis("y", "Potential number of units affected"); 

Мы устанавливаем ось Y диаграммы в поле « Potential Number of Units Affected наших данных. Мы могли бы использовать здесь метод addMeasureAxis , который определяет линейную ось из заданных значений, но, поскольку создатель Victory более чем в 20 раз превышает потенциальное количество затронутых единиц, чем MCI или Thor, результирующий столбец мог бы затмить два других , В этом случае логарифмическая шкала дает больше места для меньших значений, поэтому мы используем метод addLogAxis , который по умолчанию addLogAxis основанию 10.

 var mySeries = myChart.addSeries(["Maker", "JSON data"], dimple.plot.bar); 

Теперь, когда мы определили наши оси, мы можем связать их вместе для визуализации графики. Для этого мы выбираем гистограмму через dimple.plot.bar и привязываем ее к полю данных Maker . Второй элемент массива, JSON data , свяжет часть JSON наших данных с каждой полосой и позволит нам получить доступ к правильным данным при наведении курсора на мышку.

 mySeries.getTooltipText = function (e) { var datum = jQuery.parseJSON(e.aggField[1]); var titles = []; titles['date'] = 'Record creation date'; titles['units'] = 'Potential number of units affected'; titles['defect'] = 'Defect summary'; titles['consequence'] = 'Consequence summary'; titles['corrective'] = 'Corrective summary'; var html = ''; html += '<span class="maker">'+e.aggField[0]+'</span>'; html += '<br /><br />'; $.each(datum.items, function(index1, element) { $.each(element, function(index2, item) { $.each(item, function(key, value) { if (key === 'models') { if (value.length == 1) { html += '<strong>Model</strong>:'; } else { html += '<strong>Models</strong>:'; } html += '<ul>'; $.each(value, function(vk, val) { html += '<li>'+val+'</li>'; }); html += '</ul>'; } else { html += '<em>'+titles[key]+'</em>: '+value+'<br /><br />'; } }); }); }); $("#RecallDetails").html(html); return [ "Maker: " + e.aggField[0], "Potential number of units affected: " + parseInt(e.cy).toLocaleString('en') ]; }; 

По умолчанию всплывающие подсказки отображаются при наведении курсора мыши на единицу графика (здесь, столбец) и показывают данные осей и серий. В нашем случае: производитель (значение по оси x), потенциальное количество затронутых единиц (значение по оси y) и значение в виде простого текста наших JSON data .

Функция getTooltipText перегружена здесь, чтобы обработать данные JSON и отобразить их в другом элементе div. Он возвращает массив данных, которые мы хотим отобразить в виде всплывающей подсказки, а именно имя производителя (первое поле совокупности нашей строки данных) и количество затронутых единиц (которые мы получаем из оси Y и которые мы локализуем для общий английский формат чисел через встроенный метод toLocaleString JavaScript).

Но вернемся к разбору данных JSON.

Два агрегатных поля, к которым мы обращаемся ( aggField[0] и aggField[1] ) соответствуют массиву полей данных, который мы ранее установили как ряд ( ["Maker", "JSON data"] )), aggField сам aggField является свойством базового элемент объекта.

Мы анализируем строку JSON с parseJSON функции parseJSON jQuery, устанавливаем массив полных заголовков, соответствующих ключам нашего объекта JSON, затем, перебирая объект JSON, мы создаем строку HTML для добавления в div с идентификатором RecallDetails .

 myChart.ease = "elastic"; myChart.draw(1000); 

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

 x.shapes.selectAll("text") .style("text-anchor", "end") .each(function () { var rec = this.getBBox(); d3.select(this) .attr("transform", "rotate(-90," + (rec.x + rec.width) + "," + (rec.y + (rec.height / 2)) + ") translate(5, 0)"); }); 

Я наконец сказал? Что ж, здесь мы добавим еще один эстетический прием к меткам оси X.

По умолчанию метки оси X написаны горизонтально. Но они могут легко перекрываться, поэтому мы будем писать их вертикально. Вот тут-то и пригодится разоблачение dimple лежащих в его основе объектов D3. Обратите внимание, что мы можем изменить его только после того, как график будет нарисован, следовательно, после myChart.draw() .

Чтобы сделать это, мы сначала выбираем каждый текст метки, или, вернее, совпадающую форму SVG, связанную с осью X для каждой метки. Метод getBBox() принадлежит к InterfaceSVGLocatable и возвращает объект SVGRect, который определяет ограничивающий прямоугольник, выставляя его координаты, высоту и ширину. Затем мы выполняем поворот поля SVG и небольшой вертикальный перевод, чтобы приблизить его к линии оси X.

И вот конечный результат:

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

Вывод

В этой статье мы увидели, как очистить и подготовить данные для визуализации данных, в частности, определив структуру данных для соответствия конечному результату, который мы имели в виду. Мы использовали библиотеки dimple.js и D3.js с некоторыми ограниченными вызовами jQuery (в основном связанные с обработкой JSON). Мы взяли гистограмму из наших данных, с небольшим исследовательским взаимодействием, перегружая функцию всплывающей подсказки. Мы также получили доступ к базовому объекту D3, чтобы манипулировать метками оси X.

В качестве дополнительного примечания, SVG теперь широко поддерживается , но рекомендуется проверять его заранее (например, с помощью Modernizr ) и предоставлять запасной вариант, такой как изображение PNG, где это необходимо. Конечно, условная загрузка D3.js и dimple.js также должна быть принята во внимание.

Если вы хотите глубже погрузиться в визуализацию данных, Udacity предлагает MOOC с самостоятельным движением под названием Data Visualization и D3.js, который охватывает концепции визуализации, использование D3.js и dimple.js, повествовательные структуры и анимацию. Кроме того, сайт Майка Бостока (создатель D3.js) является идеальным источником, если вы хотите понять концепции, стоящие за этой библиотекой, в то время как dimple и D3 предоставляют список примеров для изучения.