{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n", " \n", " \n", " \n", " \n", " \n", "
\n", " \"Project\n", " \n", " \"ECMWF\n", " \n", " \"Google\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# ERA5_ARCO Pressure Level Data Exploration: Matplotlib" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Overview\n", "A team at [Google Research & Cloud](https://research.google/) are making parts of the [ECMWF Reanalysis version 5](https://www.ecmwf.int/en/forecasts/dataset/ecmwf-reanalysis-v5) (aka **ERA-5**) accessible in a [Analysis Ready, Cloud Optimized](https://www.frontiersin.org/articles/10.3389/fclim.2021.782909/full) (aka **ARCO**) format.\n", "\n", "In this notebook, we will do the following:\n", "\n", "1. Access the [ERA-5 ARCO](https://github.com/google-research/arco-era5) catalog\n", "1. Select a particular dataset and variable from the catalog\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Prerequisites\n", "\n", "| Concepts | Importance | Notes |\n", "| --- | --- | --- |\n", "| [Cartopy](https://foundations.projectpythia.org/core/cartopy/cartopy.html) | Necessary | |\n", "| [Xarray](https://foundations.projectpythia.org/core/xarray) | Necessary | |\n", "\n", "\n", "- **Time to learn**: 30 minutes" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Imports" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import xarray as xr\n", "import matplotlib.pyplot as plt\n", "import cartopy.crs as ccrs\n", "import cartopy.feature as cfeature\n", "from metpy import calc as mpcalc\n", "from metpy.units import units\n", "import metpy\n", "import numpy as np\n", "from datetime import datetime, timedelta" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Access the ARCO ERA-5 catalog on Google Cloud" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's open the **37-level isobaric surfaces reanalysis** Zarr file" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "reanalysis = xr.open_zarr(\n", " 'gs://gcp-public-data-arco-era5/ar/1959-2022-full_37-1h-0p25deg-chunk-1.zarr-v2', \n", " consolidated=True\n", ")" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "reanalysis" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "geop = reanalysis.geopotential\n", "temp = reanalysis.temperature" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "geop" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "\n", "\n", "\n", "\n", "\n", "Select time and level ranges from the dataset." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "nHours = 6 \n", "startTime = datetime(1993,3,13,18)\n", "endTime = startTime + timedelta(hours=nHours)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", " RESTRICT YOUR TIME/LEVEL RANGES!
\n", "The full dataset is over 70 TB ... if you try to load in too large a range (or forget to specify the start/stop points), you will likely run out of system memory!\n", "
" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "geopSub1 = geop.sel(time=slice(startTime, endTime), level=500)\n", "tempSub1 = temp.sel(time=slice(startTime, endTime), level=850)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Convert to dam and deg C." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "Z = mpcalc.geopotential_to_height(geopSub1).metpy.convert_units('dam')" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "T = tempSub1.metpy.convert_units('degC')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Z" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "T" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Plot the data using Matplotlib" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "projData = ccrs.PlateCarree()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "lons, lats = Z.longitude, Z.latitude" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "tLevels = np.arange(-45,39,3)\n", "zLevels = np.arange(468, 606, 6)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "res = '110m'\n", "dpi = 100\n", "fig = plt.figure(figsize=(2048/dpi, 1024/dpi))\n", "ax = plt.subplot(1,1,1,projection=projData, frameon=False)\n", "\n", "ax.add_feature(cfeature.COASTLINE.with_scale(res), edgecolor='brown', linewidth=2.5)\n", "ax.add_feature(cfeature.BORDERS.with_scale(res), edgecolor='brown', linewidth=2.5)\n", "ax.add_feature(cfeature.STATES.with_scale(res), edgecolor='brown')\n", "\n", "# Temperature (T) contour fills\n", "\n", "# Note we don't need the transform argument since the map/data projections are the same, but we'll leave it in\n", "CF = ax.contourf(lons,lats,T,levels=tLevels,cmap=plt.get_cmap('coolwarm'), extend='both', transform=projData) \n", "\n", "# Height (Z) contour lines\n", "CL = ax.contour(lons,lats,Z,zLevels,linewidths=1.25,colors='yellow', transform=projData)\n", "ax.clabel(CL, inline_spacing=0.2, fontsize=8, fmt='%.0f')\n", "fig.tight_layout(pad=.01)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "Z" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "Z.isel(time=0)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "res = '110m'\n", "dpi = 100\n", "fig = plt.figure(figsize=(2048/dpi, 1024/dpi))\n", "ax = plt.subplot(1,1,1,projection=projData, frameon=False)\n", "\n", "ax.add_feature(cfeature.COASTLINE.with_scale(res), edgecolor='brown', linewidth=2.5)\n", "ax.add_feature(cfeature.BORDERS.with_scale(res), edgecolor='brown', linewidth=2.5)\n", "ax.add_feature(cfeature.STATES.with_scale(res), edgecolor='brown')\n", "\n", "# Temperature (T) contour fills\n", "\n", "# Note we don't need the transform argument since the map/data projections are the same, but we'll leave it in\n", "CF = ax.contourf(lons,lats,T.isel(time=0),levels=tLevels,cmap=plt.get_cmap('coolwarm'), extend='both', transform=projData) \n", "\n", "# Height (Z) contour lines\n", "CL = ax.contour(lons,lats,Z.isel(time=0),zLevels,linewidths=1.25,colors='yellow', transform=projData)\n", "ax.clabel(CL, inline_spacing=0.2, fontsize=8, fmt='%.0f')\n", "fig.tight_layout(pad=.01)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "lonW, lonE, latS, latN = -130, -60, 20, 55 \n", "\n", "lonRange = np.arange(lonW, lonE + 0.1, 0.25)\n", "latRange = np.arange(latS, latN + 0.1, 0.25)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "print(latRange)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "print(lonRange)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "ZSub2 = Z.sel(latitude = latRange, longitude = lonRange)\n", "TSub2 = T.sel(latitude = latRange, longitude = lonRange)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "lats" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "lons" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "ZSub2 = Z.sel(latitude = latRange, longitude = lonRange)\n", "TSub2 = T.sel(latitude = latRange, longitude = lonRange)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "lonW, lonE, latS, latN = -130, -60, 20, 55 " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "Z.latitude" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "Z.longitude" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "ZSub2 = Z.sel(latitude = latRange, longitude = lonRange)\n", "TSub2 = T.sel(latitude = latRange, longitude = lonRange)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "lonW, lonE, latN, latS = 230, 290, 55, 20 \n", "\n", "lonRange = np.arange(lonW, lonE - 0.1, 0.25)\n", "latRange = np.arange(latN, latS - 0.1, -0.25)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "ZSub2 = Z.sel(latitude = latRange, longitude = lonRange)\n", "TSub2 = T.sel(latitude = latRange, longitude = lonRange)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "ZSub2" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "projMap = ccrs.LambertConformal(central_longitude=(lonW + lonE) / 2., central_latitude=(latS + latN) / 2.)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "%%time \n", "res = '50m'\n", "dpi = 100\n", "fig = plt.figure(figsize=(2048/dpi, 1024/dpi))\n", "ax = plt.subplot(1,1,1,projection=projMap)\n", "\n", "ax.add_feature(cfeature.COASTLINE.with_scale(res), edgecolor='brown', linewidth=2.5)\n", "ax.add_feature(cfeature.BORDERS.with_scale(res), edgecolor='brown', linewidth=2.5)\n", "ax.add_feature(cfeature.STATES.with_scale(res), edgecolor='brown')\n", "\n", "# Temperature (T) contour fills\n", "\n", "CF = ax.contourf(lons,lats,T.isel(time=0),levels=tLevels,cmap=plt.get_cmap('coolwarm'), extend='both', transform=projData) \n", "\n", "# Height (Z) contour lines\n", "CL = ax.contour(lons,lats,Z.isel(time=0),zLevels,linewidths=1.25,colors='yellow', transform=projData)\n", "ax.clabel(CL, inline_spacing=0.2, fontsize=8, fmt='%.0f')\n", "fig.tight_layout(pad=.01)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "tags": [] }, "outputs": [], "source": [ "%%time \n", "res = '50m'\n", "dpi = 100\n", "fig = plt.figure(figsize=(2048/dpi, 1024/dpi))\n", "ax = plt.subplot(1,1,1,projection=projMap)\n", "\n", "ax.set_extent([lonW, lonE, latS, latN], crs=ccrs.PlateCarree())\n", "ax.add_feature(cfeature.COASTLINE.with_scale(res), edgecolor='k', linewidth=2.5)\n", "ax.add_feature(cfeature.BORDERS.with_scale(res), edgecolor='k', linewidth=2.5)\n", "ax.add_feature(cfeature.STATES.with_scale(res), edgecolor='k')\n", "\n", "# Temperature (T) contour fills\n", "\n", "CF = ax.contourf(TSub2.longitude,TSub2.latitude,TSub2.isel(time=0),levels=tLevels,cmap=plt.get_cmap('coolwarm'), extend='both', transform=projData) \n", "\n", "# Height (Z) contour lines\n", "CL = ax.contour(TSub2.longitude,TSub2.latitude,ZSub2.isel(time=0),zLevels,linewidths=1.25,colors='yellow', transform=projData)\n", "ax.clabel(CL, inline_spacing=0.2, fontsize=14, fmt='%.0f')\n", "fig.tight_layout(pad=.01)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3 August 2023 Environment", "language": "python", "name": "aug23" }, "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.11.4" }, "nbdime-conflicts": { "local_diff": [ { "diff": [ { "diff": [ { "key": 0, "op": "addrange", "valuelist": [ "Python 3" ] }, { "key": 0, "length": 1, "op": "removerange" } ], "key": "display_name", "op": "patch" } ], "key": "kernelspec", "op": "patch" } ], "remote_diff": [ { "diff": [ { "diff": [ { "key": 0, "op": "addrange", "valuelist": [ "Python3" ] }, { "key": 0, "length": 1, "op": "removerange" } ], "key": "display_name", "op": "patch" } ], "key": "kernelspec", "op": "patch" } ] }, "toc-autonumbering": false }, "nbformat": 4, "nbformat_minor": 4 }