Python图论与网络可视化——网络结构、路径分析与生物代谢通路
Python图论与网络可视化——网络结构、路径分析与生物代谢通路
本节将深入探索图论与网络的可视化技术,涵盖网络结构展示、最短路径动态演示及生物代谢通路分析。通过NetworkX构建网络模型,结合Matplotlib实现可视化,展现图论在多领域的应用价值。
一、前言:图论与网络的重要性
图论以**顶点(节点)和边(连接)**为核心,构建复杂系统的抽象模型,广泛应用于计算机科学、社交网络、生物信息学等地方。其核心价值在于将实体关系转化为可计算、可分析的结构,例如:
- 社交网络:用户为节点,关注关系为边
- 代谢通路:代谢物为节点,酶催化反应为边
- 交通网络:地点为节点,路线为边
#mermaid-svg-JuSMNxUKAnIwSQGn {font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-JuSMNxUKAnIwSQGn .error-icon{fill:#552222;}#mermaid-svg-JuSMNxUKAnIwSQGn .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-JuSMNxUKAnIwSQGn .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-JuSMNxUKAnIwSQGn .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-JuSMNxUKAnIwSQGn .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-JuSMNxUKAnIwSQGn .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-JuSMNxUKAnIwSQGn .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-JuSMNxUKAnIwSQGn .marker{fill:#333333;stroke:#333333;}#mermaid-svg-JuSMNxUKAnIwSQGn .marker.cross{stroke:#333333;}#mermaid-svg-JuSMNxUKAnIwSQGn svg{font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-JuSMNxUKAnIwSQGn .label{font-family:\"trebuchet ms\",verdana,arial,sans-serif;color:#333;}#mermaid-svg-JuSMNxUKAnIwSQGn .cluster-label text{fill:#333;}#mermaid-svg-JuSMNxUKAnIwSQGn .cluster-label span{color:#333;}#mermaid-svg-JuSMNxUKAnIwSQGn .label text,#mermaid-svg-JuSMNxUKAnIwSQGn span{fill:#333;color:#333;}#mermaid-svg-JuSMNxUKAnIwSQGn .node rect,#mermaid-svg-JuSMNxUKAnIwSQGn .node circle,#mermaid-svg-JuSMNxUKAnIwSQGn .node ellipse,#mermaid-svg-JuSMNxUKAnIwSQGn .node polygon,#mermaid-svg-JuSMNxUKAnIwSQGn .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-JuSMNxUKAnIwSQGn .node .label{text-align:center;}#mermaid-svg-JuSMNxUKAnIwSQGn .node.clickable{cursor:pointer;}#mermaid-svg-JuSMNxUKAnIwSQGn .arrowheadPath{fill:#333333;}#mermaid-svg-JuSMNxUKAnIwSQGn .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-JuSMNxUKAnIwSQGn .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-JuSMNxUKAnIwSQGn .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-JuSMNxUKAnIwSQGn .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-JuSMNxUKAnIwSQGn .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-JuSMNxUKAnIwSQGn .cluster text{fill:#333;}#mermaid-svg-JuSMNxUKAnIwSQGn .cluster span{color:#333;}#mermaid-svg-JuSMNxUKAnIwSQGn div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-JuSMNxUKAnIwSQGn :root{--mermaid-font-family:\"trebuchet ms\",verdana,arial,sans-serif;}图论应用计算机科学生命科学工程系统算法设计数据结构代谢网络蛋白质互作交通规划电力网络
二、基本概念:图论基础
2.1 图的组成要素
通过可视化展示图的核心元素:
- 顶点:表示实体(如用户、分子)
- 边:表示关系(如连接、反应)
- 权重:量化关系强度(如距离、反应速率)
- 度:节点的连接数量
# 简化代码:核心功能说明def plot_graph_elements(): # 创建图,添加节点和边 G = nx.Graph() G.add_nodes_from(..., attributes) G.add_edges_from(..., weights) # 可视化设置 pos = 指定节点位置 nx.draw_networkx_nodes(..., 按类型着色) nx.draw_networkx_edges(..., 按权重渲染) 添加图例和文字说明
2.2 图的分类体系
根据结构特征分为:
- 随机网络(Erdős-Rényi):边随机连接
- 小世界网络(Watts-Strogatz):高聚类+短路径
- 无标度网络(Barabási-Albert):幂律度分布
- 二分图:节点分为两类,边仅跨类连接
2.3 关键分析指标
三、网络可视化与中心性分析
3.1 网络类型对比可视化
通过子图对比不同网络结构:
# 简化代码:网络类型可视化def plot_network_types(): 创建随机网络、小世界网络等 为每个网络设置布局并绘制 添加标题和统一图例
3.2 中心性度量可视化
以空手道俱乐部网络为例,对比三种中心性:
- 度中心性:节点大小反映连接数
- 介数中心性:颜色深浅反映枢纽重要性
- 接近中心性:高值节点位于网络核心
# 简化代码:中心性可视化def plot_centrality_measures(G): 计算三种中心性 按中心性值设置节点大小和颜色 分面板展示并添加颜色条
四、最短路径动态演示:Dijkstra算法
通过动画直观展示算法步骤:
- 初始化:起点设为黄色,其余为灰色
- 迭代过程:优先队列选择当前最短节点,更新邻居距离
- 路径高亮:红色标记最终路径,隐藏无效距离标签
# 简化代码:动画核心逻辑def visualize_dijkstra(G, source, target): 初始化距离和优先队列 while 队列不为空: 取出当前节点,标记为绿色 更新邻居节点距离,标记为黄色 重建路径并添加红色高亮帧 定义动画更新函数,动态渲染节点和边
优化细节:
- 调整布局参数
k=0.8/np.sqrt(len(G.nodes))
避免节点重叠 - 仅显示有限距离值(隐藏
d=inf
) - 增加动画间隔至1秒,便于观察
五、跨学科案例:糖酵解代谢通路分析
5.1 网络构建
- 节点类型:
- 底物(蓝色):Glucose
- 中间产物(绿色):Glucose-6P, Fructose-6P
- 酶(橙色):Hexokinase, Phosphofructokinase
- 边类型:
- 底物→酶:消耗关系
- 酶→产物:生成关系
5.2 关键分析
- 最短路径:从葡萄糖到丙酮酸的代谢路径
- 中心性分析:
- 介数中心性最高节点:ATP、关键酶
- 连接度最高酶:Phosphoglycerate kinase(连接4个代谢物)
# 简化代码:代谢网络分析def analyze_metabolic_network(G): 计算最短路径并打印 输出介数中心性前5节点 提取高连接度酶并展示
六、成果与教学价值
生成文件说明
6.1 图论基本元素图(graph_elements.png)
图形说明:
-
核心元素展示:
- 顶点(节点):
- 编号1-5的圆形节点,分别标注“顶点”“边”“权重”“度”“路径”
- 颜色区分类型:浅蓝色(基本元素)、紫色(属性)、绿色(度量)、橙色(结构)
- 边:带箭头的曲线,标注“连接”等关系,宽度反映权重大小(如1-2边权重3,线条最粗)
- 权重:边旁数字(如1-3边权重2)
- 度:隐含于节点连接数(如节点1连接3条边,度为3)
- 顶点(节点):
-
布局与设计:
- 采用自定义坐标布局(
pos
参数),节点分布于左上至右下,便于边的清晰展示 - 图例位于右上角,标注节点类型对应的颜色
- 采用自定义坐标布局(
-
文字说明:
- 右侧文本框总结关键概念,使用星号列表(避免特殊符号字体问题)
6.2 网络类型对比图(network_types.png)
图形说明:
-
四宫格布局:
- 随机网络(左上):
- 节点随机连接,无明显中心节点,度分布均匀
- 布局:弹簧布局(
spring_layout
),节点分散
- 小世界网络(右上):
- 局部聚类(如三角形结构)与长距离连接并存,模拟真实网络(如社交圈)
- 布局:环形布局(
circular_layout
),凸显聚类特征
- 无标度网络(左下):
- 存在少数高连接度枢纽节点(如中心节点连接8条边),符合幂律分布
- 布局:弹簧布局,枢纽节点居中
- 二分图(右下):
- 节点分为上下两层(用户与产品),边仅跨层连接,无同层边
- 布局:分层布局,用户在上、产品在下
- 随机网络(左上):
-
视觉统一:
- 所有子图使用浅蓝色节点、灰色边,节点大小统一为300像素
- 标题字体大小14,子图间距适中(
tight_layout
)
6.3 中心性度量图(centrality_measures.png)
图形说明:
-
三面板对比:
- 度中心性(左):
- 节点大小与连接数成正比,中心节点(如节点1)最大
- 颜色映射:Blues色系,深色表示高度值
- 介数中心性(中):
- 节点颜色越深,作为最短路径枢纽的频率越高(如节点9为紫色,介数最高)
- 应用场景:识别网络中的关键桥梁节点
- 接近中心性(右):
- 节点越大,到其他节点的平均距离越短(如节点0位于中心,接近中心性最高)
- 颜色映射:Reds色系,浅色表示高效率
- 度中心性(左):
-
技术细节:
- 基于空手道俱乐部网络(34节点),布局统一为弹簧布局
- 节点大小范围:500-5000像素,颜色条标注中心性值范围
6.4 最短路径动画(dijkstra_animation.gif)
动画说明:
-
动态流程:
- 初始化(0秒):起点“A”为黄色,其余节点灰色,距离标签显示“d=inf”
- 搜索阶段(1-4秒):
- 黄色节点表示当前处理节点(如A→C→D→F)
- 绿色节点表示已访问节点,距离标签更新为有限值(如C节点d=2)
- 路径高亮(5-6秒):
- 红色节点和边标注最短路径(A→C→D→F),路径长度6
-
优化细节:
- 节点间距调整:
k=0.8/np.sqrt(len(G.nodes))
,避免密集节点重叠 - 标签优化:仅显示有效距离(隐藏“d=inf”),位置自适应调整(如右侧节点标签左移)
- 动画参数:帧率1fps,每帧间隔1秒,清晰展示每一步更新
- 节点间距调整:
6.5 糖酵解代谢通路图(metabolic_network.png)
图形说明:
-
节点类型与颜色:
- 底物(浅蓝色):Glucose(起点)
- 中间产物(浅绿色):如Glucose-6P、Fructose-1,6BP
- 酶(橙色圆形):如Hexokinase、Phosphofructokinase
- 辅因子(金色):ATP、ADP、NAD+
- 产物(鲑红色):Pyruvate(终点)
-
边与反应:
- 有向边表示反应方向:
- 底物→酶:消耗关系(如Glucose→Hexokinase)
- 酶→产物:生成关系(如Hexokinase→Glucose-6P)
- 边标签:“consumed_by”“produced_by”
- 有向边表示反应方向:
-
布局与注释:
- 弹簧布局(
k=0.5
),酶节点居中,代谢物围绕分布 - 左侧文本框标注9个关键步骤(如葡萄糖磷酸化、丙酮酸生成)
- 右侧文本框总结生物学意义:净产2 ATP、生成NADH
- 弹簧布局(
6.6 代谢路径动画(metabolic_pathway_animation.gif)
动画说明:
-
路径演示:
- 起点“Glucose”→终点“Pyruvate”
- 最短路径:Glucose→Hexokinase→ADP→Pyruvate kinase→Pyruvate
- 红色高亮节点和边,路径长度4
-
动态特征:
- 酶节点(Hexokinase、Pyruvate kinase)作为中间枢纽
- 距离标签显示代谢物转化步数,隐藏无效节点标签
- 最终帧突出显示产物Pyruvate和能量分子ATP
使用建议
-
图片排版:
- 动画GIF可嵌入文档正文,静态图片以居中方式排列
- 每个图片下方添加带编号的标题和说明,如“图1 图论基本元素示意图”
-
对比分析:
- 结合网络类型图,对比随机网络与无标度网络的度分布差异
- 通过中心性图,解释为何介数中心性高的节点适合作为网络控制枢纽
-
教学应用:
- 代谢通路图可配合生物课程,讲解糖酵解的酶催化机制
- 最短路径动画可用于算法课,动态拆解Dijkstra算法的贪心策略
需要调整说明内容或补充特定细节,请随时告知!
教学要点
- 图论基础:理解顶点、边、权重的数学定义
- 网络分析:掌握不同网络类型的结构特征与中心性计算
- 算法实现:Dijkstra算法的动态演示与优化技巧
- 跨学科应用:图论在生物代谢通路中的建模与分析方法
通过可视化与算法结合,图论成为连接数学理论与实际问题的桥梁,尤其在复杂系统分析中展现出强大的建模能力。
七、完整代码(可直接运行)
import matplotlib.pyplot as pltimport networkx as nximport numpy as npfrom matplotlib.colors import LinearSegmentedColormapimport matplotlib.animation as animationfrom matplotlib.colors import ListedColormapfrom queue import PriorityQueuefrom numba import njit# 设置中文字体plt.rcParams[\"font.sans-serif\"] = [\"SimHei\", \"WenQuanYi Micro Hei\", \"Heiti TC\"]plt.rcParams[\"axes.unicode_minus\"] = False # 正确显示负号plt.rcParams[\"mathtext.fontset\"] = \"cm\" # 设置数学字体def plot_graph_elements(output_path=\"graph_elements.png\"): \"\"\"可视化图的基本元素\"\"\" plt.figure(figsize=(12, 8), dpi=130) # 创建图 G = nx.Graph() # 添加节点 G.add_nodes_from( [ (1, {\"label\": \"顶点\", \"type\": \"基本元素\"}), (2, {\"label\": \"边\", \"type\": \"基本元素\"}), (3, {\"label\": \"权重\", \"type\": \"属性\"}), (4, {\"label\": \"度\", \"type\": \"度量\"}), (5, {\"label\": \"路径\", \"type\": \"结构\"}), ] ) # 添加边 G.add_edges_from( [ (1, 2, {\"weight\": 3, \"label\": \"连接\"}), (1, 3, {\"weight\": 2}), (1, 4, {\"weight\": 1}), (2, 5, {\"weight\": 4}), (3, 4, {\"weight\": 2}), (4, 5, {\"weight\": 3}), ] ) # 节点位置 pos = {1: (0.2, 0.8), 2: (0.4, 0.6), 3: (0.1, 0.4), 4: (0.3, 0.2), 5: (0.6, 0.4)} # 绘制节点 node_types = set(nx.get_node_attributes(G, \"type\").values()) colors = plt.cm.tab10(range(len(node_types))) type_color_map = {t: colors[i] for i, t in enumerate(node_types)} node_colors = [type_color_map[G.nodes[n][\"type\"]] for n in G.nodes] nx.draw_networkx_nodes(G, pos, node_size=1500, node_color=node_colors, alpha=0.8) # 绘制边 edge_weights = [G.edges[e][\"weight\"] for e in G.edges] nx.draw_networkx_edges( G, pos, width=3, alpha=0.6, edge_color=edge_weights, edge_cmap=plt.cm.Blues ) # 绘制标签 node_labels = nx.get_node_attributes(G, \"label\") nx.draw_networkx_labels( G, pos, labels=node_labels, font_size=12, font_weight=\"bold\" ) edge_labels = nx.get_edge_attributes(G, \"label\") nx.draw_networkx_edge_labels(G, pos, edge_labels=edge_labels, font_size=10) # 添加图例 for t, color in type_color_map.items(): plt.scatter([], [], c=[color], s=200, label=t, alpha=0.8) plt.legend(loc=\"upper right\", title=\"节点类型\") # 设置标题 plt.title(\"图的基本元素与属性\", fontsize=18, pad=20) plt.axis(\"off\") # 添加概念说明(使用*替代•) plt.text( 0.7, 0.9, \"关键概念:\\n\" \"* 顶点: 实体对象\\n\" \"* 边: 实体间关系\\n\" \"* 权重: 关系强度\\n\" \"* 度: 节点连接数\\n\" \"* 路径: 节点序列\", transform=plt.gca().transAxes, fontsize=12, bbox=dict(facecolor=\"white\", alpha=0.8), ) plt.savefig(output_path, bbox_inches=\"tight\") plt.close() print(f\"图论基本元素图已保存至: {output_path}\")def plot_network_types(output_path=\"network_types.png\"): \"\"\"可视化不同网络类型\"\"\" plt.figure(figsize=(15, 5), dpi=130) # 创建不同类型的网络 networks = { \"随机网络\": nx.gnp_random_graph(15, 0.2, seed=42), \"小世界网络\": nx.watts_strogatz_graph(15, 4, 0.3, seed=42), \"无标度网络\": nx.barabasi_albert_graph(15, 2, seed=42), \"完全网络\": nx.complete_graph(15), } for i, (name, G) in enumerate(networks.items()): plt.subplot(1, len(networks), i + 1) pos = nx.spring_layout(G, seed=42) nx.draw( G, pos, with_labels=True, node_color=\"skyblue\", node_size=300, font_size=9, font_weight=\"bold\", edge_color=\"gray\", ) plt.title(name, fontsize=14) plt.axis(\"off\") plt.tight_layout() plt.savefig(output_path, bbox_inches=\"tight\") plt.close() print(f\"网络类型图已保存至: {output_path}\")def plot_centrality_measures(G, output_path=\"centrality_measures.png\"): \"\"\"可视化不同中心性度量\"\"\" plt.figure(figsize=(16, 12), dpi=130) # 计算不同的中心性 degree_centrality = nx.degree_centrality(G) betweenness_centrality = nx.betweenness_centrality(G) closeness_centrality = nx.closeness_centrality(G) eigenvector_centrality = nx.eigenvector_centrality(G) centrality_measures = { \"度中心性\": degree_centrality, \"介数中心性\": betweenness_centrality, \"接近中心性\": closeness_centrality, \"特征向量中心性\": eigenvector_centrality, } pos = nx.spring_layout(G, seed=42) for i, (name, centrality) in enumerate(centrality_measures.items(), 1): plt.subplot(2, 2, i) node_size = [v * 2000 for v in centrality.values()] node_color = list(centrality.values()) # 保存节点绘制的返回值,用于创建colorbar nodes = nx.draw_networkx_nodes( G, pos, node_size=node_size, cmap=plt.cm.viridis, node_color=node_color, alpha=0.8, ) nx.draw_networkx_edges(G, pos, alpha=0.5) nx.draw_networkx_labels(G, pos, font_size=9) plt.title(f\"{name}\", fontsize=14) plt.axis(\"off\") # 使用保存的nodes对象创建colorbar plt.colorbar(nodes, label=\"中心性值\") plt.tight_layout() plt.savefig(output_path, bbox_inches=\"tight\") plt.close() print(f\"中心性度量图已保存至: {output_path}\")@njitdef compute_mandelbrot(width, height, x_min, x_max, y_min, y_max, max_iter): \"\"\"使用Numba加速计算Mandelbrot集合\"\"\" # 创建结果数组 iterations = np.zeros((height, width), dtype=np.int32) # 计算每个像素对应的复平面坐标 for y in range(height): for x in range(width): # 将像素坐标映射到复平面 real = x_min + (x / (width - 1)) * (x_max - x_min) imag = y_min + (y / (height - 1)) * (y_max - y_min) # 初始化复数c和z c = complex(real, imag) z = complex(0, 0) # 迭代计算 for i in range(max_iter): if abs(z) > 2.0: iterations[y, x] = i break z = z * z + c else: iterations[y, x] = max_iter return iterationsdef plot_mandelbrot( output_path=\"mandelbrot.png\", width=800, height=600, x_min=-2.0, x_max=1.0, y_min=-1.5, y_max=1.5, max_iter=100,): \"\"\"绘制Mandelbrot集合\"\"\" # 计算Mandelbrot集合 iterations = compute_mandelbrot(width, height, x_min, x_max, y_min, y_max, max_iter) # 创建自定义颜色映射 colors = [ (0, 0, 0), (0.1, 0.1, 0.3), (0.2, 0.2, 0.6), (0.4, 0.4, 0.8), (0.6, 0.6, 1.0), (0.8, 0.8, 1.0), (1.0, 1.0, 1.0), ] cmap = LinearSegmentedColormap.from_list(\"mandelbrot_cmap\", colors, N=max_iter) # 绘制图像 plt.figure(figsize=(10, 8), dpi=100) plt.imshow( iterations, cmap=cmap, extent=[x_min, x_max, y_min, y_max], interpolation=\"bilinear\", ) plt.colorbar(label=\"迭代次数\") plt.title(\"Mandelbrot集合\", fontsize=16) plt.xlabel(\"实部\", fontsize=12) plt.ylabel(\"虚部\", fontsize=12) plt.savefig(output_path, bbox_inches=\"tight\") plt.close() print(f\"Mandelbrot集合图已保存至: {output_path}\")def visualize_dijkstra( G, source, target, output_path=\"dijkstra_animation.gif\", node_size=500): \"\"\" Dijkstra算法最短路径动态演示 参数: G: 网络图 source: 起点 target: 终点 output_path: 输出文件路径 node_size: 节点大小,默认为500 \"\"\" # 初始化 dist = {node: float(\"infinity\") for node in G.nodes} dist[source] = 0 previous = {node: None for node in G.nodes} visited = set() # 使用优先队列 queue = PriorityQueue() queue.put((0, source)) # 节点位置 - 使用更适合密集网络的布局算法 pos = nx.spring_layout( G, seed=42, k=0.8 / np.sqrt(len(G.nodes)) ) # 调整k值增加节点间距 # 创建图形 fig, ax = plt.subplots(figsize=(12, 10), dpi=150) # 增加图形尺寸 # 颜色映射 cmap = ListedColormap([\"lightgray\", \"yellow\", \"green\", \"red\"]) # 初始绘图 node_colors = {node: \"lightgray\" for node in G.nodes} node_colors[source] = \"yellow\" # 绘制节点和边 nodes = nx.draw_networkx_nodes( G, pos, node_color=list(node_colors.values()), node_size=node_size, alpha=0.8, ax=ax, ) edges = nx.draw_networkx_edges(G, pos, edge_color=\"gray\", alpha=0.5, ax=ax) labels = nx.draw_networkx_labels(G, pos, font_size=9, ax=ax) # 初始化距离标签 - 优化显示位置 dist_labels = {} for node in G.nodes: x, y = pos[node] # 根据节点周围空间调整标签位置 label_x = x + 0.05 if x < 0.5 else x - 0.05 label_y = y + 0.05 if y < 0.5 else y - 0.05 dist_labels[node] = ax.text( label_x, label_y, f\"d={dist[node]}\" if dist[node] != float(\"inf\") else \"\", ha=\"center\", va=\"center\", fontsize=8, bbox=dict(facecolor=\"white\", alpha=0.7, boxstyle=\"round,pad=0.1\"), ) ax.set_title(\"Dijkstra算法: 寻找最短路径\", fontsize=16) ax.set_axis_off() # 收集帧数据 frames = [] frames.append( {\"node_colors\": node_colors.copy(), \"dist\": dist.copy(), \"edge_colors\": None} ) # Dijkstra算法执行过程 while not queue.empty(): current_dist, current_node = queue.get() if current_node in visited: continue visited.add(current_node) node_colors[current_node] = \"green\" if current_node == target: break for neighbor in G.neighbors(current_node): if neighbor in visited: continue weight = G.edges[current_node, neighbor].get(\"weight\", 1) new_dist = current_dist + weight if new_dist < dist[neighbor]: dist[neighbor] = new_dist previous[neighbor] = current_node queue.put((new_dist, neighbor)) node_colors[neighbor] = \"yellow\" frames.append( { \"node_colors\": node_colors.copy(), \"dist\": dist.copy(), \"edge_colors\": None, } ) # 重建路径 path = [] current = target while current is not None: path.append(current) current = previous[current] path.reverse() # 添加路径高亮帧 for i in range(1, len(path) + 1): path_segment = path[:i] path_colors = node_colors.copy() for node in path_segment: path_colors[node] = \"red\" edge_colors = [ ( \"red\" if ( u in path_segment and v in path_segment and abs(path_segment.index(u) - path_segment.index(v)) == 1 ) else \"gray\" ) for u, v in G.edges ] frames.append( { \"node_colors\": path_colors, \"dist\": dist.copy(), \"edge_colors\": edge_colors, } ) # 动画更新函数 def update(frame_idx): ax.clear() frame = frames[frame_idx] # 绘制节点和边 node_colors_frame = frame[\"node_colors\"] nodes = nx.draw_networkx_nodes( G, pos, node_color=list(node_colors_frame.values()), node_size=node_size, alpha=0.8, ax=ax, ) edge_colors = frame[\"edge_colors\"] or \"gray\" edges = nx.draw_networkx_edges(G, pos, edge_color=edge_colors, alpha=0.5, ax=ax) labels = nx.draw_networkx_labels(G, pos, font_size=9, ax=ax) # 更新距离标签 - 只显示有限值 for node in G.nodes: dist_val = frame[\"dist\"].get(node, float(\"inf\")) if dist_val != float(\"inf\"): # 只显示有限距离值 dist_labels[node].set_text(f\"d={dist_val}\") ax.add_artist(dist_labels[node]) else: dist_labels[node].set_text(\"\") # 隐藏无限大值 # 设置标题 status = f\"当前节点: {list(G.nodes)[frame_idx % len(G.nodes)]}\" ax.set_title(f\"Dijkstra算法: {status}\", fontsize=16) ax.set_axis_off() return ax.get_children() # 创建动画 anim = animation.FuncAnimation( fig, update, frames=len(frames), interval=1000, blit=False ) # 保存GIF anim.save(output_path, writer=\"pillow\", fps=1) plt.close() print(f\"最短路径动画已保存至: {output_path}\") return path, dist[target]def metabolic_pathway_network(output_path=\"metabolic_network.png\"): \"\"\"构建并可视化代谢通路网络\"\"\" # 创建代谢网络 G = nx.DiGraph() # 添加代谢物节点 metabolites = { \"Glucose\": {\"type\": \"substrate\", \"color\": \"skyblue\"}, \"Glucose-6P\": {\"type\": \"intermediate\", \"color\": \"lightgreen\"}, \"Fructose-6P\": {\"type\": \"intermediate\", \"color\": \"lightgreen\"}, \"Fructose-1,6BP\": {\"type\": \"intermediate\", \"color\": \"lightgreen\"}, \"GAP\": {\"type\": \"intermediate\", \"color\": \"lightgreen\"}, \"DHAP\": {\"type\": \"intermediate\", \"color\": \"lightgreen\"}, \"1,3-BPG\": {\"type\": \"intermediate\", \"color\": \"lightgreen\"}, \"3PG\": {\"type\": \"intermediate\", \"color\": \"lightgreen\"}, \"2PG\": {\"type\": \"intermediate\", \"color\": \"lightgreen\"}, \"PEP\": {\"type\": \"intermediate\", \"color\": \"lightgreen\"}, \"Pyruvate\": {\"type\": \"product\", \"color\": \"salmon\"}, \"ATP\": {\"type\": \"cofactor\", \"color\": \"gold\"}, \"ADP\": {\"type\": \"cofactor\", \"color\": \"gold\"}, \"NAD+\": {\"type\": \"cofactor\", \"color\": \"violet\"}, \"NADH\": {\"type\": \"cofactor\", \"color\": \"violet\"}, \"Pi\": {\"type\": \"cofactor\", \"color\": \"lightgray\"}, \"H2O\": {\"type\": \"cofactor\", \"color\": \"lightblue\"}, } for met, attrs in metabolites.items(): G.add_node(met, **attrs) # 添加反应边 reactions = [ # 糖酵解途径 { \"substrates\": [\"Glucose\", \"ATP\"], \"products\": [\"Glucose-6P\", \"ADP\"], \"enzyme\": \"Hexokinase\", }, { \"substrates\": [\"Glucose-6P\"], \"products\": [\"Fructose-6P\"], \"enzyme\": \"Phosphoglucoisomerase\", }, { \"substrates\": [\"Fructose-6P\", \"ATP\"], \"products\": [\"Fructose-1,6BP\", \"ADP\"], \"enzyme\": \"Phosphofructokinase\", }, { \"substrates\": [\"Fructose-1,6BP\"], \"products\": [\"GAP\", \"DHAP\"], \"enzyme\": \"Aldolase\", }, { \"substrates\": [\"DHAP\"], \"products\": [\"GAP\"], \"enzyme\": \"Triose phosphate isomerase\", }, { \"substrates\": [\"GAP\", \"Pi\", \"NAD+\"], \"products\": [\"1,3-BPG\", \"NADH\", \"H+\"], \"enzyme\": \"Glyceraldehyde-3-P dehydrogenase\", }, { \"substrates\": [\"1,3-BPG\", \"ADP\"], \"products\": [\"3PG\", \"ATP\"], \"enzyme\": \"Phosphoglycerate kinase\", }, { \"substrates\": [\"3PG\"], \"products\": [\"2PG\"], \"enzyme\": \"Phosphoglycerate mutase\", }, {\"substrates\": [\"2PG\"], \"products\": [\"PEP\", \"H2O\"], \"enzyme\": \"Enolase\"}, { \"substrates\": [\"PEP\", \"ADP\"], \"products\": [\"Pyruvate\", \"ATP\"], \"enzyme\": \"Pyruvate kinase\", }, ] # 添加边 for rxn in reactions: enzyme = rxn[\"enzyme\"] # 确保酶节点有type属性 G.add_node(enzyme, type=\"enzyme\", color=\"orange\") # 底物到酶 for sub in rxn[\"substrates\"]: G.add_edge(sub, enzyme, weight=1, label=\"consumed_by\") # 酶到产物 for prod in rxn[\"products\"]: G.add_edge(enzyme, prod, weight=1, label=\"produced_by\") # 设置布局 pos = nx.spring_layout(G, seed=42, k=0.5) # 创建图像 plt.figure(figsize=(16, 12), dpi=150) # 按类型绘制节点 # 先获取所有节点的type属性,确保不包含None node_types = set() for _, attrs in G.nodes(data=True): if \"type\" in attrs: node_types.add(attrs[\"type\"]) type_colors = { \"substrate\": \"skyblue\", \"intermediate\": \"lightgreen\", \"product\": \"salmon\", \"cofactor\": \"gold\", \"enzyme\": \"orange\", } for node_type in node_types: # 使用get方法获取type属性,默认为None nodes = [n for n, attrs in G.nodes(data=True) if attrs.get(\"type\") == node_type] if nodes: # 确保有节点属于该类型 nx.draw_networkx_nodes( G, pos, nodelist=nodes, node_color=type_colors.get(node_type, \"gray\"), # 默认灰色 node_size=1500, alpha=0.8, label=node_type.capitalize(), ) # 绘制边 nx.draw_networkx_edges(G, pos, width=1.5, alpha=0.6, edge_color=\"gray\") # 绘制节点标签 nx.draw_networkx_labels(G, pos, font_size=10, font_weight=\"bold\") # 绘制酶反应标签 enzyme_edges = [ e for e in G.edges if G.nodes[e[0]].get(\"type\") == \"enzyme\" or G.nodes[e[1]].get(\"type\") == \"enzyme\" ] enzyme_labels = { (u, v): G.nodes[u].get(\"type\") == \"enzyme\" and G.nodes[v].get(\"type\") != \"enzyme\" for u, v in enzyme_edges } # 添加图例 plt.legend(loc=\"upper right\", title=\"节点类型\", fontsize=12) # 设置标题 plt.title(\"糖酵解代谢通路网络\", fontsize=20, pad=20) plt.axis(\"off\") # 添加代谢通路说明 plt.text( 0.05, 0.05, \"糖酵解关键步骤:\\n\" \"1. 葡萄糖磷酸化\\n\" \"2. 果糖-6-磷酸生成\\n\" \"3. 果糖-1,6-二磷酸生成\\n\" \"4. 甘油醛-3-磷酸生成\\n\" \"5. 1,3-二磷酸甘油酸生成\\n\" \"6. 3-磷酸甘油酸生成\\n\" \"7. 2-磷酸甘油酸生成\\n\" \"8. 磷酸烯醇式丙酮酸生成\\n\" \"9. 丙酮酸生成\", transform=plt.gca().transAxes, fontsize=12, bbox=dict(facecolor=\"white\", alpha=0.8), ) # 添加生物学意义 plt.text( 0.7, 0.05, \"生物学意义:\\n\" \"* 能量产生: 净生成2 ATP\\n\" \"* 前体提供: 为其他通路提供中间产物\\n\" \"* 氧化还原: 产生2 NADH\", transform=plt.gca().transAxes, fontsize=12, bbox=dict(facecolor=\"white\", alpha=0.8), ) plt.savefig(output_path, bbox_inches=\"tight\") plt.close() print(f\"代谢通路网络图已保存至: {output_path}\") return Gdef analyze_metabolic_network(G, source=\"Glucose\", target=\"Pyruvate\"): \"\"\"分析代谢网络的关键路径\"\"\" # 计算最短路径 path, length = visualize_dijkstra( G, source, target, output_path=\"metabolic_pathway_animation.gif\" ) print(f\"从 {source} 到 {target} 的最短路径:\") print(\" -> \".join(path)) print(f\"路径长度: {length}\") # 计算中心性 betweenness = nx.betweenness_centrality(G) top_nodes = sorted(betweenness.items(), key=lambda x: x[1], reverse=True)[:5] print(\"\\n介数中心性最高的节点:\") for node, score in top_nodes: print(f\"{node}: {score:.4f}\") # 关键酶分析 - 安全获取酶节点 enzymes = [n for n, attrs in G.nodes(data=True) if attrs.get(\"type\") == \"enzyme\"] if not enzymes: print(\"\\n未找到酶节点!\") return enzyme_degrees = {e: G.degree(e) for e in enzymes} top_enzymes = sorted(enzyme_degrees.items(), key=lambda x: x[1], reverse=True)[:3] print(\"\\n连接度最高的酶:\") for enzyme, degree in top_enzymes: print(f\"{enzyme}: 连接{degree}个代谢物\")if __name__ == \"__main__\": # 1. 图论基本元素 plot_graph_elements(output_path=\"graph_elements.png\") # 2. 网络类型可视化 plot_network_types(output_path=\"network_types.png\") # 3. 中心性度量 G_example = nx.karate_club_graph() plot_centrality_measures(G_example, output_path=\"centrality_measures.png\") # 4. 最短路径演示 # 创建带权图 G_weighted = nx.Graph() G_weighted.add_edges_from( [ (\"A\", \"B\", {\"weight\": 4}), (\"A\", \"C\", {\"weight\": 2}), (\"B\", \"D\", {\"weight\": 5}), (\"C\", \"D\", {\"weight\": 1}), (\"C\", \"E\", {\"weight\": 3}), (\"D\", \"F\", {\"weight\": 2}), (\"E\", \"F\", {\"weight\": 6}), ] ) visualize_dijkstra(G_weighted, \"A\", \"F\", output_path=\"dijkstra_animation.gif\") # 5. 代谢通路网络 metabolic_G = metabolic_pathway_network(output_path=\"metabolic_network.png\") analyze_metabolic_network(metabolic_G, source=\"Glucose\", target=\"Pyruvate\")