Skip to content

Axes Method - contourf

The contourf method creates filled contour plots, where regions between contour levels are filled with colors. This is in contrast to contour which only draws contour lines.

Basic Usage

Create filled contour plots from meshgrid data.

1. Simple Filled Contour

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(-3, 3, 100)
y = np.linspace(-3, 3, 100)
X, Y = np.meshgrid(x, y)
Z = np.exp(-(X**2 + Y**2))

fig, ax = plt.subplots()
ax.contourf(X, Y, Z)
plt.show()

2. With Colorbar

fig, ax = plt.subplots()
cf = ax.contourf(X, Y, Z)
plt.colorbar(cf, ax=ax)
plt.show()

3. With Labels

fig, ax = plt.subplots()
cf = ax.contourf(X, Y, Z)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_title('Gaussian: $e^{-(x^2+y^2)}$')
plt.colorbar(cf, ax=ax, label='Value')
plt.show()

contour vs contourf

Compare line contours with filled contours.

Side-by-Side Comparison

fig, axes = plt.subplots(1, 2, figsize=(12, 5))

# Line contours
axes[0].contour(X, Y, Z)
axes[0].set_title('contour (lines only)')

# Filled contours
cf = axes[1].contourf(X, Y, Z)
axes[1].set_title('contourf (filled)')
plt.colorbar(cf, ax=axes[1])

plt.tight_layout()
plt.show()

Combined contour and contourf

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

# Filled contours as background
cf = ax.contourf(X, Y, Z, cmap='Blues')

# Line contours on top
cs = ax.contour(X, Y, Z, colors='black', linewidths=0.5)
ax.clabel(cs, inline=True, fontsize=8)

plt.colorbar(cf, ax=ax)
ax.set_title('Filled Contours with Line Overlay')
plt.show()

Number of Levels

Control the number of contour levels.

1. Default Levels

fig, ax = plt.subplots()
cf = ax.contourf(X, Y, Z)
ax.set_title('Default Levels')
plt.colorbar(cf, ax=ax)
plt.show()

2. Specify Number of Levels

fig, axes = plt.subplots(1, 3, figsize=(15, 4))

levels_list = [5, 10, 20]

for ax, n in zip(axes, levels_list):
    cf = ax.contourf(X, Y, Z, levels=n)
    ax.set_title(f'levels={n}')
    plt.colorbar(cf, ax=ax)

plt.tight_layout()
plt.show()

3. Explicit Level Values

fig, ax = plt.subplots()
levels = [0, 0.1, 0.2, 0.4, 0.6, 0.8, 1.0]
cf = ax.contourf(X, Y, Z, levels=levels)
ax.set_title('Custom Level Values')
plt.colorbar(cf, ax=ax, ticks=levels)
plt.show()

4. Non-Uniform Levels

fig, ax = plt.subplots()
# More resolution at higher values
levels = [0, 0.05, 0.1, 0.2, 0.5, 0.7, 0.9, 1.0]
cf = ax.contourf(X, Y, Z, levels=levels)
ax.set_title('Non-Uniform Levels')
plt.colorbar(cf, ax=ax)
plt.show()

Colormap Options

Apply different colormaps to filled contours.

1. Sequential Colormaps

fig, axes = plt.subplots(1, 3, figsize=(15, 4))

cmaps = ['viridis', 'plasma', 'inferno']

for ax, cmap in zip(axes, cmaps):
    cf = ax.contourf(X, Y, Z, cmap=cmap)
    ax.set_title(f"cmap='{cmap}'")
    plt.colorbar(cf, ax=ax)

plt.tight_layout()
plt.show()

2. Diverging Colormaps

Z_div = np.sin(X) * np.cos(Y)

fig, axes = plt.subplots(1, 3, figsize=(15, 4))

cmaps = ['coolwarm', 'RdBu', 'seismic']

