Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ee.Dictionary to ee.FeatureCollection #372

Merged
merged 10 commits into from
Jan 14, 2025
41 changes: 41 additions & 0 deletions geetools/ee_dictionary.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
"""Extra methods for the ``ee.Dictionary`` class."""
from __future__ import annotations

from typing import Any

import ee

from .accessors import register_class_accessor
Expand Down Expand Up @@ -80,3 +82,42 @@ def getMany(self, list: list | ee.List) -> ee.List:
d.geetools.getMany(["foo", "bar"]).getInfo()
"""
return ee.List(list).map(lambda key: self._obj.get(key))

def toTable(self, valueType: ee.List | ee.Dictionary | Any = Any) -> ee.FeatureCollection:
"""Convert a ee.Dictionary to a ee.FeatureCollection with no geometries (table).

The keys will always be stored in `system:index` column.

Parameters:
valueType: this will define how to process the values. In case of
ee.List the values will be stored in columns named `value_<position>`.
In case of a ee.Dictionary, column names will be created from the keys.
For any other type, it will return a table with one feature with
one column per key.

Returns:
a ee.FeatureCollection in which the keys of the ee.Dictionary are
in the `system:index` and the values are in new columns.
"""

def features_from_dict(key, value) -> ee.Feature:
key = ee.String(key)
feat = ee.Feature(None, {"system:index": key})
return feat.set(ee.Dictionary(value))

def features_from_list(key, value) -> ee.Feature:
key = ee.String(key)
feat = ee.Feature(None, {"system:index": key})
value = ee.List(value)
keys = ee.List.sequence(1, value.size())
keys = keys.map(lambda k: ee.String("value_").cat(ee.Number(k).toInt()))
properties = ee.Dictionary.fromLists(keys, value)
return feat.set(properties)

if valueType == ee.Dictionary:
features = self._obj.map(features_from_dict).values()
elif valueType == ee.List:
features = self._obj.map(features_from_list).values()
else:
return ee.FeatureCollection([ee.Feature(None, self._obj)])
return ee.FeatureCollection(features)
26 changes: 26 additions & 0 deletions tests/test_Dictionary.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
"""Test the Dictionary class methods."""
import ee

import geetools # noqa


class TestFromPairs:
"""Test the fromPairs method."""
Expand Down Expand Up @@ -28,3 +30,27 @@ class TestGetMany:
def test_getMany(self):
d = ee.Dictionary({"foo": 1, "bar": 2}).geetools.getMany(["foo"])
assert d.getInfo() == [1]


class TestToTable:
"""Test the `toTable` method."""

def test_to_table_any(self, data_regression):
ee_dict = ee.Dictionary({"ADM0_NAME": "Argentina", "ADM0_CODE": "12"})
res = ee_dict.geetools.toTable()
data_regression.check(res.getInfo())

def test_to_table_list(self, data_regression):
ee_dict = ee.Dictionary({"Argentina": [12, 278.289196625], "Armenia": [13, 3.13783139285]})
res = ee_dict.geetools.toTable(ee.List)
data_regression.check(res.getInfo())

def test_to_table_dict(self, data_regression):
ee_dict = ee.Dictionary(
{
"Argentina": {"ADM0_CODE": 12, "Shape_Area": 278.289196625},
"Armenia": {"ADM0_CODE": 13, "Shape_Area": 3.13783139285},
}
)
res = ee_dict.geetools.toTable(ee.Dictionary)
data_regression.check(res.getInfo())
12 changes: 12 additions & 0 deletions tests/test_Dictionary/test_to_table_any.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
columns:
ADM0_CODE: String
ADM0_NAME: String
system:index: String
features:
- geometry: null
id: '0'
properties:
ADM0_CODE: '12'
ADM0_NAME: Argentina
type: Feature
type: FeatureCollection
18 changes: 18 additions & 0 deletions tests/test_Dictionary/test_to_table_dict.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
columns:
ADM0_CODE: Integer
Shape_Area: Float
system:index: String
features:
- geometry: null
id: Argentina
properties:
ADM0_CODE: 12
Shape_Area: 278.289196625
type: Feature
- geometry: null
id: Armenia
properties:
ADM0_CODE: 13
Shape_Area: 3.13783139285
type: Feature
type: FeatureCollection
18 changes: 18 additions & 0 deletions tests/test_Dictionary/test_to_table_list.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
columns:
system:index: String
value_1: Integer
value_2: Float
features:
- geometry: null
id: Argentina
properties:
value_1: 12
value_2: 278.289196625
type: Feature
- geometry: null
id: Armenia
properties:
value_1: 13
value_2: 3.13783139285
type: Feature
type: FeatureCollection