Skip to content

merge scipy19 docs #3557

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Nov 22, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion ci/requirements/doc.yml
Original file line number Diff line number Diff line change
@@ -6,16 +6,23 @@ dependencies:
- python=3.7
- bottleneck
- cartopy
- eccodes
- h5netcdf
- ipykernel
- ipython
- iris
- jupyter_client
- nbsphinx
- netcdf4
- numpy
- numpydoc
- pandas<0.25 # Hack around https://github.com/pydata/xarray/issues/3369
- rasterio
- seaborn
- sphinx
- sphinx-gallery
- sphinx_rtd_theme
- zarr
- pip
- pip:
- cfgrib

20 changes: 12 additions & 8 deletions doc/conf.py
Original file line number Diff line number Diff line change
@@ -76,20 +76,24 @@
"numpydoc",
"IPython.sphinxext.ipython_directive",
"IPython.sphinxext.ipython_console_highlighting",
"sphinx_gallery.gen_gallery",
"nbsphinx",
]

extlinks = {
"issue": ("https://github.com/pydata/xarray/issues/%s", "GH"),
"pull": ("https://github.com/pydata/xarray/pull/%s", "PR"),
}

sphinx_gallery_conf = {
"examples_dirs": "gallery",
"gallery_dirs": "auto_gallery",
"backreferences_dir": False,
"expected_failing_examples": list(allowed_failures),
}
nbsphinx_timeout = 600
nbsphinx_execute = "always"
nbsphinx_prolog = """
{% set docname = env.doc2path(env.docname, base=None) %}
You can run this notebook in a `live session <https://mybinder.org/v2/gh/pydata/xarray/doc/examples/master?urlpath=lab/tree/doc/{{ docname }}>`_ |Binder| or view it `on Github <https://github.com/pydata/xarray/blob/master/doc/{{ docname }}>`_.
.. |Binder| image:: https://mybinder.org/badge.svg
:target: https://mybinder.org/v2/gh/pydata/xarray/master?urlpath=lab/tree/doc/{{ docname }}
"""

autosummary_generate = True
autodoc_typehints = "none"
@@ -137,7 +141,7 @@

# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ["_build"]
exclude_patterns = ["_build", "**.ipynb_checkpoints"]

# The reST default role (used for this markup: `text`) to use for all
# documents.
16 changes: 8 additions & 8 deletions doc/data-structures.rst
Original file line number Diff line number Diff line change
@@ -485,14 +485,14 @@ in xarray:
:py:class:`pandas.Index` internally to store their values.

- **non-dimension coordinates** are variables that contain coordinate
data, but are not a dimension coordinate. They can be multidimensional
(see :ref:`examples.multidim`), and there is no relationship between the
name of a non-dimension coordinate and the name(s) of its dimension(s).
Non-dimension coordinates can be useful for indexing or plotting; otherwise,
xarray does not make any direct use of the values associated with them.
They are not used for alignment or automatic indexing, nor are they required
to match when doing arithmetic
(see :ref:`coordinates math`).
data, but are not a dimension coordinate. They can be multidimensional (see
:ref:`/examples/multidimensional-coords.ipynb`), and there is no
relationship between the name of a non-dimension coordinate and the
name(s) of its dimension(s). Non-dimension coordinates can be
useful for indexing or plotting; otherwise, xarray does not make any
direct use of the values associated with them. They are not used
for alignment or automatic indexing, nor are they required to match
when doing arithmetic (see :ref:`coordinates math`).

.. note::

