单源调用Single Call 模式

本文深入探讨了在面向对象设计中实现组合关系的具体方法,通过屏蔽构造函数和使用静态方法,确保子类只能在特定父类中实例化,有效控制了类的生命周期。

在进行面向对象得分析与设计的实践过程中我们经常会遇到聚合(Aggregations)与组合(Composition)这两种关系,聚合是一种关联形式,它指明一个聚集(整体)和组成部分之间的整体与部分的关系。组合是指一种带有很强主从关系,成分的生命期一致的聚集关联形式。一个部分可以仅属于一个组成。没有固定多重性的部分可以在组成创建后再被创建。但是一旦被创建,这些部分将与组成同时存在并同时消亡(共享生存周期)。这些部分也可以在组成消失前被移开。组成可以是递归的。

一个典型的聚合的例子是计算机,计算机的个部分和主机是松散的从属关系,一台计算机的外设可以随时接到另一台主机上使用,也就是说计算机的主机和外设有各自的生存周期,例如如果主机发生了故障,我们仍然可以把显示器接到另一台计算机上使用。

典型组合关系的例子是桌子,下图表示的就是桌子类(Coffee Table),它包括桌面类(Table Top)和桌腿类(Leg),桌面和桌腿只能从属于桌子而不会从属于其他,当桌子不存在时,桌面和桌腿也就没有意义了,也就是说三个类处于一个生存周期。

我们来考虑下面的例子,比如我们现在需要一个汽车类(Car)和一个发动机类(Engine),这两个类是个典型的组合组合关系,也就是说发动机类能在汽车类的里面被实例化而且只能在汽车类被实例化。可是我们在开发的过程中如何实现组合关系呢?

首先,我们必须保证Engine类不能直接被实例化,为了达到这个目的我们必须屏蔽掉Engine类的构造函数,例如:

1

2

3

public class Engine {

  private Engine() {  }

     }

这样我们就不能直接用new Engine()的方法来创建实例,而只能通过Engine类的一个静态方法来得到Engine类的实例,例如:

1

2

3

4

5

6

7

public class Engine {

  private Engine() {  }

  static Engine  getobject()

{

  new Engine();

}

    }

这种方法和我们实现singleton的方法是一模一样的。现在我们的Engine类已经不能直接被实例化了,但是还不能保证它只能被Car类实例化,因为在任何类中我们都可以用Engine engine=Engine.getobject()的方法得到Engine类的实例。为了保证Engine类是被Car类实例化的我们可以在Car类调用Engine.getobject()时把自己本身的引用作为一个参数传到Engine类中,例如Engine engine=Engine.getobject(this),这时的Engine类必须要做一点修改

1

2

3

4

5

6

7

public class Engine {

  private Engine() {  }

  static Engine  getobject(Car o)

{

  new Engine();

}

    }

这样只有在Car类中执行Engine engine=Engine.getobject(this)时,才能真正返回一个Engine类的实例。否则会收到一个类型不匹配的异常。

我们可能觉得到现在应该大功告成了,原来实现这么简单。

可是,细心的人会发现这样的设计存在一个很大的漏洞,Engine类虽然我们屏蔽掉了它的构造函数,但是Car类的构造函数我们并没有屏蔽掉,在任何类中如果我们执行

1

Engine engine=Engine.getobject(new Car())

我们仍然可以得到一个Engine类的实例,这样的结果是我们不能接受的,所以我们还要做一些改动。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

//Engine.java

public class Engine {

  private Engine() {  }

  static Engine  getobject(Car o)

  {

      if (o.can_load() )

      {

             return( new Engine());

      }

    else

      return null;

  }

   

}

我们看到在Car类中增加了一个方法--can_load(),用这个方法能我们能判断出Engine.getobject方法是不是从Car类内部调用的,如果是我们就返回一个Engine类的实例,否则我们就返回一个空指针null,相应的Car类的代码如下。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

//Car.java

public class Car {

  private Engine engine;

  private boolean can_load=false;

  public Car()

  {

      engine=  get_engine();

  }

final  public boolean can_load()

  {

    return can_load;

  }

  private Engine get_engine()

  {

       Engine my_engine;

       can_load=true;

       my_engine=Engine.getobject(this) ;

       can_load=false;

       return my_engine;

  }

 }

这时的Car类,多了一个布尔类型的一个变量can_load,它的作用是只有can_load的值为真时Engine类的getobjec方法才能返回一个Engine类的实例。而can_load是私有类型的变量,初始值为假,只有在Car类的内部才能改变can_load的值。这样我们在使用Engine.getobject(this)时首先把can_load的值设为真,在返回Engine类的一个实例以后再把can_load的值设为假,这样我们就可以很好的控制Engine类只能在Car类内部实例化。

最后一点要说明的是Car类的can_load()方法必须为final类型的,因为如果是非final类型的方法的话我们可以派生Car类,然后重载can_load()方法,例如:

1

2

3

4

5

6

public class newCar extends Car {

  public newCar() {

  }

  public boolean can_load(){return true;}

   

}

这样我们就可以在任何类中用Engine engine=Engine.getobject(new newCar())得到Engine类的实例,这也是我们不想看到的结果,所以一定要把Car类的can_load()方法设为final类型,这样才能保证Car类的can_load()方法不会被派生类重载。

完整的源代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

//Engine.java

  public class Engine {

  private Engine() {  }

  static Engine  getobject(Car o)

  {

      if (o.can_load() )

      {

             return( new Engine());

      }

    else

      return null;

  }

  public void start()

  {

  System.out.println("engine started");

  }

  public void stop()

  {

  System.out.println("engine stopped");

  }

}

   

  //Car.java

   public class Car {

 private Engine engine;

   private boolean can_load=false;

  public Car()

  {

      engine=  get_engine();

  }

final  public boolean can_load()

  {

    return can_load;

  }

  private Engine get_engine()

  {

       Engine my_engine;

       can_load=true;

       my_engine=Engine.getobject(this) ;

       can_load=false;

       return my_engine;

  }

  public void start()

  {

    if (engine!=null)

       engine.start();

  }

  public void stop()

  {

    if(engine!=null)

       engine.stop();

  }

  public static void main(String[] args) {

     Car car =new Car();

     car.start() ;

     car.stop() ;

  }

}

源自:https://www.ibm.com/developerworks/cn/java/l-single-call/ 

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['A']['trigger']}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['B']['trigger']}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 'zorder' 进程已结束,退出代码为 1
最新发布
09-08
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值