plotting dynamic data using matplotlib

13,821

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:

  1. Turn on interactive mode with plt.ion().
  2. Keep track of the line(s) you want to update, and overwrite their data instead of calling plot again.
  3. 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.
Share:
13,821
user3515666
Author by

user3515666

Updated on June 04, 2022

Comments

  • user3515666
    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
    user3515666 about 10 years
    This code throws an exception (within the new thread). A traceback added to my original post. @mskimm
  • user3515666
    user3515666 about 10 years
    when removing the autoscale - it's just what I was looking for, thanks, and have my virtual +1 :)
  • emeth
    emeth about 10 years
    +1, This is much better. Because I didn't know ion, I implemented several programs using thread.