好代码与坏代码:代码整洁之道 #P009#

本文探讨了为何提高代码质量至关重要,强调了科学训练而非简单重复的重要性。文章介绍了写出高质量代码的方法论,包括遵循Pythonic原则,以及命名、函数编写等方面的技巧。此外,还讨论了Python中循环后面的else语句设计的争议,认为在try...except语句中的else设计更为合理。

在这一篇文章中,我们来讨论一些更加形而上的知识,即什么是好代码、什么是坏代码,如何写出好代码。在本系列文章的第一篇中,笔者解释了什么是Pythonic,并且认为Pythonic是一些正确的废话,然后给读者推荐了《重构》和《代码整洁之道》。《重构》和《代码整洁之道》都是使用Java语言作为思想的载体,为了节省读者的时间,并且强调一些Python语言的特性,所以有了读者现在正在看的这篇文章。

在这篇文章中,首先会介绍为什么要努力写出高质量的代码;随后,在第2节中回顾写出高质量代码的方法论;第3节是本篇文章的重点,里面包含了部分代码技巧;在第4节中,会讨论一个Python中颇具争议的语法,并给出笔者自己的观点和解释。

1 为什么要努力提高代码质量

怎样成为编程高手呢?或者换个说法,怎样才能成为某个领域的顶尖高手呢?很多人都会搬出一万小时定律。但是,一万小时定律有一个很关键的地方经常被大家忽略,即一万小时并不是简单的重复一万个小时,而是科学地训练一万个小时。没有科学的训练方法,重复再多时间都是徒劳,是在相同的专业层次上浪费时间。所以说,练习的关键根本不是训练的时长,而是训练的方法。

将练习的关键不是训练时长而是训练方法引申到编程领域,成为编程高手的前提并不是你写了多少行代码,花了多少时间进行编程,而是你科学训练的时间。遗憾的是,现在大学计算机课程并没有一门课讲授如何科学的进行编程。更通俗一点说,现在大学的课程只会教如何写代码,并不会教如何写好代码。计算机科班的同学都不会强调如何写好代码,更何况大量跨专业到互联网的同学,可能根本就没有意识这些问题。这或许就是为什么中国有无数的IT工程师,而各大公司依然难以招到合适的人的原因。

作为工程师,努力提高代码质量有无数的理由:

  1. 高质量代码的系统,其健壮性、可读性和可维护性更强
  2. 开发的系统生命更持久,作为工程师,我们的工作价值更大
  3. 对于一个大型系统,工程师大部分时间是在读代码,小部分时间是在写代码,将代码写得更加可读,有利于提高自己的阅读感受和工作效率
  4. 给以后维护你代码的人留下一个好印象

越是优秀的公司越是强调代码质量,越是希望求职者能够写出高质量的代码。笔者之前在微博上看到一位微软的工程师招聘,招聘描述里明确写着读过《代码整洁之道》的优先。其实《代码整洁之道》这本书并不是重点,重点是面试官希望求职者能够对自己有更高的要求,能够对自己写的代码负责。

唠叨了这么说,笔者仅仅是希望本系列文章的读者,都能够对自己有更高的要求,能够努力写出更加简洁优美、可读性强、可维护性强的高质量代码。

2 方法论

在本系列文章的第一篇中,笔者已经传授了Pythonic的方法论。即像写书、写报纸和写文章一样来写代码,减少容易误会的地方。再来回顾一下笔者提出的方法论:

* 像写报纸一样写代码
  
