You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Dash实现点击气泡图气泡生成对应分类的NetworkX网络图

完整Dash实现方案

前置依赖安装

执行以下命令安装需要的依赖库:

pip install dash plotly networkx pandas

完整可运行代码

import dash
from dash import dcc, html, Input, Output, callback
import plotly.graph_objects as go
import networkx as nx
import pandas as pd

# ---------------------- 数据预处理 ----------------------
# 原始数据表
df = pd.DataFrame([
    ["cat1", "node1", "target1"],
    ["cat1", "node2", "target1"],
    ["cat1", "node2", "target2"],
    ["cat1", "node2", "target3"],
    ["cat1", "node2", "target4"],
    ["cat2", "node3", "target1"],
    ["cat2", "node3", "target1"],
    ["cat2", "node4", "target7"],
    ["cat2", "node6", "target7"],
], columns=["category", "source_node", "target_node"])

# 按分类预存边列表
category_edges = df.groupby("category").apply(
    lambda x: x[["source_node", "target_node"]].to_dict("records")
).to_dict()

# 分类坐标、条目数配置
node_plot_location_dict = {'cat1': [10, 4], 'cat2': [3, 4]}
category_count = df["category"].value_counts().to_dict()

# ---------------------- Dash页面配置 ----------------------
app = dash.Dash(__name__)

app.layout = html.Div([
    dcc.Location(id='url', refresh=True),
    html.H3("分类气泡图"),
    dcc.Graph(id="bubble-chart"),
    html.Hr(),
    html.H3("分类关系网络图"),
    dcc.Graph(id="network-graph"),
])

# ---------------------- 回调逻辑 ----------------------
# 初始化气泡图
@callback(
    Output("bubble-chart", "figure"),
    Input("bubble-chart", "id")
)
def update_bubble(_):
    categories = list(node_plot_location_dict.keys())
    fig = go.Figure(data=[go.Scatter(
        x = [node_plot_location_dict[c][0] for c in categories],
        y = [node_plot_location_dict[c][1] for c in categories],
        mode = 'markers+text',
        text = categories,
        textposition = 'top center',
        marker = dict(
            size = [category_count[c] * 10 for c in categories], # 气泡大小关联分类条目数
            opacity = 0.7
        ),
        customdata = categories # 存储分类名用于点击时识别
    )])
    fig.update_layout(clickmode='event+select', showlegend=False)
    return fig

# 点击气泡更新网络图
@callback(
    Output("network-graph", "figure"),
    Input("bubble-chart", "clickData"),
    prevent_initial_call=False
)
def update_network(click_data):
    # 未点击时显示提示
    if not click_data:
        return go.Figure().add_annotation(
            text="点击上方气泡图的分类查看对应网络图",
            showarrow=False, 
            font={"size": 20}
        )
    # 获取选中分类
    selected_cat = click_data["points"][0]["customdata"]
    edges = category_edges[selected_cat]
    # 生成NetworkX图
    G = nx.Graph()
    for edge in edges:
        G.add_edge(edge["source_node"], edge["target_node"])
    # 计算节点布局坐标,固定seed保证布局稳定
    pos = nx.spring_layout(G, seed=42)
    
    # 绘制边
    edge_traces = []
    for edge in G.edges():
        x0, y0 = pos[edge[0]]
        x1, y1 = pos[edge[1]]
        edge_traces.append(go.Scatter(
            x = [x0, x1, None],
            y = [y0, y1, None],
            line = dict(width=1, color="#888"),
            mode = "lines",
            hoverinfo = "none"
        ))
    
    # 绘制节点
    node_x, node_y, node_text, node_links = [], [], [], []
    for node in G.nodes():
        x, y = pos[node]
        node_x.append(x)
        node_y.append(y)
        node_text.append(node)
        # 自定义节点跳转链接规则,可按需修改
        node_links.append(f"https://example.com/node/{node}")
    
    node_trace = go.Scatter(
        x = node_x,
        y = node_y,
        mode = "markers+text",
        text = node_text,
        textposition = "top center",
        marker = dict(size=20, line_width=2),
        customdata = node_links,
        hoverinfo = "text"
    )
    
    # 组装网络图
    fig = go.Figure(data=edge_traces + [node_trace])
    fig.update_layout(
        showlegend=False,
        clickmode="event+select",
        xaxis=dict(showgrid=False, zeroline=False, showticklabels=False),
        yaxis=dict(showgrid=False, zeroline=False, showticklabels=False)
    )
    return fig

# 点击网络图节点跳转对应页面
@callback(
    Output("url", "href"),
    Input("network-graph", "clickData"),
    prevent_initial_call=True
)
def node_redirect(click_data):
    return click_data["points"][0]["customdata"]

if __name__ == "__main__":
    app.run_server(debug=True)

效果说明

  • 运行代码后访问默认的http://127.0.0.1:8050即可使用交互功能
  • 气泡大小与分类下的条目数量正相关,点击任意分类气泡,下方会自动渲染该分类的关系网络图
  • 点击网络图的任意节点,会自动跳转到提前配置的对应链接

Jupyter环境可选方案

如果需要在Jupyter中直接使用,可替换为ipywidgets+plotly的组合实现相同效果,核心的联动逻辑与上述代码一致,无需启动独立的Dash服务。

内容的提问来源于stack exchange,提问作者Slowat_Kela

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 05:48:04