|
1 | 1 | from h3pandas import h3pandas # noqa: F401
|
2 | 2 | from h3 import h3
|
3 | 3 | import pytest
|
4 |
| -from shapely.geometry import Polygon, box, Point |
| 4 | +from shapely.geometry import Polygon, LineString, MultiLineString, box, Point |
5 | 5 | import pandas as pd
|
6 | 6 | import geopandas as gpd
|
7 | 7 | from geopandas.testing import assert_geodataframe_equal
|
@@ -33,6 +33,33 @@ def basic_geodataframe_polygon(basic_geodataframe):
|
33 | 33 | return gpd.GeoDataFrame(geometry=[geom], crs="epsg:4326")
|
34 | 34 |
|
35 | 35 |
|
| 36 | +@pytest.fixture |
| 37 | +def basic_geodataframe_linestring(): |
| 38 | + geom = LineString([ |
| 39 | + (174.793092, -37.005372), (175.621138, -40.323142) |
| 40 | + ]) |
| 41 | + return gpd.GeoDataFrame(geometry=[geom], crs="epsg:4326") |
| 42 | + |
| 43 | + |
| 44 | +@pytest.fixture |
| 45 | +# NB one of the LineString parts traverses the antimeridian |
| 46 | +def basic_geodataframe_multilinestring(basic_geodataframe): |
| 47 | + geom = MultiLineString([ |
| 48 | + [[174.793092, -37.005372], [175.621138, -40.323142]], |
| 49 | + [ |
| 50 | + [168.222656, -45.79817], [171.914063, -34.307144], |
| 51 | + [178.769531, -37.926868], [183.515625, -43.992815] |
| 52 | + ] |
| 53 | + ]) |
| 54 | + return gpd.GeoDataFrame(geometry=[geom], crs="epsg:4326") |
| 55 | + |
| 56 | + |
| 57 | +@pytest.fixture |
| 58 | +def basic_geodataframe_empty_linestring(): |
| 59 | + """GeoDataFrame with Empty geometry""" |
| 60 | + return gpd.GeoDataFrame(geometry=[LineString()], crs="epsg:4326") |
| 61 | + |
| 62 | + |
36 | 63 | @pytest.fixture
|
37 | 64 | def basic_geodataframe_polygons(basic_geodataframe):
|
38 | 65 | geoms = [box(0, 0, 1, 1), box(0, 0, 2, 2)]
|
@@ -77,6 +104,11 @@ def h3_geodataframe_with_values(h3_dataframe_with_values):
|
77 | 104 | )
|
78 | 105 |
|
79 | 106 |
|
| 107 | +@pytest.fixture |
| 108 | +def h3_geodataframe_with_polyline_values(basic_geodataframe_linestring): |
| 109 | + return basic_geodataframe_linestring.assign(val=10) |
| 110 | + |
| 111 | + |
80 | 112 | # Tests: H3 API
|
81 | 113 | class TestGeoToH3:
|
82 | 114 | def test_geo_to_h3(self, basic_dataframe):
|
@@ -271,6 +303,132 @@ def test_polyfill_explode_unequal_lengths(self, basic_geodataframe_polygons):
|
271 | 303 | assert set(result["h3_polyfill"]) == expected_indices
|
272 | 304 |
|
273 | 305 |
|
| 306 | +class TestLineTrace: |
| 307 | + def test_empty_linetrace(self, basic_geodataframe_empty_linestring): |
| 308 | + result = basic_geodataframe_empty_linestring.h3.linetrace(2) |
| 309 | + assert len(result.iloc[0]["h3_linetrace"]) == 0 |
| 310 | + |
| 311 | + def test_linetrace(self, basic_geodataframe_linestring): |
| 312 | + result = basic_geodataframe_linestring.h3.linetrace(3) |
| 313 | + expected_indices = [ |
| 314 | + "83bb50fffffffff", |
| 315 | + "83bb54fffffffff", |
| 316 | + "83bb72fffffffff", |
| 317 | + "83bb0dfffffffff", |
| 318 | + "83bb2bfffffffff" |
| 319 | + ] |
| 320 | + assert len(result.iloc[0]["h3_linetrace"]) == 5 |
| 321 | + assert list(result.iloc[0]["h3_linetrace"]) == expected_indices |
| 322 | + |
| 323 | + def test_linetrace_explode(self, basic_geodataframe_linestring): |
| 324 | + result = basic_geodataframe_linestring.h3.linetrace(3, explode=True) |
| 325 | + expected_indices = [ |
| 326 | + "83bb50fffffffff", |
| 327 | + "83bb54fffffffff", |
| 328 | + "83bb72fffffffff", |
| 329 | + "83bb0dfffffffff", |
| 330 | + "83bb2bfffffffff" |
| 331 | + ] |
| 332 | + assert result.shape == (5, 2) |
| 333 | + assert result.iloc[0]['h3_linetrace'] == expected_indices[0] |
| 334 | + assert result.iloc[-1]['h3_linetrace'] == expected_indices[-1] |
| 335 | + |
| 336 | + def test_linetrace_with_values(self, h3_geodataframe_with_polyline_values): |
| 337 | + result = h3_geodataframe_with_polyline_values.h3.linetrace(3) |
| 338 | + expected_indices = [ |
| 339 | + "83bb50fffffffff", |
| 340 | + "83bb54fffffffff", |
| 341 | + "83bb72fffffffff", |
| 342 | + "83bb0dfffffffff", |
| 343 | + "83bb2bfffffffff" |
| 344 | + ] |
| 345 | + assert result.shape == (1, 3) |
| 346 | + assert 'val' in result.columns |
| 347 | + assert result.iloc[0]['val'] == 10 |
| 348 | + assert len(result.iloc[0]["h3_linetrace"]) == 5 |
| 349 | + assert list(result.iloc[0]["h3_linetrace"]) == expected_indices |
| 350 | + |
| 351 | + def test_linetrace_with_values_explode(self, |
| 352 | + h3_geodataframe_with_polyline_values): |
| 353 | + result = h3_geodataframe_with_polyline_values.h3.linetrace(3, explode=True) |
| 354 | + expected_indices = [ |
| 355 | + "83bb50fffffffff", |
| 356 | + "83bb54fffffffff", |
| 357 | + "83bb72fffffffff", |
| 358 | + "83bb0dfffffffff", |
| 359 | + "83bb2bfffffffff" |
| 360 | + ] |
| 361 | + assert result.shape == (5, 3) |
| 362 | + assert 'val' in result.columns |
| 363 | + assert result.iloc[0]['val'] == 10 |
| 364 | + assert result.iloc[0]["h3_linetrace"] == expected_indices[0] |
| 365 | + assert result.iloc[-1]['h3_linetrace'] == expected_indices[-1] |
| 366 | + assert not result["val"].isna().any() |
| 367 | + |
| 368 | + def test_linetrace_multiline(self, basic_geodataframe_multilinestring): |
| 369 | + result = basic_geodataframe_multilinestring.h3.linetrace(2) |
| 370 | + expected_indices = [ |
| 371 | + "82bb57fffffffff", "82bb0ffffffffff", |
| 372 | + "82da87fffffffff", "82da97fffffffff", |
| 373 | + "82bb67fffffffff", "82bb47fffffffff", |
| 374 | + "82bb5ffffffffff", "82bb57fffffffff", |
| 375 | + "82ba27fffffffff", "82bb1ffffffffff", |
| 376 | + "82bb07fffffffff", "82bb37fffffffff" |
| 377 | + ] |
| 378 | + assert len(result.iloc[0]["h3_linetrace"]) == 12 # 12 cells total |
| 379 | + assert list(result.iloc[0]["h3_linetrace"]) == expected_indices |
| 380 | + |
| 381 | + def test_linetrace_multiline_explode_index_parts( |
| 382 | + self, basic_geodataframe_multilinestring |
| 383 | + ): |
| 384 | + result = basic_geodataframe_multilinestring.explode( |
| 385 | + index_parts=True |
| 386 | + ).h3.linetrace( |
| 387 | + 2, explode=True |
| 388 | + ) |
| 389 | + expected_indices = [ |
| 390 | + [ |
| 391 | + "82bb57fffffffff", "82bb0ffffffffff" |
| 392 | + ], |
| 393 | + [ |
| 394 | + "82da87fffffffff", "82da97fffffffff", |
| 395 | + "82bb67fffffffff", "82bb47fffffffff", |
| 396 | + "82bb5ffffffffff", "82bb57fffffffff", |
| 397 | + "82ba27fffffffff", "82bb1ffffffffff", |
| 398 | + "82bb07fffffffff", "82bb37fffffffff" |
| 399 | + ] |
| 400 | + ] |
| 401 | + assert len(result["h3_linetrace"]) == 12 # 12 cells in total |
| 402 | + assert result.iloc[0]["h3_linetrace"] == expected_indices[0][0] |
| 403 | + assert result.iloc[-1]["h3_linetrace"] == expected_indices[-1][-1] |
| 404 | + |
| 405 | + def test_linetrace_multiline_index_parts_no_explode( |
| 406 | + self, basic_geodataframe_multilinestring |
| 407 | + ): |
| 408 | + result = basic_geodataframe_multilinestring.explode( |
| 409 | + index_parts=True |
| 410 | + ).h3.linetrace( |
| 411 | + 2, explode=False |
| 412 | + ) |
| 413 | + expected_indices = [ |
| 414 | + [ |
| 415 | + "82bb57fffffffff", "82bb0ffffffffff" |
| 416 | + ], |
| 417 | + [ |
| 418 | + "82da87fffffffff", "82da97fffffffff", |
| 419 | + "82bb67fffffffff", "82bb47fffffffff", |
| 420 | + "82bb5ffffffffff", "82bb57fffffffff", |
| 421 | + "82ba27fffffffff", "82bb1ffffffffff", |
| 422 | + "82bb07fffffffff", "82bb37fffffffff" |
| 423 | + ] |
| 424 | + ] |
| 425 | + assert len(result["h3_linetrace"]) == 2 # 2 parts |
| 426 | + assert len(result.iloc[0]["h3_linetrace"]) == 2 # 2 cells |
| 427 | + assert result.iloc[0]["h3_linetrace"] == expected_indices[0] |
| 428 | + assert len(result.iloc[-1]["h3_linetrace"]) == 10 # 10 cells |
| 429 | + assert result.iloc[-1]["h3_linetrace"] == expected_indices[-1] |
| 430 | + |
| 431 | + |
274 | 432 | class TestCellArea:
|
275 | 433 | def test_cell_area(self, indexed_dataframe):
|
276 | 434 | expected = indexed_dataframe.assign(
|
|
0 commit comments