问题
I have a tkinter app where I have different frames, each one with a different plot. I have an import function that allows me to select the data file that I want to plot.
Right now, everything is working well if I import the file right at the start of the program, i.e. as soon as the subplot is created on the canvas the data is shown.
However, if the subplot is created beforehand without any data, when I import the data and call the function to plot it, the canvas does not update the plot. BUT, if I resize the window (or maximize it) the plot is updated.
Below is the code. Any suggestion regarding the code structure are appreciated.
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:
Call the draw()
method of the canvas.
来源:https://stackoverflow.com/questions/39222641/how-to-update-a-plot-on-tkinter-canvas