Plotly 中多个 Sankey 子图的问题

Trouble with Multiple Sankey Subplots in Plotly

所以我一直在尝试创建一个包含多个 Sankey 图的图。具体来说,我不断收到一条错误消息 "Invalid property specified for object of type plotly.graph_objs.Sankey: 'xaxis'"。这似乎是在脚本到达 append_trace 命令时调用的。这是一个简单的示例代码,我在 Jupyter notebook 中 运行:

import plotly.tools as tools
import plotly.offline as offline
import plotly.graph_objs as go

offline.init_notebook_mode(connected = True)

trace1 = go.Sankey(
    node = dict(
        pad = 15,
        thickness = 20,
        line = dict(
            color = "black",
            width = 0.5
        ),
        label = ["Joe", "Molly", "Gavin", "Octavio", "Leslie", "Natasha"],
        color = ["blue", "red", "green", "yellow", "brown", "magenta"]
    ),
    link = dict(
        source = [0,1,3],
        target = [5,5,0],
        value = [6,8,3]
    )
)

trace2 = go.Sankey(
    node = dict(
        pad = 15,
        thickness = 20,
        line = dict(
            color = "black",
            width = 0.5
        ),
        label = ["Russia", "Gambia", "Sweden", "Bolivia", "Timor-Leste", "Kazakhstan", "Bhutan"],
        color = ["red", "black", "brown", "magenta", "yellow", "blue", "orange"]
    ),
    link = dict(
        source = [0,1,4,6],
        target = [7,7,7,3],
        value = [6,8,3,3]
    )
)

fig = tools.make_subplots(rows = 2, cols = 1)

fig.append_trace(trace1, 1, 1)
fig.append_trace(trace2, 2, 1)

fig['layout'].update(
    title = "Basic Sankey Diagram with Two Subplots",
    font = dict(
      size = 10
    )
)

offline.iplot(fig)

当我 运行 它时,我得到以下回溯:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-4-dd6268edf7ab> in <module>
     37 fig = tools.make_subplots(rows = 2, cols = 1)
     38 
---> 39 fig.append_trace(trace1, 1, 1)
     40 fig.append_trace(trace2, 2, 1)
     41 

/anaconda3/lib/python3.7/site-packages/plotly/basedatatypes.py in append_trace(self, trace, row, col)
   1222 """, DeprecationWarning)
   1223 
-> 1224         self.add_trace(trace=trace, row=row, col=col)
   1225 
   1226     def _set_trace_grid_position(self, trace, row, col):

/anaconda3/lib/python3.7/site-packages/plotly/basedatatypes.py in add_trace(self, trace, row, col)
   1069         return self.add_traces(data=[trace],
   1070                                rows=[row] if row is not None else None,
-> 1071                                cols=[col] if col is not None else None
   1072                                )[0]
   1073 

/anaconda3/lib/python3.7/site-packages/plotly/basedatatypes.py in add_traces(self, data, rows, cols)
   1152         if rows is not None:
   1153             for trace, row, col in zip(data, rows, cols):
-> 1154                 self._set_trace_grid_position(trace, row, col)
   1155 
   1156         # Make deep copy of trace data (Optimize later if needed)

/anaconda3/lib/python3.7/site-packages/plotly/basedatatypes.py in _set_trace_grid_position(self, trace, row, col)
   1259                                 "An axis object for ({r},{c}) subplot "
   1260                                 "cell got deleted.".format(r=row, c=col))
-> 1261             trace['xaxis'] = ref[0]
   1262             trace['yaxis'] = ref[1]
   1263 

/anaconda3/lib/python3.7/site-packages/plotly/basedatatypes.py in __setitem__(self, prop, value)
   2823             # ### Validate prop ###
   2824             if prop not in self._validators:
-> 2825                 self._raise_on_invalid_property_error(prop)
   2826 
   2827             # ### Get validator for this property ###

/anaconda3/lib/python3.7/site-packages/plotly/basedatatypes.py in _raise_on_invalid_property_error(self, *args)
   3006                                  full_obj_name=full_obj_name,
   3007                                  invalid_str=invalid_str,
-> 3008                                  prop_descriptions=self._prop_descriptions))
   3009 
   3010     def update(self, dict1=None, **kwargs):

ValueError: Invalid property specified for object of type plotly.graph_objs.Sankey: 'xaxis'

我没有在我的跟踪中指定 xaxis,所以这到底是从哪里来的?似乎这部分可能与它有关:

/anaconda3/lib/python3.7/site-packages/plotly/basedatatypes.py in _set_trace_grid_position(self, trace, row, col)
   1259                                 "An axis object for ({r},{c}) subplot "
   1260                                 "cell got deleted.".format(r=row, c=col))
-> 1261             trace['xaxis'] = ref[0]
   1262             trace['yaxis'] = ref[1]
   1263

这是一个错误吗?我不知道。

有人帮忙!

尝试 this way 不附加操作:

将此添加到两条轨迹的定义中。

type='sankey',

将您的两个子图定义为数据数组。

data = Data([trace1, trace2])

定义fig:

fig = dict(data=[data], layout=layout)
py.iplot(fig, validate=False)

最后,您需要使用字典添加布局定义,如我所引用的 post 所示。

我在 Plotly 社区论坛上 cross-posted 这个问题 here 并收到了解决它的答案(大部分)。我会在这里复制答案,这样即使 link 死了它也会被保留。

The trouble you’re running into is that make_subplots and append_trace only work for cartesian trace types right now. This is something we’re planning to improve for version 4, but in the meantime, the best approach is to specify the position of each sankey trace individually using the domain property.

import plotly.offline as offline
import plotly.graph_objs as go

offline.init_notebook_mode(connected = True)

trace1 = go.Sankey(
    node = dict(
        pad = 15,
        thickness = 20,
        line = dict(
            color = "black",
            width = 0.5
        ),
        label = ["Joe", "Molly", "Gavin", "Octavio", "Leslie", "Natasha"],
        color = ["blue", "red", "green", "yellow", "brown", "magenta"]
    ),
    link = dict(
        source = [0,1,3],
        target = [5,5,0],
        value = [6,8,3]
    ),
    domain={
        'x': [0, 0.45]
    }
)

trace2 = go.Sankey(
    node = dict(
        pad = 15,
        thickness = 20,
        line = dict(
            color = "black",
            width = 0.5
        ),
        label = ["Russia", "Gambia", "Sweden", "Bolivia", "Timor-Leste", "Canada", "Bhutan"],
        color = ["red", "black", "brown", "magenta", "yellow", "blue", "orange"]
    ),
    link = dict(
        source = [0,1,4,6],
        target = [7,7,7,3],
        value = [6,8,3,3]
    ),
    domain={
        'x': [0.55, 1.0]
    }
)

data = [trace1, trace2]

layout =  go.Layout(
    title = "Basic Sankey Diagram",
    font = dict(
      size = 10
    )
)

fig = go.Figure(data=data, layout=layout)
iplot(fig)

这会并排生成两个子图:

Sankey subplots horizontal

我们可以指定 'y' 来垂直放置子图,而不是在域中指定 'x'。

这是一个很好的 hack,缺少对 Sankey 子图的 built-in 支持。唯一的缺点是我看不出如何为子图指定单独的标题。