Progressively append and plot new data to a matplotlib line

Viewed 2474

Question

What is the way to append data to an existing matplotlib line and plot only the added portion of the line without redrawing the whole line?

Comments

Following is a simple code that plots the redraw time vs. the number of times we append a portion of data to the line.

You see the redraw time increases nearly linearly with the total size of data in the line. This points to the fact that the whole line is redrawn. I'm looking for a way to plot only a new portion of the line. In this case, the redraw time is expected to be nearly constant for the code below.

import matplotlib.pyplot as plt
import numpy as np
import time

# User input
N_chunk = 10000
N_iter = 100

# Prepare data
xx = list(range(N_chunk))
yy = np.random.rand(N_chunk).tolist()

# Prepare plot
fig, ax = plt.subplots()
ax.set_xlim([0,N_chunk])  # observe only the first chunk
line, = ax.plot(xx,yy,'-o')
fig.show()

# Appending data and redraw
dts = []
for i in range(N_iter):
    t0 = time.time()
    xs = xx[-1]+1
    xx.extend(list(range(xs,xs+N_chunk)))
    yy.extend(np.random.rand(N_chunk).tolist())
    line.set_data(xx,yy)
    fig.canvas.draw()
    dt = time.time() - t0
    dts.append(dt)
    plt.pause(1e-10)
plt.close()

# Plot the time spent for every redraw
plt.plot(list(range(N_iter)), dts, '-o')
plt.xlabel('Number of times a portion is added')
plt.ylabel('Redraw time [sec]')
plt.grid()
plt.show()

Redraw time depending on the data size

1 Answers

Here's a modified version of your code that makes use of matplotlib's interactive mode.

import matplotlib.pyplot as plt
import numpy as np
import time

# User input
N_chunk = 10000
N_iter = 100

# Prepare data
xx = np.arange(N_chunk)
yy = np.random.rand(N_chunk)

# Prepare plot
fig, ax = plt.subplots()
#ax.set_xlim([0,N_chunk])  # observe only the first chunk
line = ax.plot(xx,yy,'-o')
plt.ion()   # set interactive mode
fig.show()

# Appending data
dts = []
for i in range(N_iter):
    t0 = time.time()
    xs = xx[-1]+1
    xx=np.arange(xs,xs+N_chunk)
    yy=np.random.rand(N_chunk)
    line=ax.plot(xx,yy,'-o')
    fig.canvas.draw()
    dt = time.time() - t0
    dts.append(dt)
    plt.pause(1e-10)
plt.close()

# Plot the time spent for every redraw
plt.plot(range(N_iter), dts, '-o')
plt.xlabel('Number of times a portion is added')
plt.ylabel('Redraw time [sec]')
plt.grid()
plt.show() 

With ax.set_xlim uncommented the redraw times are:

Redraw times

On the other hand, with ax.set_xlim commented:

Redrawtimes

Clearly, calling fig.canvas.draw() redraws everything. In your case, by commenting ax.set_xlim([0,N_chunk]) you are redrawing things like the axes boundaries, tick labels, etc. You want to explore blitting as discussed in this SO to avoid redrawing axes objects.

Related