3

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()
2
  • 1
    The code you posted is not well formatted, doesn't include the right imports nor is complete to try to reproduce your error (I edited the code). It is difficult to provide an answer without a good question. Also, the arguments to both final functions, nyquist_plot and refresh plot are incomplete and not explicit. You should pass the df explicitly. In refresh_plots there is a reference to fig_nyquist that is not explicitly defined in the rest of the code snippet you posted. Could you rewrite your question with a better code snippet in order others can help you in a more precise way? Commented Aug 30, 2016 at 9:27
  • Thank you @kikocorreoso. I didn't want to give the full code because I thought that would demotivate people to read it... my bad. I just added the rest of the code. The EIS_df is a global variable (dataframe) Commented Aug 30, 2016 at 10:29

2 Answers 2

4

Call the draw() method of the canvas.

Sign up to request clarification or add additional context in comments.

2 Comments

I did it. I doesn't do anything apparently.
Success. I had to do fig_xxxxx.canvas.draw()
1

Try your_figure_name.canvas.draw_idle(), it worked for me.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.