Présentation
La vapeur d’eau intégrée, également appelée vapeur d’eau totale de colonne ou eau précipitable, correspond à la quantité de vapeur d’eau intégrée verticalement dans une colonne atmosphérique. C’est une variable importante pour la correction atmosphérique, les études des nuages, l’analyse météorologique et les applications de télédétection satellitaire.
Table of contents
- Présentation
- Qu’est-ce que la vapeur d’eau totale de colonne ?
- Pourquoi utiliser ERA5 ?
- Prérequis
- Télécharger la vapeur d’eau totale de colonne ERA5 pour une journée complète
- Ouvrir le fichier NetCDF ERA5 avec xarray
- Tracer une carte horaire de TCWV
- Carte de qualité publication avec côtes, frontières et États
- Tracer la TCWV moyenne journalière
- Convertir la TCWV en eau précipitable en centimètres
- Tracer une série temporelle moyenne sur le domaine
- Interpoler la TCWV vers une latitude et une longitude spécifiques
- Optionnel : créer un proxy de transmittance à 3.9 µm de premier ordre
- Remarques importantes
- Conclusion
- Références
Dans ce tutoriel, nous montrons comment télécharger la vapeur d’eau totale de colonne ERA5 avec Python, lire les données avec xarray, puis créer des cartes de qualité publication sur les États-Unis continentaux.
ERA5 est la réanalyse atmosphérique de cinquième génération de l’ECMWF. Le Copernicus Climate Data Store fournit des données horaires ERA5 sur niveaux simples à partir de 1940. La variable utilisée ici est total_column_water_vapour, disponible en unités kg m-2. (Climate Data Store)
Une interprétation utile est :
1 | 1 kg m-2 ≈ 1 mm d’eau précipitable |
Donc, si ERA5 indique :
1 | tcwv = 25 kg m-2 |
cela correspond approximativement à :
1 | 25 mm = 2.5 cm d’eau précipitable |
Qu’est-ce que la vapeur d’eau totale de colonne ?
La vapeur d’eau totale de colonne, souvent abrégée TCWV, représente la quantité de vapeur d’eau contenue dans une colonne atmosphérique verticale allant de la surface jusqu’au sommet de l’atmosphère. Elle est aussi couramment appelée :
| Nom | Signification |
|---|---|
| TCWV | Total column water vapor |
| IWV | Integrated water vapor |
| PWV | Precipitable water vapor |
| PW | Precipitable water |
ERA5 fournit cette quantité sous forme d’une variable maillée nommée :
1 | total_column_water_vapour
|
Dans le fichier NetCDF téléchargé, le nom court de la variable est généralement :
1 | tcwv
|
Les unités sont :
1 | kg m-2 |
La documentation Copernicus définit la vapeur d’eau totale de colonne comme la quantité totale de vapeur d’eau dans une colonne s’étendant de la surface jusqu’au sommet de l’atmosphère, avec des unités kg m-2. (Climate Data Store)
Pourquoi utiliser ERA5 ?
ERA5 est utile parce qu’elle fournit des champs atmosphériques horaires, globalement complets. Pour les applications de télédétection satellitaire, la TCWV peut être utilisée comme indicateur de premier ordre de l’absorption atmosphérique, en particulier dans les régions spectrales infrarouges affectées par la vapeur d’eau.
Par exemple, en télédétection des feux, la vapeur d’eau affecte la transmittance atmosphérique près de la fenêtre sensible aux feux autour de 3.7–4.0 µm. La TCWV seule ne constitue pas une solution complète de transfert radiatif, mais c’est une première variable utile à explorer lorsque l’on construit un workflow de correction atmosphérique.
Prérequis
Installez les paquets Python nécessaires :
1 | pip install cdsapi xarray netCDF4 matplotlib cartopy |
Ou avec conda :
1 | conda install -c conda-forge cdsapi xarray netcdf4 matplotlib cartopy |
Vous avez également besoin d’un compte Copernicus Climate Data Store.

