D.j.
D.j.

Reputation: 3

Plot doesn't refresh to plot new points when using matplotlib

I'm trying to create a plot that updates when given a set of points ([x,y]) but the figure gets stuck on the first plot points and won't plot the rest of the data. I looped a function call but it gets stuck on the first call. I need to be able to give the function multiple sets of single x and y values, and have them plot in a graph.

This is the code I have so far.

import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib import style
from numpy import *
from time import sleep
import random as rd

class graphUpdater():

    def __init__(self):
        # Initialize arrays to be plotted
        self.xs = []
        self.ys = []

        style.use('fivethirtyeight') # Figure Style
        self.fig = plt.figure() # Initialize figure
        self.ax1 = self.fig.add_subplot(111) # Create a subplot
        # Ensure the figure auto-scales to fit all points. Might be overkill
        self.ax1.set_autoscalex_on(True)
        self.ax1.set_autoscaley_on(True)
        self.ax1.set_autoscale_on(True)
        self.ax1.autoscale(enable = True, axis = 'both', tight = False)
        self.ax1.autoscale_view(False, True, True)

    # Function that plots the arrays xs and ys. Also plots a linear regression of the data
    def plotPoint(self):
        self.ax1.clear() # Clears previous values to save memory
        xp = linspace(min(self.xs), max(self.xs)) # x-range for regression
        if(len(self.xs) > 1): # Conditional for regression, can't linearise 1 point
            p1 = polyfit(self.xs, self.ys, 1) # Get the coefficients of the polynomial (slope of line)
            self.ax1.plot(xp, polyval(p1, xp)) # Plot the line
        self.ax1.plot(self.xs, self.ys, "+") # Plot the raw data points
        self.ax1.set_xlabel('(L/A)*I') # Axis and title labels
        self.ax1.set_ylabel('V')
        self.ax1.set_title('DC Potential Drop')

    def appendPlot(self, x, y):
        self.xs.append(float(x)) # Append xs with x value
        self.ys.append(float(y)) # Append ys with y value
        self.plotPoint() # Call the plotPoint function to plot new array values
        plt.show(block=False) # Plot and release so graphs can be over written

# Call the function
plsWork = graphUpdater() # I'm very hopeful
i = 0
while(i < 50):
    plsWork.appendPlot(i, rd.randint(0, 20))
    i += 1
    sleep(0.1)
quit_case = input("Hit 'Enter' to Quit") # Conditional so the plot won't disappear

It doesn't work fully. If you put a breakpoint on the quit_case line and run it on debugger on pycharm it plots the graph "properly".

Upvotes: 0

Views: 693

Answers (1)

ImportanceOfBeingErnest
ImportanceOfBeingErnest

Reputation: 339120

Don't use plt.show(block=False) and don't use time.sleep. Instead, matplotlib provides an animation module, which can be used to avoid such problems as here.

import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib import style
from numpy import *
from time import sleep
import random as rd
#%matplotlib notebook use in case of running this in a Jupyter notebook

class graphUpdater():

    def __init__(self):
        # Initialize arrays to be plotted
        self.xs = []
        self.ys = []

        style.use('fivethirtyeight') # Figure Style
        self.fig = plt.figure() # Initialize figure
        self.ax1 = self.fig.add_subplot(111) # Create a subplot
        # Ensure the figure auto-scales to fit all points. Might be overkill
        self.ax1.set_autoscalex_on(True)
        self.ax1.set_autoscaley_on(True)
        self.ax1.set_autoscale_on(True)
        self.ax1.autoscale(enable = True, axis = 'both', tight = False)
        self.ax1.autoscale_view(False, True, True)

    # Function that plots the arrays xs and ys. Also plots a linear regression of the data
    def plotPoint(self):
        self.ax1.clear() # Clears previous values to save memory
        xp = linspace(min(self.xs), max(self.xs)) # x-range for regression
        if(len(self.xs) > 1): # Conditional for regression, can't linearise 1 point
            p1 = polyfit(self.xs, self.ys, 1) # Get the coefficients of the polynomial (slope of line)
            self.ax1.plot(xp, polyval(p1, xp)) # Plot the line
        self.ax1.plot(self.xs, self.ys, "+") # Plot the raw data points
        self.ax1.set_xlabel('(L/A)*I') # Axis and title labels
        self.ax1.set_ylabel('V')
        self.ax1.set_title('DC Potential Drop')

    def appendPlot(self, x, y):
        self.xs.append(float(x)) # Append xs with x value
        self.ys.append(float(y)) # Append ys with y value
        self.plotPoint() # Call the plotPoint function to plot new array values

# Call the function
plsWork = graphUpdater() # I'm very hopeful

f = lambda i: plsWork.appendPlot(i, rd.randint(0, 20))

ani = animation.FuncAnimation(plsWork.fig, f, frames=50, interval=100, repeat=False)
plt.show()

Upvotes: 1

Related Questions