for ax, cmap in zip(axes, cmaps):
    cf = ax.contourf(X, Y, Z_div, cmap=cmap)
    ax.set_title(f"cmap='{cmap}'")
    plt.colorbar(cf, ax=ax)

plt.tight_layout()
plt.show()

3. Perceptually Uniform

fig, axes = plt.subplots(1, 3, figsize=(15, 4))

cmaps = ['cividis', 'magma', 'YlOrRd']

for ax, cmap in zip(axes, cmaps):
    cf = ax.contourf(X, Y, Z, cmap=cmap)
    ax.set_title(f"cmap='{cmap}'")
    plt.colorbar(cf, ax=ax)

plt.tight_layout()
plt.show()

Alpha Transparency

Control the transparency of filled regions.

1. Opaque Fill

fig, ax = plt.subplots()
cf = ax.contourf(X, Y, Z, alpha=1.0)
ax.set_title('alpha=1.0 (opaque)')
plt.colorbar(cf, ax=ax)
plt.show()

2. Semi-Transparent Fill

fig, ax = plt.subplots()
cf = ax.contourf(X, Y, Z, alpha=0.7)
ax.set_title('alpha=0.7')
plt.colorbar(cf, ax=ax)
plt.show()

3. Alpha Comparison

fig, axes = plt.subplots(1, 3, figsize=(15, 4))

alphas = [1.0, 0.6, 0.3]

for ax, alpha in zip(axes, alphas):
    cf = ax.contourf(X, Y, Z, alpha=alpha)
    ax.set_title(f'alpha={alpha}')
    plt.colorbar(cf, ax=ax)

plt.tight_layout()
plt.show()

Extend Option

Handle values outside the specified level range.

1. extend='neither'

fig, ax = plt.subplots()
levels = [0.2, 0.4, 0.6, 0.8]
cf = ax.contourf(X, Y, Z, levels=levels, extend='neither')
ax.set_title("extend='neither'")
plt.colorbar(cf, ax=ax)
plt.show()

2. extend='both'

fig, ax = plt.subplots()
cf = ax.contourf(X, Y, Z, levels=levels, extend='both')
ax.set_title("extend='both'")
plt.colorbar(cf, ax=ax)
plt.show()

3. Extend Comparison

fig, axes = plt.subplots(2, 2, figsize=(12, 10))

extends = ['neither', 'min', 'max', 'both']
levels = [0.2, 0.4, 0.6, 0.8]

for ax, extend in zip(axes.flat, extends):
    cf = ax.contourf(X, Y, Z, levels=levels, extend=extend)
    ax.set_title(f"extend='{extend}'")
    plt.colorbar(cf, ax=ax)

plt.tight_layout()
plt.show()

Mathematical Functions

Visualize various mathematical functions.

1. Bivariate Normal PDF

def bivariate_normal(X, Y, mu_x=0, mu_y=0, sigma_x=1, sigma_y=1, rho=0):
    z = ((X - mu_x) / sigma_x)**2 - 2 * rho * (X - mu_x) * (Y - mu_y) / (sigma_x * sigma_y) + ((Y - mu_y) / sigma_y)**2
    return np.exp(-z / (2 * (1 - rho**2))) / (2 * np.pi * sigma_x * sigma_y * np.sqrt(1 - rho**2))

x = np.linspace(-3, 3, 100)
y = np.linspace(-3, 3, 100)
X, Y = np.meshgrid(x, y)
Z = bivariate_normal(X, Y, rho=0.5)

fig, ax = plt.subplots(figsize=(8, 6))
cf = ax.contourf(X, Y, Z, levels=20, cmap='Blues')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_title('Bivariate Normal (ρ=0.5)')
ax.set_aspect('equal')
plt.colorbar(cf, ax=ax, label='Density')
plt.show()

2. Saddle Function

Z = X**2 - Y**2

fig, ax = plt.subplots(figsize=(8, 6))
cf = ax.contourf(X, Y, Z, levels=20, cmap='coolwarm')
cs = ax.contour(X, Y, Z, levels=20, colors='black', linewidths=0.3)
ax.set_title('Saddle: $z = x^2 - y^2$')
ax.set_aspect('equal')
plt.colorbar(cf, ax=ax)
plt.show()

