0

I am trying to animate a live graph in a wx.Panel. I would like to have the x-axis update like this example. Many of the examples I see are basic and don't take into consideration other controls and functions in the class. Others have so many extras that I get lost in the weeds. I can't get the animation command in the right place or update the x-axis. Here is the code:

import wx
import logging
import numpy as np
import matplotlib
import time
import matplotlib.animation as animation

matplotlib.use('WXAgg')

import matplotlib.pyplot as plt

from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
from matplotlib.backends.backend_wx import NavigationToolbar2Wx
from matplotlib.figure import Figure

fTemp = ""
x = 0

class TempClass(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1, title="", size=(600,500))
        panel = wx.Panel(self)

        self.fig = Figure(figsize=(6,4), dpi=75, facecolor='lightskyblue', edgecolor='r')
        self.canvas = FigureCanvas(self, -1, self.fig)
        self.ax = self.fig.add_subplot(111)

        self.ax2 = self.ax.twinx()
        self.ax.set_ylim(60,90)
        self.ax.set_xlim(0,24)
        self.ax2.set_ylim(0,100)

        # major ticks every 5, minor ticks every 1                                      
        xmajor_ticks = np.arange(0, 24, 5)                                              
        xminor_ticks = np.arange(0, 24, 1)                                               

        self.ax.set_xticks(xmajor_ticks)                                                       
        self.ax.set_xticks(xminor_ticks, minor=True)                                           
        self.ax.grid()  

        self.ax.set_xlabel('Hour')
        self.ax.set_ylabel('Temp')
        self.ax2.set_ylabel('Humidity')
        self.ax.set_title('Temperature')

        # The graph does not show in the panel when this in uncommented
        #self.ani = animation.FuncAnimation(self.fig, self.onPlotTemp, interval=1000)

        self.fanSensorTimer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.onPlotTemp, self.fanSensorTimer)

        self.fanSensorBtn = wx.Button(self, -1, "Start Sensor")
        self.Bind(wx.EVT_BUTTON, self.onStartTempPlot, self.fanSensorBtn)

        font1 = wx.Font(18, wx.DEFAULT,wx.NORMAL,wx.BOLD)
        self.displayTemp = wx.StaticText(self, -1, "Current Tempurature")
        self.curTempTxt = wx.TextCtrl(self, -1, "0",size=(100,40), style=wx.TE_READONLY|wx.TE_CENTRE|wx.BORDER_NONE)
        self.curTempTxt.SetFont(font1)
        self.displayHum = wx.StaticText(self, -1, "Current Humidity")
        self.curHumTxt = wx.TextCtrl(self, -1,"0", size=(100,40), style=wx.TE_READONLY|wx.TE_CENTRE|wx.BORDER_NONE)
        self.curHumTxt.SetFont(font1)

        self.displayBox = wx.GridBagSizer(hgap=5,vgap=5)
        self.displayBox.Add(self.displayTemp, pos=(0,0), flag=wx.TOP|wx.LEFT, border=5)
        self.displayBox.Add(self.displayHum, pos=(0,1), flag=wx.TOP, border=5)
        self.displayBox.Add(self.curTempTxt, pos=(1,0), flag=wx.ALL, border=5)
        self.displayBox.Add(self.curHumTxt, pos=(1,1), flag=wx.ALL, border=5)

#---------
        self.vbox = wx.BoxSizer(wx.VERTICAL)
        self.vbox.Add(self.canvas, wx.ALIGN_CENTER|wx.ALL, 1)
        self.vbox.Add(self.fanSensorBtn)
        self.vbox.Add(self.displayBox, wx.ALIGN_CENTER|wx.ALL, 1)
        self.SetSizer(self.vbox)
        self.vbox.Fit(self)

    def start(self):
        # get temp/humidity reading from node
        pass


    def readTemp(self, data1, data2):
        "Populates Current Temp"
        global fTemp
        self.curTempTxt.Clear()
        a = format(data1, '08b')
        b = format(data2, '08b')
        x = a+b
        y = int(x, base=2)
        cTemp = ((175.72 * y)/65536)-46.85
        fTemp = cTemp *1.8+32
        cel = format(cTemp,'.1f')
        far = format(fTemp,'.1f')
        self.curTempTxt.WriteText(far + (u'\u00b0')+"F")

    def rh1(self, data1, data2):
        "Populates Current RH"
        global relhum
        self.curHumTxt.Clear()
        a = format(data1, '08b')
        b = format(data2, '08b')
        x = a+b
        y = int(x, base=2)
        rh = ((125 * y)/65536)-6
        relhum = format(rh,'.1f')
        self.curHumTxt.WriteText(relhum + " %")


    def onStartTempPlot(self,event):
        #set for a short time period for testing purposes
        self.fanSensorTimer.Start(5000)  
        print "Timer Started"

    def onPlotTemp(self,event):
        global fTemp, x, relhum
        x +=1
        y = int(fTemp)
        y2 = float(relhum)

        self.ax.plot(x,y,'r.')
        self.ax2.plot(x,y2,'k.')

        self.fig.canvas.draw()

        # send message to node for another reading of temp/humidity