4 changes: 3 additions & 1 deletion doc/examples.rst
Original file line number Diff line number Diff line change
@@ -7,4 +7,6 @@ Examples
examples/weather-data
examples/monthly-means
examples/multidimensional-coords
auto_gallery/index
examples/visualization_gallery
examples/ROMS_ocean_model
examples/ERA5-GRIB-example
121 changes: 121 additions & 0 deletions doc/examples/ERA5-GRIB-example.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# GRIB Data Example "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"GRIB format is commonly used to disemminate atmospheric model data. With Xarray and the cfgrib engine, GRIB data can easily be analyzed and visualized."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import xarray as xr\n",
"import matplotlib.pyplot as plt"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To read GRIB data, you can use `xarray.load_dataset`. The only extra code you need is to specify the engine as `cfgrib`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"ds = xr.tutorial.load_dataset('era5-2mt-2019-03-uk.grib', engine='cfgrib')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's create a simple plot of 2-m air temperature in degrees Celsius:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"ds = ds - 273.15\n",
"ds.t2m[0].plot(cmap=plt.cm.coolwarm)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"With CartoPy, we can create a more detailed plot, using built-in shapefiles to help provide geographic context:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import cartopy.crs as ccrs\n",
"import cartopy\n",
"fig = plt.figure(figsize=(10,10))\n",
"ax = plt.axes(projection=ccrs.Robinson())\n",
"ax.coastlines(resolution='10m')\n",
"plot = ds.t2m[0].plot(cmap=plt.cm.coolwarm, transform=ccrs.PlateCarree(), cbar_kwargs={'shrink':0.6})\n",
"plt.title('ERA5 - 2m temperature British Isles March 2019')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Finally, we can also pull out a time series for a given location easily:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"ds.t2m.sel(longitude=0,latitude=51.5).plot()\n",
"plt.title('ERA5 - London 2m temperature March 2019')"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"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.7.3"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
226 changes: 226 additions & 0 deletions doc/examples/ROMS_ocean_model.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# ROMS Ocean Model Example"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The Regional Ocean Modeling System ([ROMS](http://myroms.org)) is an open source hydrodynamic model that is used for simulating currents and water properties in coastal and estuarine regions. ROMS is one of a few standard ocean models, and it has an active user community.\n",
"\n",
"ROMS uses a regular C-Grid in the horizontal, similar to other structured grid ocean and atmospheric models, and a stretched vertical coordinate (see [the ROMS documentation](https://www.myroms.org/wiki/Vertical_S-coordinate) for more details). Both of these require special treatment when using `xarray` to analyze ROMS ocean model output. This example notebook shows how to create a lazily evaluated vertical coordinate, and make some basic plots. The `xgcm` package is required to do analysis that is aware of the horizontal C-Grid."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import cartopy.crs as ccrs\n",
"import cartopy.feature as cfeature\n",
"import matplotlib.pyplot as plt\n",
"%matplotlib inline\n",
"\n",
"import xarray as xr"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Load a sample ROMS file. This is a subset of a full model available at \n",
"\n",
" http://barataria.tamu.edu/thredds/catalog.html?dataset=txla_hindcast_agg\n",
" \n",
"The subsetting was done using the following command on one of the output files:\n",
"\n",
" #open dataset\n",
" ds = xr.open_dataset('/d2/shared/TXLA_ROMS/output_20yr_obc/2001/ocean_his_0015.nc')\n",
" \n",
" # Turn on chunking to activate dask and parallelize read/write.\n",
" ds = ds.chunk({'ocean_time': 1})\n",
" \n",
" # Pick out some of the variables that will be included as coordinates\n",
" ds = ds.set_coords(['Cs_r', 'Cs_w', 'hc', 'h', 'Vtransform'])\n",
" \n",
" # Select a a subset of variables. Salt will be visualized, zeta is used to \n",
" # calculate the vertical coordinate\n",
" variables = ['salt', 'zeta']\n",
" ds[variables].isel(ocean_time=slice(47, None, 7*24), \n",
" xi_rho=slice(300, None)).to_netcdf('ROMS_example.nc', mode='w')\n",
"\n",
"So, the `ROMS_example.nc` file contains a subset of the grid, one 3D variable, and two time steps."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Load in ROMS dataset as an xarray object"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# load in the file\n",
"ds = xr.tutorial.open_dataset('ROMS_example.nc', chunks={'ocean_time': 1})\n",
"\n",
"# This is a way to turn on chunking and lazy evaluation. Opening with mfdataset, or \n",
"# setting the chunking in the open_dataset would also achive this.\n",
"ds"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Add a lazilly calculated vertical coordinates\n",
"\n",
"Write equations to calculate the vertical coordinate. These will be only evaluated when data is requested. Information about the ROMS vertical coordinate can be found (here)[https://www.myroms.org/wiki/Vertical_S-coordinate]\n",
"\n",
"In short, for `Vtransform==2` as used in this example, \n",
"\n",
"$Z_0 = (h_c \\, S + h \\,C) / (h_c + h)$\n",
"\n",
"$z = Z_0 (\\zeta + h) + \\zeta$\n",
"\n",
"where the variables are defined as in the link above."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"if ds.Vtransform == 1:\n",
" Zo_rho = ds.hc * (ds.s_rho - ds.Cs_r) + ds.Cs_r * ds.h\n",
" z_rho = Zo_rho + ds.zeta * (1 + Zo_rho/ds.h)\n",
"elif ds.Vtransform == 2:\n",
" Zo_rho = (ds.hc * ds.s_rho + ds.Cs_r * ds.h) / (ds.hc + ds.h)\n",
" z_rho = ds.zeta + (ds.zeta + ds.h) * Zo_rho\n",
"\n",
"ds.coords['z_rho'] = z_rho.transpose() # needing transpose seems to be an xarray bug\n",
"ds.salt"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### A naive vertical slice\n",
"\n",
"Create a slice using the s-coordinate as the vertical dimension is typically not very informative."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": false
},
"outputs": [],
"source": [
"ds.salt.isel(xi_rho=50, ocean_time=0).plot()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can feed coordinate information to the plot method to give a more informative cross-section that uses the depths. Note that we did not need to slice the depth or longitude information separately, this was done automatically as the variable was sliced."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"section = ds.salt.isel(xi_rho=50, eta_rho=slice(0, 167), ocean_time=0)\n",
"section.plot(x='lon_rho', y='z_rho', figsize=(15, 6), clim=(25, 35))\n",
"plt.ylim([-100, 1]);"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### A plan view\n",
"\n",
"Now make a naive plan view, without any projection information, just using lon/lat as x/y. This looks OK, but will appear compressed because lon and lat do not have an aspect constrained by the projection."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"ds.salt.isel(s_rho=-1, ocean_time=0).plot(x='lon_rho', y='lat_rho')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"And let's use a projection to make it nicer, and add a coast."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"proj = ccrs.LambertConformal(central_longitude=-92, central_latitude=29)\n",
"fig = plt.figure(figsize=(15, 5))\n",
"ax = plt.axes(projection=proj)\n",
"ds.salt.isel(s_rho=-1, ocean_time=0).plot(x='lon_rho', y='lat_rho', \n",
" transform=ccrs.PlateCarree())\n",
"\n",
"coast_10m = cfeature.NaturalEarthFeature('physical', 'land', '10m',\n",
" edgecolor='k', facecolor='0.8')\n",
"ax.add_feature(coast_10m)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"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.6.7"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
325 changes: 325 additions & 0 deletions doc/examples/monthly-means.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,325 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Calculating Seasonal Averages from Timeseries of Monthly Means \n",
"=====\n",
"\n",
"Author: [Joe Hamman](https://github.com/jhamman/)\n",
"\n",
"The data used for this example can be found in the [xarray-data](https://github.com/pydata/xarray-data) repository. You may need to change the path to `rasm.nc` below.\n",
"\n",
"Suppose we have a netCDF or `xarray.Dataset` of monthly mean data and we want to calculate the seasonal average. To do this properly, we need to calculate the weighted average considering that each month has a different number of days."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2018-11-28T20:51:35.958210Z",
"start_time": "2018-11-28T20:51:35.936966Z"
}
},
"outputs": [],
"source": [
"%matplotlib inline\n",
"import numpy as np\n",
"import pandas as pd\n",
"import xarray as xr\n",
"from netCDF4 import num2date\n",
"import matplotlib.pyplot as plt "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Some calendar information so we can support any netCDF calendar. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2018-11-28T20:51:35.991620Z",
"start_time": "2018-11-28T20:51:35.960336Z"
}
},
"outputs": [],
"source": [
"dpm = {'noleap': [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],\n",
" '365_day': [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],\n",
" 'standard': [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],\n",
" 'gregorian': [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],\n",
" 'proleptic_gregorian': [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],\n",
" 'all_leap': [0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],\n",
" '366_day': [0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],\n",
" '360_day': [0, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30]} "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### A few calendar functions to determine the number of days in each month\n",
"If you were just using the standard calendar, it would be easy to use the `calendar.month_range` function."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2018-11-28T20:51:36.015151Z",
"start_time": "2018-11-28T20:51:35.994079Z"
}
},
"outputs": [],
"source": [
"def leap_year(year, calendar='standard'):\n",
" \"\"\"Determine if year is a leap year\"\"\"\n",
" leap = False\n",
" if ((calendar in ['standard', 'gregorian',\n",
" 'proleptic_gregorian', 'julian']) and\n",
" (year % 4 == 0)):\n",
" leap = True\n",
" if ((calendar == 'proleptic_gregorian') and\n",
" (year % 100 == 0) and\n",
" (year % 400 != 0)):\n",
" leap = False\n",
" elif ((calendar in ['standard', 'gregorian']) and\n",
" (year % 100 == 0) and (year % 400 != 0) and\n",
" (year < 1583)):\n",
" leap = False\n",
" return leap\n",
"\n",
"def get_dpm(time, calendar='standard'):\n",
" \"\"\"\n",
" return a array of days per month corresponding to the months provided in `months`\n",
" \"\"\"\n",
" month_length = np.zeros(len(time), dtype=np.int)\n",
" \n",
" cal_days = dpm[calendar]\n",
" \n",
" for i, (month, year) in enumerate(zip(time.month, time.year)):\n",
" month_length[i] = cal_days[month]\n",
" if leap_year(year, calendar=calendar) and month == 2:\n",
" month_length[i] += 1\n",
" return month_length"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Open the `Dataset`"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2018-11-28T20:51:36.072316Z",
"start_time": "2018-11-28T20:51:36.016594Z"
}
},
"outputs": [],
"source": [
"ds = xr.tutorial.open_dataset('rasm').load()\n",
"print(ds)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Now for the heavy lifting:\n",
"We first have to come up with the weights,\n",
"- calculate the month lengths for each monthly data record\n",
"- calculate weights using `groupby('time.season')`\n",
"\n",
"Finally, we just need to multiply our weights by the `Dataset` and sum allong the time dimension. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2018-11-28T20:51:36.132413Z",
"start_time": "2018-11-28T20:51:36.073708Z"
}
},
"outputs": [],
"source": [
"# Make a DataArray with the number of days in each month, size = len(time)\n",
"month_length = xr.DataArray(get_dpm(ds.time.to_index(), calendar='noleap'),\n",
" coords=[ds.time], name='month_length')\n",
"\n",
"# Calculate the weights by grouping by 'time.season'.\n",
"# Conversion to float type ('astype(float)') only necessary for Python 2.x\n",
"weights = month_length.groupby('time.season') / month_length.astype(float).groupby('time.season').sum()\n",
"\n",
"# Test that the sum of the weights for each season is 1.0\n",
"np.testing.assert_allclose(weights.groupby('time.season').sum().values, np.ones(4))\n",
"\n",
"# Calculate the weighted average\n",
"ds_weighted = (ds * weights).groupby('time.season').sum(dim='time')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2018-11-28T20:51:36.152913Z",
"start_time": "2018-11-28T20:51:36.133997Z"
}
},
"outputs": [],
"source": [
"print(ds_weighted)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2018-11-28T20:51:36.190765Z",
"start_time": "2018-11-28T20:51:36.154416Z"
}
},
"outputs": [],
"source": [
"# only used for comparisons\n",
"ds_unweighted = ds.groupby('time.season').mean('time')\n",
"ds_diff = ds_weighted - ds_unweighted"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2018-11-28T20:51:40.264871Z",
"start_time": "2018-11-28T20:51:36.192467Z"
}
},
"outputs": [],
"source": [
"# Quick plot to show the results\n",
"notnull = pd.notnull(ds_unweighted['Tair'][0])\n",
"\n",
"fig, axes = plt.subplots(nrows=4, ncols=3, figsize=(14,12))\n",
"for i, season in enumerate(('DJF', 'MAM', 'JJA', 'SON')):\n",
" ds_weighted['Tair'].sel(season=season).where(notnull).plot.pcolormesh(\n",
" ax=axes[i, 0], vmin=-30, vmax=30, cmap='Spectral_r', \n",
" add_colorbar=True, extend='both')\n",
" \n",
" ds_unweighted['Tair'].sel(season=season).where(notnull).plot.pcolormesh(\n",
" ax=axes[i, 1], vmin=-30, vmax=30, cmap='Spectral_r', \n",
" add_colorbar=True, extend='both')\n",
"\n",
" ds_diff['Tair'].sel(season=season).where(notnull).plot.pcolormesh(\n",
" ax=axes[i, 2], vmin=-0.1, vmax=.1, cmap='RdBu_r',\n",
" add_colorbar=True, extend='both')\n",
"\n",
" axes[i, 0].set_ylabel(season)\n",
" axes[i, 1].set_ylabel('')\n",
" axes[i, 2].set_ylabel('')\n",
"\n",
"for ax in axes.flat:\n",
" ax.axes.get_xaxis().set_ticklabels([])\n",
" ax.axes.get_yaxis().set_ticklabels([])\n",
" ax.axes.axis('tight')\n",
" ax.set_xlabel('')\n",
" \n",
"axes[0, 0].set_title('Weighted by DPM')\n",
"axes[0, 1].set_title('Equal Weighting')\n",
"axes[0, 2].set_title('Difference')\n",
" \n",
"plt.tight_layout()\n",
"\n",
"fig.suptitle('Seasonal Surface Air Temperature', fontsize=16, y=1.02)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2018-11-28T20:51:40.284898Z",
"start_time": "2018-11-28T20:51:40.266406Z"
}
},
"outputs": [],
"source": [
"# Wrap it into a simple function\n",
"def season_mean(ds, calendar='standard'):\n",
" # Make a DataArray of season/year groups\n",
" year_season = xr.DataArray(ds.time.to_index().to_period(freq='Q-NOV').to_timestamp(how='E'),\n",
" coords=[ds.time], name='year_season')\n",
"\n",
" # Make a DataArray with the number of days in each month, size = len(time)\n",
" month_length = xr.DataArray(get_dpm(ds.time.to_index(), calendar=calendar),\n",
" coords=[ds.time], name='month_length')\n",
" # Calculate the weights by grouping by 'time.season'\n",
" weights = month_length.groupby('time.season') / month_length.groupby('time.season').sum()\n",
"\n",
" # Test that the sum of the weights for each season is 1.0\n",
" np.testing.assert_allclose(weights.groupby('time.season').sum().values, np.ones(4))\n",
"\n",
" # Calculate the weighted average\n",
" return (ds * weights).groupby('time.season').sum(dim='time')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"anaconda-cloud": {},
"kernelspec": {
"display_name": "Python 3",
"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.6.8"
},
"toc": {
"base_numbering": 1,
"nav_menu": {},
"number_sections": true,
"sideBar": true,
"skip_h1_title": false,
"title_cell": "Table of Contents",
"title_sidebar": "Contents",
"toc_cell": true,
"toc_position": {},
"toc_section_display": true,
"toc_window_display": true
}
},
"nbformat": 4,
"nbformat_minor": 2
}
244 changes: 0 additions & 244 deletions doc/examples/monthly-means.rst

