Cartes climatiques
Ce pipeline cartographie les indicateurs climatiques annuels sur les secteurs du Rwanda. Il
nettoie les valeurs climatiques ERA5-Land indexées par établissement de santé, aligne leurs
noms sur les limites admin3, joint les deux et produit une carte choroplèthe par classes.
La source complète est analysis/spatial-analysis/Climate_maps.ipynb.
Le résultat final est une carte choroplèthe à deux panneaux de la température moyenne annuelle et des précipitations totales :

Les données
Le classeur climatique (Climate data.xls) contient les variables ERA5-Land par établissement
de santé, la localisation de l’établissement étant décrite par la hiérarchie des unités
organisationnelles DHIS2. Seules cinq variables sont conservées :
| Colonne source | Renommée en |
|---|---|
RF001 Relative humidity (ERA5-Land) | humidity |
TMP001 Air temperature (ERA5-Land) | Average_temperature |
TMP002 Max air temperature (ERA5-Land) | Max_temperature |
TMP005 Min temperature (ERA5-Land) | Min_temperature |
RF003 Precipitation (ERA5-Land) | Rainfall |
Les niveaux d’unités organisationnelles correspondent à la hiérarchie administrative —
orgunitlevel3 est le district et orgunitlevel5 le secteur, qui sert de clé de jointure
pour admin3.
Pipeline
Lire le classeur climatique
L’en-tête s’étend sur deux lignes : la première ligne est donc ignorée, et l’ancien format
.xls nécessite le moteur xlrd :
import pandas as pd
cl_df = pd.read_excel("Climate data.xls", engine="xlrd", skiprows=1)Dériver les clés de jointure
Les noms de district et de secteur sont extraits des colonnes d’unités organisationnelles puis normalisés (la clé de secteur est ensuite combinée avec le district pour lever l’ambiguïté des noms de secteurs en double) :
cl_df["District"] = cl_df["orgunitlevel3"].str.split(" ").str[0]
cl_df["Sector"] = cl_df["orgunitlevel5"].str.split(r"[ _-]").str[0].str.capitalize()Renommer et sélectionner
cl_df["humidity"] = cl_df["RF001 Relative humidity (ERA5-Land)"]
cl_df["Average_temperature"] = cl_df["TMP001 Air temperature (ERA5-Land)"]
cl_df["Max_temperature"] = cl_df["TMP002 Max air temperature (ERA5-Land)"]
cl_df["Min_temperature"] = cl_df["TMP005 Min temperature (ERA5-Land)"]
cl_df["Rainfall"] = cl_df["RF003 Precipitation (ERA5-Land)"]
climate_data = cl_df[["periodname", "Sector", "District", "Average_temperature",
"Max_temperature", "Min_temperature", "Rainfall", "humidity"]]
climate_data["periodname"] = pd.to_datetime(climate_data["periodname"], format="%B %Y")Joindre aux secteurs
Le shapefile admin3 fournit la géométrie. Une clé combinée District + Sector des deux
côtés rend la fusion sans ambiguïté :
merged = pd.merge(admin3, climate_data, on="Sector", how="inner")Agréger à l’année
Les lignes mensuelles sont réduites à une température annuelle moyenne et à des
précipitations totales par secteur, puis reconstruites en GeoDataFrame :
import geopandas as gpd
agg = merged[merged["periodname"].dt.year == year_to_plot]
g = (agg.groupby("adm_name", as_index=False)
.agg({"geometry": "first",
"Average_temperature": "mean",
"Rainfall": "sum"}))
gdf = gpd.GeoDataFrame(g, geometry="geometry", crs=merged.crs)Standardisation des noms
L’étape de loin la plus sujette aux erreurs est la mise en correspondance des noms de secteurs des données climatiques avec le shapefile. L’orthographe varie d’un système à l’autre, et une clé sans correspondance fait silencieusement disparaître un secteur de la jointure interne. Les corrections connues sont appliquées explicitement :
Aligner les noms de lieux des données climatiques avec le shapefile admin3 afin qu’aucun secteur ne soit perdu lors de la jointure.
- Avant de fusionner tout jeu de données indexé par établissement avec les limites administratives
- Chaque fois qu’une jointure interne renvoie moins de secteurs que prévu
# Shapefile side
admin3["ADM3_EN"].replace("Mageregere", "Mageragere", inplace=True)
admin3["ADM3_EN"].replace("Shyrongi", "Shyorongi", inplace=True)
admin3["Sector"] = admin3["ADM2_EN"] + " " + admin3["ADM3_EN"]
# Climate side
climate_data["Sector"].replace("Ririma", "Rilima", inplace=True)- Une jointure interne masque les non-correspondances — comparez le nombre de lignes avant et après pour repérer les secteurs perdus
- Ces corrections sont propres aux limites NISR de 2006 ; vérifiez-les avec le shapefile que vous chargez réellement
Classes et rendu
La carte choroplèthe utilise des seuils de classes fixes et significatifs plutôt qu’un dégradé
continu, afin que la carte se lise d’un coup d’œil. La température et les précipitations ont
chacune leurs propres classes et leur propre palette (YlOrRd pour la température, Blues
pour les précipitations) :
temp_bins = [0, 15, 17, 19, 22, gdf["Average_temperature"].max()]
temp_labels = ["0-15", "15-17", "17-19", "19-22", "> 22"]
precip_bins = [0, 200, 300, 500, 800, gdf["Rainfall"].max()]
precip_labels = ["0-200", "200-300", "300-500", "500-800", "> 800"]Chaque panneau trace la colonne de valeurs avec sa palette, superpose les limites
admin1–admin3 pour le contexte et construit une légende à partir des couleurs des classes.
Voir la dernière cellule du notebook pour la figure complète à deux panneaux.
Cette image est régénérée par analysis/spatial-analysis/generate_figures.py, qui exécute
Climate_maps.ipynb et écrit climate_two_panel_map.png en local ; elle est ensuite publiée
sur Hugging Face (nhic/rwanda-spatial/charts/) par scripts/upload-spatial-to-hf.sh.