if __name__ == "__main__":
    app = wx.App(False)
    frame = TempClass()
    frame.Show()
    frame.start()
    logging.basicConfig(level=logging.DEBUG)
    app.MainLoop()

I would like to see the x axis increment as the data is plotted beyond the 24 hour point on the graph; when data for point 25 appears, the first point is dropped and the x axis shows '25'. The animation is commented out because it causes the graph to disappear until a point is plotted.

Here is a runnable example of what I am trying to achieve with the x axis:

    import numpy
    from matplotlib.pylab import *
    from mpl_toolkits.axes_grid1 import host_subplot
    import matplotlib.animation as animation


    # Sent for figure
    font = {'size'   : 9}
    matplotlib.rc('font', **font)

    # Setup figure and subplots
    f0 = figure(num = 0, figsize = (6, 4))#, dpi = 100)
    f0.suptitle("Oscillation decay", fontsize=12)
    ax01 = subplot2grid((2, 2), (0, 0))

    # Set titles of subplots
    ax01.set_title('Position vs Time')

    # set y-limits
    ax01.set_ylim(0,2)

    # sex x-limits
    ax01.set_xlim(0,1)

    # Turn on grids
    ax01.grid(True)

    # set label names
    ax01.set_xlabel("x")
    ax01.set_ylabel("py")

    # Data Placeholders
    yp1=zeros(0)
    yv1=zeros(0)
    yp2=zeros(0)
    yv2=zeros(0)
    t=zeros(0)

    # set plots
    p011, = ax01.plot(t,yp1,'b-', label="yp1")
    p012, = ax01.plot(t,yp2,'g-', label="yp2")

    # set lagends
    ax01.legend([p011,p012], [p011.get_label(),p012.get_label()])


    # Data Update
    xmin = 0
    xmax = 24
    x = 0

    def updateData(self):
            global x
            global yp1
            global yv1
            global yp2
            global yv2
            global t

            tmpp1 = 1 + exp(-x) *sin(2 * pi * x)
            tmpv1 = - exp(-x) * sin(2 * pi * x) + exp(-x) * cos(2 * pi * x) * 2 * pi
            yp1=append(yp1,tmpp1)
            yv1=append(yv1,tmpv1)
            yp2=append(yp2,0.5*tmpp1)
            yv2=append(yv2,0.5*tmpv1)
            t=append(t,x)

            x += 1

            p011.set_data(t,yp1)
            p012.set_data(t,yp2)

            if x >= xmax-1:
                    p011.axes.set_xlim(x-xmax+1,x+1)

            return p011 

    # interval: draw new frame every 'interval' ms
    # frames: number of frames to draw
    simulation = animation.FuncAnimation(f0, updateData, blit=False, frames=200, interval=20, repeat=False)


    plt.show()
4
  • Try to remove the line self.ax = self.figure.add_subplot(111) from the tempPlot function, otherwise you recreate self.ax in every iteration of the animation. Commented Apr 21, 2017 at 16:25
  • I tried and I couldn't make your suggestion work. I reworked the code some and edited my question. Hopefully the new code will show the problem I am having. Thank you @ImportanceOfBeingErnest Commented Apr 21, 2017 at 19:24
  • Now I am getting "lost in the weeds". Is this the minimal reproducible example that is needed to reproduce the issue? You also don't have a clear problem description. What exactly is the problem you are having? Where is the FuncAnimation gone? Commented Apr 21, 2017 at 19:29
  • I deleted some extra code from the last post and added more detail to my question. I apologize, I can't actually run my code without the sensor. This is my first attempt at an animated graph and my second attempt at using matplotlib. Commented Apr 21, 2017 at 20:23

1 Answer 1

1

You are not incrementing the X axis limit or the ticks.

def onPlotTemp(self,event):
    global fTemp, x, relhum
    x +=1
    y = int(fTemp)
    y2 = float(relhum)
    if x >= 24-1:
            self.ax.set_xlim(x-24+1,x+1)
            xmajor_ticks = np.arange(x-24+1,x+5, 5)
            xminor_ticks = np.arange(x-24+1, x+1,1)
            self.ax.set_xticks(xmajor_ticks)
            self.ax.set_xticks(xminor_ticks, minor=True)

    self.ax.plot(x,y,'r.')
    self.ax2.plot(x,y2,'k.')

    self.fig.canvas.draw()

I'm not sure if the above resets the ticks the way you want them but you get the idea. Obviously I have hard-coded 24 as your limit, you may want to create a variable to sort that out.

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

1 Comment

That did it! Thank you.

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.