Densité de population : Côte d’Ivoire

Choroplèthe de densité réelle (WorldPop) avec flèche du Nord, logo en filigrane et légende par classes hors-carte.

Carte minimaliste sur les 14 régions administratives de Côte d’Ivoire, frontières récupérées via Bound().get_admin() (aucun fichier local requis), colorées par densité de population réelle : population 2020 estimée par WorldPop (grille ~100 m, ajustée sur les estimations ONU, CC BY 4.0), sommée par région via RasterTools.zonal_statistics() et rapportée à la superficie réelle de chaque région. Pensée comme point de départ pour une carte de rapport ou de présentation : choroplèthe, flèche du Nord, logo et légende, sans texte enrichi ni annotation par entité.

La densité ivoirienne est dominée par le district d’Abidjan (~2 550 hab/km², loin devant le reste du pays) : une coloration linéaire écraserait donc toutes les autres régions dans la même teinte pâle. La carte colore sur une échelle logarithmique (np.log10), tout en affichant les vraies valeurs en hab/km² dans la légende — pratique standard pour une variable aussi étalée.

Techniques utilisées :

import os
import requests
import numpy as np
import cartograpy as cp
from cartograpy.processing import RasterTools

# --- Frontières réelles : 14 régions administratives ---------------------
regions = cp.Bound().get_admin("CIV", adm=1).set_crs("EPSG:4326")
regions["superficie_km2"] = regions.to_crs(regions.estimate_utm_crs()).area / 1e6

# --- Population réelle : grille WorldPop 2020 (~100 m, ajustée ONU) ------
os.makedirs("_pop_cache", exist_ok=True)
pop_tif = "_pop_cache/civ_ppp_2020_UNadj.tif"
if not os.path.exists(pop_tif):
    url = "https://data.worldpop.org/GIS/Population/Global_2000_2020/2020/CIV/civ_ppp_2020_UNadj.tif"
    with requests.get(url, stream=True, timeout=120) as r:
        r.raise_for_status()
        with open(pop_tif, "wb") as f:
            for chunk in r.iter_content(chunk_size=1 << 20):
                f.write(chunk)

# --- Population par région = somme des pixels dans chaque polygone -------
regions = (
    RasterTools(pop_tif)
    .zonal_statistics(regions, stats=["sum"])
    .rename(columns={"sum": "population"})
)
regions["densite_hab_km2"] = regions["population"] / regions["superficie_km2"]
regions["log_densite"] = np.log10(regions["densite_hab_km2"])

m = cp.Map(figsize=(8, 8), dpi=150, basemap=False, title="")
m.set_background_color("white")
m.add_polygons_choropleth(
    regions, column_to_plot="log_densite", cmap="YlOrRd",
    edge_color="black", linewidth=0.5,
    show_labels=False, show_colorbar=False,
)
m.hide_gridline()
m.add_north_arrow(location="upper right", scale=0.35)
m.add_image("assets/img/logo.png", (0.10, 0.10), zoom=0.05)
m.add_custom_text(
    "Densité de population (hab/km²) : Côte d'Ivoire",
    (0.5, 0.92), to="fig", fontsize=13, ha="center", va="center",
)

# --- Légende par classes (quantiles), en valeurs réelles -----------------
cmap_obj = cp.load_cmap("YlOrRd")
lmin, lmax = regions["log_densite"].min(), regions["log_densite"].max()
edges = np.quantile(regions["densite_hab_km2"], [0, 1 / 3, 2 / 3, 1])
items = [
    (f"{edges[i]:,.0f} - {edges[i + 1]:,.0f} hab/km²",
     cmap_obj((np.log10((edges[i] + edges[i + 1]) / 2) - lmin) / (lmax - lmin)))
    for i in range(3)
]
m.add_swatch_legend(items, xy=(0.85, 0.4), to="fig",
                     rect_width=0.02, rect_height=0.03, y_step=0.03,
                     label_dx=0.045, label_dy=0.012, fontsize=9)

m.save("densite-civ.png", dpi=150)