GHSL — population projection to 2100 (GHS-WUP, R2025A)¶
The R2025A GHS-WUP (World Urbanization Prospects) family projects population and built-up forward to 2100. Here we pull GHS-WUP-POP at two epochs — 2025 and 2100 — over a Portugal-sized AOI and compare. WUP is whole-globe 1 km (no tiles), so each epoch downloads the global file once and crops.
Code cells are
NBVAL_SKIP(whole-globe downloads); the saved outputs are real.
Setup¶
Imports up front, the same way the other examples open. pyramids provides Dataset (reading the GeoTIFFs that
download() writes); earthlens provides the unified EarthLens entry point. tempfile gives us a scratch
directory for the downloaded files.
# NBVAL_SKIP
import tempfile
from pathlib import Path
import matplotlib.pyplot as plt
import numpy as np
from pyramids.dataset import Dataset
from earthlens import EarthLens
1 · Download GHS-WUP-POP at two epochs¶
GHS-WUP is whole-globe 1 km (no tiles), so each epoch downloads the global file once and crops to the AOI. We build
the request first — source, variable, the 2025 and 2100 epochs, release, and a Portugal-sized bounding box — then
download() writes one GeoTIFF per epoch into the scratch directory.
# NBVAL_SKIP
out = tempfile.mkdtemp()
wup = EarthLens(
data_source='ghsl',
variables=['GHS_WUP_POP'],
start='2025-01-01',
end='2100-12-31',
epochs=[2025, 2100],
release='R2025A',
aoi=[-9.6, 36.9, -6.0, 42.2],
path=out,
)
paths = wup.download(progress_bar=False)
The two written files — one per epoch — carry the epoch in their names:
# NBVAL_SKIP
[p.name for p in paths]
2 · Compare projected population, 2025 vs 2100¶
Read each GeoTIFF into a population array, masking the negative no-data fill to NaN, and key the arrays by epoch
so the plot can pull them by year.
# NBVAL_SKIP
def _load(p):
a = np.asarray(Dataset.read_file(str(p)).read_array(), dtype='float32')
a = a[0] if a.ndim == 3 else a
return np.where(a < 0, np.nan, a)
by_epoch = {('2025' if '_E2025' in p.name else '2100'): _load(p) for p in paths}
Side-by-side maps¶
Render the 2025 and 2100 population grids on a shared magma colour ramp so the spatial redistribution over the
century is directly comparable.
# NBVAL_SKIP
fig, axes = plt.subplots(1, 2, figsize=(11, 5))
for ax, year in zip(axes, ['2025', '2100']):
im = ax.imshow(by_epoch[year], cmap='magma')
ax.set_title(f'GHS-WUP-POP {year} (1 km)')
ax.axis('off')
fig.colorbar(im, ax=ax, shrink=0.7, label='people / cell')
plt.tight_layout()
plt.show()
3 · Projected change in total population¶
Summing each grid gives the AOI-wide population per epoch; the difference is the projected change across the AOI, 2025 → 2100.
# NBVAL_SKIP
tot = {y: float(np.nansum(a)) for y, a in by_epoch.items()}
print(f"2025: {tot['2025']:,.0f} -> 2100: {tot['2100']:,.0f}")
print(f"change: {tot['2100'] - tot['2025']:+,.0f}")