【问题标题】:NagivationToolbar fails when updating in Tkinter canvas在 Tkinter 画布中更新时 NagivationToolbar 失败
【发布时间】:2018-01-28 05:44:58
【问题描述】:

我正在尝试使用 matplotlib 更新 Tkinter 画布中的两个面板图。这是显示我当前理解的最少代码。主要问题是导航工具栏适用于初始图(y = sin(x),y​​ = cos(x)),但是当我按下更新按钮更新它时它失败了。例如,如果我放大一条曲线,我无法使用主页按钮返回其原始状态。我一直在尝试不同的方法,但无济于事。我会很感激任何人的建议。 我注意到的一个小问题是,如果我想终止绘图,我应该转到菜单栏并选择 python/quit Python,否则如果我只是单击绘图窗口左上角的 X,终端会冻结(我必须杀死终端)。
我正在使用 Python 2.7.14 和 matplotlob 2.1.0。

from Tkinter import *
import Tkinter as tk
import ttk
from math import exp
import os  # for loading files or exporting files
import tkFileDialog
##loading matplotlib modules
import matplotlib
matplotlib.use("TkAgg")
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import matplotlib.gridspec as gridspec
import numpy as np

top = tk.Tk()
top.title("Intermolecular PDFs")

top_frame = ttk.Frame(top, padding = (10, 10))
top_frame.pack()
fig = plt.figure(figsize=(10, 6), dpi=100) ##create a figure; modify the size here

x = np.linspace(0,1)
y = np.sin(x)
z = np.cos(x)

fig.add_subplot(211)

plt.title("Individual PDFs")
plt.xlabel(ur"r (\u00c5)", labelpad = 3, fontsize = 15)
plt.ylabel(ur"PDF, G (\u00c5$^{-2})$", labelpad = 10, fontsize = 15)
plt.plot(x,y, "r-", lw=2)
plt.xticks(fontsize = 11)
plt.yticks(fontsize = 11)

fig.add_subplot(212)


plt.title("Difference PDFs")
plt.xlabel(ur"r (\u00c5)", labelpad = 3, fontsize = 15)
plt.ylabel(ur"PDF, G (\u00c5$^{-2})$", labelpad = 10, fontsize = 15)
plt.plot(x,z,"g-", lw=2)
plt.xticks(fontsize = 11)
plt.yticks(fontsize = 11)

fig.tight_layout()

canvas = FigureCanvasTkAgg(fig, master = top_frame)
canvas.show()
canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)
#self.canvas.draw()

toolbar = NavigationToolbar2TkAgg(canvas, top_frame)
#self.toolbar.pack()
toolbar.update()
canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=1)


def update():
    fig.clf()

    new_x = np.linspace(1,100)
    new_y = new_x**2
    new_z = new_x**3
    fig.add_subplot(211)

    plt.title("Individual PDFs")
    plt.xlabel(ur"r (\u00c5)", labelpad = 3, fontsize = 15)
    plt.ylabel(ur"PDF, G (\u00c5$^{-2})$", labelpad = 10, fontsize = 15)
    plt.plot(new_x,new_y, "r-", lw=2)
    plt.xticks(fontsize = 11)
    plt.yticks(fontsize = 11)

    fig.add_subplot(212)


    plt.title("Difference PDFs")
    plt.xlabel(ur"r (\u00c5)", labelpad = 3, fontsize = 15)
    plt.ylabel(ur"PDF, G (\u00c5$^{-2})$", labelpad = 10, fontsize = 15)
    plt.plot(new_x,new_z,"g-", lw=2)
    plt.xticks(fontsize = 11)
    plt.yticks(fontsize = 11)

    fig.tight_layout()
    canvas.show()

ttk.Button(top_frame, text = "update",command = update).pack()


top.mainloop()

