如何在Matplotlib、Plotly和NetworkX中绘制重复X轴范围的网络图
使用Plotly实现带重复X轴域的NetworkX网络图
核心思路
要实现重复X轴域(每个域对应0-100范围)的网络图,关键在于:
- 为每个节点计算基于域编号的偏移X坐标,确保不同域的节点落在独立的0-100区间内
- 自定义X轴刻度,将累计的偏移坐标映射为每个域的0-100显示文本
- 用Plotly的散点图和线条分别绘制节点与边
完整代码示例
假设你已有包含节点域编号、域内相对位置的DataFrame,以下是可直接运行的实现代码:
import pandas as pd import networkx as nx import plotly.graph_objects as go # ---------------------- 示例数据(替换为你的实际数据) ---------------------- nodes_df = pd.DataFrame({ 'node_id': [1, 2, 3, 4, 5, 6], 'domain': [12, 12, 13, 13, 14, 14], 'x_in_domain': [20, 70, 30, 80, 50, 90], # 域内0-100的相对位置 'y': [50, 30, 60, 20, 40, 70], # Y轴坐标 'node_color': [10, 20, 30, 40, 50, 60] # 节点颜色属性(可选) }) edges_df = pd.DataFrame({ 'source': [1, 2, 3, 5], 'target': [3, 4, 5, 6] }) # ------------------------------------------------------------------------- # 创建NetworkX图 G = nx.Graph() G.add_nodes_from(nodes_df['node_id']) G.add_edges_from(edges_df[['source', 'target']].values) # 计算节点实际X坐标:域偏移量 + 域内相对位置 min_domain = nodes_df['domain'].min() nodes_df['x'] = (nodes_df['domain'] - min_domain) * 100 + nodes_df['x_in_domain'] # 准备边的坐标数据 edge_x, edge_y = [], [] for src, tgt in G.edges(): src_x = nodes_df.loc[nodes_df['node_id'] == src, 'x'].values[0] src_y = nodes_df.loc[nodes_df['node_id'] == src, 'y'].values[0] tgt_x = nodes_df.loc[nodes_df['node_id'] == tgt, 'x'].values[0] tgt_y = nodes_df.loc[nodes_df['node_id'] == tgt, 'y'].values[0] edge_x.extend([src_x, tgt_x, None]) # None用于分隔不同边 edge_y.extend([src_y, tgt_y, None]) # 准备节点的坐标与 hover 文本 node_x = nodes_df['x'].tolist() node_y = nodes_df['y'].tolist() node_text = [ f"节点ID: {n}<br>域编号: {d}<br>域内X: {x}" for n, d, x in zip(nodes_df['node_id'], nodes_df['domain'], nodes_df['x_in_domain']) ] # 构建Plotly图 fig = go.Figure() # 添加边轨迹 fig.add_trace(go.Scatter( x=edge_x, y=edge_y, mode='lines', line=dict(width=0.8, color='#666'), hoverinfo='none' )) # 添加节点轨迹 fig.add_trace(go.Scatter( x=node_x, y=node_y, mode='markers', marker=dict( size=12, color=nodes_df['node_color'], colorscale='Viridis', colorbar=dict(title='节点属性'), line=dict(width=1, color='#fff') ), text=node_text, hoverinfo='text' )) # 自定义X轴:每个域显示0-100刻度 unique_domains = sorted(nodes_df['domain'].unique()) tick_vals = [] tick_text = [] for idx, _ in enumerate(unique_domains): domain_start = idx * 100 # 添加0、50、100三个刻度点 tick_vals.extend([domain_start, domain_start+50, domain_start+100]) tick_text.extend(['0', '50', '100']) # 设置布局 fig.update_layout( xaxis=dict( tickvals=tick_vals, ticktext=tick_text, title='域(0-100)', showgrid=True, gridcolor='#eee', range=[-10, len(unique_domains)*100 + 10] # 预留左右边距 ), yaxis=dict( title='Y坐标', showgrid=True, gridcolor='#eee' ), showlegend=False, hovermode='closest', height=600, width=1200 ) # 添加域分隔虚线 for idx in range(1, len(unique_domains)): fig.add_vline(x=idx*100, line_width=2, line_dash='dash', line_color='#aaa') fig.show()
关键细节说明
- 坐标计算:通过
(域编号 - 最小域编号)*100为每个域创建独立的100单位宽度区间,叠加域内相对位置得到节点最终X坐标。 - X轴自定义:利用
tickvals和ticktext将累计坐标映射为每个域的0-100显示文本,配合垂直虚线清晰分隔不同域。 - 边的绘制:用
None分隔每条边的线段,确保Plotly正确渲染独立的边。
你可以根据实际需求调整节点大小、颜色、边样式等参数,完全匹配你的参考图效果。
内容的提问来源于stack exchange,提问作者mrq
相关产品推荐
相关产品推荐

