Image Plots
Visualizing 2D Data as Images
Spectrograms, channel matrices, heatmaps of antenna array patterns,
and 2D probability distributions are all best visualized as image
plots. Matplotlib provides imshow for regular grids and pcolormesh
for non-uniform grids, both with rich colormap support.
Definition: imshow β Display a 2D Array as an Image
imshow β Display a 2D Array as an Image
ax.imshow(Z, cmap, norm, aspect, extent, **kwargs) maps a 2D array
to colored pixels:
ax.imshow(spectrogram_db, cmap='viridis', aspect='auto',
extent=[t_min, t_max, f_min, f_max], origin='lower')
Key parameters:
cmap: colormap name (e.g.,'viridis','RdBu_r')extent:[left, right, bottom, top]for axis labelingorigin:'lower'puts row 0 at the bottom (physical convention)aspect:'auto'stretches to fill;'equal'preserves pixel rationorm:Normalize,LogNorm,SymLogNormfor nonlinear mapping
Definition: pcolormesh β Non-Uniform 2D Grid
pcolormesh β Non-Uniform 2D Grid
ax.pcolormesh(X, Y, Z, cmap, shading, **kwargs) draws colored
quadrilaterals for non-uniform or curvilinear grids:
X, Y = np.meshgrid(freq_bins, time_bins)
ax.pcolormesh(X, Y, power_db, cmap='inferno', shading='gouraud')
Unlike imshow, pcolormesh handles non-uniform spacing and
arbitrary quadrilateral cells.
Use shading='gouraud' for smooth interpolation or shading='flat'
for sharp cell boundaries.
Theorem: Perceptual Uniformity of Colormaps
A perceptually uniform colormap maps equal steps in data to equal perceived changes in color. For a colormap and lightness function :
viridis, plasma, inferno, and magma satisfy this property.
The legacy jet colormap violates it β its lightness is non-monotonic,
creating false features in images.
If you print a jet figure in grayscale, bright yellow and dark blue
both appear as similar grays, hiding real structure. viridis maps
monotonically from dark to bright.
Example: Plotting a Spectrogram with imshow
Compute and display the spectrogram of a chirp signal using
scipy.signal.spectrogram and ax.imshow.
Computation
import numpy as np
from scipy.signal import spectrogram
import matplotlib.pyplot as plt
fs = 1000
t = np.arange(0, 2, 1/fs)
f0, f1 = 10, 400
signal = np.cos(2*np.pi * (f0 + (f1-f0)*t/(2*t[-1])) * t)
f, t_spec, Sxx = spectrogram(signal, fs, nperseg=128)
Plotting
fig, ax = plt.subplots(figsize=(8, 4))
im = ax.imshow(10*np.log10(Sxx + 1e-12), aspect='auto',
origin='lower',
extent=[t_spec[0], t_spec[-1], f[0], f[-1]],
cmap='viridis')
fig.colorbar(im, ax=ax, label='Power (dB)')
ax.set(xlabel='Time (s)', ylabel='Frequency (Hz)',
title='Chirp Spectrogram')
fig.tight_layout()
Colormap Comparison
Compare how different colormaps render the same 2D data. Notice how
jet creates false features while viridis preserves the structure.
Parameters
Common Mistake: imshow Origin Convention
Mistake:
Forgetting origin='lower' when plotting physical data. By default
imshow uses matrix convention (row 0 at top), which inverts
frequency/height axes.
Correction:
Always set origin='lower' for physical data:
ax.imshow(Z, origin='lower', extent=[...])
Quick Check
Why is the 'jet' colormap considered problematic for scientific data?
It has too few colors
It is not perceptually uniform β equal data steps do not map to equal perceived color changes
It only works with integer data
It is too slow to render
jet has non-monotonic lightness, creating false features and being unreadable in grayscale.
Why This Matters: Channel Matrix Heatmaps
In MIMO systems, the channel matrix
is often visualized as a heatmap with imshow(np.abs(H), cmap='viridis').
This reveals antenna correlation structure, rank deficiency, and
spatial selectivity at a glance β information that raw numbers cannot
convey efficiently.
See full treatment in Chapter 17
Colormap
A mapping from scalar values to colors, used by imshow, pcolormesh, and scatter to encode data magnitude as color.
Related: Colorbar
Colorbar
A legend that shows the mapping between data values and colors in an image plot.