diff --git a/sepal_ui/aoi/aoi_model.py b/sepal_ui/aoi/aoi_model.py index aa1921f0..60e12503 100644 --- a/sepal_ui/aoi/aoi_model.py +++ b/sepal_ui/aoi/aoi_model.py @@ -249,10 +249,6 @@ def _from_asset(self, asset_json: dict) -> Self: # set the feature collection self.feature_collection = ee_col - # create a gdf form the feature_collection - features = self.feature_collection.getInfo()["features"] - self.gdf = gpd.GeoDataFrame.from_features(features).set_crs(epsg=4326) - return self def _from_points(self, point_json: dict) -> Self: @@ -377,20 +373,30 @@ def _from_admin(self, admin: str) -> Self: # pygaul needs extra work as ISO codes are not included in the GEE dataset if self.gee: self.feature_collection = pygaul.AdmItems(admin=admin) - features = self.feature_collection.getInfo()["features"] - self.gdf = gpd.GeoDataFrame.from_features(features).set_crs(epsg=4326) - gaul_country = str(self.gdf.ADM0_CODE.unique()[0]) - iso = json.loads(self.MAPPING.read_text())[gaul_country] - self.gdf["ISO"] = iso + + # get the ADM0_CODE to get the ISO code + feature = self.feature_collection.first() + iso = json.loads(self.MAPPING.read_text())[str(feature.get("ADM0_CODE").getInfo())] + + names = ( + (feature.propertyNames().filter(ee.Filter.stringContains("item", "NAME"))) + .map(lambda col_name: feature.get(col_name)) + .getInfo() + ) + + # generate the name from the columns + names = [su.normalize_str(name) for name in names] + names[0] = iso + self.name = "_".join(names) else: self.gdf = pygadm.AdmItems(admin=admin) - # generate the name from the columns - r = self.gdf.iloc[0] - names = [su.normalize_str(r[c]) for c in self.gdf.columns if "NAME" in c] - names[0] = r.ISO if self.gee else r.GID_0[:3] - self.name = "_".join(names) + # generate the name from the columns + r = self.gdf.iloc[0] + names = [su.normalize_str(r[c]) for c in self.gdf.columns if "NAME" in c] + names[0] = r.GID_0[:3] + self.name = "_".join(names) return self @@ -433,7 +439,7 @@ def get_columns(self) -> List[str]: Returns: sorted list of column names """ - if self.gdf is None: + if self.gdf is None and not self.feature_collection: raise Exception(ms.aoi_sel.exception.no_gdf) if self.gee: @@ -455,7 +461,7 @@ def get_fields(self, column: str) -> List[str]: sorted list of fields value """ - if self.gdf is None: + if self.gdf is None and not self.feature_collection: raise Exception(ms.aoi_sel.exception.no_gdf) if self.gee: @@ -476,7 +482,7 @@ def get_selected(self, column: str, field: str) -> Union[ee.Feature, gpd.GeoData Returns: The Feature associated with the query """ - if self.gdf is None: + if self.gdf is None and not self.feature_collection: raise Exception(ms.aoi_sel.exception.no_gdf) if self.gee: @@ -492,9 +498,13 @@ def total_bounds(self) -> Tuple[float, float, float, float]: Returns: minxx, miny, maxx, maxy """ - if self.gdf is None: + if self.gdf is None and not self.feature_collection: raise ValueError(ms.aoi_sel.exception.no_gdf) + if self.gee: + coords = self.feature_collection.geometry().bounds().coordinates().get(0).getInfo() + return [coords[0][0], coords[0][1], coords[3][0], coords[3][1]] + return self.gdf.total_bounds.tolist() def export_to_asset(self) -> Self: @@ -553,3 +563,30 @@ def get_ipygeojson(self, style: Optional[dict] = None) -> GeoJSON: self.ipygeojson = GeoJSON(data=data, style=style, name="aoi") return self.ipygeojson + + @property + def gdf(self): + """Get the geodataframe associated with the AOI.""" + if self.gee: + if not self.feature_collection: + return None + + self._load_gdf() + + return self._gdf + + @gdf.setter + def gdf(self, value): + """Set the gdf value. Used mainly to reset the gdf value.""" + self._gdf = value + + def _load_gdf(self): + """Return a geodataframe from a feature collection.""" + features = self.feature_collection.getInfo()["features"] + self._gdf = gpd.GeoDataFrame.from_features(features).set_crs(epsg=4326) + + if self.method in ["ADMIN0", "ADMIN1", "ADMIN2"]: + + gaul_country = str(self._gdf.ADM0_CODE.unique()[0]) + iso = json.loads(self.MAPPING.read_text())[gaul_country] + self._gdf["ISO"] = iso diff --git a/sepal_ui/aoi/aoi_view.py b/sepal_ui/aoi/aoi_view.py index 601411a3..41bb7483 100644 --- a/sepal_ui/aoi/aoi_view.py +++ b/sepal_ui/aoi/aoi_view.py @@ -349,7 +349,11 @@ def _update_aoi(self, *args) -> Self: if self.map_: self.map_.remove_layer("aoi", none_ok=True) self.map_.zoom_bounds(self.model.total_bounds()) - self.map_.add_layer(self.model.get_ipygeojson(self.map_style)) + + if self.gee: + self.map_.add_ee_layer(self.model.feature_collection, {}, "aoi") + else: + self.map_.add_layer(self.model.get_ipygeojson(self.map_style), "aoi") self.aoi_dc.hide() diff --git a/sepal_ui/message/en/locale.json b/sepal_ui/message/en/locale.json index f03349a2..71e0d4c9 100644 --- a/sepal_ui/message/en/locale.json +++ b/sepal_ui/message/en/locale.json @@ -80,7 +80,8 @@ "no_draw": "Please draw a shape in the map", "no_admlyr": "Select an administrative layer", "invalid_code": "The code is not in the database", - "no_gdf": "You must set the gdf before interacting with it" + "no_gdf": "You must set the gdf before interacting with it", + "no_fc": "You have to select a feature collection first" } }, "mapping": {