Contour & Filled Contour Plots

A contour plot represents a 3D surface on a flat axis by drawing curves that connect points of equal height, exactly like the elevation rings on a topographic map.

Learn Contour & Filled Contour Plots in our free Matplotlib course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a…

Part of the free Matplotlib course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

In this lesson you'll build a coordinate grid with np.meshgrid , draw line and filled contours, control the levels, label curves inline with clabel , and add a colorbar.

A contour needs a height value at every point on a 2D grid. np.meshgrid turns two 1D arrays of x and y coordinates into two 2D arrays, X and Y , that line up cell by cell. Compute Z from them and you have a surface ready to contour.

What you'll see: a set of concentric, roughly circular rings centered on the origin — the level curves of a bell-shaped bump, tightest where the surface is steepest.

ax.contour() draws only the level curves ; ax.contourf() fills the bands between them with solid color. Filled contours read like a heatmap and pair naturally with a colorbar, while line contours stay crisp for labeling. Set how many levels appear with the levels argument.

What you'll see: two panels of a wavy sine–cosine surface. The left shows just the colored level lines; the right fills the regions between them with smooth color bands and adds a colorbar.

Pass a list to levels to draw curves at exactly the values you care about, then call ax.clabel() on the contour object to write each level's number directly onto its line. inline=True breaks the curve so the label sits in the gap, and fmt controls the number format.

What you'll see: a bowl-shaped surface drawn as nested rings labeled 0.5, 1, 2, 4, and 6, sitting over a soft blue filled background that deepens toward the edges.

Replace each ___ to build the grid and draw a filled contour with a colorbar.

Hint: the grid builder is meshgrid , and the filled version of contour is contourf .

You passed a 1D array for Z. Compute it from the 2D X and Y that meshgrid returns, not from the original 1D x and y .

X , Y , and Z must all share the same 2D shape. Build Z directly from X and Y so the dimensions line up.

clabel needs the object returned by contour . Save it ( cs = ax.contour(...) ) and pass it: ax.clabel(cs, inline=True) .

Fill a bumpy surface with contourf and a colorbar, then overlay labeled black contour lines on top.

Lesson complete — you can map a surface onto a flat plot!

You built grids with np.meshgrid , drew level curves with contour , filled bands with contourf , chose your own levels, and labeled lines inline with clabel .

🚀 Up next: Displaying Images (imshow) — render 2D arrays and pictures pixel by pixel.

Practice quiz

What does ax.contour() draw?

  • Only the level curves (lines)
  • Filled color bands
  • A 3D surface
  • A scatter of points

Answer: Only the level curves (lines). ax.contour() draws just the level curves joining points of equal height.

What does ax.contourf() draw?

  • Only thin lines
  • Filled bands of solid color between levels
  • A pie chart
  • A bar chart

Answer: Filled bands of solid color between levels. ax.contourf() fills the regions between levels with solid color.

Why call np.meshgrid before a contour plot?

  • To shuffle the data
  • To set the colormap
  • To expand 1D x and y into 2D coordinate arrays
  • To rotate the axes

Answer: To expand 1D x and y into 2D coordinate arrays. meshgrid turns 1D x and y into 2D X and Y so every grid point has coordinates.

From which arrays should you compute Z?

  • The original 1D x and y
  • A random array
  • The figure object
  • The 2D X and Y from meshgrid

Answer: The 2D X and Y from meshgrid. Z must be 2D, computed from the X and Y that meshgrid returns.

What does levels=20 request?

  • Roughly 20 evenly spaced contour levels
  • Exactly 20 colors
  • 20 figures
  • A 20-inch figure

Answer: Roughly 20 evenly spaced contour levels. An integer asks Matplotlib for about that many evenly spaced levels.

How do you draw lines at exactly the values 0.5, 1, 2, 4?

  • levels=4

Passing a list to levels draws curves at exactly those values.

Which method labels contour lines with their values?

  • ax.legend()
  • ax.set_label()
  • ax.clabel(cs)
  • ax.text()

Answer: ax.clabel(cs). ax.clabel(cs, ...) writes each level's number onto its line.

What does inline=True do in ax.clabel()?

  • Fills the contours
  • Adds a colorbar
  • Rotates the figure
  • Breaks each line so the number sits in the gap

Answer: Breaks each line so the number sits in the gap. inline=True breaks the curve so the label fits cleanly inline.

What error appears if Z is 1D?

  • TypeError: Input z must be 2D
  • ValueError: bad color
  • KeyError: levels
  • RuntimeError: no mappable

Answer: TypeError: Input z must be 2D. contour needs a 2D Z; a 1D array raises 'Input z must be 2D'.

To add a colorbar to a filled contour, you pass which object to fig.colorbar()?

  • The X grid
  • The object returned by contourf()
  • The 1D y array
  • The figure title

Answer: The object returned by contourf(). Capture cf = ax.contourf(...) and call fig.colorbar(cf, ax=ax).