Can't upload shape files to Solara-geospatial
kirimaru-jp opened this issue · 2 comments
As mentioned in this issue, I would like to develop a GEE web app allowing shape file upload (similar to this), hence I am trying to combine geemap and Solara. Your tutorial above worked flawlessly.
I am trying to adapt it to Solara, locally on my computer first:
import os
import ee
import geemap
import ipywidgets as widgets
from ipyleaflet import WidgetControl
import solara
zoom = solara.reactive(4)
center = solara.reactive([40, -100])
def get_vector(upload_widget, out_dir=None):
import zipfile
import glob
if out_dir is None:
out_dir = os.path.join(os.path.expanduser('~'), 'Downloads')
if not os.path.exists(out_dir):
os.makedirs(out_dir)
vector = None
try:
[uploaded_file] = upload_widget.value
file = upload_widget.value[0]
name = file['name']
content = file['content']
out_file = os.path.join(out_dir, name)
with open(out_file, "wb") as fp:
fp.write(content)
if name.endswith('.zip'):
with zipfile.ZipFile(out_file, "r") as zip_ref:
extract_dir = os.path.join(
out_dir, name[:-4] + "_" + geemap.random_string(3)
)
zip_ref.extractall(extract_dir)
files = glob.glob(extract_dir + '/*.shp')
if len(files) > 0:
shp = files[0]
vector = geemap.shp_to_ee(shp)
else:
files = glob.glob(extract_dir + '/*.geojson')
if len(files) > 0:
geojson = files[0]
vector = geemap.geojson_to_ee(geojson)
else:
vector = geemap.geojson_to_ee(out_file)
except Exception as e:
print(e)
return vector
class Map(geemap.Map):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.upload_local_data()
self.add_layer_manager()
self.add_inspector()
def upload_local_data(self):
# Add Earth Engine dataset
dem = ee.Image('USGS/SRTMGL1_003')
# Set visualization parameters.
vis_params = {
'min': 0,
'max': 4000,
'palette': ['006633', 'E5FFCC', '662A00', 'D8D8D8', 'F5F5F5'],
}
# Add Earth Engine layers to Map
self.addLayer(dem, vis_params, 'SRTM DEM', True, 0.7)
output_widget = widgets.Output(layout={'border': '1px solid black'})
output_control = WidgetControl(widget=output_widget, position='bottomright')
self.add_control(output_control)
style = {'description_width': 'initial'}
uploader = widgets.FileUpload(
description='Upload data',
accept='.zip, .json, .geojson',
multiple=False,
button_style='primary',
style=style,
)
submit = widgets.Button(
description='Display data', button_style='success', tooltip='Click me', style=style
)
reset = widgets.Button(
description='Reset', button_style='warning', tooltip='Click me', style=style
)
with output_widget:
print('Upload shapefile or \ngeojson as a zip file')
display(uploader)
display(submit)
display(reset)
def submit_clicked(b):
if len(uploader.value) > 0:
Map.default_style = {'cursor': 'wait'}
try:
fc = get_vector(uploader)
layer_name = 'Layer ' + geemap.random_string(3)
Map.addLayer(fc, {}, layer_name)
Map.centerObject(fc)
uploader.value = ()
except Exception as e:
print(e)
Map.default_style = {'cursor': 'pointer'}
submit.on_click(submit_clicked)
def reset_clicked(b):
Map.layers = Map.layers[:3]
output_widget.clear_output()
with output_widget:
print('Upload shapefile or \ngeojson as a zip file')
display(uploader)
display(submit)
display(reset)
uploader.value = ()
reset.on_click(reset_clicked)
@solara.component
def Page():
with solara.Column(style={"min-width": "500px"}):
# solara components support reactive variables
# solara.SliderInt(label="Zoom level", value=zoom, min=1, max=20)
# using 3rd party widget library require wiring up the events manually
# using zoom.value and zoom.set
Map.element( # type: ignore
zoom=zoom.value,
on_zoom=zoom.set,
center=center.value,
on_center=center.set,
scroll_wheel_zoom=True,
add_google_map=True,
height="700px",
)
solara.Text(f"Zoom: {zoom.value}")
solara.Text(f"Center: {center.value}")
When I run the command solara run .\geemap_upload.py
, I saw this error in the Terminal but the map was still displayed
ERROR: nbextension repr_style/main not found
Then I clicked the "Upload data" button, select the file us_states.zip
, then clicked the "Display data". Nothing showed up, and this error appeared in the Terminal
'FeatureCollection' object has no attribute 'layers'
If I click the "Reset" button, this error appeares
ERROR: Uncaught exception: Traceback (most recent call last):
File "D:\ProgramData\miniconda3\envs\geemap\lib\site-packages\ipywidgets\widgets\widget.py", line 189, in __call__
local_value = callback(*args, **kwargs)
File "~\geemap_upload.py", line 147, in reset_clicked
Map.layers = Map.layers[:3]
TypeError: 'Tuple' object is not subscriptable
Could you please suggest any solution/workaround? Many thanks!
I thought that I found my mistakes, I should replace Map.
by self.
in the class Map, like the following code
class Map(geemap.Map):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.upload_local_data()
self.add_layer_manager()
self.add_inspector()
def upload_local_data(self):
# Add Earth Engine dataset
dem = ee.Image('USGS/SRTMGL1_003')
# Set visualization parameters.
vis_params = {
'min': 0,
'max': 4000,
'palette': ['006633', 'E5FFCC', '662A00', 'D8D8D8', 'F5F5F5'],
}
# Add Earth Engine layers to Map
self.addLayer(dem, vis_params, 'SRTM DEM', True, 0.7)
output_widget = widgets.Output(layout={'border': '1px solid black'})
output_control = WidgetControl(widget=output_widget, position='bottomright')
self.add_control(output_control)
style = {'description_width': 'initial'}
uploader = widgets.FileUpload(
description='Upload data',
accept='.zip, .json, .geojson',
multiple=False,
button_style='primary',
style=style,
)
submit = widgets.Button(
description='Display data', button_style='success', tooltip='Click me', style=style
)
reset = widgets.Button(
description='Reset', button_style='warning', tooltip='Click me', style=style
)
with output_widget:
print('Upload shapefile or \ngeojson as a zip file')
display(uploader)
display(submit)
display(reset)
def submit_clicked(b):
if len(uploader.value) > 0:
self.default_style = {'cursor': 'wait'}
try:
fc = get_vector(uploader)
layer_name = 'Layer ' + geemap.random_string(3)
self.addLayer(fc, {}, layer_name)
self.centerObject(fc)
uploader.value = ()
except Exception as e:
print(e)
self.default_style = {'cursor': 'pointer'}
submit.on_click(submit_clicked)
def reset_clicked(b):
self.layers = self.layers[:3]
output_widget.clear_output()
with output_widget:
print('Upload shapefile or \ngeojson as a zip file')
display(uploader)
display(submit)
display(reset)
uploader.value = ()
reset.on_click(reset_clicked)
However, when I clicked the "Reset" button continuously, this appears
Ok, so I see that the following commands
display(uploader)
display(submit)
display(reset)
are not necessary for the function reset_clicked
and they caused the issue above.
Remove them and the problem was solved!