Home > Back-end >  Not sure why my Pyplot subplot wont update over time
Not sure why my Pyplot subplot wont update over time

Time:01-18

I am working on a project that requires me to log data over time, while also plotting the data on screen with a live line graph. I have gotten everything but the line graph to work this far and am unsure what I am doing incorrectly. This is the imports that I am currently using.

import matplotlib 
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import matplotlib.animation as animation
from matplotlib import pyplot as plt
from matplotlib import style
from tkinter import *
from PIL import Image
import numpy as np
import serial
from serial import Serial
import sqlite3
import time
from datetime import datetime
from array import *
import cv2
from pathlib import Path
from itertools import count

The data that is meant to be used for the Y axis plotting is stored in an array of data. Each index in this array is to hold the last read value from the sensors, i=0 is sensor 1 and so on.

A=[0,0,0,0,0,0,0,0]

This is the definition of the subplot that I am trying to draw to. I think I am setting this up correctly, however I am not getting the expected result so likely not.

fig1 = plt.Figure(dpi=100, facecolor="#f0f0f0")
a = fig1.add_subplot(111)
a.patch.set_facecolor("#f0f0f0")


a.set_xlabel('time (Sec)')
a.set_ylabel('pressure(kPa)')
a.set_ylim(0,100)
a.set_xlim(0,30)

graph1 = FigureCanvasTkAgg(fig1, master=root)
graph1.get_tk_widget().place(x=10, y=220, width=210, height=280)
graph1.draw();

I am currently just trying to get one of the lines to draw first before handling the, seemingly, minor issue that is overlapping multiple lines. This is the function that I am trying to use in order to draw said line.

def graph_plotdata():
    global A
    global a
    line1 = []
    time = []
    
    time.append(next(index))
    line1.append(A[0])
    
    a.cla()
    a.plot(time, line1)
        
    graph1.draw()

I have tried several itterations of this code in order attempt to solve this problem. The closest I have to getting it to work is in the current state in which something is happening however instead of keeping my min and max limits on the graph it completely reformats my plot and plots an "invisible" line.

Before starting: interface program

After starting: interface reformatted

I am not overwhelmingly experienced when is comes to python libraries so bare with me.

CodePudding user response:

I use a dictionary to store the various lines and line plots and then update the plots using set_data(xdata, ydata). I'm not sure how your datastream works, so mine just updates when I push the update button and generates a random reading. You'll obviously want to change those parts to match your data input.

fig, ax = plt.subplots(1, 1)

plt.subplots_adjust(bottom = 0.20)

num_sensors = 10

latest_reading = [0]*num_sensors

lines = {index: [0] for index in range(num_sensors)}

times = [0]

line_plots = {index: ax.plot(lines[index])[0] for index in range(num_sensors)}

btn_ax = plt.axes([0.475, 0.05, 0.10, 0.05])

def update(event):
    
    latest_reading = np.random.randint(0, 10, num_sensors)
    
    times.append(times[-1]   1)
    
    for index in range(num_sensors):
        lines[index].append(latest_reading[index])
        
        line_plots[index].set_data(times, lines[index])
        
    # Adjust limits
    
    max_time_window = 20
    
    ax.set_xlim(max(0, max(times)-max_time_window), max(times))
    ax.set_ylim(0, max(lines))
    
    plt.draw()
    

btn = mpl.widgets.Button(btn_ax, 'Update')

btn.on_clicked(update)

CodePudding user response:

Thank you for the response.

I figured out the issue, it had nothing to do with my matplotlib/tkinter implementation. I just totally missed that I had a scope inheritance issue. The lists of 'time' and 'line1' are not persistent in the entire scope and therefore being rewritten to empty lists every time the 'graph_plotdata()' function is called.

my solution is as follows:

timet = []
line1 = []

"""----------Graph Updater-----------"""
def graph_plotdata():
    global B
    global a
    global graph1
    global timet
    global line1

    timet.append(next(index))
    line1.append(B[0])
    
    a.clear()
    a.plot(timet, line1)
    a.patch.set_facecolor("#f0f0f0")
    a.set_xlabel('time (Sec)')
    a.set_ylabel('pressure(kPa)')
    a.set_ylim(0,30)
    a.set_xlim(0,30)
    
    graph1.draw()

Hopefully this helps people in the future running into a similar issue!

  • Related