如何在Tkinter画布上更新图形?

3
我有一个tkinter应用程序,其中包含不同的框架,每个框架都有不同的图表。 我有一个导入函数,可以选择要绘制的数据文件。
目前,如果我在程序开始时导入文件,即在画布上创建子图时立即显示数据,则一切正常。
然而,如果子图事先创建而没有任何数据,当我导入数据并调用绘制函数时,画布不会更新绘图。但是,如果我调整窗口大小(或最大化窗口),则图形将更新。
下面是代码。欢迎提出有关代码结构的任何建议。
import numpy as np
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
matplotlib.use("TkAgg")

from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import matplotlib.animation as animation


import Tkinter as tk
import ttk
from tkFileDialog import askopenfilename

LARGE_FONT= ("Verdana", 12)
plot_colors = plt.rcParams['axes.color_cycle']
width, height = plt.figaspect(1)

fig_nyquist = Figure(figsize=(width, height), dpi=100)
plot_axes_nyquist = fig_nyquist.add_subplot(111)

fig_bode = Figure(figsize=(width, height), dpi=100)
plot_axes_bode = fig_bode.add_subplot(111)

fig_randles = Figure(figsize=(width, height), dpi=100)
plot_axes_randles = fig_randles.add_subplot(111)


class EISapp(tk.Tk):

    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)
        tk.Tk.wm_title(self, "EIS + CV Analyser")


        container = tk.Frame(self)
        container.pack(pady=10,padx=10, side="top", fill="both", expand = True)
        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.frames = {}


        for F in (menu_page, nyquist_page, bode_page, randles_page):

            frame = F(container, self)

            self.frames[F] = frame

            frame.grid(row=0, column=0, sticky="nsew")

        self.show_frame(menu_page)

    def show_frame(self, cont):

        frame = self.frames[cont]
        frame.tkraise()




class menu_page(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self,parent)
        label = tk.Label(self, text="Menu", font=LARGE_FONT)
        label.pack(pady=10,padx=10)

        import_button = ttk.Button(self, text="Import EIS data file", command=lambda: import_EIS_data())
        import_button.pack()

        nyquist_button = ttk.Button(self, text="Nyquist Plot", command=lambda: controller.show_frame(nyquist_page))
        nyquist_button.pack()

        bode_button = ttk.Button(self, text="Bode Plot", command=lambda: controller.show_frame(bode_page))
        bode_button.pack()

        randles_button = ttk.Button(self, text="Randles Plot", command=lambda: controller.show_frame(randles_page))
        randles_button.pack()



class nyquist_page(tk.Frame):

    def __init__(self, parent, controller):        
        tk.Frame.__init__(self, parent)
        label = tk.Label(self, text="Nyquist Plot", font=LARGE_FONT)
        label.pack(pady=10,padx=10)

        menu_button = ttk.Button(self, text="Menu", command=lambda: controller.show_frame(menu_page))
        menu_button.pack()

        refresh_button = ttk.Button(self, text="Refresh", command=lambda: refresh_plots())
        refresh_button.pack()

        canvas = FigureCanvasTkAgg(fig_nyquist, self)
        canvas.show()
        canvas.get_tk_widget().pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True)

        toolbar = NavigationToolbar2TkAgg(canvas, self)
        toolbar.update()

class bode_page(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        label = tk.Label(self, text="Bode Plot", font=LARGE_FONT)
        label.pack(pady=10,padx=10)

        menu_button = ttk.Button(self, text="Menu", command=lambda: controller.show_frame(menu_page))
        menu_button.pack()

        canvas = FigureCanvasTkAgg(fig_bode, self)
        canvas.show()
        canvas.get_tk_widget().pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True)

        toolbar = NavigationToolbar2TkAgg(canvas, self)
        toolbar.update()

class randles_page(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        label = tk.Label(self, text="Randles Plot", font=LARGE_FONT)
        label.pack(pady=10,padx=10)

        menu_button = ttk.Button(self, text="Menu", command=lambda: controller.show_frame(menu_page))
        menu_button.pack()

        canvas = FigureCanvasTkAgg(fig_randles, self)
        canvas.show()
        canvas.get_tk_widget().pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True)

        toolbar = NavigationToolbar2TkAgg(canvas, self)
        toolbar.update()

