АНАЛИТИКА ПЛЮС
Профессиональные услуги в сфере BI

Хордовая диаграмма в Tableau

Часть I: Моделирование данных

Хордовая диаграмма визуализирует парные отношения, поэтому нужно подготовить данные до их переноса в Tableau.

Для подготовки данных мы будем использовать (язык программирования) R.

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

Мы будем использовать пакеты tidyverse R и magrittr R для подготовки данных.

Хордовая диаграмма в Tableau, изображение №1
library(tidyverse)
library(magrittr)
product <- read_csv(".../Sample - Superstore.xls")

Когда мы загрузим данные — мы получим ранг каждого продукта.

Хордовая диаграмма в Tableau, изображение №2

Первоначальный фрагмент вывода данных:

Хордовая диаграмма в Tableau, изображение №3

Далее присоединим это к нашему необработанному набору данных. После этого нам необходимо сгруппировать данные по Product ID и Order ID, и суммировать Sale, Profit и Quantity.

Есть дополнительные поля (характеристики продуктов), которые можно сохранить в данных.

Хордовая диаграмма в Tableau, изображение №4
product_summary %<>%
  left_join(product) %>%
  filter(!is.na(rank)) %>%
  group_by(`Category`, `Sub-Category`, `Order ID`, `Product Name`, rank) %>%
  summarise(
    Sales = sum(Sales),
    Profit = sum(Profit),
    Quantity = sum(Quantity)
  ) %>% 
  arrange(rank)

Итак, следующий фрагмент вывода данных:

Хордовая диаграмма в Tableau, изображение №5

Далее, необходимо взять сводные данные по продуктам и заказам и изменить название каждого столбца, а именно: изменить Category на Category 2, Sub-Category на Sub-Category 2, Product Name на Product Name 2 и так далее.

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

Как только мы получим наше объединение по Order ID, мы будем суммировать наши данные на уровне Product — Product 2 (это наше парное сравнение). И также, мы включим все характеристики продукта в оператор Group_by.

product_summary %<>%
  rename(
    Category2 = Category,
    `Sub-Category2` = `Sub-Category`,
    `Product Name2` = `Product Name`,
    rank2 = rank,
    Sales2 = Sales,
    Profit2 = Profit,
    Quantity2 = Quantity,
  ) %>%
  right_join(product_summary) %>%
  group_by(Category, `Sub-Category`, `Product Name`, rank, Category2, `Sub-Category2`, `Product Name2`, rank2) %>%
  summarise(
    Sales = sum(Sales),
    Sales2 = sum(Sales2),
    Quantity = sum(Quantity),
    Quantity2 = sum(Quantity2),
    Profit = sum(Profit),
    Profit2 = sum(Profit2)
  ) %>%
  arrange(rank, rank2)

Хордовая диаграмма в Tableau, изображение №6

Вот, что у нас получится (следующий фрагмент вывода данных):

Хордовая диаграмма в Tableau, изображение №7

Теперь мы переходим к конечному моделированию данных, но перед этим рекомендуем избавиться от любых пар, где Product ID и Product ID 2 совпадают. Также предлагаем добавить столбец с названием One и столбец с названием Level, о которых мы поговорим позже. Далее нужно создать фрейм данных с двумя столбцами: один с единицами, а второй — от 0,00 до 1,00 с шагом 0,01, а также он должен включать цифры 2, 3, 4, 5, 6, 7.
0,00 — 1,00 помогут нам сформировать хорды, 2 — 3 построят точки за хордами, а 4 — 7 построят несколько полос / линий.

Хордовая диаграмма в Tableau, изображение №8
product_summary %>%
  mutate(one = 1) %>%
  left_join(
    data_frame(
      one = 1,
      t = c(c(0:100)/100, c(2:7))
    )
  ) -> tmp

Теперь, нам нужно экспортировать данные в Tableau.

write_csv(tmp, ".../superstore_chord.csv")

 

Часть II: Построение хордовой диаграммы

Наиболее важные поля для хордовой диаграммы это rank и rank 2. Это ранги парных отношений.

Сначала нам нужно сделать исходный и конечный узлы. Для этого нам необходимо знать общее количество узлов в представлении, чтобы понять, как настроить параметр, который назовем Rank Select. В этом примере наш параметр имеет диапазон от 1 до 400.

