Quiz: Animation and Interactivity

20 questions. Aim for mastery (18+).


Multiple Choice (10 questions)

1. The core matplotlib class for creating animations is:

(a) plt.animate() (b) matplotlib.animation.FuncAnimation (c) ax.animate() (d) fig.animate()

Answer **(b)** `matplotlib.animation.FuncAnimation`. Imported as `from matplotlib.animation import FuncAnimation`. Takes a figure, an update function, frames, interval, and blit parameters. Returns an animation object that can be saved or displayed.

2. What does blit=True do in FuncAnimation(..., blit=True)?

(a) Blurs the animation (b) Enables blitting, a rendering optimization that only redraws changed artists (c) Increases the frame rate (d) Enables audio in the animation

Answer **(b)** Enables blitting, a rendering optimization that only redraws changed artists. Blitting makes animations much faster by redrawing only the artists returned from the update function, instead of re-rendering the entire figure each frame. The trade-off is that static elements like titles cannot be updated during the animation when blit is True.

3. The interval parameter in FuncAnimation specifies:

(a) The total duration of the animation in seconds (b) The time between frames in milliseconds (c) The number of frames (d) The resolution in pixels

Answer **(b)** The time between frames in milliseconds. `interval=50` means 50 ms between frames, which is 20 frames per second. `interval=33` is approximately 30 fps. Common values are 30-100 ms for data animations.

4. To save an animation as a GIF, you use:

(a) ani.to_gif("animation.gif") (b) ani.save("animation.gif", writer="pillow") (c) plt.save_gif(ani, "animation.gif") (d) fig.savegif(ani, "animation.gif")

Answer **(b)** `ani.save("animation.gif", writer="pillow")`. The `save` method takes the filename and a writer. For GIFs, `writer="pillow"` uses Python's Pillow library (installed with matplotlib). For MP4, use `writer="ffmpeg"` (requires ffmpeg installed separately).

5. Event handling in matplotlib uses:

(a) fig.add_event_handler(handler) (b) fig.canvas.mpl_connect(event_name, callback) (c) ax.on_click(callback) (d) plt.on_event(event, callback)

Answer **(b)** `fig.canvas.mpl_connect(event_name, callback)`. The `mpl_connect` method binds a callback function to a named event. Common event names: `"button_press_event"`, `"motion_notify_event"`, `"key_press_event"`, `"scroll_event"`. The callback receives an event object with attributes like `xdata`, `ydata`, `button`, and `inaxes`.

6. For interactive matplotlib in Jupyter notebooks, you use:

(a) %matplotlib inline (b) %matplotlib widget or %matplotlib notebook (c) %matplotlib interactive (d) %matplotlib qt

Answer **(b)** `%matplotlib widget` or `%matplotlib notebook`. `%matplotlib widget` (using ipympl) is the modern recommendation and works in JupyterLab and Jupyter Notebook. `%matplotlib notebook` is the legacy version for classic notebooks. `%matplotlib inline` (the default) produces static images and does not support event handling.

7. When blit=True, the update function must:

(a) Return a single boolean value (b) Return the tuple of artists that were modified (c) Return None (d) Not return anything

Answer **(b)** Return the tuple of artists that were modified. The blit optimization needs to know which artists changed so it can re-render only those. Returning the modified artists as a tuple tells matplotlib which parts to redraw. If you forget to return the tuple (or return None), blit will not work correctly.

8. In the update function, to modify an existing Line2D, you call:

(a) ax.plot(...) again (b) line.set_data(new_x, new_y) (c) line.update(...) (d) line.modify(...)

Answer **(b)** `line.set_data(new_x, new_y)`. The `set_data` method modifies the existing line's data in place. Calling `ax.plot(...)` again would create a new Line2D and add it to the Axes, which is a memory leak in an animation. Always modify existing artists with their setter methods, not by creating new ones.

9. The chapter's main advice for when to use animation is:

(a) Use it whenever you can — animations are more engaging (b) Use it only when the story involves a process unfolding over time or a similar dynamic (c) Never use animation in data visualization (d) Use it only for entertainment, not for information

