From 30172688ce36572837c4f24822e7e7eb22282a32 Mon Sep 17 00:00:00 2001 From: Rambaud Pierrick <12rambau@users.noreply.github.com> Date: Sat, 23 Nov 2024 13:52:41 +0000 Subject: [PATCH] feat: create a featureCollection from a geointerface --- geetools/ee_feature_collection.py | 50 +++++++++++++++++++ tests/test_FeatureCollection.py | 30 +++++++++++ .../test_from_geo_interface.yml | 14 ++++++ .../test_from_geo_interface_from_dict.yml | 14 ++++++ 4 files changed, 108 insertions(+) create mode 100644 tests/test_FeatureCollection/test_from_geo_interface.yml create mode 100644 tests/test_FeatureCollection/test_from_geo_interface_from_dict.yml diff --git a/geetools/ee_feature_collection.py b/geetools/ee_feature_collection.py index 0a83b33e..d2fc4e34 100644 --- a/geetools/ee_feature_collection.py +++ b/geetools/ee_feature_collection.py @@ -1,6 +1,8 @@ """Toolbox for the `ee.FeatureCollection` class.""" from __future__ import annotations +from typing import Any + import ee import geopandas as gpd from matplotlib import pyplot as plt @@ -504,3 +506,51 @@ def plot( gdf.boundary.plot(ax=ax, color=color) else: gdf.plot(column=property, ax=ax, cmap=cmap) + + @classmethod + def fromGeoInterface(cls, data: Any) -> ee.FeatureCollection: + """Create a FeatureCollection from a geo interface. + + The ``geo_interface`` is a protocol representing a vector collection as a python GeoJSON-like dictionary structure. + More information is available at https://gist.github.com/sgillies/2217756. Note that the :py:class:`ee.FeatureCollection` + constructor is only supporting data represented in EPSG:4326. + + The user can either provide an object that implements the ``__geo_interface__`` method or a dictionary + that respects the protocol described in the link above. + + Parameters: + data: The geo_interface to create the FeatureCollection from. + crs: The CRS to use for the FeatureCollection. Default to "EPSG:4326". + + Returns: + The created FeatureCollection. + + Examples: + code-block:: python + + import geetools + + data = { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {"name": "Coors Field"}, + "geometry": { + "type": "Point", + "coordinates": [-104.99404, 39.75621] + } + } + ] + } + + fc = ee.FeatureCollection.geetools.fromGeoInterface(data, crs="EPSG:4326") + """ + # clean the data + if hasattr(data, "__geo_interface__"): + data = data.__geo_interface__ + elif not isinstance(data, dict): + raise ValueError("The data must be a geo_interface or a dictionary") + + # create the feature collection + return ee.FeatureCollection(data) diff --git a/tests/test_FeatureCollection.py b/tests/test_FeatureCollection.py index 19f7f9aa..3a89f3f9 100644 --- a/tests/test_FeatureCollection.py +++ b/tests/test_FeatureCollection.py @@ -292,3 +292,33 @@ def hydroshed(self): dataset = "WWF/HydroATLAS/v1/Basins/level04" region = ee.Geometry.BBox(-80, -60, -20, 20) return ee.FeatureCollection(dataset).filterBounds(region) + + +class TestFromGeoInterface: + """Test the ``fromGeoInterface`` method.""" + + def test_from_geo_interface(self, gdf, data_regression): + fc = ee.FeatureCollection.geetools.fromGeoInterface(gdf) + data_regression.check(fc.getInfo()) + + def test_from_geo_interface_from_dict(self, gdf, data_regression): + fc = ee.FeatureCollection.geetools.fromGeoInterface(gdf.__geo_interface__) + data_regression.check(fc.getInfo()) + + def test_error_from_geo_interface_(self): + with pytest.raises(ValueError): + ee.FeatureCollection.geetools.fromGeoInterface("toto") + + @pytest.fixture + def gdf(self): + data = { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {"name": "Coors Field"}, + "geometry": {"type": "Point", "coordinates": [-104.99404, 39.75621]}, + } + ], + } + return gpd.GeoDataFrame.from_features(data["features"]) diff --git a/tests/test_FeatureCollection/test_from_geo_interface.yml b/tests/test_FeatureCollection/test_from_geo_interface.yml new file mode 100644 index 00000000..a80109ad --- /dev/null +++ b/tests/test_FeatureCollection/test_from_geo_interface.yml @@ -0,0 +1,14 @@ +columns: + name: String + system:index: String +features: +- geometry: + coordinates: + - -104.99404 + - 39.75621 + type: Point + id: '0' + properties: + name: Coors Field + type: Feature +type: FeatureCollection diff --git a/tests/test_FeatureCollection/test_from_geo_interface_from_dict.yml b/tests/test_FeatureCollection/test_from_geo_interface_from_dict.yml new file mode 100644 index 00000000..a80109ad --- /dev/null +++ b/tests/test_FeatureCollection/test_from_geo_interface_from_dict.yml @@ -0,0 +1,14 @@ +columns: + name: String + system:index: String +features: +- geometry: + coordinates: + - -104.99404 + - 39.75621 + type: Point + id: '0' + properties: + name: Coors Field + type: Feature +type: FeatureCollection