Skip to content

Commit 1fe4359

Browse files
Fix conversion between shapely and cf for lines (#493)
* Fix shapely/cf for lines * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent f6c8a1f commit 1fe4359

File tree

2 files changed

+25
-33
lines changed

2 files changed

+25
-33
lines changed

cf_xarray/geometry.py

+21-29
Original file line numberDiff line numberDiff line change
@@ -328,22 +328,22 @@ def lines_to_cf(lines: xr.DataArray | Sequence):
328328
x = arr[:, 0]
329329
y = arr[:, 1]
330330

331-
node_count = np.diff(offsets[0])
331+
part_node_count = np.diff(offsets[0])
332332
if len(offsets) == 1:
333333
indices = offsets[0]
334-
part_node_count = node_count
334+
node_count = part_node_count
335335
else:
336336
indices = np.take(offsets[0], offsets[1])
337-
part_node_count = np.diff(indices)
337+
node_count = np.diff(indices)
338338

339339
geom_coords = arr.take(indices[:-1], 0)
340340
crdX = geom_coords[:, 0]
341341
crdY = geom_coords[:, 1]
342342

343343
ds = xr.Dataset(
344344
data_vars={
345-
"node_count": xr.DataArray(node_count, dims=("segment",)),
346-
"part_node_count": xr.DataArray(part_node_count, dims=(dim,)),
345+
"node_count": xr.DataArray(node_count, dims=(dim,)),
346+
"part_node_count": xr.DataArray(part_node_count, dims=("part",)),
347347
"geometry_container": xr.DataArray(
348348
attrs={
349349
"geometry_type": "line",
@@ -394,7 +394,7 @@ def cf_to_lines(ds: xr.Dataset):
394394
# Shorthand for convenience
395395
geo = ds.geometry_container.attrs
396396

397-
# The features dimension name, defaults to the one of 'part_node_count'
397+
# The features dimension name, defaults to the one of 'node_count'
398398
# or the dimension of the coordinates, if present.
399399
feat_dim = None
400400
if "coordinates" in geo:
@@ -405,36 +405,28 @@ def cf_to_lines(ds: xr.Dataset):
405405
xy = np.stack([ds[x_name].values, ds[y_name].values], axis=-1)
406406

407407
node_count_name = geo.get("node_count")
408-
part_node_count_name = geo.get("part_node_count")
408+
part_node_count_name = geo.get("part_node_count", node_count_name)
409409
if node_count_name is None:
410410
raise ValueError("'node_count' must be provided for line geometries")
411411
else:
412412
node_count = ds[node_count_name]
413+
feat_dim = feat_dim or "index"
414+
if feat_dim in ds.coords:
415+
node_count = node_count.assign_coords({feat_dim: ds[feat_dim]})
413416

414-
offset1 = np.insert(np.cumsum(node_count.values), 0, 0)
417+
# first get geometries for all the parts
418+
part_node_count = ds[part_node_count_name]
419+
offset1 = np.insert(np.cumsum(part_node_count.values), 0, 0)
415420
lines = from_ragged_array(GeometryType.LINESTRING, xy, offsets=(offset1,))
416421

417-
if part_node_count_name is None:
418-
# No part_node_count means there are no multilines
419-
# And if we had no coordinates, then the dimension defaults to "index"
420-
feat_dim = feat_dim or "index"
421-
part_node_count = xr.DataArray(node_count.values, dims=(feat_dim,))
422-
if feat_dim in ds.coords:
423-
part_node_count = part_node_count.assign_coords({feat_dim: ds[feat_dim]})
422+
# get index of offset2 values that are edges for part_node_count
423+
offset2 = np.nonzero(np.isin(offset1, np.insert(np.cumsum(node_count), 0, 0)))[0]
424424

425-
geoms = lines
426-
else:
427-
part_node_count = ds[part_node_count_name]
428-
429-
# get index of offset1 values that are edges for part_node_count
430-
offset2 = np.nonzero(
431-
np.isin(offset1, np.insert(np.cumsum(part_node_count), 0, 0))
432-
)[0]
433-
multilines = from_ragged_array(
434-
GeometryType.MULTILINESTRING, xy, offsets=(offset1, offset2)
435-
)
425+
multilines = from_ragged_array(
426+
GeometryType.MULTILINESTRING, xy, offsets=(offset1, offset2)
427+
)
436428

437-
# get items from lines or multilines depending on number of segments
438-
geoms = np.where(np.diff(offset2) == 1, lines[offset2[:-1]], multilines)
429+
# get items from lines or multilines depending on number of parts
430+
geoms = np.where(np.diff(offset2) == 1, lines[offset2[:-1]], multilines)
439431

440-
return xr.DataArray(geoms, dims=part_node_count.dims, coords=part_node_count.coords)
432+
return xr.DataArray(geoms, dims=node_count.dims, coords=node_count.coords)

cf_xarray/tests/test_geometry.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ def geometry_line_ds():
7171
y=xr.DataArray(
7272
[0, 2, 4, 6, 0, 0, 1, 1.0, 2.0, 9.5], dims=("node",), attrs={"axis": "Y"}
7373
),
74-
part_node_count=xr.DataArray([4, 3, 3], dims=("index",)),
75-
node_count=xr.DataArray([2, 2, 3, 3], dims=("segment",)),
74+
node_count=xr.DataArray([4, 3, 3], dims=("index",)),
75+
part_node_count=xr.DataArray([2, 2, 3, 3], dims=("part",)),
7676
crd_x=xr.DataArray([0.0, 0.0, 1.0], dims=("index",), attrs={"nodes": "x"}),
7777
crd_y=xr.DataArray([0.0, 0.0, 1.0], dims=("index",), attrs={"nodes": "y"}),
7878
geometry_container=xr.DataArray(
@@ -108,7 +108,7 @@ def geometry_line_without_multilines_ds():
108108
cf_ds = ds.assign(
109109
x=xr.DataArray([0, 1, 1, 1.0, 2.0, 1.7], dims=("node",), attrs={"axis": "X"}),
110110
y=xr.DataArray([0, 0, 1, 1.0, 2.0, 9.5], dims=("node",), attrs={"axis": "Y"}),
111-
node_count=xr.DataArray([3, 3], dims=("segment",)),
111+
node_count=xr.DataArray([3, 3], dims=("index",)),
112112
crd_x=xr.DataArray([0.0, 1.0], dims=("index",), attrs={"nodes": "x"}),
113113
crd_y=xr.DataArray([0.0, 1.0], dims=("index",), attrs={"nodes": "y"}),
114114
geometry_container=xr.DataArray(
@@ -247,7 +247,7 @@ def test_cf_to_shapely_for_lines_without_multilines(
247247
in_ds, expected = geometry_line_without_multilines_ds
248248
actual = cfxr.cf_to_shapely(in_ds)
249249
assert actual.dims == ("index",)
250-
xr.testing.assert_identical(actual, expected)
250+
xr.testing.assert_identical(actual.drop_vars(["crd_x", "crd_y"]), expected)
251251

252252
in_ds = in_ds.assign_coords(index=["b", "c"])
253253
actual = cfxr.cf_to_shapely(in_ds)

0 commit comments

Comments
 (0)