This file was deleted.

233 changes: 233 additions & 0 deletions doc/examples/multidimensional-coords.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Working with Multidimensional Coordinates\n",
"\n",
"Author: [Ryan Abernathey](https://github.com/rabernat)\n",
"\n",
"Many datasets have _physical coordinates_ which differ from their _logical coordinates_. Xarray provides several ways to plot and analyze such datasets."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2018-11-28T20:49:56.068395Z",
"start_time": "2018-11-28T20:49:56.035349Z"
}
},
"outputs": [],
"source": [
"%matplotlib inline\n",
"import numpy as np\n",
"import pandas as pd\n",
"import xarray as xr\n",
"import cartopy.crs as ccrs\n",
"from matplotlib import pyplot as plt"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"As an example, consider this dataset from the [xarray-data](https://github.com/pydata/xarray-data) repository."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2018-11-28T20:50:13.629720Z",
"start_time": "2018-11-28T20:50:13.484542Z"
}
},
"outputs": [],
"source": [
"ds = xr.tutorial.open_dataset('rasm').load()\n",
"ds"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In this example, the _logical coordinates_ are `x` and `y`, while the _physical coordinates_ are `xc` and `yc`, which represent the latitudes and longitude of the data."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2018-11-28T20:50:15.836061Z",
"start_time": "2018-11-28T20:50:15.768376Z"
}
},
"outputs": [],
"source": [
"print(ds.xc.attrs)\n",
"print(ds.yc.attrs)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Plotting ##\n",
"\n",
"Let's examine these coordinate variables by plotting them."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2018-11-28T20:50:17.928556Z",
"start_time": "2018-11-28T20:50:17.031211Z"
}
},
"outputs": [],
"source": [
"fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(14,4))\n",
"ds.xc.plot(ax=ax1)\n",
"ds.yc.plot(ax=ax2)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Note that the variables `xc` (longitude) and `yc` (latitude) are two-dimensional scalar fields.\n",
"\n",
"If we try to plot the data variable `Tair`, by default we get the logical coordinates."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2018-11-28T20:50:20.567749Z",
"start_time": "2018-11-28T20:50:19.999393Z"
}
},
"outputs": [],
"source": [
"ds.Tair[0].plot()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In order to visualize the data on a conventional latitude-longitude grid, we can take advantage of xarray's ability to apply [cartopy](http://scitools.org.uk/cartopy/index.html) map projections."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2018-11-28T20:50:31.131708Z",
"start_time": "2018-11-28T20:50:30.444697Z"
}
},
"outputs": [],
"source": [
"plt.figure(figsize=(14,6))\n",
"ax = plt.axes(projection=ccrs.PlateCarree())\n",
"ax.set_global()\n",
"ds.Tair[0].plot.pcolormesh(ax=ax, transform=ccrs.PlateCarree(), x='xc', y='yc', add_colorbar=False)\n",
"ax.coastlines()\n",
"ax.set_ylim([0,90]);"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Multidimensional Groupby ##\n",
"\n",
"The above example allowed us to visualize the data on a regular latitude-longitude grid. But what if we want to do a calculation that involves grouping over one of these physical coordinates (rather than the logical coordinates), for example, calculating the mean temperature at each latitude. This can be achieved using xarray's `groupby` function, which accepts multidimensional variables. By default, `groupby` will use every unique value in the variable, which is probably not what we want. Instead, we can use the `groupby_bins` function to specify the output coordinates of the group. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ExecuteTime": {
"end_time": "2018-11-28T20:50:43.670463Z",
"start_time": "2018-11-28T20:50:43.245501Z"
}
},
"outputs": [],
"source": [
"# define two-degree wide latitude bins\n",
"lat_bins = np.arange(0,91,2)\n",
"# define a label for each bin corresponding to the central latitude\n",
"lat_center = np.arange(1,90,2)\n",
"# group according to those bins and take the mean\n",
"Tair_lat_mean = ds.Tair.groupby_bins('xc', lat_bins, labels=lat_center).mean(dim=xr.ALL_DIMS)\n",
"# plot the result\n",
"Tair_lat_mean.plot()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The resulting coordinate for the `groupby_bins` operation got the `_bins` suffix appended: `xc_bins`. This help us distinguish it from the original multidimensional variable `xc`.\n",
"\n",
"**Note**: This group-by-latitude approach does not take into account the finite-size geometry of grid cells. It simply bins each value according to the coordinates at the cell center. Xarray has no understanding of grid cells and their geometry. More precise geographic regridding for Xarray data is available via the [xesmf](https://xesmf.readthedocs.io) package."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"anaconda-cloud": {},
"kernelspec": {
"display_name": "Python 3",
"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.6.8"
},
"toc": {
"base_numbering": 1,
"nav_menu": {},
"number_sections": true,
"sideBar": true,
"skip_h1_title": false,
"title_cell": "Table of Contents",
"title_sidebar": "Contents",
"toc_cell": true,
"toc_position": {},
"toc_section_display": true,
"toc_window_display": true
}
},
"nbformat": 4,
"nbformat_minor": 2
}
118 changes: 0 additions & 118 deletions doc/examples/multidimensional-coords.rst

