【问题标题】:Plotly: How to plot Sankey diagram with matching rows across different columns?Plotly:如何绘制具有跨不同列的匹配行的桑基图?
【发布时间】:2020-11-04 05:19:13
【问题描述】:

我正在通过 plotly 绘制一个桑基图来比较不同的观察分类。但是,我遇到了两个以上分类的问题,其中每个分类中的观察顺序在每个节点的输入和输出之间发生变化。

我使用的代码如下:

def pl_sankey(df, label_color, categories, value, title='Sankey Diagram', fname=None, width=3000, height=1600, scale=2):
    from IPython.display import Image
    import plotly.graph_objects as go
    import pandas as pd
    df = df.copy()
    labels = []
    colors = []
    # associate labels to colors
    for k, v in label_color.items():
        labels += [k]
        colors += [v]
    # transform df into a source-target pair
    st_df = None
    for i in range(len(categories)-1):
        _st_df = df[[categories[i],categories[i+1],value]]
        _st_df.columns = ['source', 'target', 'count']
        st_df = pd.concat([st_df, _st_df])
        st_df = st_df.groupby(['source', 'target']).agg({'count': 'sum'}).reset_index()
    # add index for source-target pair
    st_df['sourceID'] = st_df['source'].apply(lambda x: labels.index(str(x)))
    st_df['targetID'] = st_df['target'].apply(lambda x: labels.index(str(x)))
    # creating the sankey diagram
    data = dict(
        type='sankey', node=dict(
            pad=15, thickness=20, line = dict(color='black', width=0.5), label=labels, color=colors,
        ),
        link=dict(source=st_df['sourceID'], target=st_df['targetID'], value=st_df['count']),
    )
    layout = dict(title=title, font=dict(size=16, family='Arial'))  
    # creating figure
    fig = go.Figure(dict(data=[data], layout=layout))
    if fname:
        fig.write_image(f'{fname}.pdf', format='pdf', width=width, height=height, scale=scale)
    return Image(fig.to_image(format='png', width=width, height=height, scale=scale))

输入参数为:

  • pandas DataFrame df 对每组行进行分组,例如:
# g1_l1 means group1, label1

       g1      g2      g3   counts
0   g1_l1   g2_l1   g3_l1   10
1   g1_l3   g2_l2   g3_l1   1
2   g1_l1   g2_l2   g3_l2   1
3   g1_l2   g2_l2   g3_l1   40
4   g1_l2   g2_l3   g3_l2   20
5   g1_l3   g2_l1   g3_l2   10
  • label_color 是一个字典,其中键是标签,值是颜色
  • categories 是分组的列名,在本例中为 ['grouping1', 'grouping2', 'grouping3']
  • values 是计数的列名,在本例中为 'counts'

一个执行示例如下:

df = pd.DataFrame([
    ['g1_l1', 'g2_l1', 'g3_l1', 10],
    ['g1_l3', 'g2_l2', 'g3_l1', 1],
    ['g1_l1', 'g2_l2', 'g3_l2', 1],
    ['g1_l2', 'g2_l2', 'g3_l1', 40],
    ['g1_l2', 'g2_l3', 'g3_l2', 20],
    ['g1_l3', 'g2_l1', 'g3_l2', 10],
], columns=['g1', 'g2', 'g3', 'counts'])

label_color = {
    'g1_l1': '#1f77b4', 'g1_l2': '#ff7f0e', 'g1_l3': '#279e68',
    'g2_l1': '#1f77b4', 'g2_l2': '#ff7f0e', 'g2_l3': '#279e68',
    'g3_l1': '#1f77b4', 'g3_l2': '#ff7f0e',
}

pl_sankey(df, label_color, categories=df.columns[:-1], value='counts', title='', fname=None)

但是,此代码保证仅在两个相邻列之间进行行匹配。例如,考虑第 1 行:

       g1      g2      g3   counts
1   g1_l3   g2_l2   g3_l1   1

这样的行应该从第一列的绿色簇 (g1_l3) 开始,落在第二列的橙色簇 (g2_l2) 并继续到第三列的蓝色簇 (g3_l1)。但是,这在上图中没有得到尊重,第二列的输入与匹配输出的排序方式不同。

附上注释图以显示第二列中观察的跳跃(这样的观察在输入中倒数第二,但在第二列中输出倒数):

我想跟随一行从第一列到最后一列的路径。这可能吗?如何用桑基图做到这一点?

【问题讨论】:

  • 为了理解您的问题,我通过将第 1 行和第 2 行(计数列均为数字 1)修改为 5 来检查示例数据。 “g1_l1”已通过“g2_l1”降落在“g3_l1”上。此外,“g1_l3”通过“g2_l2”落在“g3_l2”上。我认为这是正确绘制的。我不明白你的问题了。
  • 嗨@r-beginners。 g1_l1 应该落在 g3_l2 上,g1_l3 应该落在 g3_l1 上。两者都应该通过 g2_l2,发生转变。我可以使用我发布的代码再次复制该行为,我认为我描述的模式是正确的。我不确定将计数更改为 5 可能是一个明智的测试,我遇到了同样的问题。谢谢

标签: python pandas plotly sankey-diagram plotly-python


【解决方案1】:

我可能在这里完全误解了一些东西,但我希望能引导你走上正确的道路。因此,如果我错了,请原谅我,但您似乎误解了 plotly sankey 图的一些内部工作原理。别担心,你是not alone

你的意思是:

这样的行应该从第一列的绿色簇(g1_l3)开始,土地 在橙色簇(g2_l2) 在第二列并继续蓝色 在第三列集群(g3_l1)

因此,如果我理解正确,您希望这种特殊关系被说明为:

但这并不是设置情节桑基图的工作方式。相反,从g1_l3g2_l2 的数量与进入g2_l2 的其他数量组合在一起,然后作为聚合值“发送”到g3_l1。你有这行的原因:

...是因为你也有g2_l2 , g3_l1, 1的关系:

如果您以某种方式成功地说明了您的数据框中的关系准确您如何在一个 sankey 数字中描述,它将不再是一个 sankey 数字。

很抱歉,目前我只能为您做这些了。

【讨论】:

  • 感谢您的回答。是的,我可能误解了桑基图的工作原理。您是否知道是否有其他方法可以在具有超过 2 组标签(列)的相同观察值上显示分类?
  • @gc5 感谢您接受我的建议。不过不确定你的最后一个问题。但我会考虑一下...
猜你喜欢
  • 2018-11-02
  • 2015-08-22
  • 2022-01-14
  • 2021-08-05
  • 2022-10-18
  • 1970-01-01
  • 2020-07-23
  • 2021-12-23
  • 1970-01-01
相关资源
最近更新 更多