import numpy as np import matplotlib.pyplot as plt import networkx as nx from matplotlib.gridspec import GridSpec from matplotlib.patches import FancyBboxPatch, Circle import matplotlib.patheffects as pe import pandas as pd # 全局样式配置(专业学术风格) plt.rcParams.update({ "font.family": ["Times New Roman", "SimHei"], # 英文用Times New Roman,中文用黑体 "font.size": 10, "axes.unicode_minus": False, "figure.dpi": 300, "axes.linewidth": 0.8, # 坐标轴线条宽度 "grid.linewidth": 0.4, # 网格线宽度 "legend.frameon": True, "legend.framealpha": 0.9, "legend.edgecolor": "white", "legend.fancybox": True }) # 专业配色方案(符合学术图表规范,区分度高) COLORS = { "A_source": "#2E86AB", # 深蓝色(A突水点及水流) "B_source": "#A23B72", # 深紫红色(B突水点及水流) "confluence": "#F18F01", # 橙色(双源合流) "full": "#C73E1D", # 深红色(已充满) "unreached": "#8A9BA8", # 浅灰色(未到达) "background": "#F8F9FA", # 浅灰背景 "grid": "#E9ECEF", # 网格色 "text": "#2D3436" # 文字色 } class MineDoubleSourceVisualizerEnhanced: def __init__(self): # 1. 构建结构化巷网络(避免随机杂乱,保证可视化清晰) self.nodes = self._generate_structured_nodes() # 结构化化节点(分区域布局) self.edges = self._generate_logical_edges() # 逻辑化巷(保证传播路径清晰) self.G = self._build_directed_graph() # 有向图(体现现水流方向) # 2. 模型核心参数(问题三一致) self.params = { "A": {"id": "P001", "trigger": 0, "pos": self.nodes["P001"]}, # 突水点A(t=0) "B": {"id": "P010", "trigger": 4, "pos": self.nodes["P010"]}, # 突水点B(t=4) "confluence": {"id": "P006", "pos": self.nodes["P006"]}, # 合流节点C "flow_rate": 30, # 单源涌水量(m³/min) "velocity": 75, # 水流速度(m/min,基于30m³/min流量计算) "width": 4, #宽度(m) "height": 3, #高度(m) "key_times": [0, 4, 7, 10, 15] # 关键时间点(覆盖全流程) } # 3. 预计算水流传播数据(确保可视化逻辑准确) self.propagation_data = self._simulate_propagation() self.confluence_analysis = self._analyze_confluence_effect() def _generate_structured_nodes(self): """生成结构化节点(分A区、B区、合流区,避免杂乱)""" nodes = {} # A突水点周边节点(左上区域) nodes["P001"] = (20, 80, 15.0) # A突水点(Z=15m,最高高程) nodes["P002"] = (10, 70, 14.5) # A下游1(水平) nodes["P003"] = (30, 70, 14.5) # A下游2(水平) nodes["P004"] = (20, 60, 14.0) # A下游3(下行) nodes["P005"] = (10, 50, 13.5) # A下游4(下行) # 合流节点及周边(中间区域) nodes["P006"] = (50, 50, 13.0) # 合流节点C(Z=13m) nodes["P007"] = (40, 60, 13.5) # 连接A区合流区 nodes["P008"] = (60, 60, 13.5) # 合流区下游1 nodes["P009"] = (50, 40, 12.5) # 合流区下游2(下行) # B突水点周边节点(右上区域) nodes["P010"] = (80, 80, 14.0) # B突水点(Z=14m) nodes["P011"] = (70, 70, 13.8) # B下游1(水平) nodes["P012"] = (90, 70, 13.8) # B下游2(水平) nodes["P013"] = (80, 60, 13.5) # B下游3(下行) nodes["P014"] = (70, 50, 13.2) # B下游4(下行,连接合流区) nodes["P015"] = (90, 50, 13.2) # B下游5(下行) # 其他补充节点(保证网络完整性) nodes["P016"] = (30, 40, 12.8) # 连接A区合流区下游 nodes["P017"] = (70, 40, 12.3) # 连接B区合流区下游 nodes["P018"] = (50, 30, 12.0) # 最终下游节点 nodes["P019"] = (30, 20, 11.5) # 最终下游节点2 nodes["P020"] = (70, 20, 11.5) # 最终下游节点3 return nodes def _generate_logical_edges(self): """生成逻辑化巷(保证水流方向清晰,避免交叉)""" edges = [ # A突水点传播路径 ("P001", "P002", {"length": 14.14}), # 斜向(10√2≈14.14m) ("P001", "P003", {"length": 14.14}), ("P001", "P004", {"length": 20.0}), # 垂直下行(20m) ("P004", "P005", {"length": 14.14}), ("P005", "P007", {"length": 36.06}), # 连接A区合流区 ("P007", "P006", {"length": 14.14}), # 到合流节点C # B突水点传播路径 ("P010", "P011", {"length": 14.14}), ("P010", "P012", {"length": 14.14}), ("P010", "P013", {"length": 20.0}), ("P013", "P014", {"length": 14.14}), ("P014", "P006", {"length": 28.28}), # 连接B区合流节点C ("P013", "P015", {"length": 14.14}), # 合流后传播路径 ("P006", "P008", {"length": 14.14}), ("P006", "P009", {"length": 20.0}), ("P009", "P018", {"length": 20.0}), ("P008", "P017", {"length": 14.14}), ("P017", "P020", {"length": 28.28}), ("P009", "P016", {"length": 28.28}), ("P016", "P019", {"length": 20.0}) ] return edges def _build_directed_graph(self): """构建有向图(体现水流方向,仅水平/下行)""" G = nx.DiGraph() for u, v, attr in self.edges: G.add_edge(u, v, length=attr["length"]) return G def _simulate_propagation(self): """模拟水流传播(精准计算到达/充满时间,含合流效应)""" # 初始化数据结构 data = { "nodes": {n: {"arrival": np.inf, "source": None} for n in self.nodes}, "edges": {f"{u}-{v}": {"arrival": np.inf, "full": np.inf, "source": None} for u, v, _ in self.edges} } # 突水点初始化 data["nodes"][self.params["A"]["id"]]["arrival"] = self.params["A"]["trigger"] data["nodes"][self.params["A"]["id"]]["source"] = "A" data["nodes"][self.params["B"]["id"]]["arrival"] = self.params["B"]["trigger"] data["nodes"][self.params["B"]["id"]]["source"] = "B" # 模拟传播过程(时间步长0.1分钟,保证精度) for t in np.arange(0, 20.1, 0.1): # 遍历所有节点,更新下游传播 for node in self.nodes: if abs(data["nodes"][node]["arrival"] - t) < 0.01: # 当前时间到达的节点 for neighbor in self.G.successors(node): edge_id = f"{node}-{neighbor}" if edge_id not in data["edges"]: continue # 计算传播时间(长度/速度) edge_len = self.G[node][neighbor]["length"] travel_time = edge_len / self.params["velocity"] arrival_t = t + travel_time # 更新边状态 if data["edges"][edge_id]["arrival"] > arrival_t: # 计算充满时间(容积/流量) volume = edge_len * self.params["width"] * self.params["height"] flow_rate = self.params["flow_rate"] full_t = arrival_t + (volume / flow_rate) data["edges"][edge_id]["arrival"] = arrival_t data["edges"][edge_id]["full"] = full_t data["edges"][edge_id]["source"] = data["nodes"][node]["source"] # 更新节点状态 if data["nodes"][neighbor]["arrival"] > arrival_t: data["nodes"][neighbor]["arrival"] = arrival_t data["nodes"][neighbor]["source"] = data["nodes"][node]["source"] elif data["nodes"][neighbor]["source"] != data["nodes"][node]["source"]: # 合流:节点标记为"both" data["nodes"][neighbor]["source"] = "both" # 合流后流量翻倍,重新计算充满时间 edge_id = f"{node}-{neighbor}" if edge_id in data["edges"]: edge_len = self.G[node][neighbor]["length"] volume = edge_len * self.params["width"] * self.params["height"] data["edges"][edge_id]["full"] = arrival_t + (volume / (2 * self.params["flow_rate"])) data["edges"][edge_id]["source"] = "both" return data def _analyze_confluence_effect(self): """分析合流效应(量化对比数据)""" confluence_node = self.params["confluence"]["id"] # 选取合流前后的关键巷 key_edges = { "A→C": "P007-P006", # A到合流点 "B→C": "P014-P006", # B到合流点 "C→D1": "P006-P008", # 合流后下游1 "C→D2": "P006-P009" # 合流后下游2 } analysis = {"node": confluence_node, "edges": {}} for name, edge_id in key_edges.items(): u, v = edge_id.split("-") edge_len = self.G[u][v]["length"] volume = edge_len * self.params["width"] * self.params["height"] # 单源充满时间(30m³/min) time_single = volume / self.params["flow_rate"] # 合流充满时间(60m³/min) time_confluence = volume / (2 * self.params["flow_rate"]) analysis["edges"][name] = { "length": edge_len, "volume": volume, "time_single": time_single, "time_confluence": time_confluence, "reduction": time_single - time_confluence, "arrival_A": self.propagation_data["edges"][edge_id]["arrival"] if "A" in name else np.inf, "arrival_B": self.propagation_data["edges"][edge_id]["arrival"] if "B" in name else np.inf } return analysis def _get_edge_style(self, edge_id, current_time): """获取巷样式(颜色、线型、宽度)""" edge_data = self.propagation_data["edges"][edge_id] # 未到达 if edge_data["arrival"] > current_time: return { "color": COLORS["unreached"], "linewidth": 1.5, "linestyle": "-.", "zorder": 1 } # 已充满 elif edge_data["full"] <= current_time: return { "color": COLORS["full"], "linewidth": 2.0, "linestyle": "-", "zorder": 3 # 提高层级让白色边框可见 } # A源水流 elif edge_data["source"] == "A": return { "color": COLORS["A_source"], "linewidth": 2.0, "linestyle": "-", "zorder": 2 } # B源水流 elif edge_data["source"] == "B": return { "color": COLORS["B_source"], "linewidth": 2.0, "linestyle": "-", "zorder": 2 } # 双源合流 else: return { "color": COLORS["confluence"], "linewidth": 2.5, "linestyle": "-", "zorder": 4 # 最高层级突出合流效果 } def _get_node_style(self, node_id, current_time): """获取节点样式(颜色、大小、标注)""" node_data = self.propagation_data["nodes"][node_id] # 突水点 if node_id == self.params["A"]["id"]: return { "color": COLORS["A_source"], "size": 120, "label": "A", "edgecolor": "white", "linewidth": 2 } elif node_id == self.params["B"]["id"]: return { "color": COLORS["B_source"], "size": 120, "label": "B", "edgecolor": "white", "linewidth": 2 } # 合流节点 elif node_id == self.params["confluence"]["id"]: return { "color": COLORS["confluence"], "size": 120, "label": "C", "edgecolor": "white", "linewidth": 2 } # 普通节点 if node_data["arrival"] > current_time: return { "color": "white", "size": 50, "label": None, "edgecolor": COLORS["unreached"], "linewidth": 1 } elif node_data["source"] == "A": return { "color": COLORS["A_source"], "size": 60, "label": None, "edgecolor": "white", "linewidth": 1 } elif node_data["source"] == "B": return { "color": COLORS["B_source"], "size": 60, "label": None, "edgecolor": "white", "linewidth": 1 } else: # 合流节点 return { "color": COLORS["confluence"], "size": 70, "label": None, "edgecolor": "white", "linewidth": 1 } def plot_propagation_stages(self): """绘制多阶段水流传播图(核心可视化)""" fig = plt.figure(figsize=(16, 12)) fig.patch.set_facecolor(COLORS["background"]) gs = GridSpec(2, 3, figure=fig, wspace=0.2, hspace=0.3) # 绘制关键时间点的传播图 for i, time in enumerate(self.params["key_times"]): ax = fig.add_subplot(gs[i // 3, i % 3]) ax.set_facecolor(COLORS["background"]) ax.grid(True, color=COLORS["grid"], linestyle="-") # 获取2D坐标(忽略Z轴) pos_2d = {n: (self.nodes[n][0], self.nodes[n][1]) for n in self.nodes} # 绘制巷(边)- 分两层绘制以实现"描边"效果 for u, v, _ in self.edges: edge_id = f"{u}-{v}" style = self._get_edge_style(edge_id, time) # 对于需要突出的边(已充满和合流),先绘制白色粗边作为"描边" if style["color"] in [COLORS["full"], COLORS["confluence"]]: nx.draw_networkx_edges( self.G, pos_2d, edgelist=[(u, v)], ax=ax, edge_color="white", width=style["linewidth"] + 1.5, style=style["linestyle"], zorder=style["zorder"] - 0.5 ) # 绘制实际边 nx.draw_networkx_edges( self.G, pos_2d, edgelist=[(u, v)], ax=ax, edge_color=style["color"], width=style["linewidth"], style=style["linestyle"], zorder=style["zorder"] ) # 绘制节点 for node in self.nodes: style = self._get_node_style(node, time) nx.draw_networkx_nodes( self.G, pos_2d, nodelist=[node], ax=ax, node_color=style["color"], node_size=style["size"], edgecolors=style["edgecolor"], linewidths=style["linewidth"], zorder=5 # 节点在最上层 ) # 添加节点标签(仅关键节点) if style["label"]: nx.draw_networkx_labels( self.G, pos_2d, labels={node: style["label"]}, ax=ax, font_size=10, font_weight="bold", font_color="white", path_effects=[pe.Stroke(linewidth=1.5, foreground="black"), pe.Normal()], zorder=6 ) # 添加标题和坐标轴 ax.set_title(f"t = {time} 分钟", fontsize=12, pad=10, color=COLORS["text"]) ax.set_xlabel("X坐标 (m)", fontsize=9) ax.set_ylabel("Y坐标 (m)", fontsize=9) ax.set_xlim(0, 100) ax.set_ylim(10, 90) ax.tick_params(axis="both", which="major", labelsize=8) # 添加统一图例(右侧) legend_ax = fig.add_subplot(gs[:, 2]) legend_ax.set_facecolor(COLORS["background"]) legend_ax.axis("off") # 图例元素 legend_items = [ plt.Line2D([0], [0], color=COLORS["A_source"], lw=2, label="A源水流"), plt.Line2D([0], [0], color=COLORS["B_source"], lw=2, label="B源水流"), plt.Line2D([0], [0], color=COLORS["confluence"], lw=2.5, label="双源合流"), plt.Line2D([0], [0], color=COLORS["full"], lw=2, label="已充满巷"), plt.Line2D([0], [0], color=COLORS["unreached"], lw=1.5, linestyle="-.", label="未到达巷"), Circle((0, 0), 0.5, color=COLORS["A_source"], ec="white", lw=2, label="突水点A"), Circle((0, 0), 0.5, color=COLORS["B_source"], ec="white", lw=2, label="突水点B"), Circle((0, 0), 0.5, color=COLORS["confluence"], ec="white", lw=2, label="合流点C") ] # 绘制图例 legend_ax.legend( handles=legend_items, loc="center left", fontsize=10, frameon=True, framealpha=0.9, edgecolor="white", facecolor="white" ) # 添加主标题 fig.suptitle("双突水点水流蔓延过程可视化", fontsize=16, y=0.95, color=COLORS["text"]) plt.tight_layout() plt.savefig("双突水点水流蔓延过程.png", bbox_inches="tight") plt.show() def plot_confluence_comparison(self): """绘制合流效应对比图(突出模型核心差异)""" fig = plt.figure(figsize=(12, 6)) fig.patch.set_facecolor(COLORS["background"]) gs = GridSpec(1, 2, figure=fig, wspace=0.3) # 1. 充满时间对比柱状图 ax1 = fig.add_subplot(gs[0, 0]) ax1.set_facecolor(COLORS["background"]) ax1.grid(True, axis="y", color=COLORS["grid"]) # 准备数据 edges = list(self.confluence_analysis["edges"].keys()) time_single = [self.confluence_analysis["edges"][e]["time_single"] for e in edges] time_confluence = [self.confluence_analysis["edges"][e]["time_confluence"] for e in edges] x = np.arange(len(edges)) width = 0.35 # 绘制柱状图 bars1 = ax1.bar(x - width / 2, time_single, width, label="单源(30m³/min)", color=COLORS["A_source"], edgecolor="white", linewidth=0.8) bars2 = ax1.bar(x + width / 2, time_confluence, width, label="双源合流(60m³/min)", color=COLORS["confluence"], edgecolor="white", linewidth=0.8) # 添加数据标签 for bar in bars1: height = bar.get_height() ax1.text(bar.get_x() + bar.get_width() / 2., height + 0.1, f"{height:.1f}min", ha="center", va="bottom", fontsize=8) for bar in bars2: height = bar.get_height() ax1.text(bar.get_x() + bar.get_width() / 2., height + 0.1, f"{height:.1f}min", ha="center", va="bottom", fontsize=8) # 设置坐标轴 ax1.set_title("合流前后巷充满时间对比", fontsize=12, pad=10) ax1.set_xlabel("关键巷", fontsize=10) ax1.set_ylabel("充满时间(分钟)", fontsize=10) ax1.set_xticks(x) ax1.set_xticklabels(edges, fontsize=9) ax1.legend(loc="upper left", fontsize=9) ax1.set_ylim(0, max(time_single) * 1.2) # 2. 流量分配示意图 ax2 = fig.add_subplot(gs[0, 1]) ax2.set_facecolor(COLORS["background"]) ax2.axis("off") ax2.set_xlim(0, 10) ax2.set_ylim(0, 8) # 绘制流量分配图 # 标题 ax2.text(5, 7.5, "合流节点流量分配机制", ha="center", fontsize=12, fontweight="bold") # 流入箭头(A源) ax2.arrow(3, 6, 0, -1.5, width=0.2, head_width=0.5, head_length=0.3, fc=COLORS["A_source"], ec=COLORS["A_source"]) ax2.text(2.5, 6.5, "A源: 30m³/min", rotation=90, va="bottom", fontsize=10) # 流入箭头(B源) ax2.arrow(7, 6, 0, -1.5, width=0.2, head_width=0.5, head_length=0.3, fc=COLORS["B_source"], ec=COLORS["B_source"]) ax2.text(7.5, 6.5, "B源: 30m³/min", rotation=90, va="bottom", fontsize=10) # 合流节点 ax2.add_patch(Circle((5, 4), 0.8, color=COLORS["confluence"], ec="white", lw=2)) ax2.text(5, 4, "合流节点C", ha="center", va="center", fontsize=10, fontweight="bold", color="white") # 流出箭头1 ax2.arrow(3, 2.5, 0, -1.5, width=0.2, head_width=0.5, head_length=0.3, fc=COLORS["confluence"], ec=COLORS["confluence"]) ax2.text(2.5, 2.0, "分流1: 30m³/min", rotation=90, va="top", fontsize=10) # 流出箭头2 ax2.arrow(7, 2.5, 0, -1.5, width=0.2, head_width=0.5, head_length=0.3, fc=COLORS["confluence"], ec=COLORS["confluence"]) ax2.text(7.5, 2.0, "分流2: 30m³/min", rotation=90, va="top", fontsize=10) # 中间说明 ax2.text(5, 3.2, "总流量: 60m³/min", ha="center", fontsize=10, fontstyle="italic") plt.tight_layout() plt.savefig("合流效应对比流量分配.png", bbox_inches="tight") plt.show() def plot_timeline_analysis(self): """绘制时间轴分析图(展示全流程特征)""" fig = plt.figure(figsize=(14, 8)) fig.patch.set_facecolor(COLORS["background"]) ax = fig.add_subplot(111) ax.set_facecolor(COLORS["background"]) ax.grid(True, color=COLORS["grid"], linestyle="-") # 提取数据并排序 edges = list(self.propagation_data["edges"].keys()) # 按到达时间排序 sorted_edges = sorted(edges, key=lambda x: self.propagation_data["edges"][x]["arrival"]) # 只取前15条关键巷(避免过于拥挤) plot_edges = sorted_edges[:15] # 绘制时间轴 for i, edge_id in enumerate(plot_edges): data = self.propagation_data["edges"][edge_id] # 确定颜色 if data["source"] == "A": color = COLORS["A_source"] elif data["source"] == "B": color = COLORS["B_source"] else: color = COLORS["confluence"] # 对于需要突出的线条,先绘制白色粗线作为"描边" if color in [COLORS["full"], COLORS["confluence"]]: ax.plot([data["arrival"], data["full"]], [i, i], color="white", linewidth=5, solid_capstyle="round", zorder=2) # 绘制时间线 ax.plot([data["arrival"], data["full"]], [i, i], color=color, linewidth=3, solid_capstyle="round", zorder=3) # 到达时刻标记 ax.scatter(data["arrival"], i, color=color, s=50, zorder=4, edgecolors="white", linewidths=0.8) # 充满时刻标记 ax.scatter(data["full"], i, color=color, s=50, marker="s", zorder=4, edgecolors="white", linewidths=0.8) # 添加关键时间标记线 # A突水点触发 ax.axvline(x=self.params["A"]["trigger"], color=COLORS["A_source"], linestyle="--", alpha=0.7, linewidth=1.5) ax.text(self.params["A"]["trigger"], len(plot_edges) - 0.5, f"A源触发: {self.params[&#39;A&#39;][&#39;trigger&#39;]}min", color=COLORS["A_source"], va="center", rotation=90, fontsize=9) # B突水点触发 ax.axvline(x=self.params["B"]["trigger"], color=COLORS["B_source"], linestyle="--", alpha=0.7, linewidth=1.5) ax.text(self.params["B"]["trigger"], len(plot_edges) - 1.5, f"B源触发: {self.params[&#39;B&#39;][&#39;trigger&#39;]}min", color=COLORS["B_source"], va="center", rotation=90, fontsize=9) # 合流开始时间(A源到达合流点时间) confluence_time = self.propagation_data["nodes"][self.params["confluence"]["id"]]["arrival"] ax.axvline(x=confluence_time, color=COLORS["confluence"], linestyle="--", alpha=0.7, linewidth=1.5) ax.text(confluence_time, len(plot_edges) - 2.5, f"开始合流: {confluence_time:.1f}min", color=COLORS["confluence"], va="center", rotation=90, fontsize=9) # 设置坐标轴 ax.set_title("巷水流到达充满时间轴", fontsize=12, pad=10) ax.set_xlabel("时间(分钟)", fontsize=10) ax.set_ylabel("巷(按水流到达顺序)", fontsize=10) ax.set_ylim(-1, len(plot_edges)) ax.set_yticks(range(len(plot_edges))) ax.set_yticklabels(plot_edges, fontsize=8) ax.set_xlim(-0.5, 16) ax.tick_params(axis="x", labelsize=9) # 添加图例 legend_items = [ plt.Line2D([0], [0], color=COLORS["A_source"], lw=2, label="A源水流"), plt.Line2D([0], [0], color=COLORS["B_source"], lw=2, label="B源水流"), plt.Line2D([0], [0], color=COLORS["confluence"], lw=2, label="双源合流"), plt.Line2D([0], [0], marker="o", color="w", markerfacecolor="black", markersize=6, label="到达时刻"), plt.Line2D([0], [0], marker="s", color="w", markerfacecolor="black", markersize=6, label="充满时刻") ] ax.legend(handles=legend_items, loc="upper right", fontsize=9) plt.tight_layout() plt.savefig("巷水流时间轴分析.png", bbox_inches="tight") plt.show() def generate_all_visualizations(self): """生成所有优化后的可视化图表""" print("生成水流蔓延过程可视化...") self.plot_propagation_stages() print("生成合流效应对比图...") self.plot_confluence_comparison() print("生成时间轴分析图...") self.plot_timeline_analysis() print("所有可视化图表已保存为PNG文件") if __name__ == "__main__": # 创建可视化实例并生成所有图表 visualizer = MineDoubleSourceVisualizerEnhanced() visualizer.generate_all_visualizations() 代码如上 报错内容如下 E:\Anaconda\python.exe C:\Users\cheny\Desktop\PythonProject2\tu.py 生成水流蔓延过程可视化... Traceback (most recent call last): File "C:\Users\cheny\Desktop\PythonProject2\tu.py", line 630, in <module> visualizer.generate_all_visualizations() File "C:\Users\cheny\Desktop\PythonProject2\tu.py", line 616, in generate_all_visualizations self.plot_propagation_stages() File "C:\Users\cheny\Desktop\PythonProject2\tu.py", line 358, in plot_propagation_stages nx.draw_networkx_edges( TypeError: draw_networkx_edges() got an unexpected keyword argument &#39;zorder&#39; 进程已结束,退出代码为 1
最新发布
09-08
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值