This file was deleted.

296 changes: 296 additions & 0 deletions doc/examples/visualization_gallery.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,296 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Visualization Gallery\n",
"\n",
"This notebook shows common visualization issues encountered in Xarray."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import cartopy.crs as ccrs\n",
"import matplotlib.pyplot as plt\n",
"import xarray as xr\n",
"%matplotlib inline"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Load example dataset:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"ds = xr.tutorial.load_dataset('air_temperature')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Multiple plots and map projections\n",
"\n",
"Control the map projection parameters on multiple axes\n",
"\n",
"This example illustrates how to plot multiple maps and control their extent\n",
"and aspect ratio.\n",
"\n",
"For more details see [this discussion](https://github.com/pydata/xarray/issues/1397#issuecomment-299190567) on github."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"air = ds.air.isel(time=[0, 724]) - 273.15\n",
"\n",
"# This is the map projection we want to plot *onto*\n",
"map_proj = ccrs.LambertConformal(central_longitude=-95, central_latitude=45)\n",
"\n",
"p = air.plot(transform=ccrs.PlateCarree(), # the data's projection\n",
" col='time', col_wrap=1, # multiplot settings\n",
" aspect=ds.dims['lon'] / ds.dims['lat'], # for a sensible figsize\n",
" subplot_kws={'projection': map_proj}) # the plot's projection\n",
"\n",
"# We have to set the map's options on all axes\n",
"for ax in p.axes.flat:\n",
" ax.coastlines()\n",
" ax.set_extent([-160, -30, 5, 75])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Centered colormaps\n",
"\n",
"Xarray's automatic colormaps choice"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"air = ds.air.isel(time=0)\n",
"\n",
"f, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(8, 6))\n",
"\n",
"# The first plot (in kelvins) chooses \"viridis\" and uses the data's min/max\n",
"air.plot(ax=ax1, cbar_kwargs={'label': 'K'})\n",
"ax1.set_title('Kelvins: default')\n",
"ax2.set_xlabel('')\n",
"\n",
"# The second plot (in celsius) now chooses \"BuRd\" and centers min/max around 0\n",
"airc = air - 273.15\n",
"airc.plot(ax=ax2, cbar_kwargs={'label': '°C'})\n",
"ax2.set_title('Celsius: default')\n",
"ax2.set_xlabel('')\n",
"ax2.set_ylabel('')\n",
"\n",
"# The center doesn't have to be 0\n",
"air.plot(ax=ax3, center=273.15, cbar_kwargs={'label': 'K'})\n",
"ax3.set_title('Kelvins: center=273.15')\n",
"\n",
"# Or it can be ignored\n",
"airc.plot(ax=ax4, center=False, cbar_kwargs={'label': '°C'})\n",
"ax4.set_title('Celsius: center=False')\n",
"ax4.set_ylabel('')\n",
"\n",
"# Make it nice\n",
"plt.tight_layout()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Control the plot's colorbar\n",
"\n",
"Use ``cbar_kwargs`` keyword to specify the number of ticks.\n",
"The ``spacing`` kwarg can be used to draw proportional ticks."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"air2d = ds.air.isel(time=500)\n",
"\n",
"# Prepare the figure\n",
"f, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(14, 4))\n",
"\n",
"# Irregular levels to illustrate the use of a proportional colorbar\n",
"levels = [245, 250, 255, 260, 265, 270, 275, 280, 285, 290, 310, 340]\n",
"\n",
"# Plot data\n",
"air2d.plot(ax=ax1, levels=levels)\n",
"air2d.plot(ax=ax2, levels=levels, cbar_kwargs={'ticks': levels})\n",
"air2d.plot(ax=ax3, levels=levels, cbar_kwargs={'ticks': levels,\n",
" 'spacing': 'proportional'})\n",
"\n",
"# Show plots\n",
"plt.tight_layout()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Multiple lines from a 2d DataArray\n",
"\n",
"Use ``xarray.plot.line`` on a 2d DataArray to plot selections as\n",
"multiple lines.\n",
"\n",
"See ``plotting.multiplelines`` for more details."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"air = ds.air - 273.15 # to celsius\n",
"\n",
"# Prepare the figure\n",
"f, (ax1, ax2) = plt.subplots(1, 2, figsize=(8, 4), sharey=True)\n",
"\n",
"# Selected latitude indices\n",
"isel_lats = [10, 15, 20]\n",
"\n",
"# Temperature vs longitude plot - illustrates the \"hue\" kwarg\n",
"air.isel(time=0, lat=isel_lats).plot.line(ax=ax1, hue='lat')\n",
"ax1.set_ylabel('°C')\n",
"\n",
"# Temperature vs time plot - illustrates the \"x\" and \"add_legend\" kwargs\n",
"air.isel(lon=30, lat=isel_lats).plot.line(ax=ax2, x='time', add_legend=False)\n",
"ax2.set_ylabel('')\n",
"\n",
"# Show\n",
"plt.tight_layout()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## `imshow()` and rasterio map projections\n",
"\n",
"\n",
"Using rasterio's projection information for more accurate plots.\n",
"\n",
"This example extends `recipes.rasterio` and plots the image in the\n",
"original map projection instead of relying on pcolormesh and a map\n",
"transformation."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"url = 'https://github.com/mapbox/rasterio/raw/master/tests/data/RGB.byte.tif'\n",
"da = xr.open_rasterio(url)\n",
"\n",
"# The data is in UTM projection. We have to set it manually until\n",
"# https://github.com/SciTools/cartopy/issues/813 is implemented\n",
"crs = ccrs.UTM('18N')\n",
"\n",
"# Plot on a map\n",
"ax = plt.subplot(projection=crs)\n",
"da.plot.imshow(ax=ax, rgb='band', transform=crs)\n",
"ax.coastlines('10m', color='r')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Parsing rasterio geocoordinates\n",
"\n",
"Converting a projection's cartesian coordinates into 2D longitudes and\n",
"latitudes.\n",
"\n",
"These new coordinates might be handy for plotting and indexing, but it should\n",
"be kept in mind that a grid which is regular in projection coordinates will\n",
"likely be irregular in lon/lat. It is often recommended to work in the data's\n",
"original map projection (see `recipes.rasterio_rgb`)."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from rasterio.warp import transform\n",
"import numpy as np\n",
"\n",
"url = 'https://github.com/mapbox/rasterio/raw/master/tests/data/RGB.byte.tif'\n",
"da = xr.open_rasterio(url)\n",
"\n",
"# Compute the lon/lat coordinates with rasterio.warp.transform\n",
"ny, nx = len(da['y']), len(da['x'])\n",
"x, y = np.meshgrid(da['x'], da['y'])\n",
"\n",
"# Rasterio works with 1D arrays\n",
"lon, lat = transform(da.crs, {'init': 'EPSG:4326'},\n",
" x.flatten(), y.flatten())\n",
"lon = np.asarray(lon).reshape((ny, nx))\n",
"lat = np.asarray(lat).reshape((ny, nx))\n",
"da.coords['lon'] = (('y', 'x'), lon)\n",
"da.coords['lat'] = (('y', 'x'), lat)\n",
"\n",
"# Compute a greyscale out of the rgb image\n",
"greyscale = da.mean(dim='band')\n",
"\n",
"# Plot on a map\n",
"ax = plt.subplot(projection=ccrs.PlateCarree())\n",
"greyscale.plot(ax=ax, x='lon', y='lat', transform=ccrs.PlateCarree(),\n",
" cmap='Greys_r', add_colorbar=False)\n",
"ax.coastlines('10m', color='r')"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"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.7.3"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
4 changes: 2 additions & 2 deletions doc/io.rst
Original file line number Diff line number Diff line change
@@ -735,8 +735,8 @@ The ``x`` and ``y`` coordinates are generated out of the file's metadata
(``bounds``, ``width``, ``height``), and they can be understood as cartesian
coordinates defined in the file's projection provided by the ``crs`` attribute.
``crs`` is a PROJ4 string which can be parsed by e.g. `pyproj`_ or rasterio.
See :ref:`recipes.rasterio` for an example of how to convert these to
longitudes and latitudes.
See :ref:`/examples/visualization_gallery.ipynb#Parsing-rasterio-geocoordinates`
for an example of how to convert these to longitudes and latitudes.

