import ee import geemap import ipyleaflet import solara import ipywidgets as widgets from IPython.display import display zoom = solara.reactive(3) center = solara.reactive([20, 0]) def zonal_stats_chart(image, vector, **kwargs): if isinstance(vector, ee.Geometry): fc = ee.FeatureCollection(vector) elif isinstance(vector, ee.FeatureCollection): fc = vector else: raise ValueError( "The vector argument must be an ee.Geometry or ee.FeatureCollection." ) result = geemap.zonal_stats( image, fc, statistics_type="SUM", return_fc=True, verbose=False, **kwargs ) df = geemap.ee_to_df(result).T df.reset_index(inplace=True) df.columns = ["Type", "Area"] chart = geemap.bar_chart(df, "Type", "Area", x_label='', y_label="Area (m2)") chart.update_layout( margin=dict(l=0, r=0, t=10, b=0), height=280, ) return chart def add_analysis_gui(m=None, position='topright', opened=True): """Create a toolbar widget. Args: m (geemap.Map, optional): The geemap.Map instance. Defaults to None. opened (bool, optional): Whether to open the toolbar. Defaults to True. """ fc = ee.FeatureCollection('users/giswqs/public/countries') countries = fc.aggregate_array('NAME').getInfo() countries.sort() gswe = ee.ImageCollection("users/h2i_lab/gswe/gswe_datasets") image = gswe.mosaic() # esa = gswe.select("esa").mosaic() # esri = gswe.select("esri").mosaic() # jrc = gswe.select("jrc").mosaic() # osm = gswe.select("osm").mosaic() # hydrolakes = gswe.select("hydrolakes").mosaic() widget_width = "270px" padding = "0px 0px 0px 5px" # upper, right, bottom, left toolbar_button = widgets.ToggleButton( value=False, tooltip="Toolbar", icon="bar-chart", layout=widgets.Layout(width="28px", height="28px", padding="0px 0px 0px 4px"), ) close_button = widgets.ToggleButton( value=False, tooltip="Close the tool", icon="times", button_style="primary", layout=widgets.Layout(height="28px", width="28px", padding="0px 0px 0px 4px"), ) options = ["Draw an area", "Select a country"] radio = widgets.RadioButtons( options=options, layout=widgets.Layout(width=widget_width, padding=padding), style={"description_width": "initial"}, ) country = widgets.Dropdown( options=countries, value=None, layout=widgets.Layout(width=widget_width, padding=padding), ) buttons = widgets.ToggleButtons( value=None, options=["Apply", "Reset", "Close"], tooltips=["Apply", "Reset", "Close"], button_style="primary", layout=widgets.Layout(padding="0px 2px 4px 2px"), ) buttons.style.button_width = "88px" label = widgets.Label("Draw an area on the map first.") toolbar_widget = widgets.VBox() toolbar_widget.children = [toolbar_button] toolbar_header = widgets.HBox() toolbar_header.children = [close_button, toolbar_button] toolbar_footer = widgets.VBox() toolbar_footer.children = [ radio, buttons, ] def change_radio(change): if change["new"] == "Select a country": toolbar_footer.children = [radio, country, buttons] else: toolbar_footer.children = [radio, buttons] radio.observe(change_radio, "value") m.selected_country = None def change_country(change): if change["new"]: country_name = country.value country_fc = fc.filter(ee.Filter.eq('NAME', country_name)) vec_style = {'color': '000000ff', 'width': 3, 'fillColor': '00000000'} m.addLayer(country_fc.style(**vec_style), {}, 'Selected Country') m.centerObject(country_fc) m.selected_country = country_fc toolbar_footer.children = [radio, country, buttons] country.observe(change_country, "value") def toolbar_btn_click(change): if change["new"]: close_button.value = False toolbar_widget.children = [toolbar_header, toolbar_footer] else: if not close_button.value: toolbar_widget.children = [toolbar_button] toolbar_button.observe(toolbar_btn_click, "value") def close_btn_click(change): if change["new"]: toolbar_button.value = False if m is not None: if m.tool_control is not None and m.tool_control in m.controls: m.remove_control(m.tool_control) m.tool_control = None toolbar_widget.close() close_button.observe(close_btn_click, "value") def button_clicked(change): if change["new"] == "Apply": output = widgets.Output( layout=widgets.Layout(width=widget_width, padding=padding) ) if radio.value == "Select a country": toolbar_footer.children = [radio, country, buttons, output] else: toolbar_footer.children = [radio, buttons, output] with output: output.clear_output() buttons.value = None if radio.value == "Draw an area": if m.user_roi is None: display(label) buttons.value = None else: chart = zonal_stats_chart(image, m.user_roi, scale=100) display(chart) elif radio.value == "Select a country": if m.selected_country is not None: chart = zonal_stats_chart( image, m.selected_country.geometry(), scale=100 ) display(chart) elif change["new"] == "Reset": country.value = None radio.value = "Draw an area" toolbar_footer.children = [radio, buttons] elif change["new"] == "Close": if m is not None: if m.tool_control is not None and m.tool_control in m.controls: m.remove_control(m.tool_control) m.tool_control = None toolbar_widget.close() buttons.value = None buttons.observe(button_clicked, "value") toolbar_button.value = opened if m is not None: toolbar_control = ipyleaflet.WidgetControl( widget=toolbar_widget, position=position ) if toolbar_control not in m.controls: m.add_control(toolbar_control) m.tool_control = toolbar_control else: return toolbar_widget class Map(geemap.Map): def __init__(self, **kwargs): super().__init__(**kwargs) self.add_basemap('SATELLITE', show=False) self.add_ee_data() self.add_layer_manager() add_analysis_gui(self) # self.add_inspector() def add_ee_data(self): gswe = ee.ImageCollection("users/h2i_lab/gswe/gswe_datasets") self.addLayer(gswe.select("esa"), {'palette': ['red']}, "ESA") self.addLayer(gswe.select("esri"), {'palette': ['yellow']}, "ESRI") self.addLayer(gswe.select("jrc"), {'palette': ['blue']}, "JRC") self.addLayer(gswe.select("osm"), {'palette': ['green']}, "OSM") self.addLayer(gswe.select("hydrolakes"), {'palette': ['purple']}, "Hydrolakes") legend_dict = { 'ESA': 'ff0000', 'ESRI': 'ffff00', 'JRC': '0000ff', 'OSM': '00ff00', 'Hydrolakes': '800080', } self.add_legend(legend_dict=legend_dict, position='bottomleft') fc = ee.FeatureCollection('users/giswqs/public/countries') style = {'color': '000000ff', 'width': 1, 'fillColor': '00000000'} self.addLayer(fc.style(**style), {}, 'Countries', False) @solara.component def Page(): with solara.Column(style={"min-width": "500px"}): 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="800px", data_ctrl=False, )