首页 > 解决方案 > 在 plotly 上将滑块添加到有向加权图

问题描述

我想在plotly使用时绘制一个带有边权重的有向图python。最重要的是,我想添加一个滑块来对要显示的边缘进行一些阈值处理。一个简单的例子:一个有 2 个点的滑块,在第一个点上,滑块将显示所有边缘,而在第二个点上,滑块将只显示权重 > 0.5 的边缘。这只是一个简单的示例,我想将其扩展为滑块上有 10 个点(意味着 10 个不同的阈值)。

我遇到的问题是,为了可视化有向边,我为每条边绘制了一条轨迹,以便能够将轨迹的不透明度设置为相应的边权重。我还在边缘添加了一些悬停文本。所以我的绘图上有很多痕迹,1 表示节点,X 表示边缘(其中 X 是边数),X 表示边缘悬停。如何配置滑块以执行此阈值以提高可见性?

我的想法是为每个跟踪设置一个 id,将特定边缘所属的“滑块点”上下文化,但这似乎不起作用。下面是我的代码。任何帮助表示赞赏!谢谢!

import networkx as nx
import numpy as np
import matplotlib.pyplot as plt
import plotly.graph_objects as go
from tqdm import tqdm


G = nx.DiGraph()
edges = [(1,2), (2,4), (4,0), (5,1)]
edge_weights = {(1,2): 0.1, (2,4): 0.5, (4,0): 1, (5,1): 0.3}
node_weights = [0.1, 0.2, 0.3, 0.4, 0.5]

G.add_edges_from(edges)

pos = nx.spring_layout(G, k=10)  # For better example looking

# Plot nodes with go.Scatter
node_x = []
node_y = []
for node in G.nodes():
    x, y = pos[node]
    node_x.append(x)
    node_y.append(y)

traces = []
node_trace = go.Scatter(
    x=node_x, y=node_y, visible=True,
    marker=dict(
        showscale=True, color=node_weights,
        colorbar=dict(
            thickness=15,
            title='Node weights',
            xanchor='left',
            titleside='right'
        ),
        line_width=2))

traces.append(node_trace)


#Get edge trace IDs for slider filtering
edge_trace_ids = {}
for w in edge_weights:
    if w <= 0.5:
        edge_trace_ids[w] = 0
    else:
        edge_trace_ids[w] = 1


x0, y0, x1, y1 = [], [], [], []
i=0
for edge,weight in tqdm(zip(edges,edge_weights)):
    # Get the coordinates of each node
    edge_coord_source = pos[edge[0]]
    edge_coord_target = pos[edge[1]]
    x0.append(edge_coord_source[0])
    y0.append(edge_coord_source[1])
    x1.append(edge_coord_target[0])
    y1.append(edge_coord_target[1])

    # Plot edges hover with go.Scatter.
    middle_hover_trace = go.Scatter(
        x=[], y=[], hovertext=[], mode='markers', hoverinfo="text",
        marker={'size': 20, 'color': 'LightSkyBlue'}, opacity=0,
        visible=False,
        uid=edge_trace_ids[weight] #my attempt to assign ID for each trace for slider filtering
    )

    middle_hover_trace['x'] = tuple([(edge_coord_source[0] + edge_coord_target[0]) / 2])
    middle_hover_trace['y'] = tuple([(edge_coord_source[1] + edge_coord_target[1]) / 2])

    hovertext = f"Edge weight: {weight}"
    middle_hover_trace['hovertext'] = tuple([hovertext])

    traces.append(middle_hover_trace)

    # Plot edges with go.Scatter.
    # This has to be done in a loop to be able to set the opacity/color according to weights
    edge_trace = go.Scatter(
        x=tuple([edge_coord_source[0], edge_coord_target[0], None]),
        y=tuple([edge_coord_source[1], edge_coord_target[1], None]),
        mode='lines',
        marker=dict(color="red"),
        line_shape='spline',
        opacity=weight,
        visible=False,
        uid=edge_trace_ids[weight]
    )
    traces.append(edge_trace)
    i+=1


fig = go.Figure(
    data = traces,
    layout=go.Layout(
        title=dict(text="Directed Graph", font=dict(size=14, color='blue')),
        showlegend=False,
        margin=dict(b=20,l=5,r=5,t=40),
        annotations = [
            dict(
                    ax=x0[i], ay=y0[i], axref='x', ayref='y',
                    x=x1[i], y=y1[i], xref='x', yref='y',
                    showarrow=True, arrowhead=1, arrowsize=2,
                    arrowcolor="red" if w == 1 else "green",
                    opacity=w/3, visible=False, name=edge_trace_ids[w]
                )
                for i,w in enumerate(edge_weights)
        ],
        xaxis=dict(showgrid=False, zeroline=False, showticklabels=False),
        yaxis=dict(showgrid=False, zeroline=False, showticklabels=False)
    )
)



# Create and add slider
sliders_steps = 2
steps = []
for i in range(sliders_steps):
    step = dict(
        method="update",
        args=[{"visible": [False] * sliders_steps},
            {"title": "Slider switched to step: " + str(i)}],  # layout attribute
    )
    for fig_data in fig.data:
        if int(fig_data.uid) == i:
            fig_data.visible = True

    step["args"][0]["visible"][i] = True  # Toggle i'th trace to "visible"
    steps.append(step)

sliders = [dict(
    active=10,
    currentvalue={"prefix": "Frequency: "},
    pad={"t": 50},
    steps=steps
)]

fig.update_layout(sliders=sliders)

标签: pythonplotlyplotly-dashplotly-python

解决方案


推荐阅读