如何在网络风格的Plotly图中设置单独的线宽(Python 3.6 | plot.ly)?

时间:2017-09-22 22:36:11

标签: python plot graph plotly networkx

我正在为一个改编自https://plot.ly/python/network-graphs/的networkx图的plot.ly包装器。我无法弄清楚如何根据权重更改每个连接的宽度。权重在attr_dict中为weight。我尝试设置go.Line个对象,但它无法正常工作:(。有任何建议吗?(如果可能,还有教程链接:))。从我在matplotlib中创建的绘图中附加网络结构的示例。

如何在图表中为每个连接设置单独的线宽?

enter image description here

import requests
from ast import literal_eval
import plotly.offline as py
from plotly import graph_objs as go
py.init_notebook_mode(connected=True)

# Import Data
pos = literal_eval(requests.get("https://pastebin.com/raw/P5gv0FXw").text)
df_plot = pd.DataFrame(pos).T
df_plot.columns = list("xy")
edgelist = literal_eval(requests.get("https://pastebin.com/raw/2a8ErW7t").text)
_fig_kws={"figsize":(10,10)}

# Plotting Function
def plot_networkx_plotly(df_plot, pos, edgelist, _fig_kws):
    # Nodes
    node_trace = go.Scattergl(
                         x=df_plot["x"],
                         y=df_plot["y"],
                         mode="markers",
    )
    # Edges
    edge_trace = go.Scattergl(
                         x=[], 
                         y=[],
                         line=[],
                         mode="lines"
    )

    for node_A, node_B, attr_dict in edgelist:
        xA, yA = pos[node_A]
        xB, yB = pos[node_B]
        edge_trace["x"] += [xA, xB, None]
        edge_trace["y"] += [yA, yB, None]
        edge_trace["lines"].append(go.Line(width=attr_dict["weight"],color='#888'))

    # Data
    data = [node_trace, edge_trace]
    layout = {
                "width":_fig_kws["figsize"][0]*100,
                "height":_fig_kws["figsize"][1]*100,

    }
    fig = dict(data=data, layout=layout)

    py.iplot(fig)
    return fig
plot_networkx_plotly(df_plot, pos, edgelist, _fig_kws)

# ---------------------------------------------------------------------------
# PlotlyDictValueError                      Traceback (most recent call last)
# <ipython-input-72-4a5d0e26a71d> in <module>()
#      46     py.iplot(fig)
#      47     return fig
# ---> 48 plot_networkx_plotly(df_plot, pos, edgelist, _fig_kws)

# <ipython-input-72-4a5d0e26a71d> in plot_networkx_plotly(df_plot, pos, edgelist, _fig_kws)
#      25                          y=[],
#      26                          line=[],
# ---> 27                          mode="lines"
#      28     )
#      29 

# ~/anaconda/lib/python3.6/site-packages/plotly/graph_objs/graph_objs.py in __init__(self, *args, **kwargs)
#     375         d = {key: val for key, val in dict(*args, **kwargs).items()}
#     376         for key, val in d.items():
# --> 377             self.__setitem__(key, val, _raise=_raise)
#     378 
#     379     def __dir__(self):

# ~/anaconda/lib/python3.6/site-packages/plotly/graph_objs/graph_objs.py in __setitem__(self, key, value, _raise)
#     430 
#     431         if self._get_attribute_role(key) == 'object':
# --> 432             value = self._value_to_graph_object(key, value, _raise=_raise)
#     433             if not isinstance(value, (PlotlyDict, PlotlyList)):
#     434                 return

# ~/anaconda/lib/python3.6/site-packages/plotly/graph_objs/graph_objs.py in _value_to_graph_object(self, key, value, _raise)
#     535             if _raise:
#     536                 path = self._get_path() + (key, )
# --> 537                 raise exceptions.PlotlyDictValueError(self, path)
#     538             else:
#     539                 return

# PlotlyDictValueError: 'line' has invalid value inside 'scattergl'

# Path To Error: ['line']

# Current path: []
# Current parent object_names: []

# With the current parents, 'line' can be used as follows:

# Under ('figure', 'data', 'scattergl'):

#     role: object

更新Ian Kent的答案:

我不认为下面的代码可以改变所有行的权重。我尝试使用0.1列表创建所有宽度weights并得到以下图: enter image description here

但是当我做width=0.1时,它适用于所有行: enter image description here

1 个答案:

答案 0 :(得分:1)

我认为问题出现在您的代码的以下行中:

edge_trace["lines"].append(go.Line(width=attr_dict["weight"],color='#888'))

尝试使用“line”而不是“lines”。这是Plotly API的一个令人困惑的方面,但在散点图中,模式是复数,并且更改跟踪属性的参数名称是单数。所以,

trace = go.Scatter(mode = 'markers', marker = dict(...))
trace = go.Scatter(mode = 'lines', line = dict(...))

编辑:好的,所以事实证明,问题不仅仅是我现在坐下来的“线条”:

你有line参数作为类似dict的对象列表,而plotly期望它是一个类似dict的对象。建立权重列表然后立即将所有权重添加到line属性似乎有效:

edge_trace = go.Scattergl(
                     x=[],
                     y=[],
                     mode="lines"
)

weights = []
for node_A, node_B, attr_dict in edgelist:
    xA, yA = pos[node_A]
    xB, yB = pos[node_B]
    edge_trace["x"] += [xA, xB, None]
    edge_trace["y"] += [yA, yB, None]
    weights.append(attr_dict["weight"])

edge_trace['line'] = dict(width=weights,color='#888')

此外,您正在绘制节点前面的线条,从而阻碍它们。你应该改变

data = [node_trace, edge_trace]

data = [edge_trace, node_trace]

避免这种情况。