Search code examples
pythonmatplotlibtkinterfigure

How do I change the subplot parameters having a Figure in a window in Tkinter ? As for example I want to add the xlabel and ylabel


I have an application that should get data from a sensor into a live graph, a subplot that is added into a Figure. I have now a problem after adding the subplot that I don't know how to change the plot parameters as xlabel, ylabel. This works if I import plt, but not if I import a Figure that will be further added to the window in Tkinter.

#file livegraph.py

import matplotlib.animation as animation
import datetime

#this is a draft for the liveGraph class
#the objective is to get live data from a sensor 

class liveGraph:

    #by default define the interval as being 1000 mSec
    intervalAnim = 1000

    def __init__(self,fig):
        self.xax = 0
        self.xs = []
        self.ys = []

        self.ax = fig.add_subplot(111)
        self.ax.set_xlabel('teeeest')
        #fig.title('Graph test')
        #fig.set_xlabel("Time")
        #fig.ylabel("% SMS")

        self.anim = animation.FuncAnimation(fig, self.animate, interval = self.intervalAnim)

    def animate(self,i):

        self.xs.append(self.xax)
        self.ys.append(datetime.datetime.now().second)
        self.xax+=1

        self.ax.clear()
        self.ax.plot(self.xs,self.ys)

        if self.xax > 90:
            self.anim.event_source.stop()



from tkinter import *
from matplotlib import style
import matplotlib.pyplot as plt
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from livegraph import liveGraph

# Define the main_screen as a tkinter
app_screen = Tk()  # create a GUI window
app_screen.geometry("1920x1080")  # set the configuration of GUI window
app_screen.resizable(width=True,height=True)
app_screen.title("Testare izolator")  # set the title of GUI window

style.use('bmh')

#figure represents the graphic part of the system
figure = Figure(figsize=(10, 5), facecolor='white',frameon=True)
figure.suptitle('This is the figure title', fontsize=12)
#figure.add_gridspec(10,10)

#this are some parameters that I can easily change if I am using plt
# plt.title('Graph test')
#plt.xlabel("Time")
#plt.ylabel("% SMS")


#x = [ 0, 1, 2, 3, 4 ]
#y = [ 0, 1, 2, 3, 4 ]
#lines = plt.plot(x, y)
#plt.grid()
#plt.axis([0,10,0,10])
#plt.setp(lines, color= "b")

canvas = FigureCanvasTkAgg(figure, app_screen)
canvas.get_tk_widget().pack(side=TOP, anchor =NW, padx=100, pady=10)

newAnimation = liveGraph(figure)

app_screen.mainloop()  # start the GUI

