Remotely Sensed Droughts in Mozambique

Observing Climate Change from Space

The Advanced SCATterometer (ASCAT) (Source: ESA)

Overview

In this notebook we will examine the capabilities of H SAF Advanced Scatterometer (ASCAT) to monitor droughts in Mozambique. ASCAT instruments are situated onboard the Metop satellites (EUMETSAT[1]) that are in orbit around the Earth. Since 2007, these missions have yielded a continuous record of microwave backscattering and continue to produce data for the future. The longevity of the ASCAT microwave backscatter record is therefore well-suited to track climate change, such as, El Niño induced rainfall patterns over Mozambique. The surface soil moisture (SSM) retrieved from the product showcased here is available at a sampling distance of 6.25\(\,\)km, this means that one value of soil moisture is available for every 50\(\,\)km\(^2\) (5000\(\,\)ha).

More information about microwave backscattering and the fundamentals of surface soil moisture retrieval from microwave backscatter signatures can be found here:

Imports

import cartopy.crs as ccrs
import holoviews as hv
import hvplot.pandas  # noqa
import matplotlib
import numpy as np
import pandas as pd
from bokeh.models import FixedTicker

Surface Soil Moisture of Mozambique (2007 - 2025)

Let us start by having a look at monthly aggregated SSM derived from ASCAT microwave backscattering over Mozambique. We can easily load the csv-file with pandas and then plot the results with hvplot. This creates an interactive plot whereby we can map the SSM values on an Open Street Map (OSM) and scroll through all months from 2007 to the present. For convenience, we added the locations of the in-situ sensors placed for each target district in the DrySAT project. Note, that the SSM values are reported as the degree of saturation, so, in other words, how much of the surface soil pore space is filled with water. This, unlike commonly used volumetric units, which records how much of the soil’s volume is water.

ROOT = "https://git.geo.tuwien.ac.at/api/v4/projects/1266/repository/files/"


def make_url(file, lfs="true"):
    return ROOT + file + f"/raw?ref=main&lfs={lfs}"


df = pd.read_csv(
    make_url("ascat-6_25_ssm_monthly.csv"), index_col="time", parse_dates=True
)


def load_cmap(file):
    def to_hex_str(x):
        return f"#{int(x.R):02x}{int(x.G):02x}{int(x.B):02x}"

    path = r"colour-tables%2Fssm-continuous.ct"
    df = pd.read_fwf(make_url(path, "false"), names=["R", "G", "B"], nrows=200)
    brn_yl_bu_colors = df.apply(to_hex_str, axis=1).to_list()
    return matplotlib.colors.LinearSegmentedColormap.from_list("", brn_yl_bu_colors)


SSM_CMAP = load_cmap("colour-tables/ssm-continuous.ct")

locations = {
    "Muanza": {"latitude": -18.9064758, "longitude": 34.7738921},
    "Chokwé": {"latitude": -24.5894393, "longitude": 33.0262595},
    "Mabote": {"latitude": -22.0530427, "longitude": 34.1227842},
    "Mabalane": {"latitude": -23.4258788, "longitude": 32.5448211},
    "Buzi": {"latitude": -19.9747305, "longitude": 34.1391065},
}

df_locs = pd.DataFrame.from_dict(locations, "index").reset_index()

points = df_locs.hvplot.points(
    x="longitude", y="latitude", color="black", crs=ccrs.PlateCarree()
)
labels = df_locs.hvplot.labels(
    x="longitude",
    y="latitude",
    text="index",
    text_baseline="bottom",
    text_color="black",
    crs=ccrs.PlateCarree(),
)

df.hvplot.points(
    x="longitude",
    y="latitude",
    c="surface_soil_moisture",
    groupby="time",
    x_sampling=0.08,
    y_sampling=0.08,
    rasterize=True,
    crs=ccrs.PlateCarree(),
    tiles=True,
    cmap=SSM_CMAP,
    clim=(0, 100),
    frame_width=500,
    clabel="Surface soil moisture (%)",
) * points * labels

Surface Soil Moisture Timeseries

Now let us have a closer look at the five locations marked on the SSM map and plot the SSM values against time for these 5 locations—known as timeseries. To do this we have already filtered down the full dataset to only contain the five locations. This filtered dataset shows the full temporal resolution of the product. To visualize this, we highlight the density of data points falling in a certain sector of the plot with blue shading—bluer values mark a higher density of data points.

ts = pd.read_csv(
    make_url("ascat-6_25_ssm_timeseries.csv"), index_col="time", parse_dates=True
)

p = hv.Layout(
    [
        ts[ts.name == i].hvplot.scatter(
            x="time",
            y="surface_soil_moisture",
            title=i,
            rasterize=True,
            dynspread=True,
            threshold=1,
            frame_width=800,
            padding=(0.01, 0.1),
            clabel="Density of data",
        )
        for i in ts.name.unique()
    ]
).cols(1)
p