3. Sinusoidal Surface

Z = np.sin(X) * np.cos(Y)

fig, ax = plt.subplots(figsize=(8, 6))
cf = ax.contourf(X, Y, Z, levels=20, cmap='RdBu')
ax.set_title('$z = \\sin(x)\\cos(y)$')
ax.set_aspect('equal')
plt.colorbar(cf, ax=ax)
plt.show()
fig, axes = plt.subplots(2, 2, figsize=(12, 10))

functions = [
    (np.exp(-(X**2 + Y**2)), 'Gaussian', 'viridis'),
    (X**2 - Y**2, 'Saddle', 'coolwarm'),
    (np.sin(X) * np.cos(Y), 'sin(x)cos(y)', 'RdBu'),
    (np.sin(np.sqrt(X**2 + Y**2)), 'Ripple', 'plasma')
]

for ax, (Z, title, cmap) in zip(axes.flat, functions):
    cf = ax.contourf(X, Y, Z, levels=15, cmap=cmap)
    ax.set_title(title)
    ax.set_aspect('equal')
    plt.colorbar(cf, ax=ax)

plt.tight_layout()
plt.show()

Correlation Comparison

Visualize bivariate normal distributions with different correlations.

from scipy import stats

rhos = [-0.8, 0, 0.8]

fig, axes = plt.subplots(1, 3, figsize=(15, 4))

x = np.linspace(-3, 3, 100)
y = np.linspace(-3, 3, 100)
X, Y = np.meshgrid(x, y)
pos = np.dstack((X, Y))

for ax, rho in zip(axes, rhos):
    rv = stats.multivariate_normal([0, 0], [[1, rho], [rho, 1]])
    Z = rv.pdf(pos)
    cf = ax.contourf(X, Y, Z, levels=15, cmap='Blues')
    ax.set_title(f'ρ = {rho}')
    ax.set_aspect('equal')
    plt.colorbar(cf, ax=ax)

plt.tight_layout()
plt.show()

Hatching Patterns

Add hatching patterns to filled regions.

1. Basic Hatching

fig, ax = plt.subplots()
cf = ax.contourf(X, Y, Z, levels=5, hatches=['', '/', '\\', '//', '\\\\'])
ax.set_title('Contourf with Hatching')
plt.colorbar(cf, ax=ax)
plt.show()

2. Hatching Styles

fig, axes = plt.subplots(1, 3, figsize=(15, 4))

hatch_patterns = [
    ['', '/', '//', '///', '////'],
    ['', '.', '..', 'o', 'O'],
    ['', '-', '--', '+', 'x']
]

for ax, hatches in zip(axes, hatch_patterns):
    cf = ax.contourf(X, Y, Z, levels=5, hatches=hatches, cmap='Greys', alpha=0.5)
    ax.set_title(f'hatches={hatches}')

plt.tight_layout()
plt.show()

Colorbar Customization

1. Horizontal Colorbar

fig, ax = plt.subplots()
cf = ax.contourf(X, Y, Z, levels=10, cmap='viridis')
plt.colorbar(cf, ax=ax, orientation='horizontal', label='Value')
plt.show()

2. Custom Ticks

fig, ax = plt.subplots()
levels = np.linspace(0, 1, 11)
cf = ax.contourf(X, Y, Z, levels=levels, cmap='viridis')
cbar = plt.colorbar(cf, ax=ax, ticks=[0, 0.25, 0.5, 0.75, 1.0])
cbar.set_label('Intensity')
plt.show()

3. Discrete Colorbar

fig, ax = plt.subplots()
levels = [0, 0.2, 0.4, 0.6, 0.8, 1.0]
cf = ax.contourf(X, Y, Z, levels=levels, cmap='RdYlGn')
cbar = plt.colorbar(cf, ax=ax, ticks=levels)
cbar.set_ticklabels(['Very Low', 'Low', 'Medium', 'High', 'Very High', ''])
plt.show()