Solution

  • You should use self.ax. to add elements

        self.ax.set_xlabel('teeeest')
        self.ax.set_title('Graph test')
        self.ax.set_xlabel("Time")
        self.ax.set_ylabel("% SMS")
    

    but then there is other problem because self.ax.clear() removes these elements.


    First method:

    If you use self.ax.clear() then you remove labels and you have to put labels again and again

    def animate(self, i):
    
        self.xs.append(self.xax)
        #self.ys.append(datetime.datetime.now().second)
        self.ys.append(random.randint(0, 10))
        self.xax += 1
    
        self.ax.clear()
        self.ax.plot(self.xs,self.ys)
        if self.xax > 90:
            self.anim.event_source.stop()
    
        self.ax.set_xlabel('teeeest')
        self.ax.set_title('Graph test')
        self.ax.set_xlabel("Time")
        self.ax.set_ylabel("% SMS")
    

    Second method:

    To add elements only once you have to remove self.ax.clear() and instead of plot() you should create empty plot in `init

        self.ax = fig.add_subplot(111)
        self.ax.set_xlabel('teeeest')
        self.ax.set_title('Graph test')
        self.ax.set_xlabel("Time")
        self.ax.set_ylabel("% SMS")
    
        self.line, = self.ax.plot([], [])
    

    and in animation use set_data() to update data in existing plot

        self.line.set_data(self.xs, self.ys)
    

    but it will not rescale plot and you will have to do it manually (if you want to rescale it)

        self.ax.relim()  # recalculate limits
        self.ax.autoscale_view(True,True,True)  # rescale using limits
    

    Full code for first method

    import matplotlib.animation as animation
    import datetime
    import random
    #this is a draft for the liveGraph class
    #the objective is to get live data from a sensor 
    
    class liveGraph:
    
        #by default define the interval as being 1000 mSec
        intervalAnim = 1000
    
        def __init__(self, fig):
            self.xax = 0
            self.xs = []
            self.ys = []
    
            self.ax = fig.add_subplot(111)
            self.ax.set_xlabel('teeeest')
    
            self.anim = animation.FuncAnimation(fig, self.animate, interval=self.intervalAnim)
    
        def animate(self, i):
    
            self.xs.append(self.xax)
            #self.ys.append(datetime.datetime.now().second)
            self.ys.append(random.randint(0, 10))
            self.xax += 1
    
            self.ax.clear()
            self.ax.plot(self.xs,self.ys)
            if self.xax > 90:
                self.anim.event_source.stop()
    
            self.ax.set_title('Graph test')
            self.ax.set_xlabel("Time")
            self.ax.set_ylabel("% SMS")
    
    from tkinter import *
    from matplotlib import style
    import matplotlib.pyplot as plt
    from matplotlib.figure import Figure
    from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
    #from livegraph import liveGraph
    
    # Define the main_screen as a tkinter
    app_screen = Tk()  # create a GUI window
    app_screen.geometry("1920x1080")  # set the configuration of GUI window
    app_screen.resizable(width=True, height=True)
    app_screen.title("Testare izolator")  # set the title of GUI window
    
    style.use('bmh')
    
    #figure represents the graphic part of the system
    figure = Figure(figsize=(10, 5), facecolor='white', frameon=True)
    figure.suptitle('This is the figure title', fontsize=12)
    #figure.add_gridspec(10,10)
    
    #this are some parameters that I can easily change if I am using plt
    #plt.title('Graph test')
    #plt.xlabel("Time")
    #plt.ylabel("% SMS")
    
    
    #x = [ 0, 1, 2, 3, 4 ]
    #y = [ 0, 1, 2, 3, 4 ]
    #lines = plt.plot(x, y)
    #plt.grid()
    #plt.axis([0,10,0,10])
    #plt.setp(lines, color= "b")
    
    canvas = FigureCanvasTkAgg(figure, app_screen)
    canvas.get_tk_widget().pack(side=TOP, anchor=NW, padx=100, pady=10)
    
    newAnimation = liveGraph(figure)
    
    #canvas.draw()
    
    app_screen.mainloop()  # start the GUI
    

    Full code for second method

    import matplotlib.animation as animation
    import datetime
    import random
    #this is a draft for the liveGraph class
    #the objective is to get live data from a sensor 
    
    class liveGraph:
    
        #by default define the interval as being 1000 mSec
        intervalAnim = 1000
    
        def __init__(self, fig):
            self.xax = 0
            self.xs = []
            self.ys = []
    
            self.ax = fig.add_subplot(111)
            self.ax.set_xlabel('teeeest')
            self.ax.set_title('Graph test')
            self.ax.set_xlabel("Time")
            self.ax.set_ylabel("% SMS")
    
            # create empty plot at start    
            self.line, = self.ax.plot([], [])
    
            self.anim = animation.FuncAnimation(fig, self.animate, interval=self.intervalAnim)
    
        def animate(self, i):
    
            self.xs.append(self.xax)
            #self.ys.append(datetime.datetime.now().second)
            self.ys.append(random.randint(0, 2))
            self.xax += 1
    
            # update data in existing plot
            self.line.set_data(self.xs, self.ys)
    
            # rescale plot (if you need it)
            self.ax.relim()  # recalculate limits
            self.ax.autoscale_view(True,True,True)  # rescale using limits
    
            if self.xax > 90:
                self.anim.event_source.stop()
    
    from tkinter import *
    from matplotlib import style
    import matplotlib.pyplot as plt
    from matplotlib.figure import Figure
    from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
    #from livegraph import liveGraph
    
    # Define the main_screen as a tkinter
    app_screen = Tk()  # create a GUI window
    app_screen.geometry("1920x1080")  # set the configuration of GUI window
    app_screen.resizable(width=True, height=True)
    app_screen.title("Testare izolator")  # set the title of GUI window
    
    style.use('bmh')
    
    #figure represents the graphic part of the system
    figure = Figure(figsize=(10, 5), facecolor='white', frameon=True)
    figure.suptitle('This is the figure title', fontsize=12)
    #figure.add_gridspec(10,10)
    
    #this are some parameters that I can easily change if I am using plt
    #plt.title('Graph test')
    #plt.xlabel("Time")
    #plt.ylabel("% SMS")
    
    
    #x = [ 0, 1, 2, 3, 4 ]
    #y = [ 0, 1, 2, 3, 4 ]
    #lines = plt.plot(x, y)
    #plt.grid()
    #plt.axis([0,10,0,10])
    #plt.setp(lines, color= "b")
    
    canvas = FigureCanvasTkAgg(figure, app_screen)
    canvas.get_tk_widget().pack(side=TOP, anchor=NW, padx=100, pady=10)
    
    newAnimation = liveGraph(figure)
    
    #canvas.draw()
    
    app_screen.mainloop()  # start the GUI