Surveillance par séries temporelles des plantes aquatiques et des algues flottantes#

Mots-clés données utilisées ; wq_annual, données utilisées ; landsat 5, données utilisées ; landsat 7, données utilisées ; landsat 8, données utilisées ; landsat 9, données utilisées ; sentinel-2, qualité de l’eau

Aperçu#

Ce notebook fait partie d’une collection de notebooks d’analyse de la qualité de l’eau qui utilisent des données d’observation de la Terre pour évaluer les conditions des eaux de surface. Ensemble, ces notebooks offrent une vision plus globale de la qualité de l’eau en permettant une analyse à travers de multiples indicateurs.

Ce carnet se concentre sur l”Indice des algues flottantes (FAI).

Le carnet de jeu de données du Service de surveillance de la qualité de l’eau (WQMS) présente les diverses variables disponibles dans le produit annuel de qualité de l’eau. Cependant, on peut vouloir surveiller ces variables sur des échelles de temps plus courtes, comme nous le faisons avec le FAI dans ce carnet.

Un phénomène répandu sur les eaux intérieures est la présence d’algues photosynthétiques, y compris les cyanobactéries, et/ou de plantes aquatiques telles que la jacinthe d’eau. Celles-ci peuvent être surveillées en utilisant les données et services de DE Africa, ainsi que les algorithmes de télédétection publiés.

La jacinthe d’eau est particulièrement signalée comme un problème dans les lacs de la vallée du Rift, y compris certaines parties du lac Victoria, comme autour du port de Kisumu, et est un problème bien connu au barrage de Hartbeespoort, en Afrique du Sud.

Jacinthe au barrage de Hartbeespoort

Figure 1 : Jacinthe au barrage de Hartbeespoort (source).

L”Indice des algues flottantes (FAI) peut être utilisé pour cartographier et quantifier l’étendue de ces phénomènes. Le FAI est sensible au matériel photosynthétique de surface (PSM) présent à la surface de l’eau. Il peut être appliqué en utilisant les données des capteurs Sentinel-2 MSI, Landsat OLI et Landsat TM. Utilisés ensemble, MSI et OLI fournissent plus de 100 observations par an, tandis que TM assure une continuité historique remontant au début des années 2000. Ces observations, combinées avec les produits de Digital Earth Africa (DE Africa) tels que les Observations d’eau depuis l’espace (WOfS), les composites géomédians et les produits relatifs aux plans d’eau, peuvent capturer les processus de surface dynamiques et quantifier le pourcentage de la surface de l’eau affectée.

FAI#

Le FAI détecte des valeurs de réflectance dans le proche infrarouge (NIR) anormalement élevées en comparant la réflectance NIR avec la valeur attendue compte tenu des réflectances dans le rouge et l’infrarouge à ondes courtes (SWIR). L’approche prend en compte les longueurs d’onde centrales spécifiques des bandes des capteurs. Cela signifie que le FAI est mieux à même de prendre en charge des approches multi-capteurs que d’autres mesures et indices qui supposent des caractéristiques de capteur identiques.

Le NIR interpolé est donné par :

\[\text{NIR interpolé} = \text{Rouge} + (\text{SWIR} - \text{Rouge}) \cdot \frac{\lambda_{\text{NIR}} - \lambda_{\text{Rouge}}}{\lambda_{\text{SWIR}} - \lambda_{\text{Rouge}}}\]

L’indice des algues flottantes est alors défini comme :

\[\text{FAI} = \text{NIR observé} - \text{NIR interpolé}\]

Référence#

Hu, C. (2009). A novel ocean color index to detect floating algae in the global oceans. https://doi.org/10.1016/j.rse.2009.05.012

Description#

Digital Earth Africa permet une surveillance à long terme des plans d’eau grâce aux données annuelles de qualité de l’eau et une surveillance à court terme en offrant la fonctionnalité d’appliquer des algorithmes aux données d’observation sources. Dans ce carnet, nous :

  1. Charger les données annuelles

  2. Charger les données d’observation sources

  3. Dériver les valeurs FAI pour les données d’observation sources

  4. Calculer la proportion de surface d’eau affectée

  5. Produire un graphique significatif


Commencer#

Fournissez toutes les instructions particulières dont l’utilisateur pourrait avoir besoin, par exemple : Pour exécuter cette analyse, exécutez toutes les cellules du carnet, en commençant par la cellule « Load packages ».

Charger des paquets#

Importez les packages Python utilisés pour l’analyse.

Pour importer le paquet water_quality, veuillez d’abord exécuter git clone -b develop https://github.com/digitalearthafrica/deafrica_water_quality.git dans le terminal et mettre à jour le chemin ci-dessous pour le pointer.

[1]:
%matplotlib inline

import datacube
import xarray as xr
import matplotlib.pyplot as plt

from deafrica_tools.plotting import display_map
from deafrica_tools.datahandling import load_ard

import sys

