使用 matplotlib 在 Tkinter 中绘制数据 - 在列表之间切换

Posted

技术标签:

【中文标题】使用 matplotlib 在 Tkinter 中绘制数据 - 在列表之间切换【英文标题】:Plotting data in Tkinter with matplotlib - switching between lists 【发布时间】:2016-01-18 05:59:21 【问题描述】:

我正在创建一个利用 Tkintermatplotlib 的程序。我有 2 个列表列表(一个用于 x 轴,一个用于 y 轴),我希望有一个可以在列表中的列表之间切换的按钮。我从问题Interactive plot based on Tkinter and matplotlib 中获取了大部分代码,但我无法让按钮按我喜欢的方式工作。我对使用类很陌生,理解它们有点困难。

tft 是 x 数据 tf1 是 y 数据

数据示例:

x-data = [[1,2,3,4,5],[10,11,13,15,12,19],[20,25,27]]
y-data = [[5.4,6,10,11,6],[4,6,8,34,20,12],[45,25,50]]

我下面的代码将绘制列表中的一个列表,但当我单击按钮时不会在该列表中的列表之间切换。我已经注释掉了我尝试过的其他方法。当我使用它时,它总是说 App 没有属性 'line' 或 'canvas'。就像我说的,我对课程很陌生,我正在努力更好地理解它们。

我已经更新了我的代码,现在它可以识别event_num 并在按下按钮时打印正确的值。但是,该图并未使用新数据进行更新(即,它继续仅显示第一个数据集,而不是在列表之间切换)。我认为问题出在函数increasedecrease 中。我尝试使用self.line, = ax.plot(tft[self.event_num],tf1[self.event_num],'.')self.canvas.draw(),但它不起作用。我正在寻找要编辑的部分,以便图表会发生变化。

class App: 


    def __init__(self, master):
        self.event_num = 1
        # Create a container
        frame = Frame(master)
        # Create 2 buttons
        self.button_left = Button(frame,text="< Previous Event",
                                        command=self.decrease)
        self.button_left.grid(row=0,column=0)
        self.button_right = Button(frame,text="Next Event >",
                                        command=self.increase)
        self.button_right.grid(row=0,column=1)

        fig = Figure()
        ax = fig.add_subplot(111)
        fig.autofmt_xdate()
        import matplotlib.dates as mdates
        ax.fmt_xdata = mdates.DateFormatter('%Y-%m-%d')
        self.line, = ax.plot(tft[self.event_num],tf1[self.event_num],'.')


        self.canvas = FigureCanvasTkAgg(fig,master=master)
        self.canvas.show()
        self.canvas.get_tk_widget().grid(row=1,column=0)
        frame.grid(row=0,column=0)

    def decrease(self):
        self.event_num -= 1
        print self.event_num
        self.line, = ax.plot(tft[self.event_num],tf1[self.event_num],'.')
        self.canvas.draw()
        #self.canvas.draw(tft[self.event_num],tf1[self.event_num],'.')
        #self.line.set_xdata(tft[event_num])
        #self.line.set_ydata(tf1[event_num])


    def increase(self):
        self.event_num += 1
        print self.event_num
        self.line, = ax.plot(tft[self.event_num],tf1[self.event_num],'.')
        self.canvas.draw()
        #self.canvas.draw(tft[self.event_num],tf1[self.event_num],'.')
        #self.set_xdata(tft[event_num])
        #self.set_ydata(tf1[event_num])


root = Tk()
app = App(root)
root.mainloop()

【问题讨论】:

【参考方案1】:

AttributeError: App instance has no attribute 'canvas' 表示您的代码在创建/分配之前引用了 canvas 属性。

这一行:

self.button_left = Button(frame,text="< Previous Event",
                                    command=self.decrease(event_num))

正在调用decrease 方法,因为您使用了括号并提供了参数,而不是仅仅绑定处理程序。在 reduce 方法中,您正在访问 self.canvas 以调用 draw 方法。

这是在您创建 canvas 属性之前发生的,这发生在这一行:

self.canvas = FigureCanvasTkAgg(fig,master=master)

使event_num成为App对象的属性;那么您在绑定它时就不必将参数传递给处理程序。您可以通过在__init__ 中分配self.event_num = 1 来做到这一点。

【讨论】:

如果我在__init__ 中使用self.event_num = 1event_num 的值是否仍然可以更改(在列表之间切换)? 我尝试按照您的建议进行操作,但似乎无法让我更改 event_num 的值 def reduction(): self.event_num -= 1 它越来越接近我正在寻找的东西。它正在打印正确的event_num,但现在我需要它用每个新的event_num 更新图表 既然您已经解决了这个关于您遇到的错误的问题,no attribute canvasno attribute line,我鼓励您发布另一个问题。包括代码并描述具体的错误结果或剪切粘贴错误。

以上是关于使用 matplotlib 在 Tkinter 中绘制数据 - 在列表之间切换的主要内容,如果未能解决你的问题,请参考以下文章

需要帮助使用matplotlib在tkinter中绘制图形[重复]

MatplotLib (TKinter) + OpenCV 在 Python 3 中崩溃

如何在 tkinter 中更新由 matplotlib 创建的图形

在 tkinter 画布中嵌入来自 Arduino 的 Matplotlib 实时绘图数据

如何使用 matplotlib 在 python tkinter 中显示与屏幕分辨率无关的数字?

在 tkinter 中运行 matplotlib