【问题讨论】:

    标签: user-interface matplotlib tkinter-canvas


    【解决方案1】:

    主要问题是主页按钮在按下时不知道它应该参考哪个状态。它所指的原始状态甚至已经不存在了,因为此时那个身影已经被清除了。解决方法是调用

    toolbar.update()
    

    这将为按钮创建一个新的主页状态,以便在按下时恢复。

    代码还有其他一些小问题:

    • 您可以只更新其中绘制的线条的数据,而不是清除图形。这将消除大量冗余代码。
    • 我强烈建议在 Tk 中嵌入图形时根本不要使用 pyplot。相反,使用面向对象的方法,创建图形和轴等对象,然后调用它们各自的方法。 (我不确定这是否是冻结的原因,因为即使是初始代码在运行时也没有冻结。)
    • 代码中有一些不必要的命令。

    以下是一个干净的版本,上面的所有内容都得到了处理:

    import Tkinter as tk
    import ttk
    ##loading matplotlib modules
    import matplotlib
    from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
    from matplotlib.figure import Figure
    
    import numpy as np
    
    top = tk.Tk()
    top.title("Intermolecular PDFs")
    
    top_frame = ttk.Frame(top, padding = (10, 10))
    top_frame.pack()
    
    matplotlib.rcParams["xtick.labelsize"] = 11
    matplotlib.rcParams["ytick.labelsize"] = 11
    
    fig = Figure(figsize=(10, 6), dpi=100) ##create a figure; modify the size here
    
    x = np.linspace(0,1)
    y = np.sin(x)
    z = np.cos(x)
    
    ax = fig.add_subplot(211)
    
    ax.set_title("Individual PDFs")
    ax.set_xlabel(ur"r (\u00c5)", labelpad = 3, fontsize = 15)
    ax.set_ylabel(ur"PDF, G (\u00c5$^{-2})$", labelpad = 10, fontsize = 15)
    line, = ax.plot(x,y, "r-", lw=2)
    
    ax2 = fig.add_subplot(212)
    
    ax2.set_title("Difference PDFs")
    ax2.set_xlabel(ur"r (\u00c5)", labelpad = 3, fontsize = 15)
    ax2.set_ylabel(ur"PDF, G (\u00c5$^{-2})$", labelpad = 10, fontsize = 15)
    line2, = ax2.plot(x,z,"g-", lw=2)
    
    canvas = FigureCanvasTkAgg(fig, master = top_frame)
    canvas.get_tk_widget().pack(side=tk.TOP, fill=tk.BOTH, expand=1)
    
    fig.tight_layout()
    
    toolbar = NavigationToolbar2TkAgg(canvas, top_frame)
    toolbar.update()
    canvas._tkcanvas.pack(side=tk.TOP, fill=tk.BOTH, expand=1)
    
    
    def update():
        new_x = np.linspace(1,100)
        new_y = new_x**2
        new_z = new_x**3
    
        line.set_data(new_x,new_y)
        line2.set_data(new_x,new_z)
    
        ax.relim()
        ax.autoscale()
        ax2.relim()
        ax2.autoscale()
        fig.tight_layout()
        canvas.draw_idle()
        toolbar.update()
    
    ttk.Button(top_frame, text = "update",command = update).pack()
    
    
    top.mainloop()
    

    注意:在较新版本的 matplotlib 中,您应该使用 NavigationToolbar2Tk 而不是 NavigationToolbar2TkAgg

    【讨论】:

    • 感谢您的建议。我同意所有这些。一个小问题仍然存在,在我单击更新(出现新图)并放大新图后,主页按钮无法将它们恢复到初始状态(即 x2, x3 指数曲线)。有没有办法解决这个问题?
    • 我不明白这个问题。放大曲线后,按下主页按钮会按预期恢复到未缩放状态,不是吗?
    • 这个问题在不同版本的matplotlib上似乎有点复杂。在旧版本(例如 1.5.1)中,您的代码和我的代码都按预期工作。但是,在新版本的 matplotlib(例如 2.1.0)上,两个代码都有放大/主页问题。如果我错了,请纠正我。尽管如此,我认为你的代码很优雅,我从你身上学到了很多东西!谢谢。
    • 我的代码没有发现任何问题。如果您看到问题,您可以清楚地解释它们,以便我理解您的意思。
    • 我还尝试通过 conda install 将 2.1.0 版本恢复为 2.0.2。结果是两个代码都运行良好。这太出乎意料了。
    猜你喜欢
    • 1970-01-01
    • 2019-05-08
    • 1970-01-01
    • 1970-01-01
    • 2018-05-07
    • 1970-01-01
    • 2019-12-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多