import numpy as np
import matplotlib.pyplot as plt
from scipy.special import sph_harm
theta = np.linspace(0, np.pi, 200)
phi = np.linspace(0, 2 * np.pi, 400)
THETA, PHI = np.meshgrid(theta, phi, indexing='ij')
# Convert to lat/lon for plotting
lat = 90 - np.degrees(THETA)
lon = np.degrees(PHI)
cases = [
(1, 0, 'Zonal ($\\ell=1, m=0$)\nDipole: N vs S'),
(3, 0, 'Zonal ($\\ell=3, m=0$)\n3 latitude bands'),
(4, 4, 'Sectoral ($\\ell=4, m=4$)\nLongitude sectors'),
(5, 3, 'Tesseral ($\\ell=5, m=3$)\nCheckerboard'),
(6, 0, 'Zonal ($\\ell=6, m=0$)\n6 latitude bands'),
(8, 4, 'Tesseral ($\\ell=8, m=4$)\nComplex pattern'),
]
fig, axes = plt.subplots(2, 3, figsize=(13, 7),
subplot_kw={'projection': 'mollweide'})
axes = axes.ravel()
for ax, (ell, m, title) in zip(axes, cases):
Y = sph_harm(m, ell, PHI, THETA).real
lon_rad = np.radians(lon - 180)
lat_rad = np.radians(lat)
vmax = np.abs(Y).max()
ax.pcolormesh(lon_rad, lat_rad, Y,
cmap='RdBu_r', vmin=-vmax, vmax=vmax, shading='auto')
ax.set_title(title, fontsize=9, fontweight='bold', pad=8)
ax.grid(True, alpha=0.3)
plt.suptitle('Real part of spherical harmonics on the sphere',
fontsize=12, fontweight='bold', y=1.02)
plt.tight_layout()
plt.show()