Теперь нужно создать вычисление с именем Rank Select | TF которое возвращает узлы только в пределах диапазона этого параметра. Добавьте это как контекстный фильтр в представлении.

//Rank Select | TF
[Rank] <= [Rank Select]
AND 
[Rank2] <= [Rank Select]

Далее, когда мы знаем общее количество узлов, которые будут отображаться в представлении, мы можем определить исходное и конечное местоположение для каждого узла. Для этого нам нужно определить координаты Х и Y. Мы можем использовать rank и параметр Rank Select для определения местоположения вдоль единичного круга.

//x1 (source)
COS([Rank]/[Rank Select] * PI() * 2)

//x2 (destination)
COS([Rank2]/[Rank Select] * PI() * 2) 

//y1 (source)
SIN([Rank]/[Rank Select] * PI() * 2)

//y2 (destination)
SIN([Rank2]/[Rank Select] * PI() * 2)

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

Не забывайте, что мы провели некоторое моделирование данных, прежде чем загрузить их в Tableau. У нас есть столбец t, который варьируется от 0 до 1 с шагом 0,01 (плюс некоторые другие значения). Каждое из этих значений поможет нам провести линию между хордами.

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

((1-t)2 * pt1) + (2t(1-t) * pt2) + (t2 * pt3)

 

Теперь нам нужно заполнить каждую из трех точек: точка 1 — это начальная точка, точка 3 — это конечная точка, а точка 2 — это средняя точка, которую мы будем использовать. В большинстве подобных визуализаций, используют значение 0,0 для этой средней точки. Давайте посмотрим, как это выглядит:

Хордовая диаграмма в Tableau, изображение №9

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

Было бы неплохо, если бы чем ближе узлы были друг к другу, тем менее интенсивной была бы дуга. Это означает, что средняя точка должна быть динамической и основана на расстоянии длины, разделяющей два узла. Таким образом, после нескольких дней проб и ошибок автор статьи остановился на динамической средней точке,которая определяется расстоянием между двумя точками. Итак, создадим вычисление segment length.

SQRT(([x2] - [x1])^2 + ([y2] - [y1])^2)

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

//[angle x]
COS((ACOS([x1])+ACOS([x2]))/2)

//[angle y]
SIN((ASIN([y1])+ASIN([y2]))/2)

Хордовая диаграмма в Tableau, изображение №10

Вот, что у нас получилось. Раннее, когда мы проводили моделирование данных, мы ввели значения от 0 до 1 с шагом 0,01, но мы также ввели значения 2, 3, 4, 5, 6 и 7. Эти значения будут определять местоположения других элементов в этой визуализации: точки перед началом хорды, точки после конца хорды, столбцы перед точками и хордами и столбцы после точек и хорд. Вот что потребуется для того, чтобы разбить элементы:

// Separator
IF t <= 1
THEN "chord"
ELSEIF t = 2
THEN "start point"
ELSEIF t = 3
THEN "end point"
ELSEIF t = 4 OR t = 5
THEN "start bar"
ELSEIF t = 6 OR t = 7
THEN "end bar"
END

Вычисление separator поможет нам создать эту визуализацию, но для того чтобы построить визуализацию нам нужно определить высоту баров.

После этого, необходимо создать сет (набор) на основе поля rank. Назовем сет (набор) Rank | Set. После этого мы можем создать вычисления start bar и end bar.

// Start Bar
{FIXED [Rank] : SUM(IF level = 1 AND t = .5 then [Quantity] end)}
/
{MAX({FIXED [Rank] : SUM(IF level = 1 AND t = .5 then [Quantity] end)})}

// End Bar
({FIXED [Rank2] : SQRT(SUM(IF level = 1 AND t = .5 AND [Rank | Set] THEN [Quantity2] end))}
/
{MAX({FIXED [Rank] : SQRT(SUM(IF level = 1 AND t = .5 AND [Rank | Set] THEN [Quantity2] end))})}) 
* 
[start bar length]

Далее построим формулы для X и Y, которые мы далее будем использовать в представлении:

