Matplotlib多Figure列表绘图异常:系列图混入组图问题排查
问题原因分析
核心问题出在Matplotlib的figure编号复用机制上:你在初始化组和系列的figure时,都用了plt.figure(j)且j的取值范围完全相同(都是0和1)。Matplotlib中plt.figure(num)的逻辑是:如果指定的num已经对应一个存在的figure,就会直接返回这个已存在的对象,而不是创建新的。这就导致系列的figure其实和组的figure是同一个对象,后续的绘图操作自然会串到一起。
优雅的解决方法
我们可以完全避免手动指定figure编号,让Matplotlib自动分配唯一ID,同时完善绘图流程的完整性。下面是具体修改方案:
1. 修改figure初始化逻辑
把initGrpPlt和initSeriesPlt中的plt.figure(j)改为不带参数的plt.figure(),这样每次调用都会创建全新的独立figure:
def initGrpPlt(): for group in Groups._GroupRegistry: for _ in range(maxNrVdrain): fig = plt.figure() # 自动生成唯一编号的新figure group.figlist.append(fig) group.axlist.append(fig.add_subplot(111)) return def initSeriesPlt(): for series in Series._SeriesRegistry: for _ in range(maxNrVdrain): fig = plt.figure() series.figlist.append(fig) series.axlist.append(fig.add_subplot(111)) return
2. 完善系列图的显示流程
原来的代码只处理了组图的设置,漏掉了系列图的最终配置。在MainPlt中补充系列图的处理逻辑:
def MainPlt(): initGrpPlt() initSeriesPlt() # 遍历晶体管填充所有绘图数据 for trans in Transistor._TransRegistry: for j in range(maxNrVdrain): toGPlt(trans,j) toSPlt(trans,j) # 完成组图的标题等设置 for j in range(maxNrVdrain): for group in Groups._GroupRegistry: PltGrp(group,j) # 完成系列图的图例、标题设置 for j in range(maxNrVdrain): for series in Series._SeriesRegistry: PltSeries(series,j) plt.show() # 一次性显示所有创建的figure return
完整修改后的代码
# -*- coding: utf-8 -*- import matplotlib.pyplot as plt import matplotlib.cm as cm import numpy as np maxNrVdrain = 2 X = np.linspace(-np.pi, np.pi, 256,endpoint=True) A = [[1*np.cos(X),2*np.cos(X),3*np.cos(X),4*np.cos(X)],[1*np.tan(X),2*np.tan(X),3*np.tan(X),4*np.tan(X)]] B = [[2* np.sin(X),4* np.sin(X),6* np.sin(X),8* np.sin(X)],[2*np.cos(X),4*np.cos(X),6*np.cos(X),8*np.cos(X)]] class Transistor(object): _TransRegistry = [] def __init__(self,y1,y2): self._TransRegistry.append(self) self.X = X self.Y = [y1,y2] self.group = '' class Groups(): _GroupRegistry = [] def __init__(self,trans): self._GroupRegistry.append(self) self.transistors = [trans] self.figlist = [] self.axlist = [] class Series(): _SeriesRegistry = [] def __init__(self,group): self._SeriesRegistry.append(self) self.groups = [group] self.figlist = [] self.axlist = [] def initGrpPlt(): for group in Groups._GroupRegistry: for _ in range(maxNrVdrain): fig = plt.figure() group.figlist.append(fig) group.axlist.append(fig.add_subplot(111)) return def initSeriesPlt(): for series in Series._SeriesRegistry: for _ in range(maxNrVdrain): fig = plt.figure() series.figlist.append(fig) series.axlist.append(fig.add_subplot(111)) return def toGPlt(trans,j): colour = cm.rainbow(np.linspace(0, 1, 4)) group = trans.group group.axlist[j].plot(trans.X,trans.Y[j], color=colour[group.transistors.index(trans)], linewidth=1.5, linestyle="-") return def toSPlt(trans,j): colour = cm.rainbow(np.linspace(0, 1, 2)) series = Series._SeriesRegistry[0] group = trans.group if group.transistors.index(trans) == 0: series.axlist[j].plot(trans.X,trans.Y[j],color=colour[series.groups.index(group)], linewidth=1.5, linestyle="-", label = 'T = nan, RH = nan' ) else: series.axlist[j].plot(trans.X,trans.Y[j],color=colour[series.groups.index(group)], linewidth=1.5, linestyle="-") return def PltGrp(group,j): ax = group.axlist[j] ax.set_title('Test Grp') return def PltSeries(series,j): ax = series.axlist[j] ax.legend(loc='upper right', frameon=False) ax.set_title('Test Series') return def MainPlt(): initGrpPlt() initSeriesPlt() for trans in Transistor._TransRegistry: for j in range(maxNrVdrain): toGPlt(trans,j) toSPlt(trans,j) # 处理组图配置 for j in range(maxNrVdrain): for group in Groups._GroupRegistry: PltGrp(group,j) # 处理系列图配置 for j in range(maxNrVdrain): for series in Series._SeriesRegistry: PltSeries(series,j) plt.show() return def Init(): for j in range(4): trans = Transistor(A[0][j],A[1][j]) if j == 0: Groups(trans) else: Groups._GroupRegistry[0].transistors.append(trans) trans.group = Groups._GroupRegistry[0] Series(Groups._GroupRegistry[0]) for j in range(4): trans = Transistor(B[0][j],B[1][j]) if j == 0: Groups(trans) else: Groups._GroupRegistry[1].transistors.append(trans) trans.group = Groups._GroupRegistry[1] Series._SeriesRegistry[0].groups.append(Groups._GroupRegistry[1]) return def main(): Init() MainPlt() return main()
额外优化建议
- 尽量避免使用全局静态注册表(比如
_TransRegistry),可以在Init函数中直接管理实例对象,代码会更清晰可控。 - 提前计算绘图颜色映射,避免每次调用
group.transistors.index(trans)的索引查找(当晶体管数量较多时会有性能损耗)。 - 给每个figure添加更具辨识度的标题,比如包含组ID或系列名称,方便后续区分不同图表。
内容的提问来源于stack exchange,提问作者Blue
相关产品推荐
相关产品推荐

