Written and maintained by CASRAI Editorial Board
Last updated
A heatmap in Matplotlib is a color-coded image of a two-dimensional array, and Axes.imshow is the quickest way to draw one. The official Matplotlib gallery describes it this way: data that depends on two independent variables is shown “as a color coded image plot. This is often referred to as a heatmap,” and imshow makes producing such plots “particularly easy.” Most wrong-looking heatmaps come from five defaults, not from the drawing call: the origin, the tick labels, the color scale, the cell shape and the interpolation. This guide covers those first, then the steps.
What a Matplotlib heatmap is used for in research
Matplotlib heatmaps (also written “matplotlib heatmap” or “heatmap matplotlib”) show one value per cell of a grid, so they suit any result that is naturally a matrix: a correlation matrix between variables, counts per category pair, a confusion matrix, or a measurement taken at every combination of two conditions. The Matplotlib documentation’s own examples include a harvest table (vegetables by farmers) and a correlation matrix. If you work in seaborn rather than plain Matplotlib, see heatmap in seaborn; for the surrounding workflow see Python for exploratory data analysis.
Install or access
Matplotlib is installed from the Python package ecosystem; the official installation page lists the pip, conda, pixi and uv commands and shows how to check the installed version with matplotlib.__version__. The examples below follow the Matplotlib 3.11.2 documentation and use NumPy for the array. The import convention is explained in import matplotlib.pyplot as plt.
import numpy as np
import matplotlib.pyplot as plt
Step-by-step: draw a heatmap with imshow
1. Draw the matrix
Pass a 2D array to ax.imshow. Using the object-oriented interface (fig, ax = plt.subplots()) keeps later steps simple.
fig, ax = plt.subplots()
im = ax.imshow(harvest)
By default the colormap covers the full range of your data and uses the viridis colormap (the image.cmap setting). Choose another with cmap="YlGn", for example.
2. Label the rows and columns
Set tick locations and tick labels together. The Matplotlib gallery states that “it is important to set both, the tick locations (set_xticks) as well as the tick labels (set_xticklabels), otherwise they would become out of sync.” The gallery does both in one call with the labels keyword:
ax.set_xticks(range(len(farmers)), labels=farmers, rotation=45, rotation_mode="xtick")
ax.set_yticks(range(len(vegetables)), labels=vegetables)
3. Add a colorbar
A heatmap without a legend for the color scale cannot be read quantitatively. Call ax.figure.colorbar(im, ax=ax) and label it with cbar.ax.set_ylabel(...). Placement, size and label options are covered in colorbar in Matplotlib.
4. Write the values inside the cells
The gallery labels the data by “creating a Text within each cell”, with a double loop. Note that j is the column (x) and i the row (y), so the call is text(j, i, ...):
for i in range(len(vegetables)):
for j in range(len(farmers)):
ax.text(j, i, harvest[i, j], ha="center", va="center", color="w")
White text is unreadable on light cells. The gallery’s annotate_heatmap helper takes textcolors=("black", "white") (the colors used below and above a threshold) and, when no threshold is given, switches colors at half of the maximum on the image’s norm. It formats values with valfmt="{x:.2f}" by default; the gallery example uses valfmt="{x:.1f} t" to add a unit.
5. Fix the color scale with vmin and vmax
By default the colormap spans the data range of that one array, so the same color can mean different values in two figures. Set vmin and vmax explicitly to make figures comparable. The gallery’s correlation-matrix example uses vmin=-1, vmax=1, which puts the midpoint of a diverging colormap at zero correlation. Do not combine vmin/vmax with a norm instance; Matplotlib raises an error for that (a string norm name such as "log" together with vmin/vmax is allowed).
6. Use pcolormesh when the grid is uneven
imshow assumes equally spaced cells. The pcolormesh documentation notes that “if X and Y are each equidistant, imshow can be a faster alternative”, and that pcolormesh is preferred in most cases over the older pcolor. Use ax.pcolormesh(X, Y, C) when your columns or rows sit at uneven coordinates (for example, unevenly spaced doses or times).
Output and how to read it
Each cell is one array element. Row 0 is drawn at the top because the default origin is 'upper', which the documentation describes as typical for matrices and images, and cell centres sit at integer coordinates (the default extent runs from -0.5 to the number of columns minus 0.5). Read color against the colorbar, not against neighboring cells. Choose the colormap to match the data: a sequential map for values from low to high, a diverging map for data with a meaningful midpoint such as zero (see seaborn color palettes for palette types and designing effective scientific figures for accessibility).
Comparison of the main drawing functions
| Function | Use it when | Source behavior |
|---|---|---|
Axes.imshow |
Equal-sized cells from a plain array | Default aspect is 'equal' (square cells); origin='upper' puts row 0 at the top |
Axes.pcolormesh |
Cells at uneven X/Y coordinates | Takes [X, Y,] C; returns a QuadMesh; shading default is 'auto' |
Troubleshooting
Tick labels do not match the cells
You set labels without setting tick positions, or the reverse. Set both in the same call, as in step 2.
The rows appear in reverse order
This is the default origin='upper': row 0 is at the top. Pass origin="lower" if you want the first row at the bottom, and check that your tick labels follow the same order.
The cells look blurry or blended
The default interpolation is 'auto', which uses 'nearest' when the image is upsampled by a factor of three or more, and otherwise applies 'hanning' anti-aliasing (except when the upsampling is exactly a factor of one or two). For crisp cells, pass interpolation="nearest".
The cells are not square
The default aspect is 'equal'. With aspect="auto" the cells are stretched to fill the Axes (“non-square pixels”).
TypeError from pcolormesh with flat shading
With shading='flat', X and Y must have one more entry than C in each dimension (cell edges, not centres). Use 'nearest' or 'gouraud' when X and Y have the same dimensions as C. With the default 'auto', Matplotlib picks flat if X and Y are one larger and nearest if the dimensions match.
Free alternatives
| Tool | What it does |
|---|---|
seaborn heatmap |
A higher-level function built on Matplotlib (seaborn imports as sns); see heatmap in seaborn |
Matplotlib pcolormesh |
Same library, for uneven grids (step 6) |
FAQ
How do I make a heatmap in Matplotlib?
Create a 2D NumPy array, call ax.imshow(array), then add tick labels and a colorbar. No extra package is needed.
How do I show values inside the heatmap cells?
Loop over the array and call ax.text(j, i, value, ha="center", va="center") for each cell, where j is the column and i the row. Choose the text color per cell so it contrasts with the background.
How do I change the colors of a Matplotlib heatmap?
Pass cmap to imshow (for example cmap="YlGn"), and set vmin and vmax if the scale must be shared across figures.
Should I use Matplotlib or seaborn for heatmaps?
Use Matplotlib when you need full control or an uneven grid; seaborn builds on Matplotlib and is covered in the seaborn guide linked above.
Sources
- Matplotlib documentation (3.11.2), Creating annotated heatmaps, checked 2026-10-29.
- Matplotlib documentation, matplotlib.axes.Axes.imshow, checked 2026-10-29.
- Matplotlib documentation, matplotlib.axes.Axes.pcolormesh, checked 2026-10-29.