sys.path.append("/home/jovyan/deafrica_water_quality/src")
from water_quality.mapping.fai import FAI

Se connecter au datacube#

Connectez-vous au datacube pour que nous puissions accéder aux données de DE Africa. Le paramètre « app » est un nom unique pour l’analyse qui est basé sur le nom du fichier du notebook.

[2]:
dc = datacube.Datacube(app="FAI_monitoring")

Charger les données annuelles#

Nous chargeons les données annuelles de l’indice des algues flottantes à partir du Service de surveillance de la qualité de l’eau (WQMS) de DE Africa. L’emplacement par défaut est le barrage de Hartbeespoort en Afrique du Sud.

[3]:
query = {
    "x": (27.78, 27.91),
    "y": (-25.78, -25.72),
    "time": ("2020-01-01", "2025-12-31"),
}
[4]:
display_map(x=query["x"], y=query["y"])
[4]:
Make this Notebook Trusted to load map: File -> Trust Notebook
[5]:
ds_annual = dc.load(
    product="wq_annual",
    x=query["x"],
    y=query["y"],
    time=query["time"],
    measurements=["water_mask", "agm_fai"],
    resolution=(-10, 10),
    output_crs="epsg:6933",
)
[6]:
ds_annual.agm_fai.plot.imshow(robust=True, col="time", col_wrap=3);
../../../_images/sandbox_notebooks_Real_world_examples_Water_quality_FAI_monitoring_14_0.png

Charger les données d’observation sources#

Pour la surveillance à court terme, nous chargeons l’ensemble complet des observations disponibles dans DE Africa à partir des capteurs Thematic Mapper (TM ; Landsat 5 et 7), Operational Land Imager (OLI ; Landsat 8 et 9) et Multispectral Imager (MSI ; Sentinel-2).

[7]:
# Map load_ard measurements into those needed by the water_quality package per sensor
measurements = {
    "oli": {"red": "oli04", "nir": "oli05", "swir_1": "oli06", "pixel_quality": "pq"},
    "msi": {"red": "msi04", "nir_narrow": "msi8a", "swir_1": "msi11", "qa": "qa"},
    "tm": {"red": "tm03", "nir": "tm04", "swir_1": "tm05", "pixel_quality": "pq"},
}
[8]:
# Map sensors to products
products = {
    "tm": ["ls5_sr", "ls7_sr"],
    "oli": ["ls8_sr", "ls9_sr"],
    "msi": ["s2_l2a"],
}

Ensuite, nous chargeons les données à une résolution de 60 m pour 2023-2024.

[9]:
ds_list = {}

for ins in products.keys():
    ds_list[ins] = load_ard(
        dc,
        products=products[ins],
        x=query["x"],
        y=query["y"],
        time=("2023-01-01", "2024-12-31"),
        measurements=list(measurements[ins].keys()),
        output_crs="epsg:6933",
        resolution=(-60, 60),
        group_by="solar_day",
        min_gooddata=0.2,
        verbose=True,
        dask_chunks={},
    ).rename(measurements[ins])
