{ "cells": [ { "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "# Anomaly calculations" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Imports\n", "from earthkit import transforms as ekt\n", "from earthkit import data as ekd\n", "from earthkit.data.testing import earthkit_remote_test_data_file\n", "ekd.settings.set(\"cache-policy\", \"user\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Load some test data\n", "\n", "In this example we will use hourly ERA5 2m temperature data on a 0.5x0.5 spatial grid for the year 2015 as\n", "our physical data; and we will use the NUTS geometries which are stored in a geojson file.\n", "\n", "All `earthkit-transforms` methods can be called with `earthkit-data` objects (Readers and Wrappers) or with a pre-loaded `xarray`. To reduce the number of conversions in the example, we will convert to xarray in the first cell and use that data object for all subsequent steps." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Get some demonstration ERA5 data, this could be any url or path to an ERA5 grib or netCDF file.\n", "remote_era5_file = earthkit_remote_test_data_file(\"era5_temperature_france_2015_2016_2017_3deg.grib\")\n", "era5_data = ekd.from_source(\"url\", remote_era5_file)\n", "\n", "# convert to xarray to save repeated conversion in further steps\n", "era5_xr = era5_data.to_xarray(time_dim_mode=\"valid_time\")\n", "era5_xr" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Calculate the daily climatology of the ERA5 data" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "climatology_daily_mean = ekt.climatology.daily_mean(era5_xr)\n", "climatology_daily_mean" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Calculate the anomaly and relative anomaly" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "anomaly = ekt.climatology.anomaly(era5_xr, climatology_daily_mean)\n", "anomaly" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "relative_anomaly = ekt.climatology.relative_anomaly(\n", " era5_xr, climatology_daily_mean\n", ")\n", "relative_anomaly" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Plot the output for a random location" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "from datetime import datetime\n", "\n", "start, end = datetime(2015,1,1), datetime(2015,3,31)\n", "\n", "isel_kwargs = {\"latitude\":2, \"longitude\":4}\n", "sel_kwargs = {\"valid_time\": slice(start, end)}\n", "\n", "fig, ax = plt.subplots(ncols=1, nrows=1, figsize=(10,5))\n", "\n", "for data in [anomaly, relative_anomaly]:\n", " var_name = list(data.data_vars.keys())[0]\n", " p_data = data[var_name].isel(**isel_kwargs).sel(**sel_kwargs)\n", " p_data.plot(ax=ax, label=var_name)\n", "\n", "ax.set_xlim(start, end)\n", "ax.set_ylabel(\"2m temperature anomaly [K] and relative anomaly [%]\")\n", "ax.hlines(0, xmin=start, xmax=end, color=\"black\", linestyle=\"--\")\n", "ax.legend()\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": ".conda", "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.13.7" } }, "nbformat": 4, "nbformat_minor": 4 }