@@ -49,6 +49,83 @@ def geometry_ds():
4949 return cf_ds , shp_ds
5050
5151
52+ @pytest .fixture
53+ def geometry_line_ds ():
54+ from shapely .geometry import LineString , MultiLineString
55+
56+ # empty/fill workaround to avoid numpy deprecation(warning) due to the array interface of shapely geometries.
57+ geoms = np .empty (3 , dtype = object )
58+ geoms [:] = [
59+ MultiLineString ([[[0 , 0 ], [1 , 2 ]], [[4 , 4 ], [5 , 6 ]]]),
60+ LineString ([[0 , 0 ], [1 , 0 ], [1 , 1 ]]),
61+ LineString ([[1.0 , 1.0 ], [2.0 , 2.0 ], [1.7 , 9.5 ]]),
62+ ]
63+
64+ ds = xr .Dataset ()
65+ shp_da = xr .DataArray (geoms , dims = ("index" ,), name = "geometry" )
66+
67+ cf_ds = ds .assign (
68+ x = xr .DataArray (
69+ [0 , 1 , 4 , 5 , 0 , 1 , 1 , 1.0 , 2.0 , 1.7 ], dims = ("node" ,), attrs = {"axis" : "X" }
70+ ),
71+ y = xr .DataArray (
72+ [0 , 2 , 4 , 6 , 0 , 0 , 1 , 1.0 , 2.0 , 9.5 ], dims = ("node" ,), attrs = {"axis" : "Y" }
73+ ),
74+ part_node_count = xr .DataArray ([4 , 3 , 3 ], dims = ("index" ,)),
75+ node_count = xr .DataArray ([2 , 2 , 3 , 3 ], dims = ("segment" ,)),
76+ crd_x = xr .DataArray ([0.0 , 0.0 , 1.0 ], dims = ("index" ,), attrs = {"nodes" : "x" }),
77+ crd_y = xr .DataArray ([0.0 , 0.0 , 1.0 ], dims = ("index" ,), attrs = {"nodes" : "y" }),
78+ geometry_container = xr .DataArray (
79+ attrs = {
80+ "geometry_type" : "line" ,
81+ "node_count" : "node_count" ,
82+ "part_node_count" : "part_node_count" ,
83+ "node_coordinates" : "x y" ,
84+ "coordinates" : "crd_x crd_y" ,
85+ }
86+ ),
87+ )
88+
89+ cf_ds = cf_ds .set_coords (["x" , "y" , "crd_x" , "crd_y" ])
90+
91+ return cf_ds , shp_da
92+
93+
94+ @pytest .fixture
95+ def geometry_line_without_multilines_ds ():
96+ from shapely .geometry import LineString
97+
98+ # empty/fill workaround to avoid numpy deprecation(warning) due to the array interface of shapely geometries.
99+ geoms = np .empty (2 , dtype = object )
100+ geoms [:] = [
101+ LineString ([[0 , 0 ], [1 , 0 ], [1 , 1 ]]),
102+ LineString ([[1.0 , 1.0 ], [2.0 , 2.0 ], [1.7 , 9.5 ]]),
103+ ]
104+
105+ ds = xr .Dataset ()
106+ shp_da = xr .DataArray (geoms , dims = ("index" ,), name = "geometry" )
107+
108+ cf_ds = ds .assign (
109+ x = xr .DataArray ([0 , 1 , 1 , 1.0 , 2.0 , 1.7 ], dims = ("node" ,), attrs = {"axis" : "X" }),
110+ 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" ,)),
112+ crd_x = xr .DataArray ([0.0 , 1.0 ], dims = ("index" ,), attrs = {"nodes" : "x" }),
113+ crd_y = xr .DataArray ([0.0 , 1.0 ], dims = ("index" ,), attrs = {"nodes" : "y" }),
114+ geometry_container = xr .DataArray (
115+ attrs = {
116+ "geometry_type" : "line" ,
117+ "node_count" : "node_count" ,
118+ "node_coordinates" : "x y" ,
119+ "coordinates" : "crd_x crd_y" ,
120+ }
121+ ),
122+ )
123+
124+ cf_ds = cf_ds .set_coords (["x" , "y" , "crd_x" , "crd_y" ])
125+
126+ return cf_ds , shp_da
127+
128+
52129@requires_shapely
53130def test_shapely_to_cf (geometry_ds ):
54131 from shapely .geometry import Point
@@ -87,12 +164,45 @@ def test_shapely_to_cf(geometry_ds):
87164 assert set (out .dims ) == {"features" , "node" }
88165
89166
167+ @requires_shapely
168+ def test_shapely_to_cf_for_lines_as_da (geometry_line_ds ):
169+ expected , in_da = geometry_line_ds
170+
171+ actual = cfxr .shapely_to_cf (in_da )
172+ xr .testing .assert_identical (actual , expected )
173+
174+ in_da = in_da .assign_coords (index = ["a" , "b" , "c" ])
175+ actual = cfxr .shapely_to_cf (in_da )
176+ xr .testing .assert_identical (actual , expected .assign_coords (index = ["a" , "b" , "c" ]))
177+
178+
179+ @requires_shapely
180+ def test_shapely_to_cf_for_lines_as_sequence (geometry_line_ds ):
181+ expected , in_da = geometry_line_ds
182+ actual = cfxr .shapely_to_cf (in_da .values )
183+ xr .testing .assert_identical (actual , expected )
184+
185+
186+ @requires_shapely
187+ def test_shapely_to_cf_for_lines_without_multilines (
188+ geometry_line_without_multilines_ds ,
189+ ):
190+ expected , in_da = geometry_line_without_multilines_ds
191+ actual = cfxr .shapely_to_cf (in_da )
192+ xr .testing .assert_identical (actual , expected )
193+
194+
90195@requires_shapely
91196def test_shapely_to_cf_errors ():
92- from shapely .geometry import LineString , Point
197+ from shapely .geometry import Point , Polygon
93198
94- geoms = [LineString ([[1 , 2 ], [2 , 3 ]]), LineString ([[2 , 3 , 4 ], [4 , 3 , 2 ]])]
95- with pytest .raises (NotImplementedError , match = "Only point geometries conversion" ):
199+ geoms = [
200+ Polygon ([[1 , 1 ], [1 , 3 ], [3 , 3 ], [1 , 1 ]]),
201+ Polygon ([[1 , 1 , 4 ], [1 , 3 , 4 ], [3 , 3 , 3 ], [1 , 1 , 4 ]]),
202+ ]
203+ with pytest .raises (
204+ NotImplementedError , match = "Polygon geometry conversion is not implemented"
205+ ):
96206 cfxr .shapely_to_cf (geoms )
97207
98208 geoms .append (Point (1 , 2 ))
@@ -122,16 +232,47 @@ def test_cf_to_shapely(geometry_ds):
122232
123233
124234@requires_shapely
125- def test_cf_to_shapely_errors (geometry_ds ):
126- in_ds , expected = geometry_ds
127- in_ds .geometry_container .attrs ["geometry_type" ] = "line"
128- with pytest .raises (NotImplementedError , match = "Only point geometries conversion" ):
235+ def test_cf_to_shapely_for_lines (geometry_line_ds ):
236+ in_ds , expected = geometry_line_ds
237+
238+ actual = cfxr .cf_to_shapely (in_ds )
239+ assert actual .dims == ("index" ,)
240+ xr .testing .assert_identical (actual .drop_vars (["crd_x" , "crd_y" ]), expected )
241+
242+
243+ @requires_shapely
244+ def test_cf_to_shapely_for_lines_without_multilines (
245+ geometry_line_without_multilines_ds ,
246+ ):
247+ in_ds , expected = geometry_line_without_multilines_ds
248+ actual = cfxr .cf_to_shapely (in_ds )
249+ assert actual .dims == ("index" ,)
250+ xr .testing .assert_identical (actual , expected )
251+
252+ in_ds = in_ds .assign_coords (index = ["b" , "c" ])
253+ actual = cfxr .cf_to_shapely (in_ds )
254+ assert actual .dims == ("index" ,)
255+ xr .testing .assert_identical (
256+ actual .drop_vars (["crd_x" , "crd_y" ]), expected .assign_coords (index = ["b" , "c" ])
257+ )
258+
259+
260+ @requires_shapely
261+ def test_cf_to_shapely_errors (geometry_ds , geometry_line_ds ):
262+ in_ds , _ = geometry_ds
263+ in_ds .geometry_container .attrs ["geometry_type" ] = "polygon"
264+ with pytest .raises (NotImplementedError , match = "Polygon geometry" ):
129265 cfxr .cf_to_shapely (in_ds )
130266
131267 in_ds .geometry_container .attrs ["geometry_type" ] = "punkt"
132268 with pytest .raises (ValueError , match = "Valid CF geometry types are " ):
133269 cfxr .cf_to_shapely (in_ds )
134270
271+ in_ds , _ = geometry_line_ds
272+ del in_ds .geometry_container .attrs ["node_count" ]
273+ with pytest .raises (ValueError , match = "'node_count' must be provided" ):
274+ cfxr .cf_to_shapely (in_ds )
275+
135276
136277@requires_shapely
137278def test_reshape_unique_geometries (geometry_ds ):
0 commit comments