Управление подключениями к диаграмме Санки

Я пытаюсь контролировать, какие потоки подключаются друг к другу, используя диаграмму 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()

Это дает мне:

Диаграмма Санки, которая на самом деле не работает

Он должен объединять потоки с соответствующими метками.

Я прочитал это и this, но они не помогают мне понять, что на самом деле происходит.


person Ben    schedule 06.03.2018    source источник
comment
Я предполагаю, что процесс, который в конечном итоге приводит к пониманию этого, заключается не в том, чтобы создать действительно сложный пример и попытаться заставить его выглядеть правильно, а вместо этого начать с базовой схемы и попытки изменить параметры, чтобы увидеть их эффект.   -  person ImportanceOfBeingErnest    schedule 12.03.2018
comment
Также есть это пример, который может пригодиться.   -  person ImportanceOfBeingErnest    schedule 12.03.2018


Ответы (1)


Начнем с попытки разгадать путаницу

Я думаю, что мое замешательство сводится к неправильному пониманию того, что это на самом деле означает:

Обратите внимание, что указано только одно соединение, но системы образуют цепь, поскольку: (1) длины путей обоснованы и (2) ориентация и порядок потоков отражаются.

(2) Ориентация и порядок потоков зеркально отражены.

Возможно, вы неправильно поняли значение слова зеркально, что в данном случае действительно сбивает с толку. Можно подумать, что зеркальное отображение равно инвертированному, но это верно лишь отчасти:
flows (или, как вы его называете в своем коде: values) должен быть инвертирован, на этот раз вы правильно поняли. Потому что values соответствует входам (value > 0) или выходам (value < 0). И только выход может быть подключен ко входу, и наоборот.

Но orientation должен быть одинаковым для обоих потоков, которые вы пытаетесь соединить. Этот не инвертирован, но его еще нужно "отразить". Что под этим подразумевается? Что ж, если ввод-вывод смотрит в направлении стрелки, из которой он пришел, ему необходимо увидеть другой ввод-вывод (как при взгляде в зеркало), только тогда они могут подключиться друг к другу. Это не так просто объяснить как носителю языка, но я постараюсь проиллюстрировать идею:

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-й поток оранжевой системы находится в верхнем левом углу, а его аналог из синей системы - в правом нижнем углу. Эти входы / выходы никогда не смогут «видеть» друг друга.

Вы можете отменить инверсию второй системы, удалив -, который предшествует 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()

Вывод

person V. L.    schedule 14.03.2018