«Война и мир» – испытание временем

в 8:08, , рубрики: d3.js, javascript, webpack, Веб-разработка, визуализация данных, война и мир, Инфографика, лев толстой, литература, марафон

«Война и мир» – испытание временем - 1

4 декабрьских дня подряд, порядка 1300 человек на протяжении 60 часов из 30 городов читали «Войну и мир». Беспрецедентный мультимедийный проект от ВГТРК, в течении которого произведение Льва Толстого было прочитано от первой и до последней строчки. Проект захватывает своей грандиозностью и тянет на книгу рекордов Гиннесса.

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

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

«Ему было совершенно все равно в эту минуту, кто бы ни стоял над ним, что бы ни говорил о нем; он рад был только тому, что остановились над ним люди, и желал только, чтоб эти люди помогли ему и возвратили бы его к жизни, которая казалась ему столь прекрасною, потому что он так иначе понимал ее теперь»

I Том, Часть 3, Глава 19

Суть инфографики – это получение ответов на вопросы. Инфографика может отвечать, как на один из вопросов: Что? Где? Когда? Как? Так и комбинировать различные аспекты понимания нескольких вопросов. А иногда инфографика – это просто красиво, без каких-либо мер исчисления энтропии.

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

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

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

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

«Государь прямо сказал, что Совет и Сенат суть государственные сословия; он сказал, что правление должно иметь основанием не произвол, а твердые начала. Государь сказал, что финансы должны быть преобразованы и отчеты быть публичны»

II Том, Часть 3, Глава 18

Если на руках есть данные – это уже пол дела. А в чем же секрет второй половины дела?:) В том как мы быстро сможем разобраться в них!

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

Подключайте программистов на этапе проектирования и анализа данных

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

Никогда не редактируйте исходные данные вручную

Это пагубно влияет на производительность работы. Хочу сразу заверить тех, кто думают, что данные не меняются. Они меняются чаще, чем вы думаете:) Поэтому договоримся, что наша инфографика принимает те данные, которые приходят от редакторов. Так вы расширяете редакторам границы мышления, не заводя их в узкие колонки программного набора данных. Если данных слишком много и процесс подготовки на живую занимает продолжительный промежуток времени, то необходимо приводить их к нормализованному виду заранее. Но для начала этот процесс можно описать и в самой инфографике, а после выпилить в отдельный модуль подготовки данных. Как мы придерживались этого совета в рамках разработки инфографики:

Суть таймлайна – показать, как события в романе соответствуют реальному ходу исторических событий. Каждой главе, если это позволяет понять текст романа, присвоен временной диапазон или какая-то конкретная дата. Вся эта информация содержится в одном из столбцов исходной таблицы. Он-то и вызвал первые трудности, так как формат был хаотичным, но как оказалось, поддающийся определенным правилам. После непродолжительного анализа выяснилось, что существует порядка 12 паттернов. Пишем обработчики и нормализуем столбец к единому формату:

convertDate: function (date, year) {
        // чистим строку с предполагаемой датой
        date = util.clearValue(date);
        
        // может быть указано, что даты нет или ячейка будет пуста
        if (['нет', ''].indexOf(date) !== -1) {
            return null;
        }
       
        // в качестве даты может быть обычный формат 28.01.1812
        if (this.tests.testDate(date)) {
            return this.getDate(date);
        }
       
        // убираем слова паразиты, которые никак не влияют на процесс распознания даты
        var dateParts = _.without(date
            .split(/[s-]/g), 'с', 'по', 'и', 'за', 'романа');
        var patternId = '';

        // ищем для каждой подстроки возможный паттерн и собираем id паттерна
        // конечный id имеет следующий вид "42423", не найденные паттерны содержат 9-ки
        for (var key in dateParts) {
            patternId += this.getPatternId(dateParts[key]);
        }
       
        // если паттерн найден, возвращаем дату или диапазон дат
        if (this.patterns[patternId]) {
            return this.patterns[patternId](dateParts, year);
        }
}

Главы, которые соответствуют историческому периоду, описаны в другом столбце. Они так же имеет хаотическое представление, но поддаются определенной логике:

getChapters: function (chapters) {
        // может быть указано, что глав нет или ячейка будет пуста
        if (['нет', ''].indexOf(this.clearValue(chapters)) !== -1) {
            return [];
        }
        
        return _.chain(this.clearValue(chapters, true)
            // чистим ничего не значащие точку или запятую в конце строки
            .replace(/[.,]$/g, '')
            // разделителями выступают, как точки так и запятые
            .split(/[.,]/g))
            .map(chapter => {
	         // диапазоны указываются через -
                var chapters = chapter.split('-');

                if (chapters.length == 1) {
                    return chapters[0];
                }

                return _.invoke(_.range(Number(chapters[0]), Number(chapters[1]) + 1), 'toString');
            })
	    // сворачиваем внутренние массивы на один уровень
            .flatten()
            .uniq()
            .value()
        ;
}

