控制Sankey图连接

Ben*_*Ben 11 python matplotlib sankey-diagram

我正在尝试使用Matplotlib Sankey图控制哪些流相互连接.我正在修改基本的两个系统示例.

我认为我的困惑归结为误解了这实际意味着什么:

请注意,只指定了一个连接,但系统形成一个电路,因为:(1)路径的长度是合理的,(2)流的方向和顺序是镜像的.

我制作了一个使用单个数据集的玩具示例,然后为第二个系统修改它以确保所有数字都匹配.

import numpy as np
import matplotlib.pyplot as plt

from matplotlib.sankey import Sankey

plt.rcParams["figure.figsize"] = (15,10)


system_1 = [
    {"label": "1st",  "value":  2.00, "orientation":  0},
    {"label": "2nd",  "value":  0.15, "orientation": -1},
    {"label": "3rd",  "value":  0.60, "orientation": -1},
    {"label": "4th",  "value": -0.10, "orientation": -1},
    {"label": "5th",  "value":  0.25, "orientation": -1},
    {"label": "6th",  "value":  0.25, "orientation": -1},
    {"label": "7th",  "value":  0.25, "orientation": -1},
    {"label": "8th",  "value":  0.25, "orientation": -1},
    {"label": "9th",  "value":  0.25, "orientation": -1}
]

system_2 = system_1[:4]
system_2.append({"label": "new",  "value":  -0.25, "orientation": 1})


fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], title="Where are all my cows?")
flows  = [x["value"] for x in system_1]
labels = [x["label"] for x in system_1]
orientations=[x["orientation"] for x in system_1]
sankey = Sankey(ax=ax, unit="cow")
sankey.add(flows=flows, 
           labels=labels,
           label='one',
           orientations=orientations)

sankey.add(flows=[-x["value"] for x in system_2], 
           labels=[x["label"] for x in system_2],
           label='two',
           orientations=[-x["orientation"] for x in system_2], 
           prior=0, 
           connect= (0,0)
          )

diagrams = sankey.finish()
diagrams[-1].patch.set_hatch('/')
plt.legend(loc='best')


plt.show()
Run Code Online (Sandbox Code Playgroud)

这给了我:

一个没有真正起作用的sankey图

应该使用匹配标签连接流.

我读过这个这个,但他们没有帮助我了解什么是真正发生的事情.

V. *_* L. 5

让我们从尝试解决混淆开始

我认为我的困惑归结为误解了这实际上意味着什么:

请注意,只指定了一个连接,但系统形成了一个回路,因为:(1) 路径的长度是合理的,并且 (2) 流的方向和顺序是镜像的。

(2) 流的方向和顺序是镜像的。

您可能理解错误的是mirrored的含义,在这种情况下确实令人困惑。人们可能会认为,那镜像平等倒,但这只是部分正确:
flows(或者你把它在你的代码:values)必须是反向的,这一个你有正确的。因为values对应于输入(value > 0)或输出(value < 0)。并且只有输出可以连接到输入,反之亦然。

但是orientation对于您尝试连接的两个流,必须相同。这个不是倒置的,但它仍然需要“镜像”。那是什么意思?好吧,如果一个 I/O 正朝着他来自的箭头的方向看,它需要看到另一个 I/O(就像照镜子一样),只有这样他们才能连接自己。作为非母语人士解释起来并不容易,但我将尝试说明这个想法:

Able to connect:         Not able to connect:        Not able to connect:
I/O  Mirror  I/O         I/O  Mirror  I/O            I/O  Mirror  I/O
???>   |    >???          ?     |      ?                    |      ?
                          ?     |      ?             ??>    |      ?
                          v     |      ^                    |      ^
Run Code Online (Sandbox Code Playgroud)

在您的代码中,您已将orientation. 这就是为什么例如橙色系统的第三个流在左上角,而蓝色系统的对应流在右下角。不可能,这些 I/O 将永远能够“看到”彼此。

您可以通过删除-xin 方向前面的来恢复第二个系统的反转:

orientations=[x["orientation"] for x in system_2]
Run Code Online (Sandbox Code Playgroud)

您将看到,现在流彼此靠近,但您处于Not able to connect-illustration(第 2 号)中所示的情况。这意味着您的图表结构将无法以这种方式工作。您只能在以下三个方向弯曲单个流:-90°、0° 或 90°。哪位记者orientations = -1, 0 or 1。直接连接这些流的唯一方法是设置它们的orientation=0,但在我看来这不是您的目标。

您需要一种新的任务方法,这样您就不会陷入像以前那样无法再连接流的情况。我已经修改了您的代码以(也许?)达到您的目标。它看起来不再一样了,但我认为这是一个很好的开始,可以了解有关方向和镜像以及所有这些东西的概念。

(1) 路径的长度是合理的。

您将在下面的代码中看到,我已经为pathlengths变量设置了值(在第二个系统中)。我已经证明,如果您有太多需要连接的流,matplotlib 将无法再自动执行此操作。

代码和输出

import numpy as np
import matplotlib.pyplot as plt

from matplotlib.sankey import Sankey

plt.rcParams["figure.figsize"] = (15,10)


system_1 = [
    {"label": "1st",  "value": -2.00, "orientation":  1},
    {"label": "4th",  "value":  0.10, "orientation":  1},
    {"label": "2nd",  "value":  0.15, "orientation":  1},
    {"label": "3rd",  "value":  0.60, "orientation":  1},
    {"label": "5th",  "value":  0.25, "orientation": -1},
    {"label": "6th",  "value":  0.25, "orientation": -1},
    {"label": "7th",  "value":  0.25, "orientation":  1},
    {"label": "8th",  "value":  0.25, "orientation":  1},
    {"label": "9th",  "value":  0.25, "orientation":  0}
]

system_2 = [
    {"label": "1st",  "value":  2.00, "orientation":  1},
    {"label": "4th",  "value": -0.10, "orientation":  1},
    {"label": "2nd",  "value": -0.15, "orientation":  1},
    {"label": "3rd",  "value": -0.60, "orientation":  1},
    {"label": "new",  "value": -0.25, "orientation":  1}
]

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, xticks=[], yticks=[], title="Where are all my cows?")

flows_1  = [x["value"] for x in system_1]
labels_1 = [x["label"] for x in system_1]
orientations_1=[x["orientation"] for x in system_1]

flows_2  = [x["value"] for x in system_2]
labels_2 = [x["label"] for x in system_2]
orientations_2=[x["orientation"] for x in system_2]

sankey = Sankey(ax=ax, unit=None)
sankey.add(flows=flows_1, 
           labels=labels_1,
           label='one',
           orientations=orientations_1)

sankey.add(flows=flows_2, 
           labels=labels_2,
           label='two',
           orientations=orientations_2,
           pathlengths=[0, 0.4, 0.5, 0.65, 1.25],
           prior=0,
           connect=(0,0))

diagrams = sankey.finish()
diagrams[-1].patch.set_hatch('|')
diagrams[-0].patch.set_hatch('-')
plt.legend(loc='best')


plt.show()
Run Code Online (Sandbox Code Playgroud)

输出