如何移除tkinter嵌入图中xarray自动生成的色条?
解决xarray绘图切换变量时残留色条的问题
你遇到的核心问题是:xarray绘制二维变量时会自动创建独立的色条坐标轴,切换回一维变量时,仅调用ax.cla()只会清理主绘图轴的内容,不会删除色条对应的坐标轴,导致反复切换后出现多个色条。
下面提供两种直接有效的解决思路,不需要替换xarray绘图方法,也不用重建图形容器:
方法一:跟踪色条对象并主动移除
xarray的plot()方法返回的结果中包含色条对象(cbar属性),我们可以在绘制二维变量时保存这个对象,切换回一维时直接移除它。
修改代码步骤:
- 在类的
__init__方法中添加色条跟踪属性:
def __init__(self, master, ds): # 原有代码... self.plt_displayed = 'd1' self.cbar = None # 新增:跟踪色条对象 # 原有代码...
- 修改
plt_d2()方法,保存色条对象:
def plt_d2(self): self.axs.cla() # 先清理主轴内容 plot_result = self.ds['d2'].plot(ax=self.axs) self.cbar = plot_result.cbar # 保存色条对象 self.axs.set(title='This 2D data!') self.canvas.draw()
- 修改
refresh_canvas()方法,移除残留色条:
def refresh_canvas(self): self.axs.cla() # 如果存在色条,移除并重置 if self.cbar is not None: self.cbar.remove() self.cbar = None self.make_background_figure() self.canvas.draw()
方法二:批量清理figure中多余的坐标轴
如果担心漏跟踪色条对象,可以直接遍历figure的所有坐标轴,只保留主绘图轴,其余全部移除。
修改refresh_canvas()方法即可:
def refresh_canvas(self): self.axs.cla() # 移除主绘图轴之外的所有坐标轴(包括色条轴) for ax in self.fig.axes: if ax != self.axs: ax.remove() self.make_background_figure() self.canvas.draw()
修改后的完整代码(以方法一为例)
import matplotlib.pyplot as plt from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk import numpy as np import tkinter as tk import xarray as xr class MainFrame(tk.Frame): def __init__(self, master, ds): # dummy data self.ds = ds self.plt_displayed = 'd1' self.cbar = None # 新增:跟踪色条对象 self.parent = master tk.Frame.__init__(self, self.parent, bg='turquoise', borderwidth=1, relief="sunken") self.create_layout() # Protocol self.parent.protocol("WM_DELETE_WINDOW", self.window_closure_handler) def window_closure_handler(self): self.parent.quit() self.parent.destroy() def create_layout(self): # Setting up the button click_me = tk.Button(self, text='Click Me!', command=self.bind_button_click_me) # Seting up the ploting area self.make_background_figure() self.canvas = FigureCanvasTkAgg(self.fig, master=self) self.canvas.draw() toolbar = NavigationToolbar2Tk(self.canvas, self, pack_toolbar=True) toolbar.update() # Setting up the geometry toolbar.pack(side=tk.BOTTOM, fill=tk.X) plot_widget = self.canvas.get_tk_widget() plot_widget.pack(side=tk.TOP, fill=tk.BOTH, expand=True) click_me.pack() def refresh_canvas(self): self.axs.cla() # 如果存在色条,移除并重置 if self.cbar is not None: self.cbar.remove() self.cbar = None self.make_background_figure() self.canvas.draw() def make_background_figure(self): if not hasattr(self, 'fig'): self.fig, self.axs = plt.subplots(figsize=(5,4), dpi=100) self.ds['d1'].plot(ax=self.axs) self.axs.set(title='This 1D data!') self.axs.grid() def plt_d2(self): self.axs.cla() # 先清理主轴内容 plot_result = self.ds['d2'].plot(ax=self.axs) self.cbar = plot_result.cbar # 保存色条对象 self.axs.set(title='This 2D data!') self.canvas.draw() def bind_button_click_me(self): if self.plt_displayed == 'd1': self.plt_d2() self.plt_displayed = 'd2' else: self.refresh_canvas() self.plt_displayed = 'd1' def main(): # Creating some dummy data x = np.arange(0, 100, 0.1) y = np.flip(x) d1 = np.sin(2*np.pi*x/15) d2 = d1[:, None] * np.cos(2*np.pi*y/15)[None, :] ds = xr.Dataset( data_vars=dict(d1=(["x"], d1), d2=(["y", "x"], d2)), coords=dict(x=("x", x), y=("y", y)) ) root = tk.Tk() window = MainFrame(root, ds) window.pack(side='top', fill='both', expand=True) root.mainloop() if __name__ == '__main__': main()
内容的提问来源于stack exchange,提问作者gsalles
相关产品推荐
相关产品推荐

