matplotlib 在Tkinter画布中更新时,NagivationQuery失败

iyfjxgzm  于 12个月前  发布在  其他
关注(0)|答案(2)|浏览(104)

我试图使用matplotlib更新Tkinter画布中的双面板图。这里是显示我当前理解的最小代码。主要问题是导航工具栏在初始图中工作时(y = sin(x),y = cos(x)),但是当我按下更新按钮来更新它时,它失败了。例如,如果我放大一条曲线,我不能使用home键返回到原来的状态。我一直在尝试不同的方法,但无济于事。我会感谢任何人的建议。我注意到的一个小问题是,如果我想杀死情节,我应该去菜单栏,选择python/退出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()

字符串

guz6ccqo

guz6ccqo1#

主要的问题是,home键不知道它应该在被按下时指的是哪个状态。它所指的原始状态甚至不再存在,因为在此期间该图已被清除。解决此问题的方法是调用

toolbar.update()

字符串
这将尤其为按钮创建新的原始状态,以便在被按压时恢复到该状态。
代码中还有一些小问题:

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

以下是一个干净的版本,上面所有的都得到了照顾:

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
kdfy810k

kdfy810k2#

这对我来说是一个面向对象的方法。

...... your matplot definition

    plt.tight_layout()

    self.canvas.draw()
    self.canvas.flush_events()
    self.toolbar.update()

字符串

相关问题