Updating x-axis labels in matplotlib animation

2019-02-11 00:09发布

问题:

Here is a toy piece of code that illustrates my problem:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

fig, ax = plt.subplots()
xdata, ydata = [], []
ln, = plt.plot([], [], '-o', animated=True)


def init():
    ax.set_xlim(0, 2*np.pi)
    ax.set_ylim(-1, 1)
    return ln,


def update(frame):
    xdata.append(frame)
    ydata.append(np.sin(frame))
    ln.set_data(xdata, ydata)
    ax.set_xlim(np.amin(xdata), np.amax(xdata))
    return ln,


ani = FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128),
                    init_func=init, blit=True)
plt.show()

If I set blit=True then the data points are plotted just how I want them. However, the x-axis labels/ticks remain static.

If I set blit=False then the x-axis labels and ticks update just how I want them. However, none of the data points are ever plotted.

How can I get both the plotted data (sine curve) and the x-asis data to update"?

回答1:

First concerning blitting: Blitting is only applied to the content of the axes. It will affect the inner part of the axes, but not the outer axes decorators. Hence if using blit=True the axes decorators are not updated. Or inversely put, if you want the scale to update, you need to use blit=False.

Now, in the case from the question this leads to the line not being drawn. The reason is that the line has its animated attribute set to True. However, "animated" artists are not drawn by default. This property is actually meant to be used for blitting; but if no blitting is performed it will result in the artist neither be drawn nor blitted. It might have been a good idea to call this property blit_include or something similar to avoid confusion from its name.
Unfortunately, it looks like it's also not well documented. You find however a comment in the source code saying

# if the artist is animated it does not take normal part in the
# draw stack and is not expected to be drawn as part of the normal
# draw loop (when not saving) so do not propagate this change

So in total, one can ignore the presence of this argument, unless you use blitting. Even when using blitting, it can be ignored in most cases, because that property is set internally anyways.

To conclude the solution here is to not use animated and to not use blit.

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

fig, ax = plt.subplots()
xdata, ydata = [], []
ln, = plt.plot([], [], '-o')


def init():
    ax.set_xlim(0, 2*np.pi)
    ax.set_ylim(-1, 1)


def update(frame):
    xdata.append(frame)
    ydata.append(np.sin(frame))
    ln.set_data(xdata, ydata)
    ax.set_xlim(np.amin(xdata), np.amax(xdata))


ani = FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128),
                    init_func=init)
plt.show()