Как определить структуру диаграммы Санки, используя фрейм данных?
Это может звучать как очень широкий вопрос, но если вы позволите мне описать некоторые детали, я могу заверить вас, что это очень конкретный вопрос. Так же как обескураживающий, расстраивающий и вызывающий ярость.
Следующий график описывает шотландские выборы и основан на коде plot.ly:
Участок 1:
Набор данных 1:
data = [['Source','Target','Value','Color','Node, Label','Link Color'],
[0,5,20,'#F27420','Remain+No – 28','rgba(253, 227, 212, 0.5)'],
[0,6,3,'#4994CE','Leave+No – 16','rgba(242, 116, 32, 1)'],
[0,7,5,'#FABC13','Remain+Yes – 21','rgba(253, 227, 212, 0.5)'],
[1,5,14,'#7FC241','Leave+Yes – 14','rgba(219, 233, 246, 0.5)'],
[1,6,1,'#D3D3D3','Didn’t vote in at least one referendum – 21','rgba(73, 148, 206, 1)'],
[1,7,1,'#8A5988','46 – No','rgba(219, 233, 246,0.5)'],
[2,5,3,'#449E9E','39 – Yes','rgba(250, 188, 19, 1)'],
[2,6,17,'#D3D3D3','14 – Don’t know / would not vote','rgba(250, 188, 19, 0.5)'],
[2,7,2,'','','rgba(250, 188, 19, 0.5)'],
[3,5,3,'','','rgba(127, 194, 65, 1)'],
[3,6,9,'','','rgba(127, 194, 65, 0.5)'],
[3,7,2,'','','rgba(127, 194, 65, 0.5)'],
[4,5,5,'','','rgba(211, 211, 211, 0.5)'],
[4,6,9,'','','rgba(211, 211, 211, 0.5)'],
[4,7,8,'','','rgba(211, 211, 211, 0.5)']
]
Как построен участок:
Я подобрал несколько важных деталей о поведении диаграмм Санки из различных источников, таких как:
Санки автоматически упорядочивает категории, чтобы минимизировать количество совпадений
Ссылки назначаются в порядке их появления в наборе данных (row_wise)
Соревнование:
Как вы увидите ниже, узлы, метки и цвета не применяются к диаграмме в том же порядке, в котором структурирован исходный фрейм данных. Отчасти это имеет смысл, поскольку у вас есть различные элементы, описывающие один и тот же узел, такие как цвет, цели, значения и цвет ссылки. Один узел 'Remain+No – 28'
выглядит так:
И сопровождающая часть набора данных выглядит так:
[0,5,20,'#F27420','Remain+No – 28','rgba(253, 227, 212, 0.5)'],
[0,6,3,'#4994CE','Leave+No – 16','rgba(242, 116, 32, 1)'],
[0,7,5,'#FABC13','Remain+Yes – 21','rgba(253, 227, 212, 0.5)'],
Таким образом, эта часть источника описывает узел [0]
с тремя соответствующими целями [5, 6, 7]
и три ссылки со значениями [20, 3, 5]
, '#F27420'
оранжевый (ish) цвет узла и цвета 'rgba(253, 227, 212, 0.5)'
, 'rgba(242, 116, 32, 1)'
а также 'rgba(253, 227, 212, 0.5)'
опишите цвета ссылок от узла к некоторым целям. Пока что информация, которая не использовалась в приведенном выше примере:
Образец данных 2 (частичный)
[-,-,--'-------','---------------','-------------------'],
[-,-,-,'#4994CE','Leave+No – 16','-------------------'],
[-,-,-,'#FABC13','Remain+Yes – 21','-------------------'],
И эта информация используется в качестве оставшихся элементов диаграммы.
Итак, в чем вопрос? В дальнейших деталях ниже вы увидите, что все имеет смысл, пока новая строка данных в наборе данных вставляет новую ссылку и вносит другие изменения в другие элементы (цвета, метки), если эта информация еще не использовалась, Я буду еще более конкретным с использованием двух снимков экрана из установки, которую я сделал, с сюжетом слева и кодом справа:
В следующем образце данных приведена нижеприведенная схема в соответствии с логикой, описанной выше:
Образец данных 3
data = [['Source','Target','Value','Color','Node, Label','Link Color'],
[0,5,20,'#F27420','Remain+No – 28','rgba(253, 227, 212, 0.5)'],
[0,6,3,'#4994CE','Leave+No – 16','rgba(242, 116, 32, 1)'],
[0,7,5,'#FABC13','Remain+Yes – 21','rgba(253, 227, 212, 0.5)'],
[1,5,14,'#7FC241','Leave+Yes – 14','rgba(219, 233, 246, 0.5)'],
[1,6,1,'#D3D3D3','Didn’t vote in at least one referendum – 21','rgba(73, 148, 206, 1)']]
Скриншот 1 - Частичный сюжет с образцом данных 3
ВОПРОС:
Добавление строки [1,7,1,'#8A5988','46 – No','rgba(219, 233, 246,0.5)']
в наборе данных производит новую ссылку между источником [5]
и цель [7]
но применяет цвет и метку к цели 5 одновременно. Я думаю, что следующая метка, которая будет применена к диаграмме, была 'Remain+Yes – 21'
так как он не был использован. Но что здесь происходит, так это то, что лейбл '46 – No'
применяется к цели 5. ПОЧЕМУ?
Снимок экрана 2 - Частичный сюжет с образцом данных 3+ [1,7,1,'#8A5988','46 – No','rgba(219, 233, 246,0.5)']
:
И как вы узнаете, что является источником и какова цель, основанная на этом кадре данных?
Я знаю, что вопрос странный и на него трудно ответить, но я надеюсь, что у кого-то есть предложение. Я также знаю, что фрейм данных может быть не лучшим источником для диаграммы Санки. Возможно, вместо JSON?
Полный код и пример данных для легкого копирования и вставки для ноутбука Jupyter:
import pandas as pd
import numpy as np
import plotly.graph_objs as go
from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot
init_notebook_mode(connected=True)
# Original data
data = [['Source','Target','Value','Color','Node, Label','Link Color'],
[0,5,20,'#F27420','Remain+No – 28','rgba(253, 227, 212, 0.5)'],
[0,6,3,'#4994CE','Leave+No – 16','rgba(242, 116, 32, 1)'],
[0,7,5,'#FABC13','Remain+Yes – 21','rgba(253, 227, 212, 0.5)'],
[1,5,14,'#7FC241','Leave+Yes – 14','rgba(219, 233, 246, 0.5)'],
[1,6,1,'#D3D3D3','Didn’t vote in at least one referendum – 21','rgba(73, 148, 206, 1)'],
[1,7,1,'#8A5988','46 – No','rgba(219, 233, 246,0.5)'],
[2,5,3,'#449E9E','39 – Yes','rgba(250, 188, 19, 1)'],
[2,6,17,'#D3D3D3','14 – Don’t know / would not vote','rgba(250, 188, 19, 0.5)'],
[2,7,2,'','','rgba(250, 188, 19, 0.5)'],
[3,5,3,'','','rgba(127, 194, 65, 1)'],
[3,6,9,'','','rgba(127, 194, 65, 0.5)'],
[3,7,2,'','','rgba(127, 194, 65, 0.5)'],
[4,5,5,'','','rgba(211, 211, 211, 0.5)'],
[4,6,9,'','','rgba(211, 211, 211, 0.5)'],
[4,7,8,'','','rgba(211, 211, 211, 0.5)']
]
headers = data.pop(0)
df = pd.DataFrame(data, columns = headers)
scottish_df = df
data_trace = dict(
type='sankey',
domain = dict(
x = [0,1],
y = [0,1]
),
orientation = "h",
valueformat = ".0f",
node = dict(
pad = 10,
thickness = 30,
line = dict(
color = "black",
width = 0
),
label = scottish_df['Node, Label'].dropna(axis=0, how='any'),
color = scottish_df['Color']
),
link = dict(
source = scottish_df['Source'].dropna(axis=0, how='any'),
target = scottish_df['Target'].dropna(axis=0, how='any'),
value = scottish_df['Value'].dropna(axis=0, how='any'),
color = scottish_df['Link Color'].dropna(axis=0, how='any'),
)
)
layout = dict(
title = "Scottish Referendum Voters who now want Independence",
height = 772,
font = dict(
size = 10
),
)
fig = dict(data=[data_trace], layout=layout)
iplot(fig, validate=False)
1 ответ
Эта проблема выглядит действительно странно, но только до тех пор, пока вы не проанализируете plotly
создано:
Когда вы создаете сюжет sankey, вы отправляете ему:
- Список узлов
- Список ссылок
Эти списки связаны друг с другом. Когда вы создаете список узлов 5-длины, любой край будет знать о 0,1,2,3,4
в его начале и в конце. В вашей программе вы создаете узел неправильно - вы создаете список ссылок, а затем просматриваете его и создаете узлы. Посмотри на свою диаграмму. У него есть два черных узла с undefined
внутри. И какова длина вашего набора данных... Да, 5
, Индексы вашего узла заканчиваются на 4
и никакие целевые узлы действительно не определены. Вы добавляете шестой список в свой набор данных и - бинго! - имеются nodes[5]
существует! Просто попробуйте добавить еще одну новую строку в ваш набор данных:
[1,7,1,'#FF0000','WAKA','rgba(219, 233, 246,0.5)']
И вы увидите, что другая черная полоса окрашена в красный. У вас есть пять узлов (потому что у вас есть 5 ссылок, и вы создаете узел путем итерации для списка ссылок), но целевые индексы ссылок 5,6,7
, Вы можете исправить это двумя способами:
- + Изменить
Target
в вашем наборе данных для2,3,4
- Создайте узлы и ссылки отдельно (правильный путь)
Я надеюсь, что помог вам в вашей проблеме и в понимании создания сюжета (что важнее ИМО).
Изменить: Вот пример создания отдельных узлов / ссылок (обратите внимание, что node
участие в data_trace
использует только nodes_df
данные, link
участие в data_trace
использует только links_df
данные и nodes_df
а также links_df
длина не равна):
import pandas as pd
import numpy as np
import plotly.graph_objs as go
from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot
init_notebook_mode(connected=True)
nodes = [
['ID', 'Label', 'Color'],
[0,'Remain+No – 28','#F27420'],
[1,'Leave+No – 16','#4994CE'],
[2,'Remain+Yes – 21','#FABC13'],
[3,'Leave+Yes – 14','#7FC241'],
[4,'Didn’t vote in at least one referendum – 21','#D3D3D3'],
[5,'46 – No','#8A5988']
]
links = [
['Source','Target','Value','Link Color'],
[0,3,20,'rgba(253, 227, 212, 0.5)'],
[0,4,3,'rgba(242, 116, 32, 1)'],
[0,2,5,'rgba(253, 227, 212, 0.5)'],
[1,5,14,'rgba(219, 233, 246, 0.5)'],
[1,3,1,'rgba(73, 148, 206, 1)'],
[1,4,1,'rgba(219, 233, 246,0.5)'],
[1,2,10,'rgba(8, 233, 246,0.5)'],
[1,3,5,'rgba(219, 77, 246,0.5)'],
[1,5,12,'rgba(219, 4, 246,0.5)']
]
nodes_headers = nodes.pop(0)
nodes_df = pd.DataFrame(nodes, columns = nodes_headers)
links_headers = links.pop(0)
links_df = pd.DataFrame(links, columns = links_headers)
data_trace = dict(
type='sankey',
domain = dict(
x = [0,1],
y = [0,1]
),
orientation = "h",
valueformat = ".0f",
node = dict(
pad = 10,
thickness = 30,
line = dict(
color = "black",
width = 0
),
label = nodes_df['Label'].dropna(axis=0, how='any'),
color = nodes_df['Color']
),
link = dict(
source = links_df['Source'].dropna(axis=0, how='any'),
target = links_df['Target'].dropna(axis=0, how='any'),
value = links_df['Value'].dropna(axis=0, how='any'),
color = links_df['Link Color'].dropna(axis=0, how='any'),
)
)
layout = dict(
title = "Scottish Referendum Voters who now want Independence",
height = 772,
font = dict(
size = 10
),
)
fig = dict(data=[data_trace], layout=layout)
iplot(fig, validate=False)
Редактировать 2: Давайте углубимся еще глубже:) Узлы и ссылки на диаграммах Санки почти полностью независимы. Единственная информация, которая их ограничивает - индексы в исходных целях в ссылках. Таким образом, мы можем создать много узлов и без ссылок на них (просто замените их узлами / ссылками в коде Edit1):
nodes = [
['ID', 'Label', 'Color'],
[0,'Remain+No – 28','#F27420'],
[1,'Leave+No – 16','#4994CE'],
[2,'Remain+Yes – 21','#FABC13'],
[3,'Leave+Yes – 14','#7FC241'],
[4,'Didn’t vote in at least one referendum – 21','#D3D3D3'],
[5,'46 – No','#8A5988'],
[6,'WAKA1','#8A5988'],
[7,'WAKA2','#8A5988'],
[8,'WAKA3','#8A5988'],
[9,'WAKA4','#8A5988'],
[10,'WAKA5','#8A5988'],
[11,'WAKA6','#8A5988'],
]
links = [
['Source','Target','Value','Link Color'],
[0,3,20,'rgba(253, 227, 212, 0.5)'],
[0,4,3,'rgba(242, 116, 32, 1)'],
[0,2,5,'rgba(253, 227, 212, 0.5)'],
[1,5,14,'rgba(219, 233, 246, 0.5)'],
[1,3,1,'rgba(73, 148, 206, 1)'],
[1,4,1,'rgba(219, 233, 246,0.5)'],
[1,2,10,'rgba(8, 233, 246,0.5)'],
[1,3,5,'rgba(219, 77, 246,0.5)'],
[1,5,12,'rgba(219, 4, 246,0.5)']
]
И эти узлы не появятся на диаграмме.
Мы можем создавать только ссылки без узлов:
nodes = [
['ID', 'Label', 'Color'],
]
links = [
['Source','Target','Value','Link Color'],
[0,3,20,'rgba(253, 227, 212, 0.5)'],
[0,4,3,'rgba(242, 116, 32, 1)'],
[0,2,5,'rgba(253, 227, 212, 0.5)'],
[1,5,14,'rgba(219, 233, 246, 0.5)'],
[1,3,1,'rgba(73, 148, 206, 1)'],
[1,4,1,'rgba(219, 233, 246,0.5)'],
[1,2,10,'rgba(8, 233, 246,0.5)'],
[1,3,5,'rgba(219, 77, 246,0.5)'],
[1,5,12,'rgba(219, 4, 246,0.5)']
]
И у нас будут только ссылки из ниоткуда в никуда.
Если вы хотите добавить (1) новый источник со ссылкой, вы должны добавить новый список в nodes
, рассчитать его индекс (поэтому у меня есть идентификатор столбца) и добавить новый список в links
с Source
равен индексу узла.
Если вы хотите добавить (2) новую цель для существующих узлов - просто добавьте новый список в links
и напиши свое Source
а также Target
должным образом:
[1,100500,10,'rgba(219, 233, 246,0.5)'],
[1,100501,10,'rgba(8, 233, 246,0.5)'],
[1,100502,10,'rgba(219, 77, 246,0.5)'],
[1,100503,10,'rgba(219, 4, 246,0.5)']
(Здесь я создал 4 новых ссылки для 4 новых целей. Источник - узел с индексом 1
для всех них).
(3 + 4): диаграммы Санки не различают источники и цели. Все они просто узлы для Санки. Каждый узел может быть как источником, так и целью. Посмотри на это:
nodes = [
['ID', 'Label', 'Color'],
[0,'WAKA WANNA BE SOURCE','#F27420'],
[1,'WAKA WANNA BE TARGET','#4994CE'],
[2,'WAKA DON\'T KNOW WHO WANNA BE','#FABC13'],
]
links = [
['Source','Target','Value','Link Color'],
[0,1,10,'rgba(253, 227, 212, 1)'],
[0,2,10,'rgba(242, 116, 32, 1)'],
[2,1,10,'rgba(253, 227, 212, 1)'],
]
Здесь у вас будет диаграмма Санки с 3 столбцами. Узел 0 является источником, 1 является целью, а узел 2 является источником для 1 и целью для 2.