From db0006fe8f50d52ec99f2102b02bac7808f7a84c Mon Sep 17 00:00:00 2001 From: Mattia Almansi Date: Thu, 22 Jun 2023 22:19:53 +0200 Subject: [PATCH] add fire --- Makefile | 2 + README.md | 2 +- ...and_cover_classification_reliability.ipynb | 2 +- notebooks/wp5/fire_burned_area.ipynb | 342 ++++++++++++++++++ 4 files changed, 346 insertions(+), 2 deletions(-) create mode 100644 notebooks/wp5/fire_burned_area.ipynb diff --git a/Makefile b/Makefile index 7c066e0..95d9c93 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,7 @@ PROJECT := c3s_eqc_toolbox_template CONDA := conda CONDAFLAGS := COV_REPORT := html +WP := default: qa type-check @@ -17,6 +18,7 @@ type-check: conda-env-update: $(CONDA) env update $(CONDAFLAGS) -f ci/environment-ci.yml $(CONDA) env update $(CONDAFLAGS) -f environment.yml + $(CONDA) env update $(CONDAFLAGS) -f environments/environment_wp$(WP).yml docker-build: docker build -t $(PROJECT) . diff --git a/README.md b/README.md index 8e7de68..135f5e5 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ conda activate DEVELOP Before pushing to GitHub, run the following commands: -1. Update conda environment: `make conda-env-update` +1. Update conda environment choosing your wp (e.g., 5): `make conda-env-update WP=5` 1. Install this package: `pip install -e .` 1. Sync with the latest [template](https://github.com/ecmwf-projects/cookiecutter-conda-package) (optional): `make template-update` 1. Run quality assurance checks: `make qa` diff --git a/notebooks/wp5/LUCL_land_cover_classification_reliability.ipynb b/notebooks/wp5/LUCL_land_cover_classification_reliability.ipynb index 08889de..bffa1a7 100644 --- a/notebooks/wp5/LUCL_land_cover_classification_reliability.ipynb +++ b/notebooks/wp5/LUCL_land_cover_classification_reliability.ipynb @@ -42,7 +42,7 @@ "id": "092084cc", "metadata": {}, "source": [ - "## Define Parameters" + "## Define parameters" ] }, { diff --git a/notebooks/wp5/fire_burned_area.ipynb b/notebooks/wp5/fire_burned_area.ipynb new file mode 100644 index 0000000..08605a1 --- /dev/null +++ b/notebooks/wp5/fire_burned_area.ipynb @@ -0,0 +1,342 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Fire Burned Area (FIRE) events" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Import packages" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import cartopy.crs as ccrs\n", + "import cartopy.feature as cfeature\n", + "import geopandas as gpd\n", + "import matplotlib.pyplot as plt\n", + "import regionmask\n", + "import shapely\n", + "import xarray as xr\n", + "from c3s_eqc_automatic_quality_control import download, plot, utils\n", + "\n", + "plt.style.use(\"seaborn-v0_8-notebook\")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Define Parameters" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Time period\n", + "year_start = 2001\n", + "year_stop = 2019\n", + "\n", + "# Region of interest\n", + "lon_slice = slice(-10, 4)\n", + "lat_slice = slice(45, 35)\n", + "\n", + "# Shapefile with regions\n", + "shapefile_url = \"https://gisco-services.ec.europa.eu/distribution/v2/nuts/shp/NUTS_RG_20M_2021_4326.shp.zip\"" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Define request" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "request = (\n", + " \"satellite-fire-burned-area\",\n", + " {\n", + " \"format\": \"zip\",\n", + " \"origin\": \"esa_cci\",\n", + " \"sensor\": \"modis\",\n", + " \"version\": \"5_1_1cds\",\n", + " \"year\": [str(year) for year in range(year_start, year_stop + 1)],\n", + " \"variable\": \"grid_variables\",\n", + " \"month\": [\"06\", \"07\", \"08\"],\n", + " \"nominal_day\": \"01\",\n", + " },\n", + ")" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Download and regionalise" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Download and regionalize\n", + "ds = download.download_and_transform(\n", + " *request,\n", + " transform_func=utils.regionalise,\n", + " transform_func_kwargs={\"lon_slice\": lon_slice, \"lat_slice\": lat_slice},\n", + " chunks={\"year\": 1},\n", + ")\n", + "\n", + "# Reindex using year/month (shift months + 1)\n", + "ds = ds.assign_coords(\n", + " year=(\"time\", ds[\"time\"].dt.year.astype(int).values),\n", + " month=(\"time\", ds[\"time\"].dt.month.astype(int).values + 1),\n", + ")\n", + "ds = ds.set_index(time=(\"year\", \"month\")).unstack(\"time\")\n", + "\n", + "# Convert units\n", + "da = ds[\"burned_area\"]\n", + "with xr.set_options(keep_attrs=True):\n", + " da *= 1.0e-6\n", + "da.attrs[\"units\"] = \"km2\"" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Find and plot highest and lowest maxima" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "da_max = da.max(set(da.dims) - {\"year\"}, keep_attrs=True)\n", + "max_year = int(da_max.idxmax(\"year\").values)\n", + "min_year = int(da_max.idxmin(\"year\").values)\n", + "da_max.plot(xticks=da[\"year\"])\n", + "plt.xticks(rotation=90)\n", + "plt.grid()\n", + "plt.title(f\"Yearly maxima: {max_year=}, {min_year=}\")\n", + "\n", + "facet = plot.projected_map(\n", + " da.sel(year=[max_year, min_year]),\n", + " plot_func=\"imshow\",\n", + " col=\"year\",\n", + " row=\"month\",\n", + " cmap=\"Reds\",\n", + " projection=ccrs.PlateCarree(),\n", + ")\n", + "for ax in facet.axs.flatten():\n", + " ax.add_feature(cfeature.BORDERS)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Mask regions" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "lon_bounds = [-10.18, 1]\n", + "lat_bounds = [36.5, 43]\n", + "crs = \"epsg:4326\"\n", + "\n", + "lon_bounds += sorted(lon_bounds, reverse=True)\n", + "lat_bounds = [lat for lat in lat_bounds for _ in range(2)]\n", + "bbox = shapely.Polygon(zip(lon_bounds, lat_bounds))\n", + "\n", + "gdf = gpd.read_file(shapefile_url)\n", + "gdf = gdf[gdf[\"LEVL_CODE\"] == 2]\n", + "gdf = gdf[gdf.intersects(bbox)]\n", + "gdf = gdf[gdf[\"NUTS_ID\"].str.startswith((\"ES\", \"PT\"))]\n", + "gdf = gdf.to_crs(crs)\n", + "\n", + "ds.rio.write_crs(crs, inplace=True)\n", + "\n", + "regions = regionmask.from_geopandas(gdf, names=\"NUTS_NAME\")\n", + "mask = regions.mask(ds[\"longitude\"], ds[\"latitude\"])" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Bar charts and maps grouped by year" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "da_grouped = da.groupby(mask.rename(\"region\")).sum((\"latitude\", \"longitude\"))\n", + "da_grouped = da_grouped.assign_coords(region=regions.names)\n", + "ylim = (0, da_grouped.sum(\"month\").max().values)\n", + "ylabel = f\"Sum of {da.attrs['long_name']} [{da.attrs['units']}]\"\n", + "for year, da_grouped_year in da_grouped.groupby(\"year\"):\n", + " df = da_grouped_year.to_pandas()\n", + " ax = gdf.plot(\n", + " df.sum().values,\n", + " cmap=\"YlOrRd\",\n", + " vmin=ylim[0],\n", + " vmax=ylim[-1],\n", + " edgecolor=\"k\",\n", + " legend=True,\n", + " legend_kwds={\"label\": ylabel},\n", + " )\n", + " ax.set_title(year)\n", + " plt.show()\n", + "\n", + " ax = df.T.plot.bar(\n", + " title=year,\n", + " ylabel=ylabel,\n", + " stacked=True,\n", + " ylim=ylim,\n", + " )\n", + " ax.grid()\n", + " plt.show()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Bar charts grouped by region" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for region, da_grouped_region in da_grouped.groupby(\"region\"):\n", + " df = da_grouped_region.squeeze().to_pandas()\n", + " ax = df.plot.bar(\n", + " title=region,\n", + " ylabel=ylabel,\n", + " stacked=True,\n", + " ylim=ylim,\n", + " )\n", + " ax.grid()\n", + " plt.show()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Timeseries" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "da_grouped_yearly = da_grouped.sum(\"month\", keep_attrs=True)\n", + "lines = da_grouped_yearly.plot(\n", + " hue=\"region\", marker=\"o\", xticks=da[\"year\"], add_legend=False\n", + ")\n", + "_ = plt.legend(lines, da_grouped[\"region\"].values, bbox_to_anchor=(1, 1))\n", + "_ = plt.xticks(rotation=90)\n", + "_ = plt.title(\"Annual sum\")\n", + "_ = plt.grid()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Climatology" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "da_climatology = da_grouped_yearly.mean(\"year\")\n", + "ylabel = f\"{da.attrs['long_name']} [{da.attrs['units']}]\"\n", + "title = f\"Climatology ({year_start}-{year_stop})\"\n", + "ax = gdf.plot(\n", + " da_climatology.values,\n", + " cmap=\"YlOrRd\",\n", + " edgecolor=\"k\",\n", + " legend=True,\n", + " legend_kwds={\"label\": ylabel},\n", + ")\n", + "ax.set_title(title)\n", + "plt.show()\n", + "\n", + "ax = da_climatology.to_pandas().plot.bar(ylabel=ylabel)\n", + "ax.set_title(title)\n", + "plt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "eqc", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.11" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}