Answer **(b)** Use it only when the story involves a process unfolding over time or a similar dynamic. Animation adds time as a dimension. It is appropriate when time or an analog of time is part of the story (growing accumulations, converging simulations, flow, step-by-step education). For static data, animation adds motion that does not encode anything and can actually distract readers. The chapter argues for deliberate use, not universal use.

10. Change blindness affects animation design because:

(a) It makes animations easier to create (b) It means viewers struggle to notice changes when too many elements change simultaneously (c) It is a problem only for colorblind viewers (d) It only applies to static charts

Answer **(b)** It means viewers struggle to notice changes when too many elements change simultaneously. Change blindness is the perceptual phenomenon where the visual system fails to track multiple simultaneously-changing elements. For animation design, it means animations should change one thing per frame (or a few related things), keep the rest stable, and use smooth transitions. Overloading the viewer with too much motion defeats the purpose of animation.

True / False (5 questions)

11. "matplotlib's animation API is better for web-based interactive dashboards than Plotly or Bokeh."

Answer **False.** matplotlib's animation API is adequate for exporting GIFs and MP4s but is not designed for web-based interactive dashboards. Plotly and Bokeh are specifically designed for web interactivity (hover, zoom, selection, linked views) and handle those features better. Use matplotlib for static-output animations and scientific/research contexts; use Plotly or Bokeh for interactive dashboards.

12. "GIF export works out of the box with matplotlib; MP4 export requires external software (ffmpeg)."

Answer **True.** Pillow (required for GIF) is installed with matplotlib in most distributions. ffmpeg (required for MP4) is a separate command-line tool that must be installed on your system. If you cannot install ffmpeg, fall back to GIF export.

13. "Creating new Artists inside the update function is a good practice for efficient animation."

Answer **False.** Creating new Artists each frame is a memory leak — each call to `ax.plot(...)` adds a new Line2D that is never removed. This makes long animations slow and eventually crashes. The correct pattern is to create Artists once, outside the update function, and then modify their properties (with `set_data`, `set_color`, etc.) inside the update function.

14. "Updating a figure title during an animation works correctly with blit=True."

Answer **False.** Blit only re-renders the artists returned from the update function. Title changes are not re-rendered because titles are not typically returned from the update tuple. If you need to update the title during an animation, set `blit=False`. The animation will be slightly slower but the title will update correctly.

15. "matplotlib event handling works in Jupyter notebooks with the default %matplotlib inline backend."

Answer **False.** The inline backend renders static PNG images, so event handling is not possible. For interactive matplotlib in Jupyter, use `%matplotlib widget` (ipympl) or `%matplotlib notebook`. Without switching to an interactive backend, `mpl_connect` callbacks are silently ignored.

Short Answer (3 questions)

16. Describe the three main components of a FuncAnimation: the figure, the update function, and the frames. What does each one contribute?

Answer The **figure** is the matplotlib Figure that the animation will display. It contains the Axes and the artists that will be modified during the animation. The **update function** is called for each frame with the frame index or value. It modifies the artists' properties (positions, colors, text) to reflect the current state and returns the modified artists. The **frames** parameter specifies how many frames to produce — either an integer count (frames will be `range(N)`) or an iterable of frame values (each passed to the update function). Together, these three components define the animation: the figure holds the state, the update function specifies how the state changes, and the frames sequence drives the animation forward.

17. Explain the difference between FuncAnimation and ArtistAnimation. When would you use each?

Answer **FuncAnimation** calls an update function for each frame, which modifies artist properties on the fly. This is efficient (artists are computed as needed) and flexible (you can use different frame data). Use when frames depend on the current state or when frames are many and memory matters. **ArtistAnimation** takes a pre-computed list of artist lists, one per frame, and cycles through them. Use when frames are cheap to compute in advance and you want explicit control over every frame, or when you already have a collection of artists from a simulation. In practice, FuncAnimation is more flexible and used more often.

18. Describe the "change blindness" principle and give two specific recommendations for animation design that follow from it.

