Checkpoint: Advanced Plotting

Reviewed & published by Brayan K

This checkpoint is a hands-on review that combines GridSpec layouts, colormaps, colorbars, contours, imshow, tick formatting, annotations, and animation into one build.

Part of the free Matplotlib course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.

Skim the recap, then tackle the multi-step build challenge and the quiz to prove you can assemble a polished figure from every advanced tool.

What This Checkpoint Reviews

1 Quick Recap of Everything You Learned

Here is the toolkit you have built across the advanced section, one line each:

SkillKey Tool
Irregular layoutsfig.add_gridspec(), subplot_mosaic()
Color scalescmap=, Normalize(vmin, vmax)
Color legendsfig.colorbar(im, ax=)
Surfacesax.contour(), ax.contourf()
Matrices & imagesax.imshow()
Axis labelsMultipleLocator, FuncFormatter
Annotationsax.text(), ax.annotate(), mathtext
MotionFuncAnimation

2 🛠️ Build Challenge: A Polished Dashboard

Build a single figure that combines four advanced skills at once. Follow the steps, then run the starter below. A complete worked solution is available under the toggle if you get stuck.

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.ticker import PercentFormatter

# STEP 1: a GridSpec - wide chart on top, two panels below
fig = plt.figure(figsize=(9, 7), constrained_layout=True)
gs = fig.add_gridspec(2, 2, height_ratios=[1, 1.4])

ax_line = fig.add_subplot(gs[0, :])    # top row, full width
ax_heat = fig.add_subplot(gs[1, 0])    # bottom-left heatmap
ax_side = fig.add_subplot(gs[1, 1])    # bottom-right bars

# STEP 2: line chart with a percent-formatted y-axis
x = np.linspace(0, 12, 100)
ax_line.plot(x, 0.5 + 0.4 * np.sin(x))
ax_line.yaxis.set_major_formatter(PercentFormatter(xmax=1.0))
ax_line.set_title("Utilisation")

# STEP 3: heatmap + labeled colorbar
data = np.random.default_rng(7).random((8, 8))
im = ax_heat.imshow(data, cmap="viridis")
fig.colorbar(im, ax=ax_heat, shrink=0.8, label="Load")
ax_heat.set_title("Load Heatmap")

# STEP 4: side bars + an arrow annotation
ax_side.bar(["A", "B", "C"], [7, 4, 9], color="slateblue")
ax_side.annotate("best", xy=(2, 9), xytext=(1.2, 9.5),
                 arrowprops=dict(arrowstyle="->"))
ax_side.set_title("Scores")

fig.suptitle("Advanced Plotting Dashboard")
plt.show()

A richer version: a GridSpec with unequal rows and columns, a currency-formatted trend line with a peak annotation, a fixed-scale magma heatmap with a colorbar, and a percent-formatted bar panel titled with mathtext.

🎯 Your turn: put the module together

The checks above test each technique on its own. This one asks for three at once in a single figure, which is how real plots go wrong: a colour scale that silently follows the data instead of staying fixed, or a percent axis formatted against the wrong maximum. The printed lines are there so you can see each choice took effect without squinting at the picture.

# 🎯 YOUR TURN — one figure that uses three things from this module:
# a GridSpec row that spans both columns, an image with a FIXED colour scale,
# and percentage tick labels. Fill in the three ___ blanks.

import numpy as np
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib.gridspec import GridSpec
from matplotlib.ticker import PercentFormatter

grid = np.arange(16).reshape(4, 4) * 6          # 0..90, deterministic
y = np.array([0.2, 0.45, 0.6, 0.8])              # utilisation as fractions

fig = plt.figure(figsize=(6, 5))
gs = GridSpec(2, 2, figure=fig)
ax_a = fig.add_subplot(gs[0, 0])
ax_b = fig.add_subplot(gs[0, 1])
# 1) the bottom panel should span BOTH columns of row 1
ax_c = fig.add_subplot(gs[1, ___])
# 👉 replace ___ with :

# 2) fix the colour scale to 0..100 so two heat-maps are comparable,
#    even though this data only reaches 90
im = ax_a.imshow(grid, vmin=___, vmax=100, cmap="viridis")
# 👉 replace ___ with 0
fig.colorbar(im, ax=ax_a)

ax_b.plot(grid.diagonal())

# 3) show the y axis as percentages; the data is 0..1, so tell the
#    formatter that 1.0 means 100 percent
ax_c.bar(["a", "b", "c", "d"], y)
ax_c.yaxis.set_major_formatter(PercentFormatter(xmax=___))
# 👉 replace ___ with 1.0

lo, hi = im.get_clim()
print("colour scale:", int(lo), "to", int(hi))
print("data max:", int(grid.max()))
print("bottom panel spans columns:", ax_c.get_subplotspec().colspan.stop - ax_c.get_subplotspec().colspan.start)
fmt = ax_c.yaxis.get_major_formatter()
print("top tick label:", fmt(y.max()))
print("axes incl. colorbar:", len(fig.axes))

# ✅ Expected output:
# colour scale: 0 to 100
# data max: 90
# bottom panel spans columns: 2
# top tick label: 80%
# axes incl. colorbar: 4

3 📝 Checkpoint Quiz

Think through each question, then expand to check your answer.

Slice the GridSpec across all columns of the last row: fig.add_subplot(gs[1, :]). The colon means "every column".

