plotting dynamic data using matplotlib
Solution 1
There are better ways to do this using the matplotlib animation API, but here's a quick and dirty approach:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0, 10, 0.1)
y = np.sin(x)
plt.ion()
ax = plt.gca()
ax.set_autoscale_on(True)
line, = ax.plot(x, y)
for i in xrange(100):
line.set_ydata(y)
ax.relim()
ax.autoscale_view(True,True,True)
plt.draw()
y=y*1.1
plt.pause(0.1)
The key steps are:
- Turn on interactive mode with
plt.ion()
. - Keep track of the line(s) you want to update, and overwrite their data instead of calling
plot
again. - Give Python some time to update the plot window by calling
plt.pause
.
I included the code to autoscale the viewport, but that's not strictly necessary.
Solution 2
Is it hard to apply animated
? How about using thread
that updates the figure.
Even though plt.show()
is blocking, the thread
will update the figure.
import numpy as np
import matplotlib.pyplot as plt
import time
import threading
def update(x, y):
for i in xrange(100):
# clear
plt.clf()
plt.plot(x, y)
# draw figure
plt.draw()
time.sleep(1)
y=y*1.1
x = np.arange(0, 10, 0.1);
y = np.sin(x)
plt.plot(x, y)
# use thread
t = threading.Thread(target=update, args=(x, y))
t.start()
plt.show() # blocking but thread will update figure.
user3515666
Updated on June 04, 2022Comments
-
user3515666 almost 2 years
I'm writing an application do display data that changes dynamically (the data being read from a socket).
As a dummy case, I try to draw a sine with an amplitude multiplied by 1.1 each second:
import numpy as np import matplotlib.pyplot as plt import time x = np.arange(0, 10, 0.1); y = np.sin(x) for i in xrange(100): plt.plot(x, y) time.sleep(1) y=y*1.1
This obviously not the way do it, but it shows my intentions.
How can it be done correctly?
EDIT: The following is the traceback output of the code suggested in @mskimm answer:
plt.show() #Exception in thread Thread-2: Traceback (most recent call last): File "/usr/lib/python2.7/threading.py", line 552, in __bootstrap_inner self.run() File "/usr/lib/python2.7/threading.py", line 505, in run self.__target(*self.__args, **self.__kwargs) File "<ipython-input-5-ed773f8e3e84>", line 7, in update plt.draw() File "/usr/lib/pymodules/python2.7/matplotlib/pyplot.py", line 466, in draw get_current_fig_manager().canvas.draw() File "/usr/lib/pymodules/python2.7/matplotlib/backends/backend_tkagg.py", line 240, in draw tkagg.blit(self._tkphoto, self.renderer._renderer, colormode=2) File "/usr/lib/pymodules/python2.7/matplotlib/backends/tkagg.py", line 12, in blit tk.call("PyAggImagePhoto", photoimage, id(aggimage), colormode, id(bbox_array)) RuntimeError: main thread is not in main loop
EDIT 2:
it turns out that same code works when run in qtconsole... (any idea why?) How ever, each print rescaling to plot, so the "animation effect" is missing. I try to use
plt.autoscale_view(False,False,False)
but that just caused no plot at all. -
user3515666 about 10 yearsThis code throws an exception (within the new thread). A traceback added to my original post. @mskimm
-
user3515666 about 10 yearswhen removing the autoscale - it's just what I was looking for, thanks, and have my virtual +1 :)
-
emeth about 10 years+1, This is much better. Because I didn't know
ion
, I implemented several programs usingthread
.