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

Tkinter+matplotlib切换图表时如何保证单选框与滑块正常更新?

修复后完整可运行代码

import matplotlib
import tkinter as Tk
matplotlib.use("TkAgg")
import matplotlib.pyplot as plt
import numpy as np
from tkinter import *
from matplotlib.backends.backend_tkagg import (
    FigureCanvasTkAgg, NavigationToolbar2Tk)
from matplotlib.backend_bases import key_press_handler
from matplotlib.widgets import Slider, RadioButtons

def config_plot():
    fig, ax = plt.subplots()
    ax.set(xlabel='time (s)', ylabel='voltage (mV)',
           title='Graph One')
    return (fig, ax)

class matplotlibSwitchGraphs:
    def __init__(self, master):
        self.master = master
        self.frame = Frame(self.master)
        self.fig, self.ax = config_plot()
        self.graphIndex = 0
        self.canvas = FigureCanvasTkAgg(self.fig, self.master)
        # 预声明控件实例属性,避免被垃圾回收
        self.alfa_slider = None
        self.radio = None
        self.config_window()
        self.draw_graph_one()
        self.frame.pack(expand=YES, fill=BOTH)

    def config_window(self):
        self.canvas.mpl_connect("key_press_event", self.on_key_press)
        toolbar = NavigationToolbar2Tk(self.canvas, self.master)
        toolbar.update()
        self.canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)
        self.button = Button(self.master, text="Quit", command=self._quit)
        self.button.pack(side=BOTTOM)
        self.button_switch = Button(self.master, text="Switch Graphs", command=self.switch_graphs)
        self.button_switch.pack(side=BOTTOM)

    def plot_data(self):
        def func3(x, y):
            return (1 - x / 2 + x ** 5 + y ** 3) * np.exp(-(x ** 2 + y ** 2))
        dx, dy = 0.05, 0.05
        x = np.arange(-3.0, 3.0, dx)
        y = np.arange(-3.0, 3.0, dy)
        X, Y = np.meshgrid(x, y)
        self.extent = np.min(x), np.max(x), np.min(y), np.max(y)
        self.Z1 = np.add.outer(range(8), range(8)) % 2
        self.Z2 = func3(X, Y)

    def draw_graph_one(self):
        self.plot_data()
        # 清空画布所有axes,包括之前的滑块、单选框区域
        self.fig.clear()
        ax = self.fig.add_subplot(111)
        self.ax = ax.imshow(self.Z2, cmap=plt.cm.viridis, alpha=.9, interpolation='bilinear',
                             extent=self.extent)
        self.canvas.draw()

    def draw_graph_two(self):
        self.plot_data()
        # 清空画布所有axes
        self.fig.clear()
        ax1 = self.fig.add_subplot(1, 2, 1)
        ax1.imshow(self.Z1, cmap=plt.cm.gray, interpolation='nearest',
                   extent=self.extent)
        ax2 = self.fig.add_subplot(1, 2, 2)
        self.a = ax2.imshow(self.Z2, cmap=plt.cm.viridis, alpha=.9, interpolation='bilinear',
                            extent=self.extent)
        self.b = ax2.imshow(self.Z1, cmap=plt.cm.gray, interpolation='nearest',
                            extent=self.extent)
        
        self.fig.subplots_adjust(left=0.15, bottom=0.15)
        slider_ax = self.fig.add_axes([0.06, 0.25, 0.0225, 0.5])
        # 控件存为实例属性避免回收
        self.alfa_slider = Slider(slider_ax,
                             label="Transparency",
                             valmin=0,
                             valmax=1,
                             valinit=0,
                             orientation="vertical"
                             )
        self.alfa_slider.on_changed(self.update_slider)
        rax = self.fig.add_axes([0.06, 0.05, 0.15, 0.15])
        # 控件存为实例属性避免回收
        self.radio = RadioButtons(rax, ('Reds', 'Greens', 'Blues', 'Oranges', 'Wistia', 'plasma', 'inferno'), active=0)
        self.radio.on_clicked(self.update_radio)
        self.canvas.draw()

    def update_slider(self,alpha_):
        self.b.set_alpha(alpha_)
        self.canvas.draw()

    def update_radio(self,label_):
        self.b.set_cmap(label_)
        self.canvas.draw()

    def on_key_press(self,event):
        print("you pressed {}".format(event.key))
        key_press_handler(event, self.canvas, self.canvas.toolbar)

    def _quit(self):
        self.master.quit()
        self.master.destroy()

    def switch_graphs(self):
        self.graphIndex = (self.graphIndex + 1) % 2
        if self.graphIndex == 0:
            self.draw_graph_one()
        else:
            self.draw_graph_two()

def main():
    root = Tk()
    matplotlibSwitchGraphs(root)
    root.mainloop()

if __name__ == '__main__':
    main()

核心修改说明

  • 滑块、单选框控件存为实例属性,避免方法执行完后被Python垃圾回收导致回调失效,解决拖动滑块、点击单选框无响应的问题
  • 每次绘制新图表前调用self.fig.clear()清空画布上所有axes,包括滑块、单选框的专属axes,不会有残留元素影响布局,解决无法切回单子图的问题
  • 所有绘图操作都绑定到实例的figure对象,不使用plt全局方法,避免画布元素混乱
  • 修正了按键事件回调的参数错误,避免按键触发时报错

内容的提问来源于stack exchange,提问作者Gerard

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 06:57:04