viridis is perceptually uniform and color-blind friendly, so equal data steps look like equal color steps. jet has misleading bright bands that invent structure not present in the data.

A mappable — the object returned by imshow, scatter, or contourf. The colorbar reads its colormap and value range from that object, so you capture it first: im = ax.imshow(...), then fig.colorbar(im, ax=ax).

Two 2D coordinate arrays, X and Y, from your 1D x and y. You then compute Z from them so every grid point has a height to contour.

Use PercentFormatter(xmax=1.0) from matplotlib.ticker, attached with ax.yaxis.set_major_formatter(...). It turns 0.25 into 25%.

If no variable points to it, Python garbage-collects the animation and it freezes or never plays. Always write anim = FuncAnimation(...).

❓ Frequently Asked Questions

Checkpoint cleared — you've mastered advanced plotting!

You reviewed GridSpec, colormaps, colorbars, contours, imshow, ticks and formatters, annotations, and animation, then assembled them into one polished multi-panel dashboard.

Practice quiz

How do you make one subplot span the entire bottom row of a 2-row GridSpec?

  • fig.add_subplot(gs[1, 0])
  • fig.add_subplot(gs[:, 1])
  • fig.add_subplot(gs[1, :])
  • fig.add_subplot(gs[0, :])

Answer: fig.add_subplot(gs[1, :]). Slicing gs[1, :] spans every column of the last row; the colon means 'all columns'.

Why is viridis preferred over the old jet colormap?

  • It is perceptually uniform and color-blind friendly
  • It uses fewer colors
  • It is faster to render
  • It is the only colormap with a colorbar

Answer: It is perceptually uniform and color-blind friendly. viridis is perceptually uniform and color-blind friendly, so equal data steps look like equal color steps; jet invents misleading bright bands.

What must you pass to fig.colorbar()?

  • The axes object
  • The figure title
  • The colormap name as a string
  • A mappable, like the object returned by imshow

Answer: A mappable, like the object returned by imshow. fig.colorbar needs a mappable (e.g. im from imshow); it reads the colormap and value range from that object.

What does np.meshgrid build before a contour plot?

  • A single 1D array
  • Two 2D coordinate arrays X and Y
  • A colorbar
  • A list of contour levels

Answer: Two 2D coordinate arrays X and Y. meshgrid turns 1D x and y into two 2D coordinate arrays X and Y so every grid point has coordinates to compute Z from.

Which formatter turns 0.25 into 25% on an axis, and where does it live?

  • PercentFormatter from matplotlib.ticker
  • PercentLocator from matplotlib.axes
  • FormatPercent from numpy
  • ScalarFormatter from matplotlib.pyplot

Answer: PercentFormatter from matplotlib.ticker. PercentFormatter(xmax=1.0) from matplotlib.ticker, attached with ax.yaxis.set_major_formatter, renders fractions as percentages.

Why must you keep a reference to a FuncAnimation object?

  • To change its color later
  • To add a colorbar
  • Otherwise Python garbage-collects it and the animation freezes
  • It is required by plt.show only on Windows

Answer: Otherwise Python garbage-collects it and the animation freezes. If no variable references the FuncAnimation, it gets garbage-collected and never plays; always write anim = FuncAnimation(...).

Which function displays a 2D array as an image (a heatmap)?

  • ax.plot()
  • ax.imshow()
  • ax.bar()
  • ax.scatter()

Answer: ax.imshow(). ax.imshow() renders a 2D array as an image, the basis of a heatmap.

What does Normalize(vmin, vmax) control on a colormapped plot?

  • The figure size
  • The number of ticks
  • The animation frame rate
  • The data range mapped onto the colormap

Answer: The data range mapped onto the colormap. Normalize sets the vmin/vmax data range that is mapped across the colormap, fixing the color scale.

Which tick tool lets you write fully custom tick label text from a function?

  • MultipleLocator
  • FuncFormatter
  • MaxNLocator
  • AutoLocator

Answer: FuncFormatter. FuncFormatter takes a function (value, pos) -> string, letting you produce any custom tick label text.

What does MultipleLocator(5) do to an axis?

  • Limits the axis to 5 values
  • Multiplies all data by 5
  • Places major ticks at every multiple of 5
  • Adds 5 colorbars

Answer: Places major ticks at every multiple of 5. MultipleLocator(5) places major ticks at every integer multiple of 5 along the axis.

Continue this course

Frequently asked questions

What does this checkpoint cover?

It pulls together every advanced plotting skill: GridSpec layouts, colormaps and normalization, colorbars, contour plots, imshow, tick locators and formatters, text and math annotations, and FuncAnimation. The build challenge asks you to combine several of them into one polished multi-panel figure.

What if I get stuck on the build challenge?

Work one panel at a time. Get the GridSpec scaffold and three empty Axes showing first, then fill the heatmap and its colorbar, then the formatted ticks, then the annotation. A full worked solution is provided under the Show solution toggle if you want to compare.

Do I need to memorize every argument?

No. The goal is to recognize which tool solves which problem — reach for GridSpec for irregular layouts, imshow for matrices, FuncFormatter for custom tick text, and annotate for callouts. The exact keyword arguments are something you look up as you go.

What comes after this checkpoint?

The Capstone Project, where you apply everything from the whole course to build a complete, presentation-ready figure from a realistic dataset end to end.