def import_EIS_data():
    global EIS_df    
    try:
        filename = askopenfilename(defaultextension='.txt', filetypes=[('txt file','*.txt'), ('All files','*.*')]) # show an "Open" dialog box and return the path to the selected file 

        data_table = pd.read_table(filename, index_col=False, skiprows=headers_footers(filename)[0], skip_footer=headers_footers(filename)[1], names=['Temperature', 'Frequency', 'Raw Amplitude', 'Z1', 'Z2', 'Time', 'Gain level'] )

        # Convert Frequency values from kHz to Hz
        data_table['Frequency'] = data_table['Frequency'] * 1000;

        # Delete Unnecessary Columns
        data_table = data_table.drop(['Temperature', 'Gain level', 'Raw Amplitude', 'Time'], axis=1); # axis=1 selects "vertical axis" (i.e. columns instead of rows)

        # Adds calculated values of impedance modulus and angle
        data_table['Z'] = np.sqrt(data_table['Z1']**2 + data_table['Z2']**2);
        data_table['Angle'] = np.degrees( np.arctan( -data_table['Z2'] / data_table['Z1'] ) );

        EIS_df = EIS_df.append(data_table)
        refresh_plots()

    except:
        quit()




def nyquist_plot(Z1, Z2, plot_axes=None):
    if plot_axes == None:
        plot_axes = plt.subplot(111)
    if not EIS_df.empty:
        plot_axes.plot(Z1, Z2)
        plot_axes.set_xlabel('$\Re(Z)$')
        plot_axes.set_ylabel('$\Im(Z)$')  
        plot_axes.set_xlim([0, 800]);
        plot_axes.set_ylim([-800, 0]);

def bode_plot(freq, Z, angle, imped_axis=None):

    if imped_axis == None:
        imped_axis = plt.subplot(111)
    if not EIS_df.empty:    
        handle_imped, = imped_axis.plot(freq, Z, label="Impedance")
        imped_axis.set_xlabel('$Frequency$ $(Hz)$')
        imped_axis.set_ylabel('$|Z|$')
        imped_axis.semilogx()
        imped_axis.semilogy()
        imped_axis.legend(loc=2)

    #    imped_axis.set_xlim([0, 1E7]);
    #    imped_axis.set_ylim([1E-1, 1E5]);

        angle_axis = imped_axis.twinx();
        handle_angle, = angle_axis.plot(freq, angle, plot_colors[1], label="Angle", linestyle='--');

        #Configure plot design    
        angle_axis.set_ylabel(r"$\theta$ $(^{\circ}) $")
    #    angle_axis.semilogx()
        angle_axis.grid('off')
        angle_axis.set_ylim([0, 90]);
        angle_axis.legend(loc=1, handlelength=3.6)


def randles_plot(freq, Z1, Z2, plot_axes=None):
    if plot_axes == None:
        plot_axes = plt.subplot(111)
    if not EIS_df.empty:
        plot_axes.plot(1/(np.pi*np.sqrt(freq)),Z1, label='$\Re(Z)$')
        plot_axes.plot(1/(np.pi*np.sqrt(freq)),-Z2, label='$\Im(Z)$')
        plot_axes.legend(loc=2)
        plot_axes.set_xlabel('$(\sqrt{\omega})^{-1}$')
        plot_axes.set_ylabel('$Impedance$') 


def refresh_plots():
    nyquist_plot(EIS_df.Z1, EIS_df.Z2, plot_axes_nyquist)
    fig_nyquist.tight_layout()

    bode_plot(EIS_df.Frequency, EIS_df.Z, EIS_df.Angle, plot_axes_bode)
    fig_bode.tight_layout()    

    randles_plot(EIS_df.Frequency, EIS_df.Z1, EIS_df.Z2, plot_axes_randles)
    fig_randles.tight_layout()


EIS_df = pd.DataFrame(columns=['Frequency', 'Z1', 'Z2', 'Z', 'Angle'] )
app = EISapp()
app.mainloop()

1
你发布的代码格式不规范,没有包含正确的导入并且也不完整,无法尝试重现你的错误(我编辑了这段代码)。如果没有一个好的问题,提供答案就很困难。同时,两个最终函数 nyquist_plotrefresh plot 的参数是不完整和不明确的。你应该显式传递 df。在 refresh_plots 中,有一个对 fig_nyquist 的引用,在你发布的代码片段中没有明确定义。你能否使用更好的代码段重新编写你的问题,以便其他人可以更精准地帮助你? - kikocorreoso
谢谢@kikocorreoso。我不想提供完整的代码,因为我认为那会让人们失去阅读的积极性...我的错。我刚刚添加了剩下的代码。EIS_df是一个全局变量(数据帧)。 - cinico
2个回答

4

调用画布的draw()方法。


我做了。它似乎什么也没做。 - cinico
2
成功了。我必须执行fig_xxxxx.canvas.draw()。 - cinico

1
尝试使用your_figure_name.canvas.draw_idle(),这对我有效。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接