.. warning::

2 changes: 1 addition & 1 deletion doc/plotting.rst
Original file line number Diff line number Diff line change
@@ -782,7 +782,7 @@ coordinates.
Multidimensional coordinates
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

See also: :ref:`examples.multidim`.
See also: :ref:`/examples/multidimensional-coords.ipynb`.

You can plot irregular grids defined by multidimensional coordinates with
xarray, but you'll have to tell the plot function to use these coordinates
17 changes: 14 additions & 3 deletions doc/whats-new.rst
Original file line number Diff line number Diff line change
@@ -33,7 +33,18 @@ Bug fixes

Documentation
~~~~~~~~~~~~~

- Switch doc examples to use nbsphinx and replace sphinx_gallery with
notebook.
(:pull:`3105`, :pull:`3106`, :pull:`3121`)
By `Ryan Abernathey <https://github.com/rabernat>`
- Added example notebook demonstrating use of xarray with Regional Ocean
Modeling System (ROMS) ocean hydrodynamic model output.
(:pull:`3116`).
By `Robert Hetland <https://github.com/hetland>`
- Added example notebook demonstrating the visualization of ERA5 GRIB
data. (:pull:`3199`)
By `Zach Bruick <https://github.com/zbruick>` and
`Stephan Siemen <https://github.com/StephanSiemen>`

