Heatmaps & imshow

Reviewed & published by Brayan K

Matplotlib is a Python library for creating charts and visualizations — and with imshow() it can paint a 2D grid of numbers as a grid of colors called a heatmap.

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.

In this lesson you'll turn arrays into heatmaps, add a colorbar legend, label the axes, and annotate each cell with its value.

What You'll Learn in This Lesson

1 Your First Heatmap with imshow

imshow ("image show") treats a 2D array like an image: each number becomes one colored square. A colorbar turns that color scale into a readable legend.

📊 When is a heatmap the right chart?

Generate a small random grid and display it:

import numpy as np
import matplotlib.pyplot as plt

# A 5x5 grid of random values between 0 and 1
data = np.random.rand(5, 5)

# Paint the grid as colored squares
plt.imshow(data, cmap="viridis")

# Show what each color means
plt.colorbar()

plt.title("Random 5x5 Heatmap")
plt.show()
The chart this code draws: Use imshow and colorbar to display a 2D array
What this code draws, rendered with Matplotlib.

What you'll see: a 5×5 checkerboard of colors ranging from dark purple (low values near 0) through green to bright yellow (high values near 1). The colorbar on the right maps each shade back to its numeric value.

2 Labeling Axes and Choosing Colormaps

Real heatmaps have meaningful axis labels. Use plt.xticks() and plt.yticks() to replace the default 0, 1, 2… with category names, and switch the cmap to fit your data.

import numpy as np
import matplotlib.pyplot as plt

# A correlation-like 3x3 matrix
corr = np.array([
    [1.0, 0.8, 0.2],
    [0.8, 1.0, 0.5],
    [0.2, 0.5, 1.0],
])

labels = ["Price", "Size", "Age"]

plt.imshow(corr, cmap="coolwarm")
plt.colorbar()

# Put category names on both axes
plt.xticks(range(3), labels)
plt.yticks(range(3), labels)

plt.title("Correlation Matrix")
plt.show()
The chart this code draws: Add tick labels and pick a diverging colormap
What this code draws, rendered with Matplotlib.

What you'll see: a 3×3 grid where the diagonal (each variable with itself, 1.0) is the deepest red. The "Price"/"Size" cells are also warm because 0.8 is a strong correlation, while the cooler, bluer cells show weaker relationships. Both axes now read Price, Size, Age.

3 Annotating Each Cell with Its Value

A heatmap shows patterns, but readers often want the exact numbers too. Loop over the grid and call plt.text() to print each value in the center of its square.

import numpy as np
import matplotlib.pyplot as plt

data = np.array([
    [3, 7, 2],
    [8, 1, 6],
    [4, 5, 9],
])

plt.imshow(data, cmap="viridis", aspect="auto")
plt.colorbar()

# Write each value on top of its cell
for row in range(data.shape[0]):
    for col in range(data.shape[1]):
        plt.text(col, row, data[row, col],
                 ha="center", va="center", color="white")

plt.title("Annotated Heatmap")
plt.show()
The chart this code draws: Loop with plt.text() to label every square
What this code draws, rendered with Matplotlib.

What you'll see: the same colored grid, but now each square has its number printed in white in the middle. The double loop visits every (row, col) position, and aspect="auto" lets the cells stretch to fill the figure rather than staying perfectly square.

🎯 Your Turn: Fill in the Blanks

Replace each ___ to draw a heatmap with a colorbar.

import numpy as np
import matplotlib.pyplot as plt

data = np.random.rand(4, 4)

# Draw the grid with the 'plasma' colormap
plt.imshow(data, cmap="___")

# Add the color legend
plt.___()

# Display the chart
plt.show()

📋 Common Errors & Quick Reference

❌ TypeError: Invalid shape for image data

imshow needs a 2D array. Passing a flat 1D list won't work — reshape it or build a real grid first.

❌ Cell labels are invisible

Dark text on dark cells disappears. Set color="white" (or pick a lighter colormap) so the numbers stand out.

CallWhat It Does
plt.imshow(data, cmap='viridis')Draw a 2D array as colors
plt.colorbar()Add the color-to-value legend
plt.xticks(range(n), labels)Custom axis labels
plt.text(col, row, val)Annotate a single cell

🏆 Mini Challenge: Monthly Sales Grid

Draw a heatmap of sales by region and month, with a colorbar and a title.

import numpy as np
import matplotlib.pyplot as plt

# Rows = regions, columns = months
sales = np.array([
    [120, 140, 160],
    [90, 130, 150],
    [200, 180, 220],
])

# 1. Draw the heatmap
plt.imshow(sales, cmap="viridis", aspect="auto")

# 2. Add a colorbar
plt.colorbar()

# 3. Label and show
plt.xticks(range(3), ["Jan", "Feb", "Mar"])
plt.yticks(range(3), ["North", "South", "West"])
plt.title("Sales Heatmap")
plt.show()
The chart this code draws: Build a labeled sales heatmap with a colorbar
What this code draws, rendered with Matplotlib.
import matplotlib.pyplot as plt

