Skip to content

Commit

Permalink
feat: create a featureCollection from a geointerface
Browse files Browse the repository at this point in the history
  • Loading branch information
12rambau authored Nov 23, 2024
1 parent da87ffa commit 3017268
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 0 deletions.
50 changes: 50 additions & 0 deletions geetools/ee_feature_collection.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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)
30 changes: 30 additions & 0 deletions tests/test_FeatureCollection.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"])
14 changes: 14 additions & 0 deletions tests/test_FeatureCollection/test_from_geo_interface.yml
Original file line number Diff line number Diff line change
@@ -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
14 changes: 14 additions & 0 deletions tests/test_FeatureCollection/test_from_geo_interface_from_dict.yml
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 3017268

Please sign in to comment.