Internal Changes
~~~~~~~~~~~~~~~~
@@ -2777,7 +2788,7 @@ Enhancements
- Groupby operations now support grouping over multidimensional variables. A new
method called :py:meth:`~xarray.Dataset.groupby_bins` has also been added to
allow users to specify bins for grouping. The new features are described in
:ref:`groupby.multidim` and :ref:`examples.multidim`.
:ref:`groupby.multidim` and :ref:`/examples/multidimensional-coords.ipynb`.
By `Ryan Abernathey <https://github.com/rabernat>`_.

- DataArray and Dataset method :py:meth:`where` now supports a ``drop=True``
@@ -3842,7 +3853,7 @@ Enhancements
- Long attributes are now truncated at 500 characters when printing a dataset
(:issue:`338`). This should make things more convenient for working with
datasets interactively.
- Added a new documentation example, :ref:`monthly means example`. Thanks Joe
- Added a new documentation example, :ref:`/examples/monthly-means.ipynb`. Thanks Joe
Hamman!

Bug fixes
370 changes: 0 additions & 370 deletions examples/xarray_multidimensional_coords.ipynb

This file was deleted.

427 changes: 0 additions & 427 deletions examples/xarray_seasonal_means.ipynb

This file was deleted.

12 changes: 8 additions & 4 deletions xarray/tutorial.py
Original file line number Diff line number Diff line change
@@ -42,8 +42,9 @@ def open_dataset(
Parameters
----------
name : str
Name of the netcdf file containing the dataset
ie. 'air_temperature'
Name of the file containing the dataset. If no suffix is given, assumed
to be netCDF ('.nc' is appended)
e.g. 'air_temperature'
cache_dir : string, optional
The directory in which to search for and write cached data.
cache : boolean, optional
@@ -60,10 +61,13 @@ def open_dataset(
xarray.open_dataset
"""
root, ext = _os.path.splitext(name)
if not ext:
ext = ".nc"
fullname = root + ext
longdir = _os.path.expanduser(cache_dir)
fullname = name + ".nc"
localfile = _os.sep.join((longdir, fullname))
md5name = name + ".md5"
md5name = fullname + ".md5"
md5file = _os.sep.join((longdir, md5name))

if not _os.path.exists(localfile):