Python 在tkinter gui中使用导航栏后Matplotlib live plot relim

Python 在tkinter gui中使用导航栏后Matplotlib live plot relim,python,python-3.x,matplotlib,tkinter,Python,Python 3.x,Matplotlib,Tkinter,我正在用tkinter制作一个带有实时嵌入matplotlib图的gui。我使用figureCastKagg作为画布,使用NavigationToolbar2Tk作为导航栏,使用FuncAnimation来处理给定数据源的定期更新 绑定到FuncAnimation的回调在每次调用(即Line2D.set\u data(…))时重置给定行上的数据(即Axes.plot(…))的返回值)。回调还重新确定并应用适当的x轴和y轴限制,以通过 axis.relim() axis.autoscale_vie

我正在用tkinter制作一个带有实时嵌入matplotlib图的gui。我使用
figureCastKagg
作为画布,使用
NavigationToolbar2Tk
作为导航栏,使用
FuncAnimation
来处理给定数据源的定期更新

绑定到
FuncAnimation
的回调在每次调用(即
Line2D.set\u data(…)
)时重置给定行上的数据(即
Axes.plot(…)
)的返回值)。回调还重新确定并应用适当的x轴和y轴限制,以通过

axis.relim()
axis.autoscale_view()
其中,
axis
AxesSubplot
的一个实例

在使用导航栏之前,这非常有效;添加的任何新数据都会适当地反映在图形中,轴会自动重新缩放以适应它,这是我的目标

我面临的问题是,如果使用导航栏上的任何功能(平移、缩放等),重新缩放将无法继续工作,这意味着图形可能无法查看,用户查看新数据的唯一方法是手动平移到它或手动缩小,这是不可取的

实际上,这一功能是有意义的,因为它会让人恼火,例如,尝试放大一部分绘图,但立即缩小以将轴重新调整为新数据,这就是为什么我打算添加一个
tkinter.Checkbutton
来临时禁用重新缩放

我试着查看导航栏的源代码,它似乎改变了轴和画布上的状态,我只能假设这是问题所在,但到目前为止,我还没有找到“撤消”这些更改的方法。如果存在这样一种方式,我会将它绑定到
tkinter.Button
或其他东西上,以便可以重新启用自动重新缩放

我如何解决这个问题

下面是一个演示此问题的最小示例

import math
import itertools
import tkinter as tk
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
from matplotlib.animation import FuncAnimation


def xydata_generator(func, div):
    for num in itertools.count():
        num = num / div
        yield num, func(num)


class Plot(tk.Frame):

    def __init__(self, master, data_source, interval=100, *args, **kwargs):
        super().__init__(master, *args, **kwargs)

        self.data_source = data_source
        self.figure = Figure((5, 5), 100)
        self.canvas = FigureCanvasTkAgg(self.figure, self)
        self.nav_bar = NavigationToolbar2Tk(self.canvas, self)
        self.canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)
        self.axis = self.figure.add_subplot(111)
        self.x_data = []
        self.y_data = []
        self.line = self.axis.plot([], [])[0]  # Axes.plot returns a list
        # Set the data to a mutable type so we only need to append to it then force the line to invalidate its cache
        self.line.set_data(self.x_data, self.y_data)
        self.ani = FuncAnimation(self.figure, self.update_plot, interval=interval)

    def update_plot(self, _):
        x, y = next(self.data_source)  # (realistically the data source wouldn't be restricted to be a generator)
        # Because the Line2D object stores a reference to the two lists, we need only update the lists and signal
        # that the line needs to be updated.
        self.x_data.append(x)
        self.y_data.append(y)
        self.line.recache_always()
        self._refit_artists()

    def _refit_artists(self):
        self.axis.relim()
        self.axis.autoscale_view()


root = tk.Tk()
data = xydata_generator(math.sin, 5)
plot = Plot(root, data)
plot.pack(fill=tk.BOTH, expand=True)
root.mainloop()

结果很简单。要重置轴,以便调用
axes.relim()
axes.autoscale\u view()
生效,只需调用
axes.set\u autoscale\u on(True)
。每次使用导航栏上的功能(平移、缩放等)时,都必须重复此操作。

如何操作?你能解释一下在哪里以及如何准确调用轴吗?设置自动缩放(True)?我自己也在尝试做类似的事情。@Nachiket这是很久以前的事了,所以我记不清了,但我想我手动添加了一个tkinter按钮,它的回调只执行轴。设置自动缩放(True)。通过这种方式,用户可以使用导航按钮放大某处,例如,当他们想要重新启用自动缩放时,可以按下手动添加的按钮。