Skip to content

Heatmaps with pcolormesh

The ax.pcolormesh() method creates pseudocolor plots with quadrilateral cells, offering more flexibility than imshow for non-uniform grids and coordinate-based data.

Mental Model

pcolormesh() is like imshow() but with explicit coordinates. Instead of assuming a uniform pixel grid, you supply X and Y coordinate arrays that define each cell's corners. This makes it ideal for data on non-uniform grids, curvilinear coordinates, or when axes must reflect real-world units.

The key distinction: imshow = image representation (uniform pixel grid, implicit coordinates), pcolormesh = geometric representation (explicit coordinates, preserves the domain's geometry). Use imshow for matrices and images; use pcolormesh when the x/y axes represent real-world quantities with potentially non-uniform spacing.

Basic pcolormesh

Create a heatmap using pcolormesh.

1. Simple Usage

```python import matplotlib.pyplot as plt import numpy as np

np.random.seed(42) data = np.random.rand(10, 10)

fig, ax = plt.subplots() pc = ax.pcolormesh(data) plt.colorbar(pc) plt.show() ```

2. With Coordinates

```python x = np.arange(11) # 11 edges for 10 cells y = np.arange(11) X, Y = np.meshgrid(x, y)

fig, ax = plt.subplots() pc = ax.pcolormesh(X, Y, data) plt.colorbar(pc) plt.show() ```

3. Cell Centers vs Edges

```python

pcolormesh uses edges: N+1 coordinates for N cells

Data shape (10, 10) needs X, Y shape (11, 11)

```

imshow vs pcolormesh

Understanding when to use each method.

1. Key Differences

```python

imshow:

- Pixels are uniformly sized

- Origin at top-left by default

- Aspect ratio preserved

- Faster for large uniform grids

pcolormesh:

- Cells can be non-uniform

- Origin at bottom-left by default

- Aspect ratio follows data coordinates

- Supports curvilinear grids

```

2. Origin Behavior

```python fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4))

ax1.imshow(data) ax1.set_title('imshow (origin=upper)')

ax2.pcolormesh(data) ax2.set_title('pcolormesh (origin=lower)')

plt.tight_layout() plt.show() ```

3. Matching Origins

```python

Make imshow match pcolormesh

ax.imshow(data, origin='lower')

Or flip data for pcolormesh to match imshow

ax.pcolormesh(data[::-1]) ```

Non-Uniform Grids

pcolormesh excels with irregularly spaced data.

1. Logarithmic Spacing

```python x = np.logspace(0, 2, 11) # 1 to 100, log-spaced y = np.linspace(0, 10, 11) X, Y = np.meshgrid(x, y)

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

fig, ax = plt.subplots() pc = ax.pcolormesh(X, Y, data) ax.set_xscale('log') plt.colorbar(pc) plt.show() ```

2. Variable Cell Sizes

```python x = np.array([0, 1, 2, 4, 8, 16]) # Non-uniform spacing y = np.array([0, 1, 3, 6, 10]) X, Y = np.meshgrid(x, y)

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

fig, ax = plt.subplots() pc = ax.pcolormesh(X, Y, data) plt.colorbar(pc) plt.show() ```

3. Time Series Data

```python import datetime

dates = [datetime.datetime(2024, 1, i) for i in range(1, 12)] hours = np.arange(25) data = np.random.rand(24, 10)

fig, ax = plt.subplots(figsize=(10, 5)) pc = ax.pcolormesh(dates, hours, data) ax.set_ylabel('Hour') plt.colorbar(pc) plt.show() ```

Shading Options

The shading keyword controls cell rendering.

Shading Explained

flat — each cell is a single solid color. Coordinates define cell edges, so X and Y must have one more element per dimension than the data array (e.g., data is 10×10, coordinates are 11×11).

auto — matplotlib infers whether coordinates are edges or centers and adjusts automatically. This is the safest default when you are unsure about shape matching.

gouraud — colors are interpolated smoothly between vertices, producing gradient fills. Coordinates must be the same shape as the data (one value per data point, not per edge).

Most shape-mismatch errors come from confusing edge coordinates (flat) with center coordinates (gouraud). Use shading='auto' until you need explicit control.

1. Flat Shading (Default)

```python ax.pcolormesh(X, Y, data, shading='flat')

Requires X, Y one larger than data in each dimension

```

2. Auto Shading

```python

Automatically handles coordinate/data size mismatch

ax.pcolormesh(X, Y, data, shading='auto') ```

3. Gouraud Shading

```python

Interpolated colors at vertices

Requires X, Y same shape as data

x = np.arange(10) y = np.arange(10) X, Y = np.meshgrid(x, y)

ax.pcolormesh(X, Y, data, shading='gouraud') ```

Edge Colors

Add grid lines between cells.

1. Black Edges

python fig, ax = plt.subplots() pc = ax.pcolormesh(data, edgecolors='black', linewidth=0.5) plt.colorbar(pc) plt.show()

2. White Edges

python pc = ax.pcolormesh(data, edgecolors='white', linewidth=1)

3. Face Color Only

python pc = ax.pcolormesh(data, edgecolors='face') # Edges match cell color

Colormap and Range

Control color mapping identical to imshow.

1. Colormap Selection

python pc = ax.pcolormesh(data, cmap='viridis') pc = ax.pcolormesh(data, cmap='coolwarm')

2. Value Range

python pc = ax.pcolormesh(data, vmin=0, vmax=1)

3. Centered Diverging

python data_centered = np.random.randn(10, 10) max_abs = np.abs(data_centered).max() pc = ax.pcolormesh(data_centered, cmap='RdBu', vmin=-max_abs, vmax=max_abs)

Masked Data

Handle missing or invalid values.

1. Create Masked Array

```python data = np.random.rand(10, 10) mask = data < 0.2 masked_data = np.ma.masked_array(data, mask)

fig, ax = plt.subplots() pc = ax.pcolormesh(masked_data) plt.colorbar(pc) plt.show() ```

2. Set Bad Color

```python cmap = plt.cm.viridis.copy() cmap.set_bad('gray')

pc = ax.pcolormesh(masked_data, cmap=cmap) ```

3. NaN Values

```python data_with_nan = data.copy() data_with_nan[data < 0.2] = np.nan

pc = ax.pcolormesh(data_with_nan, cmap=cmap) ```

Practical Example

Create a complete heatmap with pcolormesh.

1. Generate Structured Data

python x = np.linspace(-3, 3, 50) y = np.linspace(-3, 3, 50) X, Y = np.meshgrid(x, y) Z = np.sin(X) * np.cos(Y)

2. Create Visualization

```python fig, ax = plt.subplots(figsize=(8, 6))

pc = ax.pcolormesh(X, Y, Z, cmap='RdBu', shading='auto') ax.set_xlabel('X') ax.set_ylabel('Y') ax.set_title('sin(x) × cos(y)') ax.set_aspect('equal')

plt.colorbar(pc, label='Value') plt.tight_layout() plt.show() ```

3. Add Contour Overlay

```python fig, ax = plt.subplots(figsize=(8, 6))

pc = ax.pcolormesh(X, Y, Z, cmap='RdBu', shading='auto', alpha=0.8) ax.contour(X, Y, Z, colors='black', linewidths=0.5, levels=10)

plt.colorbar(pc) plt.show() ```


Exercises

Exercise 1. Write code that creates a 2D array and displays it using ax.pcolormesh(). Add a colorbar and labels.

Solution to Exercise 1

```python import matplotlib.pyplot as plt import numpy as np

x = np.linspace(0, 5, 30) y = np.linspace(0, 3, 20) X, Y = np.meshgrid(x, y) Z = np.sin(X) * np.cos(Y)

fig, ax = plt.subplots(figsize=(8, 5)) pc = ax.pcolormesh(X, Y, Z, cmap='RdBu', shading='auto') fig.colorbar(pc, ax=ax, label='Value') ax.set_xlabel('X') ax.set_ylabel('Y') ax.set_title('pcolormesh Heatmap') plt.show() ```


Exercise 2. Explain the key difference between ax.imshow() and ax.pcolormesh(). When would you prefer pcolormesh?

Solution to Exercise 2

ax.imshow() assumes a regular (equally-spaced) grid and treats the data as an image. ax.pcolormesh() accepts explicit x and y coordinate arrays, so it can handle non-uniform (irregularly spaced) grids.

Prefer pcolormesh when your data is on an irregular grid, when you need precise control over cell edges, or when you are plotting geospatial/scientific data with non-uniform coordinates. Use imshow for simple, regularly-spaced data or actual images.


Exercise 3. Write code using pcolormesh with non-uniform grid spacing (e.g., logarithmically spaced x-coordinates).

Solution to Exercise 3

```python import matplotlib.pyplot as plt import numpy as np

x = np.logspace(0, 2, 30) # Non-uniform: 1 to 100 y = np.linspace(0, 5, 20) X, Y = np.meshgrid(x, y) Z = np.sin(np.log(X)) * np.cos(Y)

fig, ax = plt.subplots(figsize=(8, 5)) pc = ax.pcolormesh(X, Y, Z, cmap='viridis', shading='auto') fig.colorbar(pc, ax=ax, label='Value') ax.set_xlabel('X (log scale)') ax.set_ylabel('Y') ax.set_title('pcolormesh with Non-Uniform Grid') plt.show() ```


Exercise 4. Create a side-by-side comparison of the same data displayed with imshow and pcolormesh, showing that pcolormesh handles non-uniform grids correctly.

Solution to Exercise 4

```python import matplotlib.pyplot as plt import numpy as np

x = np.logspace(0, 1, 20) y = np.linspace(0, 3, 15) X, Y = np.meshgrid(x, y) Z = np.sin(X) * np.cos(Y)

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 5))

ax1.imshow(Z, cmap='RdBu', aspect='auto', origin='lower') ax1.set_title('imshow (ignores non-uniform grid)')

pc = ax2.pcolormesh(X, Y, Z, cmap='RdBu', shading='auto') fig.colorbar(pc, ax=ax2) ax2.set_title('pcolormesh (respects non-uniform grid)')

plt.tight_layout() plt.show() ```