Skip to content

Commit

Permalink
Add widget template (opengeos#557)
Browse files Browse the repository at this point in the history
  • Loading branch information
giswqs committed Sep 17, 2023
1 parent c0a8cab commit 42578da
Show file tree
Hide file tree
Showing 2 changed files with 166 additions and 12 deletions.
117 changes: 116 additions & 1 deletion leafmap/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -10705,7 +10705,9 @@ def download_google_buildings(
print(f"No buildings found for {location}.")


def google_buildings_csv_to_vector(filename: str, output: Optional[str] = None, **kwargs) -> None:
def google_buildings_csv_to_vector(
filename: str, output: Optional[str] = None, **kwargs
) -> None:
"""
Convert a CSV file containing Google Buildings data to a GeoJSON vector file.
Expand Down Expand Up @@ -10735,3 +10737,116 @@ def google_buildings_csv_to_vector(filename: str, output: Optional[str] = None,
output = os.path.splitext(filename)[0] + ".geojson"

gdf.to_file(output, **kwargs)


def widget_template(
widget=None,
opened=True,
show_close_button=True,
widget_icon="gear",
close_button_icon="times",
widget_args={},
close_button_args={},
display_widget=None,
m=None,
position="topright",
):
"""Create a widget template.
Args:
widget (ipywidgets.Widget, optional): The widget to be displayed. Defaults to None.
opened (bool, optional): Whether to open the toolbar. Defaults to True.
show_close_button (bool, optional): Whether to show the close button. Defaults to True.
widget_icon (str, optional): The icon name for the toolbar button. Defaults to 'gear'.
close_button_icon (str, optional): The icon name for the close button. Defaults to "times".
widget_args (dict, optional): Additional arguments to pass to the toolbar button. Defaults to {}.
close_button_args (dict, optional): Additional arguments to pass to the close button. Defaults to {}.
display_widget (ipywidgets.Widget, optional): The widget to be displayed when the toolbar is clicked.
m (geemap.Map, optional): The geemap.Map instance. Defaults to None.
position (str, optional): The position of the toolbar. Defaults to "topright".
"""

name = "_" + random_string() # a random attribute name

if "value" not in widget_args:
widget_args["value"] = False
if "tooltip" not in widget_args:
widget_args["tooltip"] = "Toolbar"
if "layout" not in widget_args:
widget_args["layout"] = widgets.Layout(
width="28px", height="28px", padding="0px 0px 0px 4px"
)
widget_args["icon"] = widget_icon

if "value" not in close_button_args:
close_button_args["value"] = False
if "tooltip" not in close_button_args:
close_button_args["tooltip"] = "Close the tool"
if "button_style" not in close_button_args:
close_button_args["button_style"] = "primary"
if "layout" not in close_button_args:
close_button_args["layout"] = widgets.Layout(
height="28px", width="28px", padding="0px 0px 0px 4px"
)
close_button_args["icon"] = close_button_icon

toolbar_button = widgets.ToggleButton(**widget_args)

close_button = widgets.ToggleButton(**close_button_args)

toolbar_widget = widgets.VBox()
toolbar_widget.children = [toolbar_button]
toolbar_header = widgets.HBox()
if show_close_button:
toolbar_header.children = [close_button, toolbar_button]
else:
toolbar_header.children = [toolbar_button]
toolbar_footer = widgets.VBox()

if widget is not None:
toolbar_footer.children = [
widget,
]
else:
toolbar_footer.children = []

def toolbar_btn_click(change):
if change["new"]:
close_button.value = False
toolbar_widget.children = [toolbar_header, toolbar_footer]
if display_widget is not None:
widget.outputs = ()
with widget:
display(display_widget)
else:
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:
control = getattr(m, name)
if control is not None and control in m.controls:
m.remove_control(control)
delattr(m, name)
toolbar_widget.close()

close_button.observe(close_btn_click, "value")

toolbar_button.value = opened
if m is not None:
import ipyleaflet

toolbar_control = ipyleaflet.WidgetControl(
widget=toolbar_widget, position=position
)

if toolbar_control not in m.controls:
m.add_control(toolbar_control)

setattr(m, name, toolbar_control)

else:
return toolbar_widget
61 changes: 50 additions & 11 deletions leafmap/leafmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,7 @@ def add_ee_layer(
**kwargs,
) -> None:
"""
Adds a Google Earth Engine tile layer to the map based on the tile layer URL from
Adds a Google Earth Engine tile layer to the map based on the tile layer URL from
https://github.com/opengeos/ee-tile-layers/blob/main/datasets.tsv.
Args:
Expand Down Expand Up @@ -3845,13 +3845,34 @@ def user_roi_bounds(self, decimals=4):
else:
return None

def add_widget(self, content, position="bottomright", **kwargs):
def add_widget(
self,
content,
position="bottomright",
add_header=False,
opened=True,
show_close_button=True,
widget_icon="gear",
close_button_icon="times",
widget_args={},
close_button_args={},
display_widget=None,
**kwargs,
):
"""Add a widget (e.g., text, HTML, figure) to the map.
Args:
content (str | ipywidgets.Widget | object): The widget to add.
position (str, optional): The position of the widget. Defaults to "bottomright".
**kwargs: Other keyword arguments for ipywidgets.HTML().
add_header (bool, optional): Whether to add a header with close buttons to the widget. Defaults to False.
opened (bool, optional): Whether to open the toolbar. Defaults to True.
show_close_button (bool, optional): Whether to show the close button. Defaults to True.
widget_icon (str, optional): The icon name for the toolbar button. Defaults to 'gear'.
close_button_icon (str, optional): The icon name for the close button. Defaults to "times".
widget_args (dict, optional): Additional arguments to pass to the toolbar button. Defaults to {}.
close_button_args (dict, optional): Additional arguments to pass to the close button. Defaults to {}.
display_widget (ipywidgets.Widget, optional): The widget to be displayed when the toolbar is clicked.
**kwargs: Additional arguments to pass to the HTML or Output widgets
"""

allowed_positions = ["topleft", "topright", "bottomleft", "bottomright"]
Expand All @@ -3862,15 +3883,33 @@ def add_widget(self, content, position="bottomright", **kwargs):
if "layout" not in kwargs:
kwargs["layout"] = widgets.Layout(padding="0px 4px 0px 4px")
try:
if isinstance(content, str):
widget = widgets.HTML(value=content, **kwargs)
control = ipyleaflet.WidgetControl(widget=widget, position=position)
if add_header:
if isinstance(content, str):
widget = widgets.HTML(value=content, **kwargs)
else:
widget = content

widget_template(
widget,
opened,
show_close_button,
widget_icon,
close_button_icon,
widget_args,
close_button_args,
display_widget,
self,
position,
)
else:
output = widgets.Output(**kwargs)
with output:
display(content)
control = ipyleaflet.WidgetControl(widget=output, position=position)
self.add(control)
if isinstance(content, str):
widget = widgets.HTML(value=content, **kwargs)
else:
widget = widgets.Output(**kwargs)
with widget:
display(content)
control = ipyleaflet.WidgetControl(widget=widget, position=position)
self.add(control)

except Exception as e:
raise Exception(f"Error adding widget: {e}")
Expand Down

0 comments on commit 42578da

Please sign in to comment.