5

I'm trying to monitor real-time data with matplotlib.

I found that I can update plot dynamically with interactive mode in Pyplot.

And it worked well, but one problem is 'I cannot manipulate the figure window at all'. For example, move or re-size the figure window.

Here is my code.

This is cons of interactive mode? or I'm using it incorrectly?

import matplotlib.pyplot as plt
import time
import math

# generate data
x = [0.1*_a for _a in range(1000)]
y = map(lambda x : math.sin(x), x)

# interactive mode
plt.ion() # identical plt.interactive(True)

fig, ax = plt.subplots()
# ax = plt.gca()
lines,  = ax.plot([], [])

# ax.set_ylim(-1, 1)
ax.grid()

MAX_N_DATA = 100
x_data = []
y_data = []
for i in range(len(x)):
    # New data received
    x_data.append(x[i])
    y_data.append(y[i])

    # limit data length
    if x_data.__len__() > MAX_N_DATA:
        x_data.pop(0)
        y_data.pop(0)

    # Set Data
    lines.set_xdata(x_data)
    lines.set_ydata(y_data)

    # The data limits are not updated automatically.
    ax.relim()
    # with tight True, graph flows smoothly.
    ax.autoscale_view(tight=True, scalex=True, scaley=True)

    # draw
    plt.draw()
    time.sleep(0.01)

Thank you.

JaeJun LEE
  • 1,234
  • 3
  • 11
  • 27
  • 1
    matplotlib is not so great for realtime visualisation... I'd suggest to check out [bokeh](http://bokeh.pydata.org/en/latest/) – swenzel Jul 29 '15 at 12:09

2 Answers2

1

As shown in this answer to another question, replace plt.draw() with plt.pause(0.05). This solved the problem for me.

Community
  • 1
  • 1
luator
  • 4,769
  • 3
  • 30
  • 51
0

Although I still think you should use bokeh, I'll tell you how to do it with matplotlib.

The problem why it won't work ist that matplotlib's event loop is not active and therefore it cannot digest window events (like close or resize). Unfortunately it is not possible to trigger this digestion from the outside. What you have to do is to use matplotlib's animation system.
Your code is actually quite well prepared for it so you can use FuncAnimation.

import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import math

# generate data
x = [0.1*_a for _a in range(1000)]
y = map(lambda x : math.sin(x), x)

# don't need ion, we're using block=True (see end of code)

fig, ax = plt.subplots()
fig.show()
# ax = plt.gca()
lines,  = ax.plot([], [])

# ax.set_ylim(-1, 1)
ax.grid()

MAX_N_DATA = 100
x_data = []
y_data = []

def showdata(i):

    # New data received
    x_data.append(x[i])
    y_data.append(y[i])

    # limit data length
    if x_data.__len__() > MAX_N_DATA:
        x_data.pop(0)
        y_data.pop(0)

    # Set Data
    lines.set_xdata(x_data)
    lines.set_ydata(y_data)

    # The data limits are not updated automatically.
    ax.relim()
    # with tight True, graph flows smoothly.
    ax.autoscale_view(tight=True, scalex=True, scaley=True)

    # draw will be called by the animation system

# instead of time.sleep(0.01) we use an update interval of 10ms
# which has the same effect
anim = FuncAnimation(fig, showdata, range(len(x)), interval=10, repeat=False)

# start eventloop
plt.show(block=True)
swenzel
  • 6,745
  • 3
  • 23
  • 37
  • Thanks. But it seems that this workaround does not work for me. As I mentioned, I have to plot **real-time** data. So I don't have a complete set of data to be plotted when I call the `draw` or `show`. Rather it is accumulated over time and **plotted on the fly**. – JaeJun LEE Jul 29 '15 at 13:37
  • I will check bokeh. Thanks :D – JaeJun LEE Jul 29 '15 at 13:38
  • @JaeJunLEE sorry totally forgot about this :D Well, the third parameter `range(len(x))` can be a generator that produces the data for `showdata`. If this generator takes the data from a queue or some other buffer that is filled with results from your real computation, then you will get what you need. You can also have a look at [the code](https://gist.github.com/swenzel/e18e3c991b4349c6bcb6) for my realtime spike plot. It uses multiprocessing to avoid matplotlibs main-thread-only problem. It should run with the random example when you uncomment `import nest`. – swenzel Sep 02 '15 at 10:28