diff --git a/ci/requirements/docs.yml b/ci/requirements/docs.yml index bd7915f..d2ba735 100644 --- a/ci/requirements/docs.yml +++ b/ci/requirements/docs.yml @@ -1,12 +1,10 @@ name: py-cordex-docs - channels: - conda-forge - - nodefaults - dependencies: - python=3.10 - pint-xarray + - matplotlib-base - xarray - cf_xarray - nbconvert @@ -19,9 +17,13 @@ dependencies: - cftime - pooch - pyproj + - cartopy - sphinx - - pydata-sphinx-theme #==0.8.1 # https://github.com/pydata/pydata-sphinx-theme/issues/1098 + - cdo + - python-cdo + - pydata-sphinx-theme - sphinx-book-theme>=0.3.3 - sphinx-autosummary-accessors - pip: - sphinxcontrib-mockautodoc + - myst_nb diff --git a/docs/index.rst b/docs/index.rst index 0e7124c..05ca0b1 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -2,11 +2,17 @@ .. toctree:: :maxdepth: 2 - :caption: Contents: + :hidden: + :caption: Tutorial + + notebooks/introduction + +.. toctree:: + :maxdepth: 2 + :caption: Contents installation usage - domains science contributing authors diff --git a/docs/notebooks/introduction.ipynb b/docs/notebooks/introduction.ipynb new file mode 100644 index 0000000..9e269cd --- /dev/null +++ b/docs/notebooks/introduction.ipynb @@ -0,0 +1,286 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "0e348c73-a223-47e6-a056-b3af2be49631", + "metadata": { + "tags": [] + }, + "source": [ + "# CORDEX domains" + ] + }, + { + "cell_type": "markdown", + "id": "69c0a17f-5e7f-4f18-9c61-0096c3356f3a", + "metadata": {}, + "source": [ + "The domain module should give some tools to work with preconfigured or user defined domains. Domains are defined as xarray datasets that will contain dimensions and coodinates according to CF-conventions.\n", + "\n", + "**NOTE**: The domain module mostly focuses on working with rotated cordex domains and how they are defined in the [cordex archive specifications](https://is-enes-data.github.io/cordex_archive_specifications.pdf). However, there are some regional models that use different mappings instead of `rotated_pole` or `rotated_latitude_longitude` which we focus on. Any expertise working with those different mappings is highly welcome!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c2ccbd9e-906f-4a99-9cec-be224f3f6502", + "metadata": {}, + "outputs": [], + "source": [ + "import cordex as cx" + ] + }, + { + "cell_type": "markdown", + "id": "e15112e7-9dd1-4f37-9bc0-b7caba60ffbd", + "metadata": {}, + "source": [ + "The domain module contains some useful functions to work with cordex meta data, e.g., you can get some domain grid information using" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "995d8517-9542-42c0-87de-8a12a1e762b5", + "metadata": {}, + "outputs": [], + "source": [ + "cx.domain_info(\"EUR-11\")" + ] + }, + { + "cell_type": "markdown", + "id": "197d553d-2548-459b-b537-4d1d4eef22f3", + "metadata": {}, + "source": [ + "All available cordex domains can be found in the [CORDEX domain table on github](https://github.com/WCRP-CORDEX/domain-tables) or directly from withing py-cordex, e.g." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "53d177ac-07d2-42f2-9f50-23bcdd954faf", + "metadata": {}, + "outputs": [], + "source": [ + "cx.domains.table" + ] + }, + { + "cell_type": "markdown", + "id": "f040883e-4f12-474c-8455-d085c9de9a87", + "metadata": {}, + "source": [ + "## `EUR-11` example" + ] + }, + { + "cell_type": "markdown", + "id": "46be2e7f-6a7e-4375-8901-db498bfacf47", + "metadata": {}, + "source": [ + "The heart of the module are some functions that create a dataset from the grid information, e.g." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2a6eacea-228c-49cb-b2fb-e6bcaece9819", + "metadata": {}, + "outputs": [], + "source": [ + "eur11 = cx.cordex_domain(\"EUR-11\", dummy=\"topo\")\n", + "eur11" + ] + }, + { + "cell_type": "markdown", + "id": "a8c1c352-e761-40ac-b527-4b7618fa2a18", + "metadata": {}, + "source": [ + "The `dummy='topo'` argument means, we want a dummy variable in the dataset to see how the domain looks like. For the dummy topography, we use the `cdo topo` operator in the background. So maybe you have to install `python-cdo`, e.g., `conda install -c conda-forge python-cdo`. Working with xarray datasets means, that we can use all the nice functions of xarray including plotting, e.g.," + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "be9ebf18-db8f-4f11-9798-ce7a4d028999", + "metadata": {}, + "outputs": [], + "source": [ + "eur11.topo.plot(cmap=\"terrain\")" + ] + }, + { + "cell_type": "markdown", + "id": "fe23561f-cb0d-45b3-ba88-9f228b781fe2", + "metadata": {}, + "source": [ + "Let's define a slightly more sophisticated plotting function that uses cartopy for the right [projection](https://scitools.org.uk/cartopy/docs/latest/tutorials/understanding_transform.html) with a rotated pole:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a4f984d0-e2be-41c8-883b-3f900ec14976", + "metadata": {}, + "outputs": [], + "source": [ + "import cartopy.crs as ccrs\n", + "import cartopy.feature as cf\n", + "import matplotlib.pyplot as plt\n", + "\n", + "def plot(\n", + " da,\n", + " transform=ccrs.PlateCarree(),\n", + " projection=ccrs.PlateCarree(),\n", + " vmin=None,\n", + " vmax=None,\n", + " borders=True,\n", + " xlocs=range(-180, 180, 10),\n", + " ylocs=range(-90, 90, 5),\n", + " extent=None,\n", + " figsize=(15, 10),\n", + " title=\"\",\n", + "):\n", + " \"\"\"plot a domain using the right projections and transformations with cartopy\"\"\"\n", + " plt.figure(figsize=figsize)\n", + " ax = plt.axes(projection=projection)\n", + " if extent:\n", + " ax.set_extent(extent, crs=projection)\n", + " ax.gridlines(\n", + " draw_labels=True, linewidth=0.5, color=\"gray\", xlocs=xlocs, ylocs=ylocs\n", + " )\n", + " da.plot(ax=ax, cmap=\"terrain\", transform=transform, vmin=vmin, vmax=vmax)\n", + " ax.coastlines(resolution=\"50m\", color=\"black\", linewidth=1)\n", + " if borders:\n", + " ax.add_feature(cf.BORDERS)" + ] + }, + { + "cell_type": "markdown", + "id": "0d49dc97-2987-4cce-9661-f58a821dd487", + "metadata": {}, + "source": [ + "We can now use the grid mapping information to plot the data in it's native coordinate system using cartopy:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "51aaf72a-91c6-4237-a459-23e421592287", + "metadata": {}, + "outputs": [], + "source": [ + "pole = (\n", + " eur11.rotated_latitude_longitude.grid_north_pole_longitude,\n", + " eur11.rotated_latitude_longitude.grid_north_pole_latitude,\n", + ")\n", + "pole" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8b1f002e-f7ae-48b7-ade4-f06e05638a4d", + "metadata": {}, + "outputs": [], + "source": [ + "plot(eur11.topo, transform=ccrs.RotatedPole(*pole), projection=ccrs.RotatedPole(*pole))" + ] + }, + { + "cell_type": "markdown", + "id": "678ab79a-e6e7-41b9-8418-6cc7c5851b12", + "metadata": {}, + "source": [ + "## User defined domain" + ] + }, + { + "cell_type": "markdown", + "id": "fde23b80-baca-46cd-bace-b4163e6d1c38", + "metadata": {}, + "source": [ + "The domains are actually created from a csv table that define standard cordex domains. E.g., the data used to created the `EUR-11` domain is" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "46822353-78fb-4932-ae8b-afb986f45948", + "metadata": {}, + "outputs": [], + "source": [ + "cx.domains.table.loc[\"EUR-11\"]" + ] + }, + { + "cell_type": "markdown", + "id": "c158d324-c1c7-49f4-8cc3-c659689e4366", + "metadata": {}, + "source": [ + "The domains are created using the [create_dataset](https://py-cordex.readthedocs.io/en/latest/generated/cordex.create_dataset.html) function, e.g.:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "002da124-b062-4f19-9a4a-9ca5c1d90fe3", + "metadata": {}, + "outputs": [], + "source": [ + "eur11_user = cx.create_dataset(\n", + " nlon=424,\n", + " nlat=412,\n", + " dlon=0.11,\n", + " dlat=0.11,\n", + " ll_lon=-28.375,\n", + " ll_lat=-23.375,\n", + " pollon=-162.00,\n", + " pollat=39.25,\n", + " dummy=\"topo\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "8d03c1c1-9151-4d17-9808-8cdefae93839", + "metadata": {}, + "source": [ + "We can check that this gives the same result as our preconfigured domain." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "044eeb92-4ccf-4e4b-aed8-e268bceb1e54", + "metadata": {}, + "outputs": [], + "source": [ + "eur11_user.equals(eur11)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.9.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/whats_new.rst b/docs/whats_new.rst index 0b85bec..48b0f18 100644 --- a/docs/whats_new.rst +++ b/docs/whats_new.rst @@ -20,14 +20,13 @@ Internal Changes Breaking Changes ~~~~~~~~~~~~~~~~ -- The keyword name for the CORDEX domain identifier has changed from ``short_name`` to ``domain_id``, e.g., in :py:meth:`cmor.cordex_domain` or -:py:meth:`cmor.domain_info`. If you have explicitly set this keyword, e.g., ``short_name="EUR-11"``, please change this to ``domain_id="EUR-11"``. -This will be more consistent with the attribues in the updated domain tables. +- The keyword name for the CORDEX domain identifier has changed from ``short_name`` to ``domain_id``, e.g., in :py:meth:`cmor.cordex_domain` or :py:meth:`cmor.domain_info`. If you have explicitly set this keyword, e.g., ``short_name="EUR-11"``, please change this to ``domain_id="EUR-11"``. This will be more consistent with the attribues in the updated domain tables. Documentation ~~~~~~~~~~~~~ - Unpinned sphinx-book-theme (:pull:`127`). +- Tutorial notebook is now executed and rendered on readthedocs automatically (:pull:`141`). v0.5.2 (5 April 2023) ---------------------