控制Sankey图连接

时间:2018-03-06 22:30:23

标签: 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()

这给了我:

A sankey diagram that doesn't really work

应该使用匹配标签加入流程。

我已阅读thisthis,但他们并没有帮助我了解实际发生的情况。

1 个答案:

答案 0 :(得分:4)

让我们首先尝试解决困惑

  

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

     
    

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

  

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

您可能理解错误的是镜像的含义,在这种情况下确实令人困惑。有人会认为,镜像等于倒置,但这只是部分正确:
必须颠倒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     |      ^                    |      ^

在您的代码中,您已反转orientation。这就是为什么例如橙色系统的第3个流程位于左上角,而蓝色系统的第3个流程位于右下角。没有办法,这些I / O将能够“看到”彼此。

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

orientations=[x["orientation"] for x in system_2]

你会看到现在流量彼此接近,但是你处于Not able to connect - 插图(第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()

Output