grid = [[1, 2, 3],
        [4, 5, 6],
        [7, 8, 9]]

fig, ax = plt.subplots()
im = ax.imshow(grid, cmap="magma")
ax.set_xticks(range(3), labels=["Mon", "Tue", "Wed"])
ax.set_yticks(range(3), labels=["A", "B", "C"])
bar = fig.colorbar(im, ax=ax)

print("Data shape:", im.get_array().shape)
print("Colour range:", [int(v) for v in im.get_clim()])
print("Colormap:", im.get_cmap().name)
print("X tick labels:", [t.get_text() for t in ax.get_xticklabels()])
print("Y tick labels:", [t.get_text() for t in ax.get_yticklabels()])
print("Colourbar added an axes:", len(fig.axes) == 2)

# ✅ Expected output:
# Data shape: (3, 3)
# Colour range: [1, 9]
# Colormap: magma
# X tick labels: ['Mon', 'Tue', 'Wed']
# Y tick labels: ['A', 'B', 'C']
# Colourbar added an axes: True
The chart this code draws: The array shape, the colour range matplotlib chose, the tick labels, and the axes the colourbar added
What this code draws, rendered with Matplotlib.

❓ Frequently Asked Questions

Lesson complete — you can paint data as color!

You drew heatmaps with imshow, added colorbars, labeled the axes with categories, and annotated every cell with its value.

Practice quiz

What does a heatmap display?

  • A 2D grid of numbers as a grid of colors
  • A line over time
  • A single bar per category
  • A pie of proportions

Answer: A 2D grid of numbers as a grid of colors. A heatmap encodes each cell's value as a color in a 2D grid.

Which function draws a 2D array as colored cells?

  • plt.heatmap()
  • plt.imshow()
  • plt.grid()
  • plt.matrix()

Answer: plt.imshow(). plt.imshow(data) treats a 2D array like an image, one colored pixel per value.

What does the cmap argument choose?

  • The cell size
  • The colormap (number-to-color mapping)
  • The number of bins
  • The aspect ratio

Answer: The colormap (number-to-color mapping). cmap selects the colormap that maps numbers to colors, e.g. 'viridis'.

Which call adds a legend mapping colors back to values?

  • plt.legend()
  • plt.key()
  • plt.colorbar()
  • plt.scale()

Answer: plt.colorbar(). plt.colorbar() adds the color-to-value legend strip beside the heatmap.

Which is Matplotlib's default, perceptually uniform colormap?

  • jet
  • gray
  • viridis
  • rainbow

Answer: viridis. 'viridis' is the default and is perceptually uniform.

For data ranging negative to positive (like correlations), a good colormap is...

  • A diverging map like 'coolwarm'
  • 'viridis'
  • 'gray'
  • 'hot'

Answer: A diverging map like 'coolwarm'. A diverging colormap such as 'coolwarm' centers neutral values on white.

How do you write each cell's value on top of its square?

  • plt.annotate_grid()
  • plt.text(col, row, value) in a loop
  • plt.label()
  • plt.cell_text()

Answer: plt.text(col, row, value) in a loop. Loop over rows and columns and call plt.text(col, row, value, ha='center', va='center').

Why does imshow raise 'Invalid shape for image data' on a flat 1D list?

  • The list is empty
  • imshow needs a 2D array, not a flat 1D list
  • cmap is missing
  • colorbar wasn't called

Answer: imshow needs a 2D array, not a flat 1D list. imshow needs a 2D array; reshape or build a real grid first.

Why might cell labels be invisible on a heatmap?

  • The colorbar overwrote them
  • Dark text on dark cells disappears
  • imshow hides text
  • plt.text() is deprecated

Answer: Dark text on dark cells disappears. Set color='white' (or use a lighter colormap) so dark cells don't hide the numbers.

How do you replace default 0,1,2 tick labels with category names?

  • plt.relabel()
  • plt.xticks(range(n), labels)
  • plt.names(labels)
  • plt.set_labels()

Answer: plt.xticks(range(n), labels). plt.xticks(range(n), labels) puts category names on the axis.

Continue this course

Frequently asked questions

What is a heatmap?

A heatmap displays a 2D grid of numbers as a grid of colors, where the color of each cell encodes its value. It's perfect for correlation matrices, confusion matrices, and any table where you want to spot patterns at a glance.

How do I draw a heatmap in Matplotlib?

Use plt.imshow(data, cmap='viridis'). It treats a 2D array as an image: each value becomes a colored pixel. Add plt.colorbar() so readers can map colors back to numbers.

What does cmap do?

cmap chooses the colormap — the mapping from numbers to colors. 'viridis' is the default and is perceptually uniform; others include 'plasma', 'coolwarm', and 'gray'.

How do I label the cells with their values?

Loop over the rows and columns and call plt.text(col, row, value, ha='center', va='center') for each cell. This writes each number on top of its colored square.