You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何移除tkinter嵌入图中xarray自动生成的色条?

解决xarray绘图切换变量时残留色条的问题

你遇到的核心问题是:xarray绘制二维变量时会自动创建独立的色条坐标轴,切换回一维变量时,仅调用ax.cla()只会清理主绘图轴的内容,不会删除色条对应的坐标轴,导致反复切换后出现多个色条。

下面提供两种直接有效的解决思路,不需要替换xarray绘图方法,也不用重建图形容器:

方法一:跟踪色条对象并主动移除

xarray的plot()方法返回的结果中包含色条对象(cbar属性),我们可以在绘制二维变量时保存这个对象,切换回一维时直接移除它。

修改代码步骤:

  1. 在类的__init__方法中添加色条跟踪属性:
def __init__(self, master, ds):
    # 原有代码...
    self.plt_displayed = 'd1'
    self.cbar = None  # 新增:跟踪色条对象
    # 原有代码...
  1. 修改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()
  1. 修改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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 03:47:01