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).