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

Потоковый график (Stream Graph) — это разновидность Area Chart. У графика выражена центральная ось, по обе стороны которой располагаются области. Области отображают изменения значений величин категорий во времени (как правило). График похож на поток жидкости, отсюда и его название.

Источник wikimedia.org

Подробнее про этот тип графика можно прочитать здесь, а посмотреть примеры — здесь.

1. Немного истории про Stream Graph

Потоковый график стал популярным после работы The New York Times Ebb and Flow at the Box Office, интерактивная версия есть здесь. Работа была выполнена больше десяти лет назад и завоевала премию «Malofiej 2009 awards». С потоковыми графиками можно ближе познакомиться в статье Andy Kirk Making Sence of Streamgraphs

Вот несколько примеров графиков такого типа в Tableau:

Paying the President by Alex Jones

Paying the President by Ludovic Tavernier

40 Years of Music Industry Sales by Laura Elliot

Про создание потоковых графиков в Tableau было написано несколько статей. Один из хороших примеров статьи про создание потоковых графиков в Tableau — это пост Ludovic Tavernier о том, как подготовить данные в Excel и сделать такой график в Tableau. Две другие визуализации из списка выше основаны также на предварительно подготовленных данных. Для этого можно использовать Alteryx или Python.

Все потоковые графики в Tableau, приведенные выше, используют полигоны для визуализации. Однако, полигоны в Tableau не анимированы, то есть, новая фича Animated Transition не работает с полигонами, поэтому, эти графики статичны. Проблема, решаемая в данной статье — создание анимированного потокового графика, поэтому дальше будем работать с тем, что Tableau умеет анимировать — это Area Chart. Это единственный тип меток, который подойдет для нашей задачи.

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

Для проекта #MakeoverMonday 2020, week 21 я сделал визуализацию «40 Years of US Music Sales», которая полностью интерактивна: есть возможность выбора типа графика, отображаемой метрики, типа сортировки категорий, а также возможность выбора дат, и, при этом, эта версия полностью анимирована.

Клик для перехода на визуализацию

Другой потоковый графика я сделал по данным кассовых сборов фильмов в США за 2019 год. Анимация в этом визе включена только на второй вкладке, поскольку на первой вкладке слишком много точек, и Tableau Public не может быстро анимировать этот график. Но можно скачать проект, включить анимацию на Tableau Desktop и посмотреть как она работает.

Клик для перехода на визуализацию

Давайте построим график такого типа в Tableau.

2. Подготовка данных для потокового графика

В качестве источника данных возьмем датасет с ourworldindata.org. Данные содержат информацию о мировом потреблении энергии с 1800 по 2018 год. Для того, чтобы Tableau было легче анимировать график, уменьшим количество данных — возьмем шаг 10 лет. В конечном итоге получим три поля:

Value — это значение потребленной энергии в терраватт-часах. Type — тип источника энергии.

В потоковом графике каждая точка на оси времени переходит по гладкой кривой, поэтому нужно добавить несколько точек между соседними точками дат. Есть несколько вариантов функций, которыми можно описать такие переходы, например, полиномы или логистические функции. В своей визуализации я для этого я использовал синусоиду, которая на промежутке от -π/2 до π/2 является S-образной функцией, но она образует более плавные переходы по сравнению с логистической функцией.

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

Для того, чтобы дополнить датасет точками переходов, добавим поля с названиями: -1.5708, -1.3464 …. 1.5708

Значение -1.5708 — это PI/2, а значение в каждой следующей ячейке равно значению предыдущей плюс PI()/14, где 14 — это количество частей, на которое мы делим синусоиду. Таким образом, получим 15 новых столбцов.

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

Первая точка синусоиды или столбец ‘-1.5708’ будет полностью повторять столбец ‘Value’, т.е. D=C. Следующие столбцы будут вычисляться по формуле:

=$C2+(VLOOKUP($B2,$B3:$C$1215,2,FALSE)-$C2)*(SIN(E$1)+1)/2 для ячейки E2.

Смысл этой формулы в том, чтобы при помощи VLOOKUP найти соседнее значение для каждой категории и построить переход между этими значениями. Например, для года 1800 категории Coal в диапазоне $B3:$C$1215 ищется следующий по порядку год 1810, берется ‘Value’ для этой строки и умножается на функцию синуса. 1215 — это последняя строка в датасете. Если протянуть формулы на все колонки и строки, то получим переходы для всех значений.

Теперь данные готовы, c ними можно работать в Tableau.

Получившийся файл со всеми вычислениями в формате .xlsx можно скачать по ссылке.

3. Построение графика в Tableau

Загрузим данные в Tableau и сделаем Pivot для всех полей -1.5708, -1.3464 …. 1.5708:

Следующим шагом сделаем UNION для этой же таблицы и получим поля Table Name, Pivot Field Names, Pivot Field Values:

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

То есть, мы убрали все точки переходов и оставили только значение Pivot Field Names = -1.5708 или начальные точки исходного датасета плюс убрали из Table Name дополнительную таблицу, которую присоединили юнионом. Получился обычный Area Chart. Точно такой же график получился бы, если бы мы строили его по исходным данным.

Давайте посмотрим как реализуются переходы между датами.

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

Давайте расположим все эти точки на оси X

Cделаем вычисляемое поле X:

10*([Pivot Field Names]+1.57)/(1.57*2) + [Year]

Это поле будет располагать все точки по оси X последовательно. Коэффициент 10 здесь отвечает за сдвиг на 10 лет каждого следующего десятилетия, поскольку в исходном датасете шаг — 10 лет. Числа 1.57 (это π/2) сдвигают каждую синусоиду к началу координат, то есть мы получаем локальный ноль для каждого года. Если в Rows положить сумму Pivot Field Values и добавить все точки на график, то получим следующее:

