From 47efecf574ef9a21bb59368ffba67b267f1d2750 Mon Sep 17 00:00:00 2001 From: Rambaud Pierrick <12rambau@users.noreply.github.com> Date: Tue, 6 Apr 2021 17:57:59 +0200 Subject: [PATCH 1/5] Update en.rst --- doc/en.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/en.rst b/doc/en.rst index 3d3d79a..f118237 100644 --- a/doc/en.rst +++ b/doc/en.rst @@ -1,5 +1,5 @@ -Clip time series -================ +Vector file manager +=================== .. warning:: @@ -7,4 +7,4 @@ Clip time series .. tip:: - Please open an issue on their repository : https://github.com/openforis/clip-time-series/issues/new + Please open an issue on their repository : https://github.com/openforis/import-to-ee/issues/new From 30d7201c9622b41fa02fb3bf33351ec2dac9f678 Mon Sep 17 00:00:00 2001 From: Rambaud Pierrick <12rambau@users.noreply.github.com> Date: Tue, 6 Apr 2021 17:58:47 +0200 Subject: [PATCH 2/5] typo --- doc/en.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/en.rst b/doc/en.rst index f118237..bb0b9c0 100644 --- a/doc/en.rst +++ b/doc/en.rst @@ -7,4 +7,4 @@ Vector file manager .. tip:: - Please open an issue on their repository : https://github.com/openforis/import-to-ee/issues/new + Please open an issue on their repository : https://github.com/openforis/import_to_gee/issues/new From 33c11aad0b79216957414ee57e20e600f9c561da Mon Sep 17 00:00:00 2001 From: Rambaud Pierrick <12rambau@users.noreply.github.com> Date: Tue, 6 Apr 2021 18:00:06 +0200 Subject: [PATCH 3/5] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 167c16d..22b5112 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# File transfer management +# Vector file manager ## About This module is a 2 step wrapper to upload AOI to Google Earth Engine From 2f707d60f5ef1b1139106a324b6c3889f2625c4f Mon Sep 17 00:00:00 2001 From: Pierrick Rambaud Date: Thu, 3 Jun 2021 12:29:39 +0000 Subject: [PATCH 4/5] adapt to sepal_ui v2 --- component/{io => model}/__init__.py | 0 component/scripts/tiling.py | 16 +-- component/scripts/utils.py | 21 +-- component/tile/download_tile.py | 40 +++--- component/tile/tile_tile.py | 58 ++++---- component/widget/link_dialog.py | 17 +-- download_ui.ipynb | 7 +- no_ui.ipynb | 205 +++------------------------- tiling_ui.ipynb | 59 ++++++-- ui.ipynb | 6 +- 10 files changed, 122 insertions(+), 307 deletions(-) rename component/{io => model}/__init__.py (100%) diff --git a/component/io/__init__.py b/component/model/__init__.py similarity index 100% rename from component/io/__init__.py rename to component/model/__init__.py diff --git a/component/scripts/tiling.py b/component/scripts/tiling.py index 88ad6b7..2965982 100644 --- a/component/scripts/tiling.py +++ b/component/scripts/tiling.py @@ -20,15 +20,10 @@ def set_grid(aoi, grid_batch, grid_name, output): """compute a grid around a given aoi (ee.FeatureCollection) that fits the Planet Lab requirements""" # get the shape of the aoi in EPSG:4326 proj - aoi_json = geemap.ee_to_geojson(aoi) - aoi_shp = unary_union([sg.shape(feat['geometry']) for feat in aoi_json['features']]) - aoi_gdf = gpd.GeoDataFrame({'geometry': [aoi_shp]}, crs="EPSG:4326").to_crs('EPSG:3857') + aoi_gdf = aoi.to_crs('EPSG:3857') output.add_live_msg(cm.digest_aoi) - # extract the aoi shape - aoi_shp_proj = aoi_gdf['geometry'][0] - # retreive the bounding box aoi_bb = sg.box(*aoi_gdf.total_bounds) aoi_bb.bounds @@ -88,7 +83,7 @@ def set_grid(aoi, grid_batch, grid_name, output): grid = gpd.GeoDataFrame({'batch': batch, 'x':x, 'y':y, 'names':names, 'geometry':squares}, crs='EPSG:3857') # cut the grid to the aoi extends - mask = grid.intersects(aoi_shp_proj) + mask = grid.intersects(aoi_gdf.dissolve()['geometry'][0]) grid = grid.loc[mask] # project back to 4326 @@ -100,7 +95,7 @@ def set_grid(aoi, grid_batch, grid_name, output): output.add_live_msg(cm.grid_complete, 'success') - return geemap.geojson_to_ee(json.loads(grid.to_json())) + return geemap.geojson_to_ee(grid.__geo_interface__) def preview_square(geometry, grid_size): @@ -114,10 +109,7 @@ def preview_square(geometry, grid_size): .envelope \ .to_crs('EPSG:4326') - # convert gpd to GeoJson - json_df = json.loads(square.to_json()) - - return geemap.geojson_to_ee(json_df) + return geemap.geojson_to_ee(square.__geo_interface__) diff --git a/component/scripts/utils.py b/component/scripts/utils.py index 07b35cb..9d28f2c 100644 --- a/component/scripts/utils.py +++ b/component/scripts/utils.py @@ -13,23 +13,4 @@ def display_asset(output, asset): output.add_msg(cm.asset_created.format(asset), 'success') - return asset - -def isAsset(asset_descripsion, folder): - """Check if the asset already exist in the user asset folder - - Args: - asset_descripsion (str) : the descripsion of the asset - folder (str): the folder of the glad assets - - Returns: - exist (bool): true if already in folder - """ - exist = False - liste = ee.data.listAssets({'parent': folder})['assets'] - for asset in liste: - if asset['name'] == os.path.join(folder,asset_descripsion): - exist = True - break - - return exist \ No newline at end of file + return asset \ No newline at end of file diff --git a/component/tile/download_tile.py b/component/tile/download_tile.py index f18061f..4eed3e4 100644 --- a/component/tile/download_tile.py +++ b/component/tile/download_tile.py @@ -21,10 +21,6 @@ class DownloadTile(sw.Tile): def __init__(self): - self.output = sw.Alert()#.add_msg('import your file') - - self.btn = sw.Btn(cm.download.import_btn, icon = 'mdi-check', class_='mt-4') - self.select_type = v.Select( label= cm.download.select_type, items= self.SELECT_TYPE, @@ -38,9 +34,9 @@ def __init__(self): super().__init__( 'aoi_widget', cm.download.title, - btn = self.btn, inputs = [self.select_type, self.input_file], - output = self.output + alert = sw.Alert(), + btn = sw.Btn(cm.download.import_btn, icon = 'mdi-check', class_='mt-4') ) self.select_type.observe(self.on_type_change, 'v_model') @@ -63,18 +59,16 @@ def on_type_change(self, change): return + @su.loading_button(debug=False) def load_file(self, widget, data, event): - # toggle the btn - widget.toggle_loading() - - self.output.add_msg(cm.download.start) + self.alert.add_msg(cm.download.start) # load the files myfiles = self.input_file.get_files() # test that the file is not empty - if not self.output.check_input(myfiles, cm.download.no_file): return widget.toggle_loading() + if not self.alert.check_input(myfiles, cm.download.no_file): return #################################### ## test the file sended ## @@ -84,27 +78,25 @@ def load_file(self, widget, data, event): if self.select_type.v_model == self.SELECT_TYPE[1]: if Path(myfiles[0]['name']).suffix != '.csv': - self.output.add_msg(cm.download.not_csv, 'error') - return widget.toggle_loading() + self.alert.add_msg(cm.download.not_csv, 'error') + return # shp type if self.select_type.v_model == self.SELECT_TYPE[0]: - - name = set([Path(f['name']).stem for f in myfiles]) if len(name) > 1: - self.output.add_msg(cm.download.naming_bug, 'error') - return widget.toggle_loading() + self.alert.add_msg(cm.download.naming_bug, 'error') + return suffixes = [Path(f['name']).suffix for f in myfiles] if not all(ext in suffixes for ext in self.SHP_SUFFIX[:3]): - self.output.add_msg(cm.download.missing_files.format(", ".join(self.SHP_SUFFIX[:3])), 'error') - return widget.toggle_loading() + self.alert.add_msg(cm.download.missing_files.format(", ".join(self.SHP_SUFFIX[:3])), 'error') + return if not all(ext in self.SHP_SUFFIX for ext in suffixes): - self.output.add_msg(cm.download.unknown_extention.format(", ".join(self.SHP_SUFFIX)), 'error') - return widget.toggle_loading() + self.alert.add_msg(cm.download.unknown_extention.format(", ".join(self.SHP_SUFFIX)), 'error') + return ###################################### ## download all the files ## @@ -116,7 +108,7 @@ def load_file(self, widget, data, event): path = cp.down_dir.joinpath(unidecode.unidecode(file['name'])) if path.is_file(): - self.output.add_msg(cm.download.already_exist.format(path), 'warning') + self.alert.add_msg(cm.download.already_exist.format(path), 'warning') break src = file['file_obj'] @@ -128,6 +120,6 @@ def load_file(self, widget, data, event): if self.select_type.v_model == self.SELECT_TYPE[0]: path = path.stem + '.shp' - self.output.add_msg(cm.download.complete.format(path), 'success') + self.alert.add_msg(cm.download.complete.format(path), 'success') - return widget.toggle_loading() \ No newline at end of file + return \ No newline at end of file diff --git a/component/tile/tile_tile.py b/component/tile/tile_tile.py index 05fcecc..fc29e16 100644 --- a/component/tile/tile_tile.py +++ b/component/tile/tile_tile.py @@ -4,7 +4,10 @@ import ipyvuetify as v from sepal_ui import sepalwidgets as sw from sepal_ui.scripts import gee +from sepal_ui.scripts import utils as su +from sepal_ui import color import ee +from traitlets import Int from component import scripts as cs from component.message import cm @@ -13,7 +16,9 @@ class TileTile(sw.Tile): - def __init__(self, m, aoi_io): + updated = Int(0).tag(sync=True) + + def __init__(self, m, aoi_model): # to store the final asset self.assetId = None @@ -21,8 +26,8 @@ def __init__(self, m, aoi_io): # the map to display the final tile self.m = m - #store the aoi_io - self.aoi_io = aoi_io + #store the aoi_model + self.aoi_model = aoi_model # inputs self.grid_name = v.TextField( @@ -37,53 +42,44 @@ def __init__(self, m, aoi_io): type = 'number' ) - self.btn = sw.Btn(cm.tile.btn, icon = 'mdi-check') - - self.output = sw.Alert() - # the aoi default btn is not set to btn anymore (to avoid conflict with the standard btn) # to mimic its behaviour in the dialog interface we wire 2 attribute btn and aoi_btn to the same Btn object - self.aoi_select_btn = self.btn - self.aoi_output = self.output - self.io = SimpleNamespace(assetId=None) + self.model = SimpleNamespace(asset_name=None) super().__init__( 'tile_widget', cm.tile.title, - btn = self.btn, inputs = [self.batch_size, self.grid_name], - output = self.output + alert = sw.Alert(), + btn = sw.Btn(cm.tile.btn, icon = 'mdi-check') ) # link the component together self.btn.on_event('click', self.create_grid) self.batch_size.observe(self.write_name, 'v_model') + @su.loading_button(debug=False) def create_grid(self, widget, data, event): - # toggle the btn - widget.toggle_loading() - # read the data - aoi = self.aoi_io + aoi = self.aoi_model grid_name = self.grid_name.v_model grid_batch = int(self.batch_size.v_model) #check the vars - if not self.output.check_input(aoi.get_aoi_name(), cm.no_aoi): return widget.toggle_loading() - if not self.output.check_input(grid_batch, cm.no_size): return widget.toggle_loading() - if not self.output.check_input(grid_name, cm.no_name): return widget.toggle_loading() - + if not self.alert.check_input(aoi.name, cm.no_aoi): return + if not self.alert.check_input(grid_batch, cm.no_size): return + if not self.alert.check_input(grid_name, cm.no_name): return - #try: - grid = cs.set_grid(aoi.get_aoi_ee(), grid_batch, grid_name, self.output) + grid = cs.set_grid(aoi.gdf, grid_batch, grid_name, self.alert) # get exportation parameters folder = ee.data.getAssetRoots()[0]['id'] asset = os.path.join(folder, grid_name) # export - if not cs.isAsset(grid_name, folder): + if not gee.is_asset(grid_name, folder): + task_config = { 'collection': grid, 'description':grid_name, @@ -92,7 +88,7 @@ def create_grid(self, widget, data, event): task = ee.batch.Export.table.toAsset(**task_config) task.start() - gee.wait_for_completion(grid_name, self.output) + gee.wait_for_completion(grid_name, self.alert) self.assetId = asset @@ -104,24 +100,20 @@ def create_grid(self, widget, data, event): # display the asset on the map self.m.addLayer( ee.FeatureCollection(asset), - {'color': v.theme.themes.dark.accent}, + {'color': color.accent}, cm.tile.grid_layer ) - self.io.assetId = cs.display_asset(self.output, asset) - - #except Exception as e: - # self.output.add_live_msg(str(e), 'error') - - # toggle the loading - widget.toggle_loading() + self.model.asset_name = cs.display_asset(self.alert, asset) + + self.updated += 1 return def write_name(self, change): # read the inputs - aoi_name = self.aoi_io.get_aoi_name() + aoi_name = self.aoi_model.name grid_batch = int(self.batch_size.v_model) if self.batch_size.v_model else 0 name = f'{aoi_name}_Grid_{grid_batch}' if aoi_name else None diff --git a/component/widget/link_dialog.py b/component/widget/link_dialog.py index bbf6680..9f9d2cf 100644 --- a/component/widget/link_dialog.py +++ b/component/widget/link_dialog.py @@ -37,25 +37,14 @@ def __init__(self, tile): children = [self.card] ) - # self.link.on_event('click', self.select_all) - self.tile.aoi_select_btn.observe(self.fire_dialog, 'loading') - - # the pyperclip method does not work with SEPAL - #def select_all(self, widget, data, event): - # - # # copy the data to clipboard - # pyperclip.copy(self.link) - # - # # select all the link to prevent pyperclip failures - # - # return + self.tile.observe(self.fire_dialog, 'updated') def fire_dialog(self, link): # the toggle btn has changed let's see if it's for a good reason - if self.tile.aoi_output.type == 'success': + if self.tile.alert.type == 'success': self.value = True - self.link.v_model = self.tile.io.assetId.replace('projects/earthengine-legacy/assets/', '') + self.link.v_model = self.tile.model.asset_name.replace('projects/earthengine-legacy/assets/', '') return \ No newline at end of file diff --git a/download_ui.ipynb b/download_ui.ipynb index 0ef9969..3f6ee27 100644 --- a/download_ui.ipynb +++ b/download_ui.ipynb @@ -29,11 +29,8 @@ "metadata": {}, "outputs": [], "source": [ - "#create the asset variables object \n", - "ig_export_io = aoi.Aoi_io()\n", - "\n", "#create the tile \n", - "ig_export = aoi.TileAoi(ig_export_io, methods = ['Draw a shape', 'Upload file', 'Use points file'])\n", + "ig_export = aoi.AoiTile(methods = ['DRAW', 'SHAPE', 'POINTS'])\n", "ig_export.set_title(cm.to_gee.title)\n", "\n", "#this tile will only be displayed if voila is launch from this notebook \n", @@ -46,7 +43,7 @@ "metadata": {}, "outputs": [], "source": [ - "ig_dialog = widget.LinkDialog(ig_export)\n", + "ig_dialog = widget.LinkDialog(ig_export.view)\n", "ig_dialog" ] } diff --git a/no_ui.ipynb b/no_ui.ipynb index 19048f5..ef18812 100644 --- a/no_ui.ipynb +++ b/no_ui.ipynb @@ -2,38 +2,9 @@ "cells": [ { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "22108dea7f3246e092181423fd9a80aa", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "HTML(value='\\n