Reputation: 1734
I have a question concerning updating dynamically scatter plots from matplotlib. I have the following class in Python
''' PolygonHandler.py - Python source for polygon handling '''
import numpy as np
import matplotlib.pyplot as plt
class PolygonHandler:
# Constructor
def __init__(self):
self.X = []
self.Y = []
self.numberPoints = 0
# Print the polygon
def draw(self):
plt.scatter(self.X,self.Y)
plt.draw()
def update(self):
for i in range(1,self.numberPoints):
self.X[i] += np.random.normal()*0.01
self.Y[i] += np.random.normal()*0.01
# append a point
def add(self,x,y):
self.numberPoints += 1
self.X.append(x)
self.Y.append(y)
This class is used in a real time loop that receives information and adds the points to the PolygonHandler class. Now for the purpose of an example, I want to design the following loop
P = PolygonHandler()
P.add(1,1)
P.add(2,2)
P.add(1,2)
plt.ion()
plt.show()
while (True):
P.draw()
P.update()
How can I tell the interpreter to draw the scatter plots, and once done to remove the former points after updating ? Right now, my plot draws the points and all their previous positions.
Vincent
Thanks a lot for your help
PS : An other problem I have is that the window that is opened by matplotlib freezes and stops answering as soon as I clicked on it (for example to move it to another place on my screen), is there a way to prevent that ?
Upvotes: 3
Views: 3046
Reputation: 1911
you can do it like this. It accepts x,y as list and output a scatter plot plus a linear trend on the same plot.
from IPython.display import clear_output
from matplotlib import pyplot as plt
%matplotlib inline
def live_plot(x, y, figsize=(7,5), title=''):
clear_output(wait=True)
plt.figure(figsize=figsize)
plt.xlim(0, training_steps)
plt.ylim(0, 100)
x= [float(i) for i in x]
y= [float(i) for i in y]
if len(x) > 1:
plt.scatter(x,y, label='axis y', color='k')
m, b = np.polyfit(x, y, 1)
plt.plot(x, [x * m for x in x] + b)
plt.title(title)
plt.grid(True)
plt.xlabel('axis x')
plt.ylabel('axis y')
plt.show();
you just need to call live_plot(x, y)
inside a loop. here's how it looks:
Upvotes: 0
Reputation: 22671
Here you have one way to go, using animations from matplotlib.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
class PolygonHandler:
# Constructor
def __init__(self):
self.X = []
self.Y = []
self.numberPoints = 0
self.fig , ax = plt.subplots()
self.sc = ax.scatter(self.X,self.Y)
ax.set_xlim(0,3)
ax.set_ylim(0,3)
# Print the polygon
def update(self,_):
for i in range(self.numberPoints):
self.X[i] += np.random.normal()*0.01
self.Y[i] += np.random.normal()*0.01
self.sc.set_offsets(np.column_stack((self.X,self.Y)))
return self.sc,
# append a point
def add(self,x,y):
self.numberPoints += 1
self.X.append(x)
self.Y.append(y)
And this way you plot your 3 random walks:
P = PolygonHandler()
P.add(1,1)
P.add(2,2)
P.add(1,2)
ani = animation.FuncAnimation(P.fig, P.update, interval=10,blit=False)
the key element is the method set_offsets()
, that substitutes the data of the scatter plot. Then such scatter object is returned by update()
, so that matplotlib knows that it must be updated. For another source with a matplotlib animation handled by a class, see this matplotlib example.
With blit=True in the last line the animation is faster, but depending on your OS it may not work.
Upvotes: 1