From eec817baad23c9c9b07bedbf2587d566810414ab Mon Sep 17 00:00:00 2001 From: Julia Signell Date: Fri, 3 May 2024 14:58:27 -0400 Subject: [PATCH 1/6] Add docs about converting between shapely and cf --- cf_xarray/geometry.py | 5 ++- doc/geometry.md | 93 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 95 insertions(+), 3 deletions(-) diff --git a/cf_xarray/geometry.py b/cf_xarray/geometry.py index 8794b876..16b612e4 100644 --- a/cf_xarray/geometry.py +++ b/cf_xarray/geometry.py @@ -94,9 +94,10 @@ def shapely_to_cf(geometries: xr.DataArray | Sequence, grid_mapping: str | None A dataset with shapely geometry objects translated into CF-compliant variables : - 'x', 'y' : the node coordinates - 'crd_x', 'crd_y' : the feature coordinates (might have different names if `grid_mapping` is available). - - 'node_count' : The number of nodes per feature. Absent if all instances are Points. + - 'node_count' : The number of nodes per feature. Always present for Lines and Polygons. For Points: only present if there are multipart geometries. + - 'part_node_count' : The number of nodes per individual geometry. Only for Lines with multipart geometries and for Polygons with multipart geometries or holes. + - 'interior_ring' : Integer boolean indicating whether rings are interior or exterior. Only for Polygons with holes. - 'geometry_container' : Empty variable with attributes describing the geometry type. - - Other variables are not implemented as only Points are currently understood. References ---------- diff --git a/doc/geometry.md b/doc/geometry.md index 1fddea17..adf75aa2 100644 --- a/doc/geometry.md +++ b/doc/geometry.md @@ -1,7 +1,98 @@ +--- +jupytext: + text_representation: + format_name: myst +kernelspec: + display_name: Python 3 + name: python3 +--- + ```{eval-rst} .. currentmodule:: xarray ``` # Geometries -See {py:func}`cf_xarray.shapely_to_cf`, {py:func}`cf_xarray.cf_to_shapely` +See + +1. {py:func}`cf_xarray.shapely_to_cf` +1. {py:func}`cf_xarray.cf_to_shapely` + +In order to support vectors as well as arrays `cf_xarray` can convert between shapely objects +and CF-compliant representations of those geometries. + +Let's start by creating an xarray object containing some shapely geometries. This example uses +a `xr.DataArray` but these functions also work with a `xr.Dataset` where one of the data variables +contains an array of shapes. + +```{code-cell} +import cf_xarray as cfxr +import xarray as xr + +from shapely.geometry import MultiPoint, Point + +da = xr.DataArray( + [ + MultiPoint([(1.0, 2.0), (2.0, 3.0)]), + Point(3.0, 4.0), + Point(4.0, 5.0), + Point(3.0, 4.0), + ], + dims=("index",), + name="geometry" +) +``` + +```{warning} +`cf_xarray` does not support handle multiple types of shapes (Point, Line, Polygon) in one +`xr.DataArray`, but multipart geometries are supported and can be mixed with single-part +geometries of the same type. +``` + +Now we can take that `xr.DataArray` containing shapely geometries and convert it to cf: + +```{code-cell} +ds_cf = cfxr.shapely_to_cf(da) +ds_cf +``` + +This function returns a `xr.Dataset` containing the CF fields needed to reconstruct the +geometries. In particular there are: + +- 'x', 'y' : the node coordinates +- 'crd_x', 'crd_y' : the feature coordinates (might have different names if `grid_mapping` is available). +- 'node_count' : The number of nodes per feature. Always present for Lines and Polygons. For +Points: only present if there are multipart geometries. +- part_node_count : The number of nodes per individual geometry. Only for Lines with multipart +geometries and for Polygons with multipart geometries or holes. +- interior_ring : Integer boolean indicating whether ring is interior or exterior. Only for +Polygons with holes. +- 'geometry_container' : Empty variable with attributes describing the geometry type. + +Here are the attributes on `geometry_container`. This pattern mimics the convention of +specifying spatial reference information in the attrs of the empty array `spatial_ref`. + +```{code-cell} +ds_cf.geometry_container.attrs +``` + +```{note} +Z axis is not yet supported for any shapes. +``` + +This `xr.Dataset` can be converted back into a `xr.DataArray` of shapely geometries: + +```{code-cell} +cfxr.cf_to_shapely(ds_cf) +``` + +This conversion adds coordinates that aren't in the `xr.DataArray` that we started with. +By default these are called `crd_x` and `crd_y` unless `grid_mapping` is specified. + +## Gotchas + +For MultiPolygons with holes the CF notation is slightly ambiguous on which hole is associated +with which polygon. This is problematic because shapely stores holes within the polygon +object that they are associated with. `cf_xarray` assumes that the the shapes are interleaved +such that the holes (interior rings) are associated with the exteriors (exterior rings) that +immediately precede them. From d3dab28492a6e5f76e5a538a39e62370e1cfb19b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 3 May 2024 19:00:20 +0000 Subject: [PATCH 2/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- doc/geometry.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/doc/geometry.md b/doc/geometry.md index adf75aa2..96fc7bae 100644 --- a/doc/geometry.md +++ b/doc/geometry.md @@ -13,10 +13,10 @@ kernelspec: # Geometries -See +See -1. {py:func}`cf_xarray.shapely_to_cf` -1. {py:func}`cf_xarray.cf_to_shapely` +1. {py:func}`cf_xarray.shapely_to_cf` +1. {py:func}`cf_xarray.cf_to_shapely` In order to support vectors as well as arrays `cf_xarray` can convert between shapely objects and CF-compliant representations of those geometries. @@ -37,7 +37,7 @@ da = xr.DataArray( Point(3.0, 4.0), Point(4.0, 5.0), Point(3.0, 4.0), - ], + ], dims=("index",), name="geometry" ) @@ -49,7 +49,7 @@ da = xr.DataArray( geometries of the same type. ``` -Now we can take that `xr.DataArray` containing shapely geometries and convert it to cf: +Now we can take that `xr.DataArray` containing shapely geometries and convert it to cf: ```{code-cell} ds_cf = cfxr.shapely_to_cf(da) @@ -61,12 +61,12 @@ geometries. In particular there are: - 'x', 'y' : the node coordinates - 'crd_x', 'crd_y' : the feature coordinates (might have different names if `grid_mapping` is available). -- 'node_count' : The number of nodes per feature. Always present for Lines and Polygons. For -Points: only present if there are multipart geometries. -- part_node_count : The number of nodes per individual geometry. Only for Lines with multipart -geometries and for Polygons with multipart geometries or holes. +- 'node_count' : The number of nodes per feature. Always present for Lines and Polygons. For + Points: only present if there are multipart geometries. +- part_node_count : The number of nodes per individual geometry. Only for Lines with multipart + geometries and for Polygons with multipart geometries or holes. - interior_ring : Integer boolean indicating whether ring is interior or exterior. Only for -Polygons with holes. + Polygons with holes. - 'geometry_container' : Empty variable with attributes describing the geometry type. Here are the attributes on `geometry_container`. This pattern mimics the convention of @@ -93,6 +93,6 @@ By default these are called `crd_x` and `crd_y` unless `grid_mapping` is specifi For MultiPolygons with holes the CF notation is slightly ambiguous on which hole is associated with which polygon. This is problematic because shapely stores holes within the polygon -object that they are associated with. `cf_xarray` assumes that the the shapes are interleaved -such that the holes (interior rings) are associated with the exteriors (exterior rings) that +object that they are associated with. `cf_xarray` assumes that the the shapes are interleaved +such that the holes (interior rings) are associated with the exteriors (exterior rings) that immediately precede them. From f2cace1eea9e9dfd02f4d4500ba59b0693745b68 Mon Sep 17 00:00:00 2001 From: Julia Signell Date: Fri, 3 May 2024 15:26:42 -0400 Subject: [PATCH 3/6] Add shapely to docs env --- ci/doc.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/ci/doc.yml b/ci/doc.yml index 9481e505..361c02d2 100644 --- a/ci/doc.yml +++ b/ci/doc.yml @@ -19,6 +19,7 @@ dependencies: - pooch - pint - regex + - shapely - furo - myst-nb - pip: From b3c45f4158f9d920fba979d47f8d9a5c2a27eea7 Mon Sep 17 00:00:00 2001 From: Julia Signell Date: Fri, 3 May 2024 16:13:31 -0400 Subject: [PATCH 4/6] Apply suggestions from code review Co-authored-by: Deepak Cherian --- doc/geometry.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/doc/geometry.md b/doc/geometry.md index 96fc7bae..593296a3 100644 --- a/doc/geometry.md +++ b/doc/geometry.md @@ -13,10 +13,11 @@ kernelspec: # Geometries -See - +```seealso +1. [The CF conventions on Geometries](http://cfconventions.org/Data/cf-conventions/cf-conventions-1.11/cf-conventions.html#geometries) 1. {py:func}`cf_xarray.shapely_to_cf` 1. {py:func}`cf_xarray.cf_to_shapely` +``` In order to support vectors as well as arrays `cf_xarray` can convert between shapely objects and CF-compliant representations of those geometries. @@ -59,15 +60,15 @@ ds_cf This function returns a `xr.Dataset` containing the CF fields needed to reconstruct the geometries. In particular there are: -- 'x', 'y' : the node coordinates -- 'crd_x', 'crd_y' : the feature coordinates (might have different names if `grid_mapping` is available). -- 'node_count' : The number of nodes per feature. Always present for Lines and Polygons. For +- `'x'`, `'y'` : the node coordinates +- `'crd_x'`, `'crd_y'` : the feature coordinates (might have different names if `grid_mapping` is available). +- `'node_count'` : The number of nodes per feature. Always present for Lines and Polygons. For Points: only present if there are multipart geometries. -- part_node_count : The number of nodes per individual geometry. Only for Lines with multipart +- `'part_node_count'` : The number of nodes per individual geometry. Only for Lines with multipart geometries and for Polygons with multipart geometries or holes. -- interior_ring : Integer boolean indicating whether ring is interior or exterior. Only for +- `'interior_ring'` : Integer boolean indicating whether ring is interior or exterior. Only for Polygons with holes. -- 'geometry_container' : Empty variable with attributes describing the geometry type. +- `'geometry_container`' : Empty variable with attributes describing the geometry type. Here are the attributes on `geometry_container`. This pattern mimics the convention of specifying spatial reference information in the attrs of the empty array `spatial_ref`. From 792def4e073072ccb4b24c330eff3a2d5b63046b Mon Sep 17 00:00:00 2001 From: Deepak Cherian Date: Fri, 3 May 2024 14:21:27 -0600 Subject: [PATCH 5/6] Update doc/geometry.md --- doc/geometry.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/geometry.md b/doc/geometry.md index 593296a3..753458a7 100644 --- a/doc/geometry.md +++ b/doc/geometry.md @@ -13,7 +13,7 @@ kernelspec: # Geometries -```seealso +```{seealso} 1. [The CF conventions on Geometries](http://cfconventions.org/Data/cf-conventions/cf-conventions-1.11/cf-conventions.html#geometries) 1. {py:func}`cf_xarray.shapely_to_cf` 1. {py:func}`cf_xarray.cf_to_shapely` From eb6ec182a82408bc78e2b2b7cf4319f4d2159f6f Mon Sep 17 00:00:00 2001 From: Deepak Cherian Date: Fri, 3 May 2024 14:27:46 -0600 Subject: [PATCH 6/6] Update doc/geometry.md --- doc/geometry.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/geometry.md b/doc/geometry.md index 753458a7..21640aa7 100644 --- a/doc/geometry.md +++ b/doc/geometry.md @@ -19,8 +19,8 @@ kernelspec: 1. {py:func}`cf_xarray.cf_to_shapely` ``` -In order to support vectors as well as arrays `cf_xarray` can convert between shapely objects -and CF-compliant representations of those geometries. +`cf_xarray` can convert between vector geometries represented as shapely objects +and CF-compliant array representations of those geometries. Let's start by creating an xarray object containing some shapely geometries. This example uses a `xr.DataArray` but these functions also work with a `xr.Dataset` where one of the data variables