// x
IF t >= 0 AND t <= 1
THEN
(( (1 - [t])^2 ) * [1b. x1]) +
(2 * (1 - [t]) * [t] *  
  (
    ((2 - [segment length])/ 2) *
    [angle x]
  )
) + 
([t]^2 * [x2])
ELSEIF t = 2
THEN 1.07 * [x1]
ELSEIF t = 3
THEN 1.07 * [x2]
ELSEIF t = 4
THEN 1.14 * [x1]
ELSEIF t = 5
THEN (1.14 + ([start bar length]* [bar height])) * [x1]
ELSEIF t = 6
THEN 1.14 * [x2]
ELSEIF t = 7
THEN (1.14 + ([end bar length]* [bar height])) * [x2]
END

//y
IF t >= 0 AND t <= 1
THEN
(( (1 - [t])^2 ) * [1d. y1]) +
(2 * (1 - [t]) * [t] *  
  (
    ((2 - [segment length])/ 2) *
    [angle y] 
  )
) + 
([t]^2 * [y2])
ELSEIF t = 2
THEN 1.07 * [y1]
ELSEIF t = 3
THEN 1.07 * [y2]
ELSEIF t = 4
THEN 1.14 * [y1]
ELSEIF t = 5
THEN (1.14 + ([start bar length]* [bar height])) * [y1]
ELSEIF t = 6
THEN 1.14 * [y2]
ELSEIF t = 7
THEN (1.14 + ([end bar length]* [bar height])) * [y2]
END

Теперь перейдем к созданию визуализации. У нас уже есть одно измерение в качестве фильтра. Перетаскиваем пилюлю Х на полку Rows, перетаскиваем пилюлю Y на полку Columns. Перетаскиваем Rank | Set на карточку Color. Далее измените тип метки на Line и перетащите пилюлю t на карточку Path. Перетащите separator, Product Name, Rank и Rank2 на карточку Detail.

Создайте Set Action на основании поля Rank. Далее мы получим не совсем то, что хотели бы. Основная проблема заключается в том, что у нас больше данных, чем нам нужно для этой визуализации. Это видно из визуализации, так как у нас есть хорды, которые идут в обоих направлениях.

Хордовая диаграмма в Tableau, изображение №11

Давайте поправим нашу визуализацию. Для этого необходимо следующее:

CASE [separator]
WHEN "chord"
THEN IF [Rank | set]
    THEN TRUE
    ELSE TRUE
//    ELSE {FIXED [Rank] : MIN(Rank2)} = Rank2
    END
WHEN "start point"
THEN IF [Rank | set]
    THEN TRUE
    ELSE {FIXED [Rank] : MIN([Rank2])} = [Rank2]
    END
WHEN "start bar"
THEN IF [Rank | set]
    THEN FALSE
    ELSE IF {COUNTD(IF [Rank | set] THEN [Rank] END)} = 0
         THEN TRUE
         ELSE FALSE
         END
    END
WHEN "end bar"
THEN IF [Rank | set]
    THEN TRUE
    ELSE FALSE
    END
END

Добавьте это в фильтр и выберите TRUE. Почти закончили, теперь давайте добавим еще несколько функций: dynamic labels и size.

// dynamic labels
IF [5c. Rank | set] AND [3. separator] = "end bar" AND t = 7
THEN [Product Name2]
ELSEIF [5c. Rank | set] AND [3. separator] = "start bar" AND [t] = 5
THEN [Product Name]
END

// Size
IF CONTAINS([3. separator], "bar")
THEN 20
ELSEIF CONTAINS([3. separator], "point")
THEN ([Quantity]) * 3
ELSE 5
END

Перетаскиваем dynamic labels на карточку Label и пилюлю size на карточку Size.

Хордовая диаграмма в Tableau, изображение №12

Готово!

Ссылка на визуализацию (рабочая книга доступна для скачивания): https://public.tableau.com/profile/stanke#!/vizhome/SuperstoreChord/Chordwthings

Ссылка на источник: https://www.tessellationtech.io

x

Этот сайт использует файлы cookies, чтобы облегчить вам пользование нашим веб-сайтом.

Продолжая использовать этот веб-сайт, вы даете согласие на использование файлов cookies.