diff --git a/geetools/ee_feature_collection.py b/geetools/ee_feature_collection.py index 8498833a..664ad3f1 100644 --- a/geetools/ee_feature_collection.py +++ b/geetools/ee_feature_collection.py @@ -5,6 +5,7 @@ import ee import geopandas as gpd +import shapely from matplotlib import pyplot as plt from matplotlib.axes import Axes @@ -711,7 +712,12 @@ def plot( gdf.plot(column=property, ax=ax, cmap=cmap) @classmethod - def fromGeoInterface(cls, data: dict | GeoInterface) -> ee.FeatureCollection: + def fromGeoInterface( + cls, + data: dict | GeoInterface, + drop_z: bool = False, + crs: str = "EPSG:4326", + ) -> ee.FeatureCollection: """Create a :py:class:`ee.FeatureCollection` from a geo interface. The ``geo_interface`` is a protocol representing a vector collection as a python GeoJSON-like dictionary structure. @@ -723,7 +729,8 @@ def fromGeoInterface(cls, data: dict | GeoInterface) -> ee.FeatureCollection: Parameters: data: The geo_interface to create the :py:class:`ee.FeatureCollection` from. - crs: The CRS to use for the FeatureCollection. Default to ``EPSG:4326``. + crs: The CRS of the input data. Defaults to "EPSG:4326". + drop_z: Whether to drop the Z dimension from the geometries. Defaults to False. Returns: The created :py:class:`ee.FeatureCollection` from the geo_interface. @@ -755,5 +762,10 @@ def fromGeoInterface(cls, data: dict | GeoInterface) -> ee.FeatureCollection: elif not isinstance(data, dict): raise ValueError("The data must be a geo_interface or a dictionary") + if drop_z: + gdf = gpd.GeoDataFrame.from_features(data["features"], crs=crs) + gdf.geometry = shapely.force_2d(gdf.geometry.values) + data = gdf.__geo_interface__ + # create the feature collection return ee.FeatureCollection(data) diff --git a/tests/test_FeatureCollection.py b/tests/test_FeatureCollection.py index 88414a52..a72f8a59 100644 --- a/tests/test_FeatureCollection.py +++ b/tests/test_FeatureCollection.py @@ -331,6 +331,12 @@ def test_error_from_geo_interface_(self): with pytest.raises(ValueError): ee.FeatureCollection.geetools.fromGeoInterface("toto") + def test_from_geo_interface_z(self, gdfZ, ee_feature_collection_regression): + with pytest.raises(ee.ee_exception.EEException): + ee.FeatureCollection.geetools.fromGeoInterface(gdfZ) + fc = ee.FeatureCollection.geetools.fromGeoInterface(gdfZ, drop_z=True) + ee_feature_collection_regression.check(fc, prescision=4) + @pytest.fixture def gdf(self): data = { @@ -344,3 +350,17 @@ def gdf(self): ], } return gpd.GeoDataFrame.from_features(data["features"]) + + @pytest.fixture + def gdfZ(self): + data = { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {"name": "Coors Field"}, + "geometry": {"type": "Point", "coordinates": [-104.99404, 39.75621, 1000]}, + } + ], + } + return gpd.GeoDataFrame.from_features(data["features"]) diff --git a/tests/test_FeatureCollection/serialized_test_from_geo_interface_z.yml b/tests/test_FeatureCollection/serialized_test_from_geo_interface_z.yml new file mode 100644 index 00000000..50b50f01 --- /dev/null +++ b/tests/test_FeatureCollection/serialized_test_from_geo_interface_z.yml @@ -0,0 +1,24 @@ +result: '0' +values: + '0': + functionInvocationValue: + arguments: + features: + arrayValue: + values: + - functionInvocationValue: + arguments: + geometry: + functionInvocationValue: + arguments: + coordinates: + constantValue: + - -104.99404 + - 39.75621 + functionName: GeometryConstructors.Point + metadata: + constantValue: + name: Coors Field + system:index: '0' + functionName: Feature + functionName: Collection diff --git a/tests/test_FeatureCollection/test_from_geo_interface_z.yml b/tests/test_FeatureCollection/test_from_geo_interface_z.yml new file mode 100644 index 00000000..19fb9377 --- /dev/null +++ b/tests/test_FeatureCollection/test_from_geo_interface_z.yml @@ -0,0 +1,11 @@ +features: +- geometry: + coordinates: + - -104.994 + - 39.7562 + type: Point + id: '0' + properties: + name: Coors Field + type: Feature +type: FeatureCollection