Plotting two graphs in real time with wx and matplotlib

49 views Asked by At

I want to plot the data from a sensor in real time to two figures (simultaneously) using wx and matplotlib (data is coming through Arduino Serial). I have been able to plot the data on the second plot, but not in the first one, as it can be checked in this screenshot:

enter image description here

I am using wx.boxsizer to create 3 parts in the window (function Initbody), where the second and the third parts are for each graph. Then the function InitMPL calls to matplotlib. Finally I use a thread to call to the animation for the graph plotting. Find here the full code:

import wx
import numpy as np
import matplotlib.figure as mfigure
import matplotlib.animation as manim
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg
import serial.tools.list_ports
import threading
import data
import gui
import read_serial
import data_proc as dproc

class FlowBattGUI(wx.Frame):
    def __init__(self, data_queue=None, parent=None):
        super().__init__(None, style=wx.MAXIMIZE_BOX | wx.RESIZE_BORDER 
                         | wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX, title='Flow Battery Gui')

        creds = sheets.verify_and_cred()
        self.service = sheets.build('sheets', 'v4', credentials=creds)

        self.data_queue = data_queue

        self.InitGUI()

    def InitGUI(self):

        self.SetSize(1800, 1000)
        self.Center()

        self.InitMenu()

        panel = wx.Panel(self)
        
        self.InitBody(panel)

# Initalize the main GUI components
def InitBody(self, panel : wx.Panel):

    body_sizer = wx.BoxSizer(wx.VERTICAL)

    CtrlPanelsizer = wx.BoxSizer(wx.HORIZONTAL)
    self.InitCtrlPanel(panel, CtrlPanelsizer)
    body_sizer.Add(CtrlPanelsizer, 0, wx.EXPAND)

    ocvsizer = wx.BoxSizer(wx.HORIZONTAL)
    l1 = wx.StaticText(panel,label = "OCV vs time", style = wx.ALIGN_CENTRE)
    body_sizer.Add(l1, 0,  wx.ALIGN_CENTER_HORIZONTAL, 20)
    self.InitMPL(panel, ocvsizer)
    body_sizer.Add(ocvsizer, 1, wx.EXPAND)

    m2sizer = wx.BoxSizer(wx.HORIZONTAL)
    l2 = wx.StaticText(panel,label = "Derivative vs time", style = wx.ALIGN_CENTRE)
    body_sizer.Add(l2, 0,  wx.ALIGN_CENTER_HORIZONTAL, 20)
    self.InitMPL(panel, m2sizer)
    body_sizer.Add(m2sizer, 1, wx.EXPAND)

    bsizer = wx.BoxSizer(wx.HORIZONTAL)
    self.InitCmdPanel(panel, bsizer)
    body_sizer.Add(bsizer, 0, wx.EXPAND, 5)

    panel.SetSizer(body_sizer)

# Initialize the MatPlotLib section
def InitMPL(self, panel : wx.Panel, sizer : wx.BoxSizer):
    
    self.fig = mfigure.Figure()
    self.ax = self.fig.subplots()   
    
    self.fig.set_figheight(2)

    self.canv = FigureCanvasWxAgg(panel, wx.ID_ANY, self.fig)
    self.times = []
    self.values = []
    self.animator = manim.FuncAnimation(self.fig, self.anim, interval=600)

    sizer.Add(self.canv, 1, wx.ALL | wx.EXPAND, 5)
    
def anim(self,i):
    if self.data_queue == None:
        # this is to setup the data queue
        if i != 0:
            self.values.append(np.random.rand())
        else:
            self.values = []
            return
        self.ax.clear()
        self.ax.plot(np.arange(1,i+1), self.values, 'd-')
    else: 
        # data queue is already set up 
        new_data = None
        if i != 0:
            if len(self.times) == 60:
                # clear data after 60 points
                self.values = []
                self.times = []

            # should be of type SensorData
            if not self.data_queue:
                return
            new_data = self.data_queue.pop(0)
            if new_data == None:
                return
            if new_data.data == None or new_data.time == None:
                return

            self.values.append(float(new_data.data))
            self.times.append(float(new_data.time))
        else:
            self.values = []
            return
        self.ax.clear()

        self.ax.plot(np.arange(1,len(self.values)+1), self.values, 'd-')

        t = threading.Thread(target=self.writeData, args=[new_data])
        t.start()

def writeData(self, new_data):
    sheets.append_range(self.service, new_data, "Sheet1!A2")
    data.append_data(new_data.encstr)

def start_gui(data_queue : list):

    print(data_queue)

    # Create a new app in wx
    app = wx.App()
    frame = FlowBattGUI(data_queue, None)
    frame.Show(True)
    app.MainLoop()

Is this possible?

0

There are 0 answers