То есть, получился Area Chart с плавными переходами.

Если присмотреться внимательно к этому рисунку и подумать как можно сделать потоковый график, то можно прийти к выводу, что внизу надо поместить еще одну область, которая поднимет все точки до половины диапазона оси Y. Для этой фейковой области нам как раз и был нужен UNION, а по сути это еще одна такая же таблица с теми же данными.
Сделаем новое вычисляемое поле Type New:

IIF([Table Name]=’Energy1′, ‘ZZZ’, [Type])

Это поле делит датасет на 2 равные части: фейковую ZZZ и данные, которые мы будем отображать.

Следующее вычисляемое поле Y:

IF [Type New]=’ZZZ’ THEN 0.25*(

{ FIXED : MAX( { FIXED [Year], [Pivot Field Names]: SUM([Pivot Field Values])})} —

{ FIXED [Year], [Pivot Field Names]: SUM([Pivot Field Values])})

ELSE [Pivot Field Values]

END

Это полe находит верхнюю границу значений по оси ординат и в каждой точке смещает вверх фейковую область, которая, в свою очередь, поднимает все остальные области. Грануляцию меняем на Type New и получаем потоковый график:

Надо область ZZZ закрасить белым цветом. Еще можно в грануляцию добавить год. Получим следующий график:

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

Включив анимацию и добавив Type и Year в контекстные фильтры, можно посмотреть как работает анимированный график:

4. Удаление лишних точек

В датасете есть много нулевых значений, например, для ядерной энергетики с 1800 по 1960 год.

Эти цифры не несут смысла, но добавляют точки на график.

Нулевые точки в этой визуализации не нужны, их можно удалить в датасете или сделать вычисляемое поле в Tableau и отфильтровать их на уровне экстракта. В нашем случае вычисляемое поле Zero Point Filter:

[Year] <= { FIXED [Type]: MAX ({ FIXED [Type], [Year]: MAX(IIF([Value]=0 AND [Pivot Field Values] = 0, [Year], NULL))})}-10

Оно разбирает значения на True и False.

False здесь — это точки с нулевыми значениями, их можно отфильтровать, используя поле Zero Point Filter в качестве фильтра экстракта.

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

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

5. Сортировка

По умолчанию области на графике сортируются в алфавитном порядке. Название ‘ZZZ’ для фейковой области связано как раз с алфавитным порядком и такое название позволяет ей оставаться внизу. Можно менять порядок сортировки и использовать для этого вычисляемые поля.

Дальше сделаем сортировку типов энергоресурсов:

  • В алфавитном порядке
  • По величине значений
  • В хронологическом порядке

Также предусмотрим возможность сортировки в восходящем и нисходящем порядке. Для этого сделаем 2 параметра типа Integer: Sort Order и Sort Type:

После чего добавим новое вычисляемое поле Sort Field:

IIF([Sort Order]=0,

CASE [Sort]
WHEN 1 THEN IIF(MAX([Type New])=’ZZZ’,0, MAX(ASCII([Type])))
WHEN 2 THEN IIF(MAX([Type New])=’ZZZ’,0,1/ MAX({ FIXED [Type]: SUM([Value])}))
WHEN 3 THEN IIF(MAX([Type New])=’ZZZ’,0, MIN([Year]))

END
,

CASE [Sort]
WHEN 1 THEN IIF(MAX([Type New])=’ZZZ’,0, 1/MAX(ASCII([Type])))
WHEN 2 THEN IIF(MAX([Type New])=’ZZZ’,0, MAX({ FIXED [Type]: SUM([Value])}))
WHEN 3 THEN IIF(MAX([Type New])=’ZZZ’,0, 1/ MIN([Year]))

END)

Будем сортировать категории по новому полю Sort Field:

После этого параметры сортировки будут работать корректно:

Подобным образом можно описать сортировку категорий по любому алгоритму.

6. Трансформация графиков

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

Создадим параметр Chart Type:

Создадим новое поле YY:

CASE [Chart Type]
WHEN 1 THEN AVG([Y])
WHEN 2 THEN AVG([Pivot Field Values])
WHEN 3 THEN SUM([Pivot Field Values]) / TOTAL(SUM([Pivot Field Values]))
END

Это поле будет отвечать за значение по оси ординат при переключении типов графика. Заменим на полке Rows поле Y на поле YY и добавим новое поле Chart Type Filter в фильтры:

IIF([Chart Type]= 2 and [Table Name]=’Energy1′ OR [Chart Type]= 3 and [Table Name]=‘Energy1’ , FALSE, TRUE)

В итоге получим следующую картину:

Переключения между двумя типами графиков выглядят так:

Теперь график полностью готов.

7. Производительность анимированных графиков

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

В нашем примере исходно для каждой синусоиды использовалось 15 точек:

Можно сократить количество точек то восьми, отфильтровав несколько значение Pivot Field Names:

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

Еще можно убрать самую последнюю точку на графике (она перейдет в начало следующей синусоиды), сократив общее количество до пяти.
То есть, количество точек можно сократить в 3 раза, при этом качество пострадает не очень сильно.

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

8. Итоговая визуализация

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

IIF([Type New]=’ZZZ’,»,’Year ‘+STR([Year]))

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

Для stream graph еще есть проблема перекрытия сетки координат белой фейковой областью, поэтому для цветов графика лучше взять насыщенные темные цвета и снизить прозрачность областей до 20-30%. Можно сетку убрать совсем.

Осталось на дашборд вынести фильтры и параметры и немного поработать над его внешним видом:

Заключение

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