/opt/venv/lib/python3.12/site-packages/deafrica_tools/datahandling.py:245: UserWarning: Setting 'min_gooddata' percentage to > 0.0 will cause dask arrays to compute when loading pixel-quality data to calculate 'good pixel' percentage. This can slow the return of your dataset.
  warnings.warn(
Using pixel quality parameters for USGS Collection 2
Finding datasets
    ls5_sr
    ls7_sr
Counting good quality pixels for each time step
Filtering to 19 out of 20 time steps with at least 20.0% good quality pixels
Applying pixel quality/cloud mask
Re-scaling Landsat C2 data
Returning 19 time steps as a dask array
Using pixel quality parameters for USGS Collection 2
Finding datasets
    ls8_sr
/opt/venv/lib/python3.12/site-packages/deafrica_tools/datahandling.py:565: FutureWarning: In a future version of xarray the default value for compat will change from compat='no_conflicts' to compat='override'. This is likely to lead to different results when combining overlapping variables with the same name. To opt in to new defaults and get rid of these warnings now use `set_options(use_new_combine_kwarg_defaults=True) or set compat explicitly.
  ds = xr.merge([ds_data, ds_masks])
/opt/venv/lib/python3.12/site-packages/deafrica_tools/datahandling.py:245: UserWarning: Setting 'min_gooddata' percentage to > 0.0 will cause dask arrays to compute when loading pixel-quality data to calculate 'good pixel' percentage. This can slow the return of your dataset.
  warnings.warn(
    ls9_sr
Counting good quality pixels for each time step
Filtering to 132 out of 164 time steps with at least 20.0% good quality pixels
Applying pixel quality/cloud mask
Re-scaling Landsat C2 data
Returning 132 time steps as a dask array
Using pixel quality parameters for Sentinel 2
Finding datasets
    s2_l2a
/opt/venv/lib/python3.12/site-packages/deafrica_tools/datahandling.py:565: FutureWarning: In a future version of xarray the default value for compat will change from compat='no_conflicts' to compat='override'. This is likely to lead to different results when combining overlapping variables with the same name. To opt in to new defaults and get rid of these warnings now use `set_options(use_new_combine_kwarg_defaults=True) or set compat explicitly.
  ds = xr.merge([ds_data, ds_masks])
/opt/venv/lib/python3.12/site-packages/deafrica_tools/datahandling.py:245: UserWarning: Setting 'min_gooddata' percentage to > 0.0 will cause dask arrays to compute when loading pixel-quality data to calculate 'good pixel' percentage. This can slow the return of your dataset.
  warnings.warn(
Counting good quality pixels for each time step
/opt/venv/lib/python3.12/site-packages/rasterio/warp.py:385: NotGeoreferencedWarning: Dataset has no geotransform, gcps, or rpcs. The identity matrix will be returned.
  dest = _reproject(
Filtering to 228 out of 290 time steps with at least 20.0% good quality pixels
Applying pixel quality/cloud mask
Returning 228 time steps as a dask array

Dériver les valeurs FAI pour les données d’observation sources#

[10]:
fai_list = []

for ins in products.keys():
    fai_list.append(FAI(ds_list[ins], ins))

Calculer la proportion de surface d’eau affectée#

Tout d’abord, nous spécifions un seuil de 0,05 au-dessus duquel nous « détectons » le FAI pour calculer la couverture FAI. Ce seuil est choisi car les valeurs de FAI supérieures à 0,05 ont peu de chances d’être du bruit.

[11]:
fai_threshold = 0.05
[12]:
# Concat FAI across sensors
fai = xr.concat(fai_list, dim="time").sortby("time")
[13]:
# Compute the monthly mean FAI
fai_monthly = fai.resample(time="ME").mean().compute()
[14]:
# Align the annual water to the monthly data's spatio-temporal dimensions
water_mask_aligned = ds_annual.water_mask.reindex_like(fai_monthly, method="nearest")
[15]:
# Calculate where the monthly data is above the threshold and in the water mask
fai_monthly = fai_monthly.where(fai_monthly > fai_threshold).where(
    water_mask_aligned == 1
)
[16]:
# Visualise the data
fai_monthly.plot.imshow(col="time", col_wrap=4);
../../../_images/sandbox_notebooks_Real_world_examples_Water_quality_FAI_monitoring_28_0.png
[17]:
# Calculate FAI cover as pixels detected above FAI threshold, divided by total number of pixels, expressed as a percentage
fai_cover = (
    (fai_monthly.count(dim=("x", "y")) / water_mask_aligned.count(dim=("x", "y"))) * 100
).round(2)
[18]:
# Convert results to a dataframe
monthly_results = (
    fai_cover.reset_coords("spatial_ref", drop=True)
    .to_dataframe(name="fai_cover")
    .reset_index()
)
[19]:
ds_annual["fai_cover_percent"] = (
    (
        ds_annual.agm_fai.count(dim=("x", "y"))
        / ds_annual.water_mask.count(dim=("x", "y"))
    )
    * 100
).round(2)
[20]:
annual_results = (
    ds_annual[["fai_cover_percent"]]
    .reset_coords("spatial_ref", drop=True)
    .to_dataframe()
    .reset_index()
)
annual_results["year"] = annual_results["time"].dt.year

Produire un graphique significatif#

Comme le montre le graphique ci-dessous, la couverture FAI annuelle est plus faible car elle représente la fraction de la surface pour laquelle des valeurs de FAI supérieures à 0,05 étaient typiques pour cette année-là. En revanche, les estimations mensuelles montrent une plus grande variabilité, capturant les changements à court terme des conditions du FAI.

[21]:
fig, ax = plt.subplots(1, 1)
annual_results.plot(x="time", y="fai_cover_percent", drawstyle="steps-mid", ax=ax)
monthly_results.plot(x="time", y="fai_cover", linestyle=":", marker="o", ax=ax);
../../../_images/sandbox_notebooks_Real_world_examples_Water_quality_FAI_monitoring_34_0.png

Informations Complémentaires#

Licence : Le code de ce carnet est sous licence Apache, version 2.0 <https://www.apache.org/licenses/LICENSE-2.0>. Les données de Digital Earth Africa sont sous licence Creative Commons par attribution 4.0 <https://creativecommons.org/licenses/by/4.0/>.

Contact : Si vous avez besoin d’aide, veuillez poster une question sur le canal Slack Open Data Cube <http://slack.opendatacube.org/>`__ ou sur le GIS Stack Exchange en utilisant la balise open-data-cube (vous pouvez consulter les questions posées précédemment ici). Si vous souhaitez signaler un problème avec ce bloc-notes, vous pouvez en déposer un sur Github.

Version de Datacube compatible :

[22]:
print(datacube.__version__)
1.9.13

Dernier test :

[23]:
from datetime import datetime

datetime.today().strftime("%Y-%m-%d")
[23]:
'2026-03-24'