Answer **Change blindness** is the perceptual phenomenon where the visual system fails to notice changes that occur during abrupt transitions or across many simultaneously-changing elements. The visual system can track perhaps one or two moving things at a time, and beyond that, individual motions blur into a general sense of "things are moving." **Recommendation 1**: Change one thing per frame — add one data point, advance one step, highlight one new element — rather than trying to animate everything at once. **Recommendation 2**: Keep the rest stable — titles, axes, background, and static elements should not change during the animation, so the viewer has a stable reference to track the moving elements against. Other recommendations: use smooth transitions rather than abrupt jumps, limit the total duration to 5-10 seconds, and end with a static final frame that tells the whole story.

Applied Scenarios (2 questions)

19. You want to animate the climate temperature line chart to show how the data builds from 1880 to 2024, with a moving dot tracking the current year and a title that displays the current year. Write the FuncAnimation code.

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

years = np.arange(1880, 2025)
temperature = -0.3 + (years - 1880) * 0.01 + np.random.randn(len(years)) * 0.15

fig, ax = plt.subplots(figsize=(12, 5))
ax.set_xlim(1880, 2024)
ax.set_ylim(-0.8, 1.6)
ax.set_ylabel("Temperature Anomaly (°C)")
ax.set_xlabel("Year")
ax.axhline(0, color="gray", linewidth=0.5, linestyle="--")
ax.spines["top"].set_visible(False)
ax.spines["right"].set_visible(False)

line, = ax.plot([], [], color="#d62728", linewidth=1.8)
dot, = ax.plot([], [], "o", color="#d62728", markersize=8)

def update(frame):
    if frame == 0:
        line.set_data([], [])
        dot.set_data([], [])
        ax.set_title("Global Temperature, 1880-1880")
    else:
        line.set_data(years[:frame], temperature[:frame])
        dot.set_data([years[frame-1]], [temperature[frame-1]])
        ax.set_title(f"Global Temperature, 1880-{years[frame-1]}")
    return (line, dot)

# blit=False because the title updates
ani = FuncAnimation(fig, update, frames=len(years)+1, interval=40, blit=False)
ani.save("climate_animation.gif", writer="pillow", fps=25)
Key points: two artists (line and dot) updated together, title set in the update function (requiring `blit=False`), interval of 40 ms for ~25 fps, save as GIF with pillow.

20. You have a scatter plot of 500 points and want to make it interactive so that hovering over any point displays its coordinates in a tooltip. Write the code (assuming %matplotlib widget in Jupyter or a GUI backend).

Answer
import numpy as np
import matplotlib.pyplot as plt

np.random.seed(42)
x = np.random.randn(500)
y = np.random.randn(500)

fig, ax = plt.subplots(figsize=(10, 7))
sc = ax.scatter(x, y, alpha=0.7, s=50)
ax.set_title("Interactive Scatter — hover for details")

# Initially-invisible annotation
annot = ax.annotate(
    "",
    xy=(0, 0),
    xytext=(10, 10),
    textcoords="offset points",
    bbox=dict(boxstyle="round", facecolor="white", edgecolor="gray"),
    arrowprops=dict(arrowstyle="->"),
)
annot.set_visible(False)

def update_annot(ind):
    idx = ind["ind"][0]
    pos = sc.get_offsets()[idx]
    annot.xy = pos
    annot.set_text(f"Point {idx}\n({pos[0]:.2f}, {pos[1]:.2f})")

def on_hover(event):
    if event.inaxes != ax:
        return

    cont, ind = sc.contains(event)
    if cont:
        update_annot(ind)
        annot.set_visible(True)
        fig.canvas.draw_idle()
    else:
        if annot.get_visible():
            annot.set_visible(False)
            fig.canvas.draw_idle()

fig.canvas.mpl_connect("motion_notify_event", on_hover)
plt.show()
This follows the pattern from Section 15.6. The key elements: create an initially-invisible annotation, register a `motion_notify_event` handler, check `sc.contains(event)` for hover detection, update the annotation position and text when a point is found, and call `fig.canvas.draw_idle()` to refresh the display. Requires an interactive backend (`%matplotlib widget` in Jupyter or any GUI backend outside it).

Review against the mastery thresholds. This is the final quiz for Part III. You have now covered matplotlib architecture, essential chart types, customization, multi-panel layouts, specialized types, and animation/interactivity. Part IV begins with seaborn — a high-level statistical visualization library built on matplotlib.