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.
There are better ways to do this using thematplotlib 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:
plt.ion()
.plot
again.plt.pause
.I included the code to autoscale the viewport, but that's not strictly necessary.
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.
Another solution is to redraw the plot from scratch. Surely it's slower than updating it point by point, but if you have not many points, the overhead is negligible.
from IPython import display
def dynamic_plot(X,Y, figsize=[10,5], max_x=None, min_y=None, max_y=None):
'''plots dependency between X and Y dynamically: after each call current graph is redrawn'''
gcf().set_size_inches(figsize)
cla()
plot(X,Y)
if max_x:
plt.gca().set_xlim(right=max_x)
if min_y:
plt.gca().set_ylim(bottom=min_y)
if max_y:
plt.gca().set_ylim(top=max_y)
display.display(gcf())
display.clear_output(wait=True)
And the demo use for jupyter notebook:
import time
X=[]
Y=[]
for i in range(10):
X.append(i)
Y.append(i**.5)
dynamic_plot(X,Y,[14,10], max_x=10, max_y=4)
time.sleep(0.3)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.