Skip to content

Commit 08fb286

Browse files
jsignellpre-commit-ci[bot]dcherian
authored
Add docs about converting between shapely and cf (#512)
* Add docs about converting between shapely and cf * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Add shapely to docs env * Apply suggestions from code review Co-authored-by: Deepak Cherian <dcherian@users.noreply.github.com> * Update doc/geometry.md * Update doc/geometry.md --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Deepak Cherian <dcherian@users.noreply.github.com>
1 parent 9d2c87f commit 08fb286

File tree

3 files changed

+97
-3
lines changed

3 files changed

+97
-3
lines changed

cf_xarray/geometry.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -94,9 +94,10 @@ def shapely_to_cf(geometries: xr.DataArray | Sequence, grid_mapping: str | None
9494
A dataset with shapely geometry objects translated into CF-compliant variables :
9595
- 'x', 'y' : the node coordinates
9696
- 'crd_x', 'crd_y' : the feature coordinates (might have different names if `grid_mapping` is available).
97-
- 'node_count' : The number of nodes per feature. Absent if all instances are Points.
97+
- 'node_count' : The number of nodes per feature. Always present for Lines and Polygons. For Points: only present if there are multipart geometries.
98+
- 'part_node_count' : The number of nodes per individual geometry. Only for Lines with multipart geometries and for Polygons with multipart geometries or holes.
99+
- 'interior_ring' : Integer boolean indicating whether rings are interior or exterior. Only for Polygons with holes.
98100
- 'geometry_container' : Empty variable with attributes describing the geometry type.
99-
- Other variables are not implemented as only Points are currently understood.
100101
101102
References
102103
----------

ci/doc.yml

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ dependencies:
1919
- pooch
2020
- pint
2121
- regex
22+
- shapely
2223
- furo
2324
- myst-nb
2425
- pip:

doc/geometry.md

+93-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,99 @@
1+
---
2+
jupytext:
3+
text_representation:
4+
format_name: myst
5+
kernelspec:
6+
display_name: Python 3
7+
name: python3
8+
---
9+
110
```{eval-rst}
211
.. currentmodule:: xarray
312
```
413

514
# Geometries
615

7-
See {py:func}`cf_xarray.shapely_to_cf`, {py:func}`cf_xarray.cf_to_shapely`
16+
```{seealso}
17+
1. [The CF conventions on Geometries](http://cfconventions.org/Data/cf-conventions/cf-conventions-1.11/cf-conventions.html#geometries)
18+
1. {py:func}`cf_xarray.shapely_to_cf`
19+
1. {py:func}`cf_xarray.cf_to_shapely`
20+
```
21+
22+
`cf_xarray` can convert between vector geometries represented as shapely objects
23+
and CF-compliant array representations of those geometries.
24+
25+
Let's start by creating an xarray object containing some shapely geometries. This example uses
26+
a `xr.DataArray` but these functions also work with a `xr.Dataset` where one of the data variables
27+
contains an array of shapes.
28+
29+
```{code-cell}
30+
import cf_xarray as cfxr
31+
import xarray as xr
32+
33+
from shapely.geometry import MultiPoint, Point
34+
35+
da = xr.DataArray(
36+
[
37+
MultiPoint([(1.0, 2.0), (2.0, 3.0)]),
38+
Point(3.0, 4.0),
39+
Point(4.0, 5.0),
40+
Point(3.0, 4.0),
41+
],
42+
dims=("index",),
43+
name="geometry"
44+
)
45+
```
46+
47+
```{warning}
48+
`cf_xarray` does not support handle multiple types of shapes (Point, Line, Polygon) in one
49+
`xr.DataArray`, but multipart geometries are supported and can be mixed with single-part
50+
geometries of the same type.
51+
```
52+
53+
Now we can take that `xr.DataArray` containing shapely geometries and convert it to cf:
54+
55+
```{code-cell}
56+
ds_cf = cfxr.shapely_to_cf(da)
57+
ds_cf
58+
```
59+
60+
This function returns a `xr.Dataset` containing the CF fields needed to reconstruct the
61+
geometries. In particular there are:
62+
63+
- `'x'`, `'y'` : the node coordinates
64+
- `'crd_x'`, `'crd_y'` : the feature coordinates (might have different names if `grid_mapping` is available).
65+
- `'node_count'` : The number of nodes per feature. Always present for Lines and Polygons. For
66+
Points: only present if there are multipart geometries.
67+
- `'part_node_count'` : The number of nodes per individual geometry. Only for Lines with multipart
68+
geometries and for Polygons with multipart geometries or holes.
69+
- `'interior_ring'` : Integer boolean indicating whether ring is interior or exterior. Only for
70+
Polygons with holes.
71+
- `'geometry_container`' : Empty variable with attributes describing the geometry type.
72+
73+
Here are the attributes on `geometry_container`. This pattern mimics the convention of
74+
specifying spatial reference information in the attrs of the empty array `spatial_ref`.
75+
76+
```{code-cell}
77+
ds_cf.geometry_container.attrs
78+
```
79+
80+
```{note}
81+
Z axis is not yet supported for any shapes.
82+
```
83+
84+
This `xr.Dataset` can be converted back into a `xr.DataArray` of shapely geometries:
85+
86+
```{code-cell}
87+
cfxr.cf_to_shapely(ds_cf)
88+
```
89+
90+
This conversion adds coordinates that aren't in the `xr.DataArray` that we started with.
91+
By default these are called `crd_x` and `crd_y` unless `grid_mapping` is specified.
92+
93+
## Gotchas
94+
95+
For MultiPolygons with holes the CF notation is slightly ambiguous on which hole is associated
96+
with which polygon. This is problematic because shapely stores holes within the polygon
97+
object that they are associated with. `cf_xarray` assumes that the the shapes are interleaved
98+
such that the holes (interior rings) are associated with the exteriors (exterior rings) that
99+
immediately precede them.

0 commit comments

Comments
 (0)