From d95501432e04379b00e86140cb49b96ff30585fd Mon Sep 17 00:00:00 2001 From: Jessica Scheick Date: Mon, 3 Apr 2023 18:10:55 -0400 Subject: [PATCH 01/23] add advanced/accessors section and remove accessors part 2 from xarray ecosystem --- advanced/accessors/01_accessor_examples.ipynb | 109 ++++++++++++++++++ advanced/accessors/accessors.md | 17 +++ intermediate/xarray_ecosystem.ipynb | 104 +++++------------ 3 files changed, 154 insertions(+), 76 deletions(-) create mode 100644 advanced/accessors/01_accessor_examples.ipynb create mode 100644 advanced/accessors/accessors.md diff --git a/advanced/accessors/01_accessor_examples.ipynb b/advanced/accessors/01_accessor_examples.ipynb new file mode 100644 index 00000000..737a47c8 --- /dev/null +++ b/advanced/accessors/01_accessor_examples.ipynb @@ -0,0 +1,109 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Creating custom accessors" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Introduction\n", + "\n", + "An accessor is a way of attaching a custom function to xarray types so that it can be called as if it were a method while retaining a clear separation between \"core\" xarray API and custom API. It enables you to easily extend and customize xarray's functionality while limiting naming conflicts and minimizing the chances of your code breaking with xarray upgrades.\n", + "\n", + "If you've used [rioxarray](https://corteva.github.io/rioxarray/stable/) (e.g. `da.rio.crs`) or [hvplot](https://hvplot.holoviz.org/) (e.g. `ds.hvplot()`), you may have already used an xarray accessor without knowing it!" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Easy steps to create your own accessor\n", + "\n", + "1. Create your custom class, including the mandatory `__init__` method\n", + "2. Add the `xr.register_dataarray_accessor()` or `xr.register_dataset_accessor()` \n", + "3. Use your custom functions " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Example 1: accessing scipy functionality" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For example, imagine you're a statistician who regularly uses a special `skewness` function which acts on dataarrays but is only of interest to people in your specific field.\n", + "\n", + "You can create a method which applies this skewness function to an xarray objects, and then register the method under a custom `stats` accessor like this" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from scipy.stats import skew\n", + "\n", + "\n", + "@xr.register_dataarray_accessor(\"stats\")\n", + "class StatsAccessor:\n", + " def __init__(self, da):\n", + " self._da = da\n", + "\n", + " def skewness(self, dim):\n", + " return self._da.reduce(func=skew, dim=dim)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can conveniently access this functionality via the `stats` accessor" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ds['air'].stats.skewness(dim=\"time\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notice how the presence of `.stats` clearly differentiates our new \"accessor method\" from core xarray methods." + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Example 2: creating your own functions" + ] + } + ], + "metadata": { + "language_info": { + "name": "python" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/advanced/accessors/accessors.md b/advanced/accessors/accessors.md new file mode 100644 index 00000000..b76491bd --- /dev/null +++ b/advanced/accessors/accessors.md @@ -0,0 +1,17 @@ + +## Why create a custom accessor + +- You can easily create a custom suite of tools that work on Xarray objects +- It keeps your workflows cleaner and simpler +- Your project-specific code is easy to share without needing to create a software package +- It's easy to implement: you don't need to integrate any code in Xarray + +## Next + +See the [documentation](https://docs.xarray.dev/en/stable/internals/extending-xarray.html) for more. + +Follow the tutorial for example custom accessors and their uses. + +```{tableofcontents} + +``` diff --git a/intermediate/xarray_ecosystem.ipynb b/intermediate/xarray_ecosystem.ipynb index a08f1cd8..b431da0a 100644 --- a/intermediate/xarray_ecosystem.ipynb +++ b/intermediate/xarray_ecosystem.ipynb @@ -1,18 +1,20 @@ { "cells": [ { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", - "# A Tour of the Xarray Ecosystem\n", + "# Customizing Xarray: A Tour of the Xarray Ecosystem\n", "\n", "Xarray is easily extensible.\n", - "This means it is easy to add onto to build custom packages that tackle particular computational problems.\n", + "This means it is easy to add onto to build custom packages that tackle particular computational problems\n", + "or supply domain specific functionality.\n", "\n", "These packages can plug in to xarray in various different ways. They may build directly on top of xarray, or they may take advantage of some of xarray's dedicated interfacing features:\n", - "- Accessors\n", + "- Accessors (extensions)\n", "- Backend (filetype) entrypoint\n", "- Metadata attributes\n", "- Duck-array wrapping interface\n", @@ -20,6 +22,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -31,6 +34,14 @@ "- [pint-xarray](https://pint-xarray.readthedocs.io/en/latest/), for unit-aware computations using pint." ] }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Specific examples for implementing your own xarray customizations using these interfacing features are available in the ADVANCED section of this book." + ] + }, { "cell_type": "code", "execution_count": null, @@ -49,6 +60,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": { "tags": [] @@ -58,9 +70,7 @@ "\n", "The accessor-style syntax is used heavily by the other libraries we are about to cover.\n", "\n", - "For users accessors just allow us to have a method-like syntax on xarray objects, for example `da.hvplot()`, `da.pint.quantify()`, or `da.cf.describe()`.\n", - "\n", - "For developers who are interested in defining their own accessors, see the section on accessors at the bottom of this page." + "For users, accessors just allow us to have a familiar dot (method-like) syntax on xarray objects, for example `da.hvplot()`, `da.pint.quantify()`, or `da.cf.describe()`.\n" ] }, { @@ -71,10 +81,11 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ - "The [HoloViews library](https://holoviews.org/) makes great use of accessors to allow seamless plotting of xarray data using a completely different plotting backend." + "The [HoloViews library](https://holoviews.org/) makes great use of accessors to allow seamless plotting of xarray data using a completely different plotting backend (by default, xarray uses [matplotlib](https://matplotlib.org/))." ] }, { @@ -119,10 +130,11 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ - "For some more examples of how powerful holoviews is [see here](https://tutorial.xarray.dev/intermediate/hvplot.html)." + "For some more examples of how powerful HoloViews is [see here](https://tutorial.xarray.dev/intermediate/hvplot.html)." ] }, { @@ -153,10 +165,11 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ - "You can explicitly use rioxarray's 'rasterio' engine to load myriad geospatial raster formats, below is a [Cloud-Optimized Geotiff](https://www.cogeo.org) from an AWS [public dataset](https://registry.opendata.aws/sentinel-1-rtc-indigo/) of synthetic aperture radar data over Washington, State, USA. `overview_level=4` is an argument specific to the `rasterio` engine that allows opening a pre-computed lower resolution \"overview\" of the data." + "You can explicitly use rioxarray's 'rasterio' engine to load myriad geospatial raster formats. Below is a [Cloud-Optimized Geotiff](https://www.cogeo.org) from an AWS [public dataset](https://registry.opendata.aws/sentinel-1-rtc-indigo/) of synthetic aperture radar data over Washington, State, USA. `overview_level=4` is an argument specific to the `rasterio` engine that allows opening a pre-computed lower resolution \"overview\" of the data." ] }, { @@ -171,10 +184,11 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ - "The `spatial_ref` coordinate is added by rioxarray to store standardized geospatial Coordinate Reference System (CRS) information, we can access that information and additional methods via the `.rio` accessor:" + "The `spatial_ref` coordinate is added by rioxarray to store standardized geospatial Coordinate Reference System (CRS) information. We can access that information and additional methods via the `.rio` accessor:" ] }, { @@ -187,10 +201,11 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ - "EPSG refers to 'European Petroleum Survey Group' a database of the many CRS definitions for our Planet used over the years! EPSG=32610 is the [\"UTM 10N\" CRS](https://epsg.io/32610), with coordinate units in meters. Let's say you want longitude,latitude coordinate points in degrees instead. You'd have to *reproject* this data:" + "EPSG refers to 'European Petroleum Survey Group', a database of the many CRS definitions for our Planet used over the years! EPSG=32610 is the [\"UTM 10N\" CRS](https://epsg.io/32610), with coordinate units in meters. Let's say you want longitude,latitude coordinate points in degrees instead. You'd have to *reproject* this data:" ] }, { @@ -204,10 +219,11 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ - "Note that that the size of the data has changed as well as the coordinate values. This is typical of reprojection, your data must be resampled and often interpolated to match the new CRS grid! A quick plot will compare the results of our reprojected data:" + "Note that that the size of the data has changed as well as the coordinate values. This is typical of reprojection, as your data must be resampled and often interpolated to match the new CRS grid! A quick plot will compare the results of our reprojected data:" ] }, { @@ -631,70 +647,6 @@ "Take a look at the [pint-xarray documentation](https://pint-xarray.readthedocs.io/en/latest/) or the [pint documentation](https://pint.readthedocs.io/en/stable/) if you get stuck." ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Accessors part 2 - defining custom accessors" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "An accessor is a way of attaching a custom function to xarray types so that it can be called as if it were a method, but while retaining a clear separation between \"core\" xarray API and custom API." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "For example, imagine you're a statistician who regularly uses a special `skewness` function which acts on dataarrays but is only of interest to people in your specific field.\n", - "\n", - "You can create a method which applies this skewness function to an xarray objects, and then register the method under a custom `stats` accessor like this" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from scipy.stats import skew\n", - "\n", - "\n", - "@xr.register_dataarray_accessor(\"stats\")\n", - "class StatsAccessor:\n", - " def __init__(self, da):\n", - " self._da = da\n", - "\n", - " def skewness(self, dim):\n", - " return self._da.reduce(func=skew, dim=dim)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we can conveniently access this functionality via the `stats` accessor" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "ds['air'].stats.skewness(dim=\"time\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Notice how the presence of `.stats` clearly differentiates our new \"accessor method\" from core xarray methods." - ] - }, { "cell_type": "markdown", "metadata": {}, From 65d69846ba41b299cf016bfb97f5f42f4361bcce Mon Sep 17 00:00:00 2001 From: Jessica Scheick Date: Wed, 12 Apr 2023 12:10:20 -0400 Subject: [PATCH 02/23] add geoid offset ex --- advanced/accessors/01_accessor_examples.ipynb | 132 +++++++++++++++++- advanced/accessors/accessors.md | 14 -- 2 files changed, 130 insertions(+), 16 deletions(-) diff --git a/advanced/accessors/01_accessor_examples.ipynb b/advanced/accessors/01_accessor_examples.ipynb index 737a47c8..3abf2467 100644 --- a/advanced/accessors/01_accessor_examples.ipynb +++ b/advanced/accessors/01_accessor_examples.ipynb @@ -17,11 +17,26 @@ "\n", "An accessor is a way of attaching a custom function to xarray types so that it can be called as if it were a method while retaining a clear separation between \"core\" xarray API and custom API. It enables you to easily extend and customize xarray's functionality while limiting naming conflicts and minimizing the chances of your code breaking with xarray upgrades.\n", "\n", - "If you've used [rioxarray](https://corteva.github.io/rioxarray/stable/) (e.g. `da.rio.crs`) or [hvplot](https://hvplot.holoviz.org/) (e.g. `ds.hvplot()`), you may have already used an xarray accessor without knowing it!" + "If you've used [rioxarray](https://corteva.github.io/rioxarray/stable/) (e.g. `da.rio.crs`) or [hvplot](https://hvplot.holoviz.org/) (e.g. `ds.hvplot()`), you may have already used an xarray accessor without knowing it!\n", + "\n", + "The [Xarray documentation](https://docs.xarray.dev/en/stable/internals/extending-xarray.html) has some more technical details, and this tutorial provides example custom accessors and their uses." ] }, { "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Why create a custom accessor\n", + "\n", + "- You can easily create a custom suite of tools that work on Xarray objects\n", + "- It keeps your workflows cleaner and simpler\n", + "- Your project-specific code is easy to share\n", + "- It's easy to implement: you don't need to integrate any code into Xarray\n", + "- it makes it easier to perform checks and write code documentation because you only have to create them once!" + ] + }, + { "cell_type": "markdown", "metadata": {}, "source": [ @@ -94,7 +109,120 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Example 2: creating your own functions" + "## Example 2: creating your own workflows\n", + "\n", + "Perhaps you find yourself running similar code for multiple xarray objects or across related projects. By packing your code into an extension, it makes it easy to repeat the same operation while reducing the likelihood of [human introduced] errors.\n", + "\n", + "Consider someone who frequently converts their elevations to be relative to the geoid (rather than the ellipsoid) using a custom, local conversion (otherwise, we'd recommend using an established conversion library like [pyproj](https://pypi.org/project/pyproj/) to switch between datums)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "@xr.register_dataarray_accessor(\"geoidxr\")\n", + "class GeoidXR:\n", + " \"\"\"\n", + " An extension for an XArray dataset that will calculate geoidal elevations from a local source file.\n", + " \"\"\"\n", + " # ----------------------------------------------------------------------\n", + " # Constructors\n", + "\n", + " def __init__(\n", + " self,\n", + " xrds,\n", + " ):\n", + "\n", + " self._xrds = xrds\n", + " # Running this function on init will check that my dataset has all the needed dimensions and variables\n", + " # as specific to my workflow, saving time and headache later if they were missing and the computation fails\n", + " # partway through.\n", + " self._validate(self, req_dim = ['x','y','dtime'], req_vars = {'elevation':['x','y','dtime']})\n", + " \n", + "\n", + " # ----------------------------------------------------------------------\n", + " # Methods\n", + "\n", + " @staticmethod\n", + " def _validate(self, req_dim=None, req_vars=None):\n", + " '''\n", + " Make sure the xarray dataset has the correct dimensions and variables\n", + "\n", + " req_dim : list of str\n", + " List of all required dimension names\n", + "\n", + " req_vars : list of str\n", + " List of all required variable names\n", + " '''\n", + "\n", + " if req_dim is not None:\n", + " if all([dim not in list(self._xrds.dims) for dim in req_dim]):\n", + " raise AttributeError(\"Required dimensions are missing\")\n", + " if req_vars is not None:\n", + " if all([var not in self._xrds.variables for var in req_vars.keys()]):\n", + " raise AttributeError(\"Required variables are missing\")\n", + "\n", + "\n", + " # Notice that 'geoid' has been added to the req_vars list\n", + " def to_geoid(self, req_dim=['dtime','x','y'], req_vars={'elevation':['x','y','dtime','geoid']},\n", + " source=None):\n", + " \"\"\"\n", + " Get geoid layer from your local file, which is provided to the function as \"source\",\n", + " and apply the offset to all elevation values.\n", + " Adds 'geoid_offset' keyword to \"offsets\" attribute so you know the geoid offset was applied.\n", + "\n", + " req_dim : list of str\n", + " List of all required dimension names.\n", + "\n", + " req_vars : list of str\n", + " List of all required variable names\n", + "\n", + " source : str\n", + " Full path to your source file containing geoid offsets\n", + " \"\"\"\n", + "\n", + " # check to make sure you haven't already run this function (and are thus applying the offset twice)\n", + " try:\n", + " values = (self._xrds.attrs['offset_names'])\n", + " assert 'geoid_offset' not in values, \"You've already applied the geoid offset!\"\n", + " values = list([values])+ ['geoid_offset']\n", + " except KeyError:\n", + " values = ['geoid_offset']\n", + "\n", + " self._validate(self, req_dim, req_vars)\n", + "\n", + " # read in your geoid values\n", + " # WARNING: this implementation assumes your geoid values are in the same CRS and grid as the data you are applying\n", + " # them to. If not, you will need to reproject and/or resample them to match the data to which you are applying them.\n", + " # That step is not included here to emphasize the accessor aspect of the workflow.\n", + " with rasterio.open(source) as src:\n", + " geoid = src['geoid_varname']\n", + " \n", + " # As noted above, this step will fail or produce unreliable results if your data is not properly gridded\n", + " self._xrds['elevation'] = self._xrds.elevation - geoid\n", + "\n", + " self._xrds.attrs['offset_names'] = values\n", + "\n", + " return self._xrds\n" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, each time we want to convert our ellipsoid data to the geoid, we only have to run one line of code, and it will also perform a multitude of checks for us to make sure we're performing exactly the operation we expect. Imagine the possibilities (and decrease in frustration)!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ds = ds.geoidxr.to_geoid(source='/Path/to/Custom/source/file.nc')" ] } ], diff --git a/advanced/accessors/accessors.md b/advanced/accessors/accessors.md index b76491bd..f49df5d2 100644 --- a/advanced/accessors/accessors.md +++ b/advanced/accessors/accessors.md @@ -1,17 +1,3 @@ - -## Why create a custom accessor - -- You can easily create a custom suite of tools that work on Xarray objects -- It keeps your workflows cleaner and simpler -- Your project-specific code is easy to share without needing to create a software package -- It's easy to implement: you don't need to integrate any code in Xarray - -## Next - -See the [documentation](https://docs.xarray.dev/en/stable/internals/extending-xarray.html) for more. - -Follow the tutorial for example custom accessors and their uses. - ```{tableofcontents} ``` From 5dd2950ca3a321a5119a7af48bb08a6b117097e7 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 12 Apr 2023 16:19:30 +0000 Subject: [PATCH 03/23] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- advanced/accessors/01_accessor_examples.ipynb | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/advanced/accessors/01_accessor_examples.ipynb b/advanced/accessors/01_accessor_examples.ipynb index 3abf2467..46f562be 100644 --- a/advanced/accessors/01_accessor_examples.ipynb +++ b/advanced/accessors/01_accessor_examples.ipynb @@ -127,6 +127,7 @@ " \"\"\"\n", " An extension for an XArray dataset that will calculate geoidal elevations from a local source file.\n", " \"\"\"\n", + "\n", " # ----------------------------------------------------------------------\n", " # Constructors\n", "\n", @@ -134,13 +135,13 @@ " self,\n", " xrds,\n", " ):\n", - "\n", " self._xrds = xrds\n", " # Running this function on init will check that my dataset has all the needed dimensions and variables\n", " # as specific to my workflow, saving time and headache later if they were missing and the computation fails\n", " # partway through.\n", - " self._validate(self, req_dim = ['x','y','dtime'], req_vars = {'elevation':['x','y','dtime']})\n", - " \n", + " self._validate(\n", + " self, req_dim=['x', 'y', 'dtime'], req_vars={'elevation': ['x', 'y', 'dtime']}\n", + " )\n", "\n", " # ----------------------------------------------------------------------\n", " # Methods\n", @@ -164,10 +165,13 @@ " if all([var not in self._xrds.variables for var in req_vars.keys()]):\n", " raise AttributeError(\"Required variables are missing\")\n", "\n", - "\n", " # Notice that 'geoid' has been added to the req_vars list\n", - " def to_geoid(self, req_dim=['dtime','x','y'], req_vars={'elevation':['x','y','dtime','geoid']},\n", - " source=None):\n", + " def to_geoid(\n", + " self,\n", + " req_dim=['dtime', 'x', 'y'],\n", + " req_vars={'elevation': ['x', 'y', 'dtime', 'geoid']},\n", + " source=None,\n", + " ):\n", " \"\"\"\n", " Get geoid layer from your local file, which is provided to the function as \"source\",\n", " and apply the offset to all elevation values.\n", @@ -185,9 +189,9 @@ "\n", " # check to make sure you haven't already run this function (and are thus applying the offset twice)\n", " try:\n", - " values = (self._xrds.attrs['offset_names'])\n", + " values = self._xrds.attrs['offset_names']\n", " assert 'geoid_offset' not in values, \"You've already applied the geoid offset!\"\n", - " values = list([values])+ ['geoid_offset']\n", + " values = list([values]) + ['geoid_offset']\n", " except KeyError:\n", " values = ['geoid_offset']\n", "\n", @@ -199,13 +203,13 @@ " # That step is not included here to emphasize the accessor aspect of the workflow.\n", " with rasterio.open(source) as src:\n", " geoid = src['geoid_varname']\n", - " \n", + "\n", " # As noted above, this step will fail or produce unreliable results if your data is not properly gridded\n", " self._xrds['elevation'] = self._xrds.elevation - geoid\n", "\n", " self._xrds.attrs['offset_names'] = values\n", "\n", - " return self._xrds\n" + " return self._xrds" ] }, { @@ -229,8 +233,7 @@ "metadata": { "language_info": { "name": "python" - }, - "orig_nbformat": 4 + } }, "nbformat": 4, "nbformat_minor": 2 From 30639fa13bf61b9715ff6a24038106fcdf66cfab Mon Sep 17 00:00:00 2001 From: Jessica Scheick Date: Wed, 12 Apr 2023 12:22:03 -0400 Subject: [PATCH 04/23] add new tutorial to toc --- _toc.yml | 3 +++ advanced/accessors/01_accessor_examples.ipynb | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/_toc.yml b/_toc.yml index 713fd663..3ea2b69e 100644 --- a/_toc.yml +++ b/_toc.yml @@ -55,6 +55,9 @@ parts: sections: - file: advanced/backends/1.Backend_without_Lazy_Loading.ipynb - file: advanced/backends/2.Backend_with_Lazy_Loading.ipynb + - file: advanced/accessors/accessors.md + sections: + - file: advanced/accessors/01_accessor_examples.ipynb - caption: Workshops chapters: diff --git a/advanced/accessors/01_accessor_examples.ipynb b/advanced/accessors/01_accessor_examples.ipynb index 46f562be..86c669c0 100644 --- a/advanced/accessors/01_accessor_examples.ipynb +++ b/advanced/accessors/01_accessor_examples.ipynb @@ -15,7 +15,7 @@ "source": [ "## Introduction\n", "\n", - "An accessor is a way of attaching a custom function to xarray types so that it can be called as if it were a method while retaining a clear separation between \"core\" xarray API and custom API. It enables you to easily extend and customize xarray's functionality while limiting naming conflicts and minimizing the chances of your code breaking with xarray upgrades.\n", + "An accessor is a way of attaching a custom function to xarray types so that it can be called as if it were a method while retaining a clear separation between \"core\" xarray API and custom API. It enables you to easily *extend* (which is why you'll sometimes see it referred to as an extension) and customize xarray's functionality while limiting naming conflicts and minimizing the chances of your code breaking with xarray upgrades.\n", "\n", "If you've used [rioxarray](https://corteva.github.io/rioxarray/stable/) (e.g. `da.rio.crs`) or [hvplot](https://hvplot.holoviz.org/) (e.g. `ds.hvplot()`), you may have already used an xarray accessor without knowing it!\n", "\n", From e33bc9986811da73c5f36eff12c05b702cf54878 Mon Sep 17 00:00:00 2001 From: Jessica Scheick Date: Fri, 26 May 2023 10:35:39 -0400 Subject: [PATCH 05/23] make example 1 executable --- advanced/accessors/01_accessor_examples.ipynb | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/advanced/accessors/01_accessor_examples.ipynb b/advanced/accessors/01_accessor_examples.ipynb index 86c669c0..dd1af26b 100644 --- a/advanced/accessors/01_accessor_examples.ipynb +++ b/advanced/accessors/01_accessor_examples.ipynb @@ -67,8 +67,20 @@ "cell_type": "code", "execution_count": null, "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[1;31mRunning cells with 'icepyxml' requires ipykernel package.\n", + "\u001b[1;31mRun the following command to install 'ipykernel' into the Python environment. \n", + "\u001b[1;31mCommand: 'conda install -n icepyxml ipykernel --update-deps --force-reinstall'" + ] + } + ], "source": [ + "import xarray as xr\n", "from scipy.stats import skew\n", "\n", "\n", @@ -94,7 +106,9 @@ "metadata": {}, "outputs": [], "source": [ - "ds['air'].stats.skewness(dim=\"time\")" + "ds = xr.tutorial.load_dataset(\"air_temperature\")\n", + "ds[\"skewair\"] = ds['air'].stats.skewness(dim=\"time\")\n", + "ds" ] }, { @@ -231,8 +245,19 @@ } ], "metadata": { + "kernelspec": { + "display_name": "icepyxml", + "language": "python", + "name": "python3" + }, "language_info": { - "name": "python" + "name": "python", + "version": "3.10.8 | packaged by conda-forge | (main, Nov 22 2022, 08:31:57) [Clang 14.0.6 ]" + }, + "vscode": { + "interpreter": { + "hash": "eeef546aa85c5aee566c457bd2890cafb9e11a3b514b94bbf230bf44d1caf251" + } } }, "nbformat": 4, From 79a3420e489c35fa926e127066cec7a6ee56cbfb Mon Sep 17 00:00:00 2001 From: Jessica Scheick Date: Fri, 26 May 2023 11:00:41 -0400 Subject: [PATCH 06/23] start making ex 2 executable --- advanced/accessors/01_accessor_examples.ipynb | 37 ++++++++++++------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/advanced/accessors/01_accessor_examples.ipynb b/advanced/accessors/01_accessor_examples.ipynb index dd1af26b..291df253 100644 --- a/advanced/accessors/01_accessor_examples.ipynb +++ b/advanced/accessors/01_accessor_examples.ipynb @@ -67,18 +67,7 @@ "cell_type": "code", "execution_count": null, "metadata": {}, - "outputs": [ - { - "ename": "", - "evalue": "", - "output_type": "error", - "traceback": [ - "\u001b[1;31mRunning cells with 'icepyxml' requires ipykernel package.\n", - "\u001b[1;31mRun the following command to install 'ipykernel' into the Python environment. \n", - "\u001b[1;31mCommand: 'conda install -n icepyxml ipykernel --update-deps --force-reinstall'" - ] - } - ], + "outputs": [], "source": [ "import xarray as xr\n", "from scipy.stats import skew\n", @@ -136,6 +125,9 @@ "metadata": {}, "outputs": [], "source": [ + "import rasterio\n", + "import xarray as xr\n", + "\n", "@xr.register_dataarray_accessor(\"geoidxr\")\n", "class GeoidXR:\n", " \"\"\"\n", @@ -240,8 +232,17 @@ "metadata": {}, "outputs": [], "source": [ - "ds = ds.geoidxr.to_geoid(source='/Path/to/Custom/source/file.nc')" + "ds = xr.tutorial.load_dataset(\"ASE_ice_velocity.nc\")\n", + "#ds = ds.geoidxr.to_geoid(source='/Path/to/Custom/source/file.nc')\n", + "ds" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { @@ -251,8 +252,16 @@ "name": "python3" }, "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", "name": "python", - "version": "3.10.8 | packaged by conda-forge | (main, Nov 22 2022, 08:31:57) [Clang 14.0.6 ]" + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.6" }, "vscode": { "interpreter": { From 0d8dd9e63c94ba42788185392393270d8a9bfdc4 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 26 May 2023 15:01:02 +0000 Subject: [PATCH 07/23] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- advanced/accessors/01_accessor_examples.ipynb | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/advanced/accessors/01_accessor_examples.ipynb b/advanced/accessors/01_accessor_examples.ipynb index 291df253..cf850136 100644 --- a/advanced/accessors/01_accessor_examples.ipynb +++ b/advanced/accessors/01_accessor_examples.ipynb @@ -128,6 +128,7 @@ "import rasterio\n", "import xarray as xr\n", "\n", + "\n", "@xr.register_dataarray_accessor(\"geoidxr\")\n", "class GeoidXR:\n", " \"\"\"\n", @@ -233,7 +234,7 @@ "outputs": [], "source": [ "ds = xr.tutorial.load_dataset(\"ASE_ice_velocity.nc\")\n", - "#ds = ds.geoidxr.to_geoid(source='/Path/to/Custom/source/file.nc')\n", + "# ds = ds.geoidxr.to_geoid(source='/Path/to/Custom/source/file.nc')\n", "ds" ] }, @@ -246,11 +247,6 @@ } ], "metadata": { - "kernelspec": { - "display_name": "icepyxml", - "language": "python", - "name": "python3" - }, "language_info": { "codemirror_mode": { "name": "ipython", @@ -260,8 +256,7 @@ "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.6" + "pygments_lexer": "ipython3" }, "vscode": { "interpreter": { From c1344290de0c6b7c8a2f50cc282effa439b05106 Mon Sep 17 00:00:00 2001 From: Jessica Scheick Date: Thu, 8 Jun 2023 17:38:30 -0400 Subject: [PATCH 08/23] add insar velocity accessor example --- advanced/accessors/01_accessor_examples.ipynb | 191 ++++++++++++++++-- 1 file changed, 176 insertions(+), 15 deletions(-) diff --git a/advanced/accessors/01_accessor_examples.ipynb b/advanced/accessors/01_accessor_examples.ipynb index cf850136..d0506b3d 100644 --- a/advanced/accessors/01_accessor_examples.ipynb +++ b/advanced/accessors/01_accessor_examples.ipynb @@ -1,7 +1,6 @@ { "cells": [ { - "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -9,7 +8,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -23,7 +21,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -108,7 +105,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -116,6 +112,171 @@ "\n", "Perhaps you find yourself running similar code for multiple xarray objects or across related projects. By packing your code into an extension, it makes it easy to repeat the same operation while reducing the likelihood of [human introduced] errors.\n", "\n", + "Here we wrap the reorganization of InSAR ice velocity data illustrated in [this tutorial](https://tutorial.xarray.dev/data_cleaning/ice_velocity.html?highlight=ice_velocity) into a custom Xarray extension that makes it easy to re-apply each time you begin working with a new InSAR velocity dataset. Please see the linked tutorial for details on the data, applications, and each step in this process." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import os\n", + "import pandas as pd\n", + "import xarray as xr\n", + "\n", + "@xr.register_dataarray_accessor(\"insar_vel\")\n", + "class InsarReorg:\n", + " \"\"\"\n", + " An extension for an XArray dataset that will prepare InSAR data for analysis.\n", + "\n", + " Re-organize the data from its native structure to have x and y velocity and error along a time dimension.\n", + " \"\"\"\n", + "\n", + " # ----------------------------------------------------------------------\n", + " # Constructors\n", + "\n", + " def __init__(\n", + " self,\n", + " xrds,\n", + " ):\n", + " self._xrds = xrds\n", + " # Running this function on init will check that my dataset has all the needed dimensions and variables\n", + " # as specific to my workflow, saving time and headache later if they were missing and the computation fails\n", + " # partway through.\n", + " self._validate(\n", + " self, req_dim=['nx', 'ny'], req_vars={'xaxis': ['nx'], 'yaxis': ['ny']}\n", + " )\n", + "\n", + " # ----------------------------------------------------------------------\n", + " # Methods\n", + "\n", + " @staticmethod\n", + " def _validate(self, req_dim=None, req_vars=None):\n", + " '''\n", + " Make sure the xarray dataset has the correct dimensions and variables\n", + "\n", + " req_dim : list of str\n", + " List of all required dimension names\n", + " req_vars : list of str\n", + " List of all required variable names\n", + " '''\n", + "\n", + " if req_dim is not None:\n", + " if all([dim not in list(self._xrds.dims) for dim in req_dim]):\n", + " raise AttributeError(\"Required dimensions are missing\")\n", + " if req_vars is not None:\n", + " if all([var not in self._xrds.variables for var in req_vars.keys()]):\n", + " raise AttributeError(\"Required variables are missing\")\n", + " print(\"successfully validated your dataset\")\n", + "\n", + "\n", + " def change_vars_to_coords(\n", + " self,\n", + " req_dim=['ny', 'nx'],\n", + " req_vars={'xaxis': ['nx'], 'yaxis': ['ny']},\n", + " ):\n", + " \"\"\"\n", + " Turn the xaxis and y axis variables into coordinates.\n", + "\n", + " req_dim : list of str\n", + " List of all required dimension names.\n", + " req_vars : list of str\n", + " List of all required variable names\n", + " \"\"\"\n", + "\n", + " # Note: here this ends up being equivalent to the check done in the init, \n", + " # but it can be useful to check for the dimensions and variables you need for a given function if one depends on the outcome of another.\n", + " self._validate(self, req_dim, req_vars)\n", + "\n", + " self._xrds = self._xrds.swap_dims({'ny': 'yaxis', 'nx': 'xaxis'})\n", + " self._xrds = self._xrds.rename({'xaxis': 'x', 'yaxis': 'y'})\n", + "\n", + " return self._xrds\n", + " \n", + "\n", + " def reorg_dataset(\n", + " self\n", + " ):\n", + " \"\"\"\n", + " Reorganize the data by time for each of the desired end variables (here vx, vy, err)\n", + "\n", + " \"\"\"\n", + "\n", + " reorged = []\n", + " for reorg_var in ['vx','vy','err']:\n", + " ds = self.reorg_var_time(reorg_var)\n", + " reorged.append(ds)\n", + "\n", + " reorged_ds = xr.merge(reorged)\n", + "\n", + " return reorged_ds\n", + "\n", + " \n", + " def reorg_var_time(self, reorg_var):\n", + " \"\"\"\n", + " Repeat the process for a given variable.\n", + "\n", + " Figure out which of the original variables are time steps for this variable and turn each one into a dataarray.\n", + " Add a time dimension and update the variable name for each dataarray.\n", + " Combine the modified data arrays back into a single dataset.\n", + " \"\"\"\n", + " \n", + " # create storage list for reorganizing\n", + " var_ls = list(self._xrds)\n", + " to_reorg = [var for var in var_ls if reorg_var in var]\n", + " \n", + " # list the arrays from the original dataset that correspond to the variable\n", + " das_to_reorg = [self._xrds[var] for var in to_reorg]\n", + "\n", + " # add the time dimension\n", + " das_to_reorg = [das_to_reorg[var].expand_dims('time') for var in range(len(das_to_reorg))]\n", + "\n", + " # update variable name to remove time\n", + " das_to_reorg = [das_to_reorg[var].rename(reorg_var) for var in range(len(das_to_reorg))]\n", + "\n", + " ds = xr.concat(das_to_reorg, dim='time')\n", + " \n", + " return ds\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ds = xr.tutorial.open_dataset('ASE_ice_velocity.nc')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ds = ds.insar_vel.change_vars_to_coords()\n", + "ds" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ds = ds.insar_vel.reorg_dataset()\n", + "ds" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Example 3: creating your own workflows with locally stored corrections\n", + "\n", "Consider someone who frequently converts their elevations to be relative to the geoid (rather than the ellipsoid) using a custom, local conversion (otherwise, we'd recommend using an established conversion library like [pyproj](https://pypi.org/project/pyproj/) to switch between datums)." ] }, @@ -220,7 +381,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -230,23 +390,24 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [ + "\"raises-exception\"" + ] + }, "outputs": [], "source": [ - "ds = xr.tutorial.load_dataset(\"ASE_ice_velocity.nc\")\n", - "# ds = ds.geoidxr.to_geoid(source='/Path/to/Custom/source/file.nc')\n", + "ds = ds.geoidxr.to_geoid(source='/Path/to/Custom/source/file.nc')\n", "ds" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, "language_info": { "codemirror_mode": { "name": "ipython", From 774700ab837dee48b7069a8f430a36d7beab8a22 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 8 Jun 2023 21:42:08 +0000 Subject: [PATCH 09/23] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- advanced/accessors/01_accessor_examples.ipynb | 30 ++++++------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/advanced/accessors/01_accessor_examples.ipynb b/advanced/accessors/01_accessor_examples.ipynb index d0506b3d..5bf04bac 100644 --- a/advanced/accessors/01_accessor_examples.ipynb +++ b/advanced/accessors/01_accessor_examples.ipynb @@ -126,6 +126,7 @@ "import pandas as pd\n", "import xarray as xr\n", "\n", + "\n", "@xr.register_dataarray_accessor(\"insar_vel\")\n", "class InsarReorg:\n", " \"\"\"\n", @@ -145,9 +146,7 @@ " # Running this function on init will check that my dataset has all the needed dimensions and variables\n", " # as specific to my workflow, saving time and headache later if they were missing and the computation fails\n", " # partway through.\n", - " self._validate(\n", - " self, req_dim=['nx', 'ny'], req_vars={'xaxis': ['nx'], 'yaxis': ['ny']}\n", - " )\n", + " self._validate(self, req_dim=['nx', 'ny'], req_vars={'xaxis': ['nx'], 'yaxis': ['ny']})\n", "\n", " # ----------------------------------------------------------------------\n", " # Methods\n", @@ -171,7 +170,6 @@ " raise AttributeError(\"Required variables are missing\")\n", " print(\"successfully validated your dataset\")\n", "\n", - "\n", " def change_vars_to_coords(\n", " self,\n", " req_dim=['ny', 'nx'],\n", @@ -186,7 +184,7 @@ " List of all required variable names\n", " \"\"\"\n", "\n", - " # Note: here this ends up being equivalent to the check done in the init, \n", + " # Note: here this ends up being equivalent to the check done in the init,\n", " # but it can be useful to check for the dimensions and variables you need for a given function if one depends on the outcome of another.\n", " self._validate(self, req_dim, req_vars)\n", "\n", @@ -194,18 +192,15 @@ " self._xrds = self._xrds.rename({'xaxis': 'x', 'yaxis': 'y'})\n", "\n", " return self._xrds\n", - " \n", "\n", - " def reorg_dataset(\n", - " self\n", - " ):\n", + " def reorg_dataset(self):\n", " \"\"\"\n", " Reorganize the data by time for each of the desired end variables (here vx, vy, err)\n", "\n", " \"\"\"\n", "\n", " reorged = []\n", - " for reorg_var in ['vx','vy','err']:\n", + " for reorg_var in ['vx', 'vy', 'err']:\n", " ds = self.reorg_var_time(reorg_var)\n", " reorged.append(ds)\n", "\n", @@ -213,7 +208,6 @@ "\n", " return reorged_ds\n", "\n", - " \n", " def reorg_var_time(self, reorg_var):\n", " \"\"\"\n", " Repeat the process for a given variable.\n", @@ -222,11 +216,11 @@ " Add a time dimension and update the variable name for each dataarray.\n", " Combine the modified data arrays back into a single dataset.\n", " \"\"\"\n", - " \n", + "\n", " # create storage list for reorganizing\n", " var_ls = list(self._xrds)\n", " to_reorg = [var for var in var_ls if reorg_var in var]\n", - " \n", + "\n", " # list the arrays from the original dataset that correspond to the variable\n", " das_to_reorg = [self._xrds[var] for var in to_reorg]\n", "\n", @@ -237,9 +231,8 @@ " das_to_reorg = [das_to_reorg[var].rename(reorg_var) for var in range(len(das_to_reorg))]\n", "\n", " ds = xr.concat(das_to_reorg, dim='time')\n", - " \n", - " return ds\n", - "\n" + "\n", + " return ds" ] }, { @@ -403,11 +396,6 @@ } ], "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, "language_info": { "codemirror_mode": { "name": "ipython", From e0dad6ae5d26dd99313fb908f4bdf4f72d486eed Mon Sep 17 00:00:00 2001 From: Jessica Scheick Date: Thu, 8 Jun 2023 17:48:30 -0400 Subject: [PATCH 10/23] apply edits from PR --- advanced/accessors/01_accessor_examples.ipynb | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/advanced/accessors/01_accessor_examples.ipynb b/advanced/accessors/01_accessor_examples.ipynb index 5bf04bac..16201b66 100644 --- a/advanced/accessors/01_accessor_examples.ipynb +++ b/advanced/accessors/01_accessor_examples.ipynb @@ -8,12 +8,13 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## Introduction\n", "\n", - "An accessor is a way of attaching a custom function to xarray types so that it can be called as if it were a method while retaining a clear separation between \"core\" xarray API and custom API. It enables you to easily *extend* (which is why you'll sometimes see it referred to as an extension) and customize xarray's functionality while limiting naming conflicts and minimizing the chances of your code breaking with xarray upgrades.\n", + "An accessor is a way of attaching a custom function to an xarray data structure (`DataArray` or `DataSet`) so that it can be called as if it were a method while retaining a clear separation between \"core\" xarray API and custom API. It enables you to easily *extend* (which is why you'll sometimes see it referred to as an extension) and customize xarray's functionality while limiting naming conflicts and minimizing the chances of your code breaking with xarray upgrades.\n", "\n", "If you've used [rioxarray](https://corteva.github.io/rioxarray/stable/) (e.g. `da.rio.crs`) or [hvplot](https://hvplot.holoviz.org/) (e.g. `ds.hvplot()`), you may have already used an xarray accessor without knowing it!\n", "\n", @@ -21,6 +22,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -30,7 +32,7 @@ "- It keeps your workflows cleaner and simpler\n", "- Your project-specific code is easy to share\n", "- It's easy to implement: you don't need to integrate any code into Xarray\n", - "- it makes it easier to perform checks and write code documentation because you only have to create them once!" + "- It makes it easier to perform checks and write code documentation because you only have to create them once!" ] }, { @@ -66,8 +68,8 @@ "metadata": {}, "outputs": [], "source": [ - "import xarray as xr\n", "from scipy.stats import skew\n", + "import xarray as xr\n", "\n", "\n", "@xr.register_dataarray_accessor(\"stats\")\n", @@ -126,8 +128,7 @@ "import pandas as pd\n", "import xarray as xr\n", "\n", - "\n", - "@xr.register_dataarray_accessor(\"insar_vel\")\n", + "@xr.register_dataset_accessor(\"insar_vel\")\n", "class InsarReorg:\n", " \"\"\"\n", " An extension for an XArray dataset that will prepare InSAR data for analysis.\n", @@ -156,6 +157,8 @@ " '''\n", " Make sure the xarray dataset has the correct dimensions and variables\n", "\n", + " Parameters\n", + " ----------\n", " req_dim : list of str\n", " List of all required dimension names\n", " req_vars : list of str\n", @@ -178,6 +181,8 @@ " \"\"\"\n", " Turn the xaxis and y axis variables into coordinates.\n", "\n", + " Parameters\n", + " ----------\n", " req_dim : list of str\n", " List of all required dimension names.\n", " req_vars : list of str\n", @@ -283,7 +288,7 @@ "import xarray as xr\n", "\n", "\n", - "@xr.register_dataarray_accessor(\"geoidxr\")\n", + "@xr.register_dataset_accessor(\"geoidxr\")\n", "class GeoidXR:\n", " \"\"\"\n", " An extension for an XArray dataset that will calculate geoidal elevations from a local source file.\n", @@ -312,9 +317,10 @@ " '''\n", " Make sure the xarray dataset has the correct dimensions and variables\n", "\n", + " Parameters\n", + " ----------\n", " req_dim : list of str\n", " List of all required dimension names\n", - "\n", " req_vars : list of str\n", " List of all required variable names\n", " '''\n", @@ -337,13 +343,13 @@ " Get geoid layer from your local file, which is provided to the function as \"source\",\n", " and apply the offset to all elevation values.\n", " Adds 'geoid_offset' keyword to \"offsets\" attribute so you know the geoid offset was applied.\n", - "\n", + " \n", + " Parameters\n", + " ----------\n", " req_dim : list of str\n", " List of all required dimension names.\n", - "\n", " req_vars : list of str\n", " List of all required variable names\n", - "\n", " source : str\n", " Full path to your source file containing geoid offsets\n", " \"\"\"\n", From 55421e59e262d0461a0bc86c35eaf6a8ed2c1707 Mon Sep 17 00:00:00 2001 From: Jessica Scheick Date: Thu, 8 Jun 2023 17:54:34 -0400 Subject: [PATCH 11/23] debug new tutorial --- advanced/accessors/01_accessor_examples.ipynb | 54 ++++++++----------- 1 file changed, 21 insertions(+), 33 deletions(-) diff --git a/advanced/accessors/01_accessor_examples.ipynb b/advanced/accessors/01_accessor_examples.ipynb index 16201b66..f56cf8c2 100644 --- a/advanced/accessors/01_accessor_examples.ipynb +++ b/advanced/accessors/01_accessor_examples.ipynb @@ -8,13 +8,12 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## Introduction\n", "\n", - "An accessor is a way of attaching a custom function to an xarray data structure (`DataArray` or `DataSet`) so that it can be called as if it were a method while retaining a clear separation between \"core\" xarray API and custom API. It enables you to easily *extend* (which is why you'll sometimes see it referred to as an extension) and customize xarray's functionality while limiting naming conflicts and minimizing the chances of your code breaking with xarray upgrades.\n", + "An accessor is a way of attaching a custom function to xarray types so that it can be called as if it were a method while retaining a clear separation between \"core\" xarray API and custom API. It enables you to easily *extend* (which is why you'll sometimes see it referred to as an extension) and customize xarray's functionality while limiting naming conflicts and minimizing the chances of your code breaking with xarray upgrades.\n", "\n", "If you've used [rioxarray](https://corteva.github.io/rioxarray/stable/) (e.g. `da.rio.crs`) or [hvplot](https://hvplot.holoviz.org/) (e.g. `ds.hvplot()`), you may have already used an xarray accessor without knowing it!\n", "\n", @@ -22,7 +21,6 @@ ] }, { - "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -32,7 +30,7 @@ "- It keeps your workflows cleaner and simpler\n", "- Your project-specific code is easy to share\n", "- It's easy to implement: you don't need to integrate any code into Xarray\n", - "- It makes it easier to perform checks and write code documentation because you only have to create them once!" + "- it makes it easier to perform checks and write code documentation because you only have to create them once!" ] }, { @@ -68,8 +66,8 @@ "metadata": {}, "outputs": [], "source": [ - "from scipy.stats import skew\n", "import xarray as xr\n", + "from scipy.stats import skew\n", "\n", "\n", "@xr.register_dataarray_accessor(\"stats\")\n", @@ -139,15 +137,9 @@ " # ----------------------------------------------------------------------\n", " # Constructors\n", "\n", - " def __init__(\n", - " self,\n", - " xrds,\n", - " ):\n", + " def __init__(self, xrds):\n", " self._xrds = xrds\n", - " # Running this function on init will check that my dataset has all the needed dimensions and variables\n", - " # as specific to my workflow, saving time and headache later if they were missing and the computation fails\n", - " # partway through.\n", - " self._validate(self, req_dim=['nx', 'ny'], req_vars={'xaxis': ['nx'], 'yaxis': ['ny']})\n", + " \n", "\n", " # ----------------------------------------------------------------------\n", " # Methods\n", @@ -155,10 +147,12 @@ " @staticmethod\n", " def _validate(self, req_dim=None, req_vars=None):\n", " '''\n", - " Make sure the xarray dataset has the correct dimensions and variables\n", + " Make sure the xarray dataset has the correct dimensions and variables.\n", + " \n", + " Running this function will check that my dataset has all the needed dimensions and variables\n", + " for a given function, saving time and headache later if they were missing and the computation fails\n", + " partway through.\n", "\n", - " Parameters\n", - " ----------\n", " req_dim : list of str\n", " List of all required dimension names\n", " req_vars : list of str\n", @@ -171,8 +165,11 @@ " if req_vars is not None:\n", " if all([var not in self._xrds.variables for var in req_vars.keys()]):\n", " raise AttributeError(\"Required variables are missing\")\n", - " print(\"successfully validated your dataset\")\n", + " # print(\"successfully validated your dataset\")\n", "\n", + " # ----------------------------------------------------------------------\n", + " # Functions\n", + " \n", " def change_vars_to_coords(\n", " self,\n", " req_dim=['ny', 'nx'],\n", @@ -181,16 +178,12 @@ " \"\"\"\n", " Turn the xaxis and y axis variables into coordinates.\n", "\n", - " Parameters\n", - " ----------\n", " req_dim : list of str\n", " List of all required dimension names.\n", " req_vars : list of str\n", " List of all required variable names\n", " \"\"\"\n", "\n", - " # Note: here this ends up being equivalent to the check done in the init,\n", - " # but it can be useful to check for the dimensions and variables you need for a given function if one depends on the outcome of another.\n", " self._validate(self, req_dim, req_vars)\n", "\n", " self._xrds = self._xrds.swap_dims({'ny': 'yaxis', 'nx': 'xaxis'})\n", @@ -287,7 +280,6 @@ "import rasterio\n", "import xarray as xr\n", "\n", - "\n", "@xr.register_dataset_accessor(\"geoidxr\")\n", "class GeoidXR:\n", " \"\"\"\n", @@ -317,10 +309,9 @@ " '''\n", " Make sure the xarray dataset has the correct dimensions and variables\n", "\n", - " Parameters\n", - " ----------\n", " req_dim : list of str\n", " List of all required dimension names\n", + "\n", " req_vars : list of str\n", " List of all required variable names\n", " '''\n", @@ -343,13 +334,13 @@ " Get geoid layer from your local file, which is provided to the function as \"source\",\n", " and apply the offset to all elevation values.\n", " Adds 'geoid_offset' keyword to \"offsets\" attribute so you know the geoid offset was applied.\n", - " \n", - " Parameters\n", - " ----------\n", + "\n", " req_dim : list of str\n", " List of all required dimension names.\n", + "\n", " req_vars : list of str\n", " List of all required variable names\n", + "\n", " source : str\n", " Full path to your source file containing geoid offsets\n", " \"\"\"\n", @@ -389,11 +380,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "tags": [ - "\"raises-exception\"" - ] - }, + "metadata": {}, "outputs": [], "source": [ "ds = ds.geoidxr.to_geoid(source='/Path/to/Custom/source/file.nc')\n", @@ -411,7 +398,8 @@ "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython3" + "pygments_lexer": "ipython3", + "version": "3.10.6" }, "vscode": { "interpreter": { From 7432617f86730293a809c999bf85d9269dc10f64 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 8 Jun 2023 21:57:57 +0000 Subject: [PATCH 12/23] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- advanced/accessors/01_accessor_examples.ipynb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/advanced/accessors/01_accessor_examples.ipynb b/advanced/accessors/01_accessor_examples.ipynb index f56cf8c2..b78e7f76 100644 --- a/advanced/accessors/01_accessor_examples.ipynb +++ b/advanced/accessors/01_accessor_examples.ipynb @@ -126,6 +126,7 @@ "import pandas as pd\n", "import xarray as xr\n", "\n", + "\n", "@xr.register_dataset_accessor(\"insar_vel\")\n", "class InsarReorg:\n", " \"\"\"\n", @@ -139,7 +140,6 @@ "\n", " def __init__(self, xrds):\n", " self._xrds = xrds\n", - " \n", "\n", " # ----------------------------------------------------------------------\n", " # Methods\n", @@ -148,7 +148,7 @@ " def _validate(self, req_dim=None, req_vars=None):\n", " '''\n", " Make sure the xarray dataset has the correct dimensions and variables.\n", - " \n", + "\n", " Running this function will check that my dataset has all the needed dimensions and variables\n", " for a given function, saving time and headache later if they were missing and the computation fails\n", " partway through.\n", @@ -169,7 +169,7 @@ "\n", " # ----------------------------------------------------------------------\n", " # Functions\n", - " \n", + "\n", " def change_vars_to_coords(\n", " self,\n", " req_dim=['ny', 'nx'],\n", @@ -280,6 +280,7 @@ "import rasterio\n", "import xarray as xr\n", "\n", + "\n", "@xr.register_dataset_accessor(\"geoidxr\")\n", "class GeoidXR:\n", " \"\"\"\n", @@ -398,8 +399,7 @@ "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.6" + "pygments_lexer": "ipython3" }, "vscode": { "interpreter": { From 52f7d09e5c6f1d0681f220397bf7599b8e99eafb Mon Sep 17 00:00:00 2001 From: Jessica Scheick Date: Thu, 8 Jun 2023 18:08:51 -0400 Subject: [PATCH 13/23] add cross ref in tutorial --- data_cleaning/ice_velocity.ipynb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/data_cleaning/ice_velocity.ipynb b/data_cleaning/ice_velocity.ipynb index 27327c15..45977c21 100644 --- a/data_cleaning/ice_velocity.ipynb +++ b/data_cleaning/ice_velocity.ipynb @@ -1,6 +1,7 @@ { "cells": [ { + "attachments": {}, "cell_type": "markdown", "id": "3c29d537", "metadata": {}, @@ -13,7 +14,9 @@ "\n", "Downloaded data is `.hdr` and `.dat` files for each year, and a `.nc` for all of the years together. \n", "\n", - "The `.nc` object is a dataset with dimensions x,y and data vars for each year. So for each year there are `vx`,`vy`,`err` vars. We'd like to re-organize this so that there are 3 variables (`vx`, `vy` and `err`) that exist along a time dimension." + "The `.nc` object is a dataset with dimensions x,y and data vars for each year. So for each year there are `vx`,`vy`,`err` vars. We'd like to re-organize this so that there are 3 variables (`vx`, `vy` and `err`) that exist along a time dimension.\n", + "\n", + "Note: These steps were turned into a accessor/extension example, which can be viewed [here](https://tutorial.xarray.dev/advanced/accessors/01_accessor_examples.html)." ] }, { From 78ea4d5352aeba781349f06450785e8bc32cf36c Mon Sep 17 00:00:00 2001 From: Jessica Scheick Date: Thu, 8 Jun 2023 18:15:29 -0400 Subject: [PATCH 14/23] re-add raises-exception cell tag --- advanced/accessors/01_accessor_examples.ipynb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/advanced/accessors/01_accessor_examples.ipynb b/advanced/accessors/01_accessor_examples.ipynb index b78e7f76..7010a0b3 100644 --- a/advanced/accessors/01_accessor_examples.ipynb +++ b/advanced/accessors/01_accessor_examples.ipynb @@ -381,7 +381,11 @@ { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [ + "raises-exception" + ] + }, "outputs": [], "source": [ "ds = ds.geoidxr.to_geoid(source='/Path/to/Custom/source/file.nc')\n", From 36e5402668890c518917fe1a79af8a8dfa6e9a82 Mon Sep 17 00:00:00 2001 From: Jessica Scheick Date: Fri, 30 Jun 2023 12:07:31 -0400 Subject: [PATCH 15/23] use note directive --- data_cleaning/ice_velocity.ipynb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/data_cleaning/ice_velocity.ipynb b/data_cleaning/ice_velocity.ipynb index 45977c21..bfce20cc 100644 --- a/data_cleaning/ice_velocity.ipynb +++ b/data_cleaning/ice_velocity.ipynb @@ -16,7 +16,9 @@ "\n", "The `.nc` object is a dataset with dimensions x,y and data vars for each year. So for each year there are `vx`,`vy`,`err` vars. We'd like to re-organize this so that there are 3 variables (`vx`, `vy` and `err`) that exist along a time dimension.\n", "\n", - "Note: These steps were turned into a accessor/extension example, which can be viewed [here](https://tutorial.xarray.dev/advanced/accessors/01_accessor_examples.html)." + "```{note}\n", + "These steps were turned into a accessor/extension example, which can be viewed [here](accessors).\n", + "```" ] }, { From fd3d2144f9a83d025f2f0c4c07c4b368349fa16e Mon Sep 17 00:00:00 2001 From: Jessica Scheick Date: Fri, 30 Jun 2023 12:25:41 -0400 Subject: [PATCH 16/23] PR review suggestions --- advanced/accessors/01_accessor_examples.ipynb | 9 +++++++-- intermediate/xarray_ecosystem.ipynb | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/advanced/accessors/01_accessor_examples.ipynb b/advanced/accessors/01_accessor_examples.ipynb index 7010a0b3..69e07cd9 100644 --- a/advanced/accessors/01_accessor_examples.ipynb +++ b/advanced/accessors/01_accessor_examples.ipynb @@ -8,12 +8,13 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## Introduction\n", "\n", - "An accessor is a way of attaching a custom function to xarray types so that it can be called as if it were a method while retaining a clear separation between \"core\" xarray API and custom API. It enables you to easily *extend* (which is why you'll sometimes see it referred to as an extension) and customize xarray's functionality while limiting naming conflicts and minimizing the chances of your code breaking with xarray upgrades.\n", + "An accessor is a way of attaching a custom function to xarray objects so that it can be called as if it were a method while retaining a clear separation between \"core\" xarray API and custom API. It enables you to easily *extend* (which is why you'll sometimes see it referred to as an extension) and customize xarray's functionality while limiting naming conflicts and minimizing the chances of your code breaking with xarray upgrades.\n", "\n", "If you've used [rioxarray](https://corteva.github.io/rioxarray/stable/) (e.g. `da.rio.crs`) or [hvplot](https://hvplot.holoviz.org/) (e.g. `ds.hvplot()`), you may have already used an xarray accessor without knowing it!\n", "\n", @@ -67,6 +68,7 @@ "outputs": [], "source": [ "import xarray as xr\n", + "xr.set_options(display_expand_attrs=False, display_expand_coords=False)\n", "from scipy.stats import skew\n", "\n", "\n", @@ -263,12 +265,15 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "## Example 3: creating your own workflows with locally stored corrections\n", "\n", - "Consider someone who frequently converts their elevations to be relative to the geoid (rather than the ellipsoid) using a custom, local conversion (otherwise, we'd recommend using an established conversion library like [pyproj](https://pypi.org/project/pyproj/) to switch between datums)." + "Consider someone who frequently converts their elevations to be relative to the geoid (rather than the ellipsoid) using a custom, local conversion (otherwise, we'd recommend using an established conversion library like [pyproj](https://pypi.org/project/pyproj/) to switch between datums).\n", + "\n", + "An accessor provides an elegant way to build (once) and apply (as often as needed!) this custom conversion on top of the existing xarray ecosystem without the need to copy-paste the code into the start of each project. By standardizing our approach and adding a few sanity checks within the accessor, we also eliminate the risk of accidentally applying the correction multiple times." ] }, { diff --git a/intermediate/xarray_ecosystem.ipynb b/intermediate/xarray_ecosystem.ipynb index b431da0a..00ba87e0 100644 --- a/intermediate/xarray_ecosystem.ipynb +++ b/intermediate/xarray_ecosystem.ipynb @@ -7,7 +7,7 @@ "source": [ "\n", "\n", - "# Customizing Xarray: A Tour of the Xarray Ecosystem\n", + "# A Tour of Xarray Customizations\n", "\n", "Xarray is easily extensible.\n", "This means it is easy to add onto to build custom packages that tackle particular computational problems\n", From 6172e7962dc14a97462228110023f2864cd139f8 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 30 Jun 2023 16:42:19 +0000 Subject: [PATCH 17/23] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- advanced/accessors/01_accessor_examples.ipynb | 1 + 1 file changed, 1 insertion(+) diff --git a/advanced/accessors/01_accessor_examples.ipynb b/advanced/accessors/01_accessor_examples.ipynb index 69e07cd9..99befb17 100644 --- a/advanced/accessors/01_accessor_examples.ipynb +++ b/advanced/accessors/01_accessor_examples.ipynb @@ -68,6 +68,7 @@ "outputs": [], "source": [ "import xarray as xr\n", + "\n", "xr.set_options(display_expand_attrs=False, display_expand_coords=False)\n", "from scipy.stats import skew\n", "\n", From 77ea3ba7bd253bef23c956a340c0afc4fb624813 Mon Sep 17 00:00:00 2001 From: Jessica Scheick Date: Fri, 30 Jun 2023 12:48:29 -0400 Subject: [PATCH 18/23] fix accessor path --- data_cleaning/ice_velocity.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_cleaning/ice_velocity.ipynb b/data_cleaning/ice_velocity.ipynb index bfce20cc..9934576e 100644 --- a/data_cleaning/ice_velocity.ipynb +++ b/data_cleaning/ice_velocity.ipynb @@ -17,7 +17,7 @@ "The `.nc` object is a dataset with dimensions x,y and data vars for each year. So for each year there are `vx`,`vy`,`err` vars. We'd like to re-organize this so that there are 3 variables (`vx`, `vy` and `err`) that exist along a time dimension.\n", "\n", "```{note}\n", - "These steps were turned into a accessor/extension example, which can be viewed [here](accessors).\n", + "These steps were turned into a accessor/extension example, which can be viewed [here](advanced/accessors).\n", "```" ] }, From 8875193018dcbb3626c064d95c05f30ee08c5593 Mon Sep 17 00:00:00 2001 From: Jessica Scheick Date: Fri, 30 Jun 2023 13:01:31 -0400 Subject: [PATCH 19/23] fix accessor path --- data_cleaning/ice_velocity.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_cleaning/ice_velocity.ipynb b/data_cleaning/ice_velocity.ipynb index 9934576e..36a43c6c 100644 --- a/data_cleaning/ice_velocity.ipynb +++ b/data_cleaning/ice_velocity.ipynb @@ -17,7 +17,7 @@ "The `.nc` object is a dataset with dimensions x,y and data vars for each year. So for each year there are `vx`,`vy`,`err` vars. We'd like to re-organize this so that there are 3 variables (`vx`, `vy` and `err`) that exist along a time dimension.\n", "\n", "```{note}\n", - "These steps were turned into a accessor/extension example, which can be viewed [here](advanced/accessors).\n", + "These steps were turned into a accessor/extension example, which can be viewed [here](advanced/accessors/01_accessor_examples).\n", "```" ] }, From 135777b0b70f931c05101cdaf63143dacdf030ca Mon Sep 17 00:00:00 2001 From: Jessica Scheick Date: Fri, 30 Jun 2023 13:09:47 -0400 Subject: [PATCH 20/23] add random newline to see if another push will get github to update the PR --- data_cleaning/ice_velocity.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data_cleaning/ice_velocity.ipynb b/data_cleaning/ice_velocity.ipynb index 36a43c6c..9392e6bb 100644 --- a/data_cleaning/ice_velocity.ipynb +++ b/data_cleaning/ice_velocity.ipynb @@ -18,7 +18,7 @@ "\n", "```{note}\n", "These steps were turned into a accessor/extension example, which can be viewed [here](advanced/accessors/01_accessor_examples).\n", - "```" + "```\n" ] }, { From 4fd7b821a46f850a80e464f4b223135733ed4891 Mon Sep 17 00:00:00 2001 From: Jessica Scheick Date: Fri, 30 Jun 2023 13:15:01 -0400 Subject: [PATCH 21/23] make non-relative path --- data_cleaning/ice_velocity.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/data_cleaning/ice_velocity.ipynb b/data_cleaning/ice_velocity.ipynb index 9392e6bb..5172cb96 100644 --- a/data_cleaning/ice_velocity.ipynb +++ b/data_cleaning/ice_velocity.ipynb @@ -17,8 +17,8 @@ "The `.nc` object is a dataset with dimensions x,y and data vars for each year. So for each year there are `vx`,`vy`,`err` vars. We'd like to re-organize this so that there are 3 variables (`vx`, `vy` and `err`) that exist along a time dimension.\n", "\n", "```{note}\n", - "These steps were turned into a accessor/extension example, which can be viewed [here](advanced/accessors/01_accessor_examples).\n", - "```\n" + "These steps were turned into a accessor/extension example, which can be viewed [here](/advanced/accessors/01_accessor_examples).\n", + "```" ] }, { From d1b814f3c4ec2ce1cf047ce37f8835a0fcea34af Mon Sep 17 00:00:00 2001 From: Jessica Scheick Date: Mon, 3 Jul 2023 14:43:36 -0400 Subject: [PATCH 22/23] fix a few typos --- advanced/accessors/01_accessor_examples.ipynb | 22 ++++++++++++------- intermediate/xarray_ecosystem.ipynb | 3 +-- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/advanced/accessors/01_accessor_examples.ipynb b/advanced/accessors/01_accessor_examples.ipynb index 99befb17..6eaa5529 100644 --- a/advanced/accessors/01_accessor_examples.ipynb +++ b/advanced/accessors/01_accessor_examples.ipynb @@ -14,7 +14,7 @@ "source": [ "## Introduction\n", "\n", - "An accessor is a way of attaching a custom function to xarray objects so that it can be called as if it were a method while retaining a clear separation between \"core\" xarray API and custom API. It enables you to easily *extend* (which is why you'll sometimes see it referred to as an extension) and customize xarray's functionality while limiting naming conflicts and minimizing the chances of your code breaking with xarray upgrades.\n", + "An accessor is a way of attaching a custom function to xarray objects so that it can be called as if it were a method while retaining a clear separation between the \"core\" xarray API and custom API. It enables you to easily *extend* (which is why you'll sometimes see it referred to as an extension) and customize xarray's functionality while limiting naming conflicts and minimizing the chances of your code breaking with xarray upgrades.\n", "\n", "If you've used [rioxarray](https://corteva.github.io/rioxarray/stable/) (e.g. `da.rio.crs`) or [hvplot](https://hvplot.holoviz.org/) (e.g. `ds.hvplot()`), you may have already used an xarray accessor without knowing it!\n", "\n", @@ -22,6 +22,7 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ @@ -31,7 +32,7 @@ "- It keeps your workflows cleaner and simpler\n", "- Your project-specific code is easy to share\n", "- It's easy to implement: you don't need to integrate any code into Xarray\n", - "- it makes it easier to perform checks and write code documentation because you only have to create them once!" + "- It makes it easier to perform checks and write code documentation because you only have to create them once!" ] }, { @@ -53,12 +54,13 @@ ] }, { + "attachments": {}, "cell_type": "markdown", "metadata": {}, "source": [ "For example, imagine you're a statistician who regularly uses a special `skewness` function which acts on dataarrays but is only of interest to people in your specific field.\n", "\n", - "You can create a method which applies this skewness function to an xarray objects, and then register the method under a custom `stats` accessor like this" + "You can create a method which applies this skewness function to an xarray object and then register the method under a custom `stats` accessor like this:" ] }, { @@ -68,10 +70,9 @@ "outputs": [], "source": [ "import xarray as xr\n", - "\n", - "xr.set_options(display_expand_attrs=False, display_expand_coords=False)\n", "from scipy.stats import skew\n", "\n", + "xr.set_options(display_expand_attrs=False, display_expand_coords=False)\n", "\n", "@xr.register_dataarray_accessor(\"stats\")\n", "class StatsAccessor:\n", @@ -156,6 +157,8 @@ " for a given function, saving time and headache later if they were missing and the computation fails\n", " partway through.\n", "\n", + " Parameters\n", + " ----------\n", " req_dim : list of str\n", " List of all required dimension names\n", " req_vars : list of str\n", @@ -181,6 +184,8 @@ " \"\"\"\n", " Turn the xaxis and y axis variables into coordinates.\n", "\n", + " Parameters\n", + " ----------\n", " req_dim : list of str\n", " List of all required dimension names.\n", " req_vars : list of str\n", @@ -316,9 +321,10 @@ " '''\n", " Make sure the xarray dataset has the correct dimensions and variables\n", "\n", + " Parameters\n", + " ----------\n", " req_dim : list of str\n", " List of all required dimension names\n", - "\n", " req_vars : list of str\n", " List of all required variable names\n", " '''\n", @@ -342,12 +348,12 @@ " and apply the offset to all elevation values.\n", " Adds 'geoid_offset' keyword to \"offsets\" attribute so you know the geoid offset was applied.\n", "\n", + " Parameters\n", + " ----------\n", " req_dim : list of str\n", " List of all required dimension names.\n", - "\n", " req_vars : list of str\n", " List of all required variable names\n", - "\n", " source : str\n", " Full path to your source file containing geoid offsets\n", " \"\"\"\n", diff --git a/intermediate/xarray_ecosystem.ipynb b/intermediate/xarray_ecosystem.ipynb index 00ba87e0..a587aa9a 100644 --- a/intermediate/xarray_ecosystem.ipynb +++ b/intermediate/xarray_ecosystem.ipynb @@ -10,8 +10,7 @@ "# A Tour of Xarray Customizations\n", "\n", "Xarray is easily extensible.\n", - "This means it is easy to add onto to build custom packages that tackle particular computational problems\n", - "or supply domain specific functionality.\n", + "This means it is easy to add on to to build custom packages that tackle particular computational problems or supply domain specific functionality.\n", "\n", "These packages can plug in to xarray in various different ways. They may build directly on top of xarray, or they may take advantage of some of xarray's dedicated interfacing features:\n", "- Accessors (extensions)\n", From 97162b334b75f1a87cb23b782bb9f6dc609e1128 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 3 Jul 2023 18:43:56 +0000 Subject: [PATCH 23/23] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- advanced/accessors/01_accessor_examples.ipynb | 1 + 1 file changed, 1 insertion(+) diff --git a/advanced/accessors/01_accessor_examples.ipynb b/advanced/accessors/01_accessor_examples.ipynb index 6eaa5529..ab96e8bd 100644 --- a/advanced/accessors/01_accessor_examples.ipynb +++ b/advanced/accessors/01_accessor_examples.ipynb @@ -74,6 +74,7 @@ "\n", "xr.set_options(display_expand_attrs=False, display_expand_coords=False)\n", "\n", + "\n", "@xr.register_dataarray_accessor(\"stats\")\n", "class StatsAccessor:\n", " def __init__(self, da):\n",