Après avoir créé votre compte, configurez vos identifiants CDS API dans (configuration CDSAPI) :
1 | ~/.cdsapirc |
Le fichier devrait ressembler à ceci :
1 2 | url: https://cds.climate.copernicus.eu/api key: YOUR_PERSONAL_ACCESS_TOKEN |
Vous devez également accepter les conditions de licence du jeu de données ERA5 sur niveaux simples dans l’interface web du CDS. Sinon, les requêtes Python peuvent échouer avec une erreur telle que :
1 | required licences not accepted |

Télécharger la vapeur d’eau totale de colonne ERA5 pour une journée complète
L’exemple suivant télécharge la vapeur d’eau totale de colonne horaire sur un domaine approximatif couvrant les États-Unis continentaux pour le 8 août 2019.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | import cdsapi dataset = "reanalysis-era5-single-levels" request = { "product_type": ["reanalysis"], "variable": ["total_column_water_vapour"], "year": ["2019"], "month": ["08"], "day": ["08"], "time": [ "00:00", "01:00", "02:00", "03:00", "04:00", "05:00", "06:00", "07:00", "08:00", "09:00", "10:00", "11:00", "12:00", "13:00", "14:00", "15:00", "16:00", "17:00", "18:00", "19:00", "20:00", "21:00", "22:00", "23:00", ], "data_format": "netcdf", "download_format": "unarchived", # Boîte englobante : Nord, Ouest, Sud, Est "area": [50.0, -130.0, 24.0, -65.0], } client = cdsapi.Client() client.retrieve(dataset, request).download("era5_tcwv_conus_20190808.nc") |
Le champ area utilise l’ordre :
1 | [North, West, South, East] |
Pour cet exemple :
1 | [50.0, -130.0, 24.0, -65.0] |
signifie :
| Limite | Valeur |
|---|---|
| Nord | 50.0°N |
| Ouest | 130.0°W |
| Sud | 24.0°N |
| Est | 65.0°W |
Cela couvre les États-Unis continentaux avec une certaine marge.
Ouvrir le fichier NetCDF ERA5 avec xarray
1 2 3 4 5 | import xarray as xr ds = xr.open_dataset("era5_tcwv_conus_20190808.nc") print(ds) |

La variable TCWV est généralement nommée :
1 | tcwv = ds["tcwv"] |
Inspectez la variable :
1 2 3 4 5 | tcwv = ds["tcwv"] print(tcwv) print(tcwv.attrs) print(tcwv.coords) |

Selon la sortie CDS, la coordonnée temporelle peut être nommée valid_time ou time. Le code suivant la détecte automatiquement :
1 2 3 | time_name = "valid_time" if "valid_time" in tcwv.coords else "time" print("Coordonnée temporelle :", time_name) |
Tracer une carte horaire de TCWV
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | import matplotlib.pyplot as plt tcwv0 = tcwv.isel({time_name: 0}) plt.figure(figsize=(10, 6)) tcwv0.plot( cmap="viridis", cbar_kwargs={"label": "TCWV (kg m$^{-2}$ / mm)"} ) plt.title(f"Vapeur d’eau totale de colonne ERA5 sur CONUS\n{tcwv0[time_name].values}") plt.xlabel("Longitude") plt.ylabel("Latitude") plt.show() |
Cela donne une carte rapide de la vapeur d’eau totale de colonne pour la première heure téléchargée.

Carte de qualité publication avec côtes, frontières et États
Pour obtenir des cartes plus propres, utilisez cartopy.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | import matplotlib.pyplot as plt import cartopy.crs as ccrs import cartopy.feature as cfeature tcwv0 = tcwv.isel({time_name: 0}) fig = plt.figure(figsize=(11, 6.5)) ax = fig.add_axes( [0.07, 0.12, 0.78, 0.76], projection=ccrs.PlateCarree() ) cax = fig.add_axes([0.88, 0.18, 0.025, 0.62]) p = tcwv0.plot( ax=ax, transform=ccrs.PlateCarree(), cmap="viridis", add_colorbar=False ) cbar = fig.colorbar(p, cax=cax) cbar.set_label("Vapeur d’eau totale de colonne (kg m$^{-2}$ / mm)") ax.add_feature(cfeature.COASTLINE, linewidth=0.8) ax.add_feature(cfeature.BORDERS, linewidth=0.8) ax.add_feature(cfeature.STATES, linewidth=0.35, edgecolor="white", alpha=0.8) ax.set_extent([-130, -65, 24, 50], crs=ccrs.PlateCarree()) gl = ax.gridlines( draw_labels=True, linewidth=0.3, alpha=0.4, linestyle="--" ) gl.top_labels = False gl.right_labels = False ax.set_title( f"Vapeur d’eau totale de colonne ERA5 sur CONUS\n{tcwv0[time_name].values}", fontsize=13 ) plt.show() |

La position de la barre de couleurs est contrôlée manuellement avec :
1 | cax = fig.add_axes([0.88, 0.18, 0.025, 0.62]) |
Les valeurs signifient :
1 | [left, bottom, width, height] |
Donc, pour rendre la barre de couleurs plus courte, réduisez la hauteur :
1 | cax = fig.add_axes([0.88, 0.22, 0.025, 0.50]) |
Tracer la TCWV moyenne journalière
Comme le fichier contient 24 champs horaires, nous pouvons calculer la moyenne journalière :
1 2 3 4 5 6 7 8 9 10 11 12 13 | tcwv_daily_mean = tcwv.mean(dim=time_name) plt.figure(figsize=(10, 6)) tcwv_daily_mean.plot( cmap="viridis", cbar_kwargs={"label": "TCWV moyenne journalière (kg m$^{-2}$ / mm)"} ) plt.title("Moyenne journalière ERA5 de la vapeur d’eau totale de colonne sur CONUS\n2019-08-08") plt.xlabel("Longitude") plt.ylabel("Latitude") plt.show() |

Une version de qualité publication :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | fig = plt.figure(figsize=(11, 6.5)) ax = fig.add_axes( [0.07, 0.12, 0.78, 0.76], projection=ccrs.PlateCarree() ) cax = fig.add_axes([0.88, 0.18, 0.025, 0.62]) p = tcwv_daily_mean.plot( ax=ax, transform=ccrs.PlateCarree(), cmap="viridis", add_colorbar=False ) cbar = fig.colorbar(p, cax=cax) cbar.set_label("TCWV moyenne journalière (kg m$^{-2}$ / mm)") ax.add_feature(cfeature.COASTLINE, linewidth=0.8) ax.add_feature(cfeature.BORDERS, linewidth=0.8) ax.add_feature(cfeature.STATES, linewidth=0.35, edgecolor="white", alpha=0.8) ax.set_extent([-130, -65, 24, 50], crs=ccrs.PlateCarree()) gl = ax.gridlines( draw_labels=True, linewidth=0.3, alpha=0.4, linestyle="--" ) gl.top_labels = False gl.right_labels = False ax.set_title( "Moyenne journalière ERA5 de la vapeur d’eau totale de colonne sur CONUS\n2019-08-08", fontsize=13 ) plt.show() |

Convertir la TCWV en eau précipitable en centimètres
La TCWV ERA5 est exprimée en kg m-2, ce qui est numériquement équivalent à des millimètres d’eau précipitable.
Par conséquent :
1 2 | tcwv_mm = tcwv tcwv_cm = tcwv / 10.0 |
Vous pouvez ajouter des métadonnées :
1 2 3 | tcwv_cm = tcwv / 10.0 tcwv_cm.attrs["long_name"] = "Vapeur d’eau totale de colonne" tcwv_cm.attrs["units"] = "cm" |
Puis tracer :
1 2 3 4 5 6 7 8 9 10 11 12 13 | tcwv0_cm = tcwv_cm.isel({time_name: 0}) plt.figure(figsize=(10, 6)) tcwv0_cm.plot( cmap="viridis", cbar_kwargs={"label": "TCWV (cm)"} ) plt.title(f"Vapeur d’eau totale de colonne ERA5 sur CONUS\n{tcwv0_cm[time_name].values}") plt.xlabel("Longitude") plt.ylabel("Latitude") plt.show() |
Tracer une série temporelle moyenne sur le domaine
Pour voir l’évolution horaire sur le domaine :
1 2 3 4 5 6 7 8 9 10 11 | tcwv_mean = tcwv.mean(dim=["latitude", "longitude"]) plt.figure(figsize=(8, 4)) tcwv_mean.plot(marker="o") plt.title("Vapeur d’eau totale de colonne ERA5 moyenne sur le domaine") plt.ylabel("TCWV (kg m$^{-2}$ / mm)") plt.xlabel("Temps") plt.grid(True, alpha=0.3) plt.show() |

Vous pouvez également tracer le minimum, la moyenne et le maximum :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | tcwv_min = tcwv.min(dim=["latitude", "longitude"]) tcwv_mean = tcwv.mean(dim=["latitude", "longitude"]) tcwv_max = tcwv.max(dim=["latitude", "longitude"]) plt.figure(figsize=(8, 4)) plt.plot(tcwv[time_name], tcwv_min, marker="o", label="min") plt.plot(tcwv[time_name], tcwv_mean, marker="o", label="mean") plt.plot(tcwv[time_name], tcwv_max, marker="o", label="max") plt.title("Statistiques de la TCWV ERA5 sur le domaine") plt.ylabel("TCWV (kg m$^{-2}$ / mm)") plt.xlabel("Temps") plt.legend() plt.grid(True, alpha=0.3) plt.show() |

Interpoler la TCWV vers une latitude et une longitude spécifiques
Pour les applications satellitaires, nous avons souvent besoin de la valeur de TCWV à l’emplacement d’une détection de feu, d’un pixel nuageux ou d’un point de validation.
Exemple de point :
1 2 | lat = 45.8326 lon = -120.5 |
Sélectionnez l’heure ERA5 la plus proche :
1 2 3 | import pandas as pd target_time = pd.Timestamp("2019-08-08T20:15:00") |
Puis interpolez :
1 2 3 4 5 6 7 8 | tcwv_at_time = tcwv.sel({time_name: target_time}, method="nearest") tcwv_point = tcwv_at_time.interp( latitude=lat, longitude=lon ) print(float(tcwv_point.values)) |
Pour plusieurs points stockés dans un DataFrame pandas :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | import pandas as pd import xarray as xr # Exemple de DataFrame df = pd.DataFrame({ "latitude": [40.0, 42.5, 45.0], "longitude": [-120.0, -115.0, -110.0], "acq_date_time": [ "2019-08-08T18:20:00", "2019-08-08T19:45:00", "2019-08-08T20:10:00", ], }) df["acq_date_time"] = pd.to_datetime(df["acq_date_time"]) tcwv_values = [] for _, row in df.iterrows(): tcwv_at_time = tcwv.sel( {time_name: row["acq_date_time"]}, method="nearest" ) value = tcwv_at_time.interp( latitude=row["latitude"], longitude=row["longitude"] ) tcwv_values.append(float(value.values)) df["tcwv_kg_m2"] = tcwv_values df["tcwv_cm"] = df["tcwv_kg_m2"] / 10.0 print(df) |
Optionnel : créer un proxy de transmittance à 3.9 µm de premier ordre
La TCWV n’est pas équivalente à la transmittance atmosphérique. Cependant, pour les applications liées aux feux satellitaires, elle peut être utilisée pour construire un proxy simple de premier ordre.
Une approximation de base de type Beer-Lambert est :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | import numpy as np def clear_sky_transmittance_3p9_from_tcwv( tcwv_kg_m2, view_zenith_deg, a=0.04, b=0.06 ): """ Transmittance claire approximative de premier ordre à 3.9 µm à partir de la vapeur d’eau totale de colonne ERA5. Parameters ---------- tcwv_kg_m2 : float or array-like Vapeur d’eau totale de colonne ERA5 en kg m-2. Numériquement équivalente aux mm d’eau précipitable. view_zenith_deg : float or array-like Angle zénithal de visée du satellite en degrés. a, b : float Coefficients empiriques. Ils devraient à terme être ajustés ou remplacés par une table de correspondance de transfert radiatif. Returns ------- T : float or array-like Transmittance atmosphérique approximative entre 0 et 1. """ tcwv_cm = tcwv_kg_m2 / 10.0 mu = np.cos(np.deg2rad(view_zenith_deg)) tau = a + b * tcwv_cm return np.exp(-tau / mu) |
Exemple :
1 2 3 4 5 6 7 8 9 | view_zenith_deg = 35.0 T_clear = clear_sky_transmittance_3p9_from_tcwv( tcwv_kg_m2=tcwv, view_zenith_deg=view_zenith_deg ) T_clear.attrs["long_name"] = "Transmittance claire approximative à 3.9 µm" T_clear.attrs["units"] = "1" |
Tracez le premier pas de temps :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | T0 = T_clear.isel({time_name: 0}) plt.figure(figsize=(10, 6)) T0.plot( cmap="viridis", vmin=0, vmax=1, cbar_kwargs={"label": "Transmittance approximative à 3.9 µm"} ) plt.title(f"Transmittance claire approximative à 3.9 µm\nVZA = {view_zenith_deg}°") plt.xlabel("Longitude") plt.ylabel("Latitude") plt.show() |
Il ne s’agit que d’un proxy de premier ordre. Une approche physiquement plus robuste consisterait à utiliser RTTOV, MODTRAN ou libRadtran avec les profils verticaux, l’altitude de surface, la géométrie de visée et la fonction de réponse spectrale du capteur.
Remarques importantes
La TCWV ERA5 est utile, mais elle ne doit pas être confondue avec la transmittance atmosphérique complète.
| Quantité | Signification |
|---|---|
| TCWV | Quantité de vapeur d’eau dans la colonne atmosphérique |
| Transmittance | Fraction du rayonnement transmise à travers l’atmosphère |
| Épaisseur optique nuageuse | Atténuation optique par les nuages |
| Profondeur optique des aérosols | Atténuation optique par les aérosols ou la fumée |
Pour la télédétection des feux, en particulier près de 3.7–4.0 µm, la vapeur d’eau n’est qu’une partie du problème de correction atmosphérique. Une correction complète dépend aussi des profils verticaux d’humidité et de température, de l’angle de visée, de la pression, de l’altitude, des aérosols et de la fonction de réponse spectrale du capteur.
Conclusion
Dans ce tutoriel, nous avons téléchargé la vapeur d’eau totale de colonne ERA5 pour une journée complète sur CONUS, ouvert les données avec xarray, tracé des cartes horaires et journalières, puis extrait des valeurs de TCWV à des emplacements spécifiques.
C’est une première étape utile vers des workflows de correction atmosphérique. Pour les applications de feux satellitaires, la TCWV peut aider à expliquer les variations spatiales et temporelles de l’absorption par la vapeur d’eau et peut être utilisée comme entrée de premier ordre pour estimer la transmittance claire à 3.9 µm.
L’étape suivante consiste à combiner la TCWV avec la géométrie de visée satellitaire et à comparer la transmittance approximative obtenue à un produit de référence, ou à remplacer l’approximation empirique par un modèle de transfert radiatif.
Références
| Links | Site |
|---|---|
| Données horaires ERA5 sur niveaux simples depuis 1940 jusqu’à aujourd’hui | Copernicus Climate Data Store |
| Statistiques journalières ERA5 sur niveaux simples | Copernicus Climate Data Store |
| Configuration et documentation de l’API CDS | Copernicus Climate Data Store |
| Documentation xarray | xarray |
| Documentation Cartopy | Cartopy |
| Documentation Matplotlib | Matplotlib |
| Documentation ERA5 | ECMWF Confluence |
| Base de données des paramètres ERA5 : vapeur d’eau totale de colonne | Base de données des paramètres ECMWF |