Full Customization

1. Complete Example

x = np.linspace(-4, 4, 150)
y = np.linspace(-4, 4, 150)
X, Y = np.meshgrid(x, y)
Z = np.exp(-(X**2 + Y**2) / 2) / (2 * np.pi)

fig, ax = plt.subplots(figsize=(9, 7))

cf = ax.contourf(X, Y, Z, levels=20, cmap='Blues')
cs = ax.contour(X, Y, Z, levels=10, colors='navy', linewidths=0.5, alpha=0.7)
ax.clabel(cs, inline=True, fontsize=8, fmt='%.3f')

ax.set_xlabel('$x$', fontsize=12)
ax.set_ylabel('$y$', fontsize=12)
ax.set_title('Standard Bivariate Normal PDF', fontsize=14)
ax.set_aspect('equal')

cbar = plt.colorbar(cf, ax=ax)
cbar.set_label('Probability Density', fontsize=11)

plt.tight_layout()
plt.show()

2. Publication-Quality Figure

from scipy import stats

x = np.linspace(-3, 3, 150)
y = np.linspace(-3, 3, 150)
X, Y = np.meshgrid(x, y)
pos = np.dstack((X, Y))

rv = stats.multivariate_normal([0, 0], [[1, 0.6], [0.6, 1]])
Z = rv.pdf(pos)

fig, ax = plt.subplots(figsize=(9, 7))

cf = ax.contourf(X, Y, Z, levels=15, cmap='viridis')
cs = ax.contour(X, Y, Z, levels=8, colors='white', linewidths=0.5, alpha=0.8)

ax.set_xlabel('$X$', fontsize=13)
ax.set_ylabel('$Y$', fontsize=13)
ax.set_title('Bivariate Normal Distribution ($\\rho = 0.6$)', fontsize=14, fontweight='bold')
ax.set_aspect('equal')
ax.tick_params(labelsize=11)

cbar = plt.colorbar(cf, ax=ax, shrink=0.85)
cbar.set_label('Probability Density', fontsize=12)

plt.tight_layout()
plt.show()

Practical Applications

1. Terrain Map

np.random.seed(42)
from scipy.ndimage import gaussian_filter

# Generate terrain-like data
Z_terrain = np.random.rand(100, 100)
Z_terrain = gaussian_filter(Z_terrain, sigma=10) * 1000

x = np.linspace(0, 10, 100)
y = np.linspace(0, 10, 100)
X, Y = np.meshgrid(x, y)

fig, ax = plt.subplots(figsize=(10, 8))
cf = ax.contourf(X, Y, Z_terrain, levels=20, cmap='terrain')
cs = ax.contour(X, Y, Z_terrain, levels=10, colors='black', linewidths=0.3)
ax.clabel(cs, inline=True, fontsize=7, fmt='%.0f m')
ax.set_title('Topographic Map')
ax.set_xlabel('Distance (km)')
ax.set_ylabel('Distance (km)')
plt.colorbar(cf, ax=ax, label='Elevation (m)')
plt.show()

2. Temperature Field

# Simulated temperature field
Z_temp = 20 + 10 * np.exp(-((X - 1)**2 + Y**2) / 2) - 5 * np.exp(-((X + 1)**2 + (Y - 1)**2) / 1)

fig, ax = plt.subplots(figsize=(10, 8))
cf = ax.contourf(X, Y, Z_temp, levels=20, cmap='coolwarm')
cs = ax.contour(X, Y, Z_temp, levels=10, colors='black', linewidths=0.3)
ax.clabel(cs, inline=True, fontsize=8, fmt='%.1f°C')
ax.set_title('Temperature Distribution')
ax.set_xlabel('x')
ax.set_ylabel('y')
plt.colorbar(cf, ax=ax, label='Temperature (°C)')
plt.show()