Кэшируйте все, что можно при запуске вашей инфографики

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

// кэшируем в данные для лет пиксельные показатели и ссылку на svg - элемент
yearTimelineView.selectAll('.year')
        .data(yearsData)
        .enter()
        .append('g')
        .each(function(d) {
            d.yearNext = d.year + 1;
            d.startYearY = timeScale(new Date(d.year, 0));
            d.endYearY = timeScale(new Date(d.yearNext, 0));
            d.localYearY = (d.endYearY - d.startYearY)/2
            d.yearView = d3.select(this);
        })
;

Готовьте многослойные данные

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

// столько различных наборов данных понадобилось для постоения таймлайна
var timelineData,
    filteredTimelineData,
    historyFilteredTimelineData,
    yearsData,
    dataByType,
    dataLinks,
    dataUrls,
    dataChapters;

Выворачивайте данные наизнанку

Манипулируйте данными с помощью библиотек: underscore, lodash и встроенными в d3 функциями. Всегда добивайтесь того формата, который обеспечит вам комфортную работу. Наиболее красочные примеры выворачивания данных в инфографике:

Исходные данные представлены 4-мя таблицами. Не самый лучший формат для построения двух зависимых таймлайнов (история и роман). Так как инфографика все-таки про книгу, то основным таймлайном мы выбрали роман, исторический же был удостоен второстепенной роли. Основаная таблица описывает три рода событий: только в романе, только в истории и смежные события. Одно смежное событие описано двумя строками данных, а связь проставляется через поле related_book_id в смежном историческом событии. Так как в качестве основного таймлайна была выбрана книга, таблицу пришлось вывернуть в два зависимых списка, связанных по полю related_book_id.

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

Покройте данные тестами

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

// vpc - уникальный идентификатор том, часть, глава
// во всей работе идентификаторы приводятся к унифицированному формату
console.log(v.id, 'не верный формат vlc_id:', v.vpc_id);

// проверяем существующие связи в смежных событиях
console.log(historyEvent.id, 'нет такого id в цитатах:', historyEvent.related_book_id);

Закончите прототип в первые 10 часов

Это даст представление, где есть самые серьезные несостыковки в вашем понимании работы данных. Что это дало нам:

Смогли на раннем этапе определить то, что сетка соответствия романа истории слишком громоздкая порядка 350 временных засечек. Причем добрая половина из них приходится на скромный период в 1812 году. Хорошая идея с аналогией тетрадки в линеечку оказалась только хорошей идеей. От этой реализации пришлось отказаться. Вместо нее мы оставили сетку смежных событий, она отчасти реализует эту функциональность. Так это выглядело, когда была сетка:

«Война и мир» – испытание временем - 2

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

«Война и мир» – испытание временем - 3

События романа развиваются с 1805 по 1820 год, но покрытие событиями неравномерное. Было принято решение провести масштабирование лет от количества событий. Алгоритм следующий 35% высоты таймлайна приходится на все года в равных долях, оставшиеся 65% делятся между годами с событиями, пропорционально количеству событий.

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

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

Так выглядит финальный вариант инфографики:

«Война и мир» – испытание временем - 4

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

III Том, Часть 3, Глава 19

Кроме практик и методологий есть немаловажный пункт – инструменты. Что бы понять, как все устроено в d3, не нужно иметь 7 пядей во лбу. Для начала доведем до автоматизма навыки работы с тремя базовыми особенностями библиотеки:

  • Конструкция: enter – update – exit. Заучиваем, как мантру. Чем чаще вы применяете ее в работе, тем лучше – это характеризует успешную подготовку ваших данных.
  • Масштабирование данных. Вторая по популярности особенность фремворка.
  • Хелпер по рисованию path. Без него трудно представить хотя бы один проект на d3.

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

II Том, Часть 5, Глава 22

Остался заключительный штрих, подготовка проекта к продакшену. В качестве системы сборки я использовал webpack. Прозрачность и плоская структура правил позволяет совершенно позабыть о рутинности задачи. Здесь лежит чистый шаблон для запуска проекта с webpack’ом (он же используется в инфографике).

Эпилог

«Есть только две добродетели: деятельность и ум»

I Том, Часть 1, Глава 22

Все сражения начинаются в нашей голове. Стремитесь к миру в голове и мир воцарится вокруг вас.

Хотелось бы поблагодарить своих экс-коллег из РИА студии инфографики и всех участников литературного марафона за данное мероприятие.

Хм, а что, интересная мысль: сделать инфографику про то, как читали «Войну и мир»..?!

Исходники таймлайна
Шаблон с webpack
Инфографический проект «Война и мир»
Отдельно таймлайн здесь

Автор: 3GinGer

Источник

Поделиться новостью

* - обязательные к заполнению поля