Skip to content

gui module

This module contains the user interface for the prismatools package.

spectralWidget (HBox)

A widget for spectral data visualization on a map.

Attributes:

Name Type Description
_host_map Map

The map to host the widget.

on_close function

Function to be called when the widget is closed.

_output_widget widgets.Output

The output widget to display results.

_output_control ipyleaflet.WidgetControl

The control for the output widget.

_on_map_interaction function

Function to handle map interactions.

_spectral_widget SpectralWidget

The spectral widget itself.

_spectral_control ipyleaflet.WidgetControl

The control for the spectral widget.

Source code in prismatools/gui.py
class spectralWidget(widgets.HBox):
    """
    A widget for spectral data visualization on a map.

    Attributes:
        _host_map (Map): The map to host the widget.
        on_close (function): Function to be called when the widget is closed.
        _output_widget (widgets.Output): The output widget to display results.
        _output_control (ipyleaflet.WidgetControl): The control for the output widget.
        _on_map_interaction (function): Function to handle map interactions.
        _spectral_widget (SpectralWidget): The spectral widget itself.
        _spectral_control (ipyleaflet.WidgetControl): The control for the spectral widget.
    """

    def __init__(
        self, host_map, stack=True, position="topright", xlim=None, ylim=None, **kwargs
    ):
        """
        Initializes a new instance of the SpectralWidget class.

        Args:
            host_map (Map): The map to host the widget.
            stack (bool, optional): Whether to stack the plots. Defaults to True.
            position (str, optional): The position of the widget on the map. Defaults to "topright".
            xlim (tuple, optional): The x-axis limits. Defaults to None.
            ylim (tuple, optional): The y-axis limits. Defaults to None.
        """
        self._host_map = host_map
        self.on_close = None
        self._stack = stack
        self._show_plot = False

        fig_margin = {"top": 20, "bottom": 35, "left": 50, "right": 20}
        fig = plt.figure(
            # title=None,
            fig_margin=fig_margin,
            layout={"width": "500px", "height": "300px"},
        )

        self._fig = fig
        self._host_map._fig = fig

        layer_names = list(host_map.cog_layer_dict.keys())
        layers_widget = widgets.Dropdown(options=layer_names)
        layers_widget.layout.width = "18ex"

        close_btn = widgets.Button(
            icon="times",
            tooltip="Close the widget",
            button_style="primary",
            layout=widgets.Layout(width="32px"),
        )

        reset_btn = widgets.Button(
            icon="trash",
            tooltip="Remove all markers",
            button_style="primary",
            layout=widgets.Layout(width="32px"),
        )

        stack_btn = widgets.ToggleButton(
            value=stack,
            icon="area-chart",
            tooltip="Stack spectral signatures",
            button_style="primary",
            layout=widgets.Layout(width="32px"),
        )

        def reset_btn_click(_):
            if hasattr(self._host_map, "_plot_marker_cluster"):
                self._host_map._plot_marker_cluster.markers = []
                self._host_map._plot_markers = []

            if hasattr(self._host_map, "_spectral_data"):
                self._host_map._spectral_data = {}

            self._output_widget.clear_output()
            self._show_plot = False
            plt.clear()

        reset_btn.on_click(reset_btn_click)

        save_btn = widgets.Button(
            icon="floppy-o",
            tooltip="Save the data to a CSV",
            button_style="primary",
            layout=widgets.Layout(width="32px"),
        )

        def chooser_callback(chooser):
            if chooser.selected:
                file_path = chooser.selected
                self._host_map.spectral_to_csv(file_path)
                if (
                    hasattr(self._host_map, "_file_chooser_control")
                    and self._host_map._file_chooser_control in self._host_map.controls
                ):
                    self._host_map.remove_control(self._host_map._file_chooser_control)
                    self._host_map._file_chooser.close()

        def save_btn_click(_):
            if not hasattr(self._host_map, "_spectral_data"):
                return

            self._output_widget.clear_output()
            file_chooser = FileChooser(
                os.getcwd(), layout=widgets.Layout(width="454px")
            )
            file_chooser.filter_pattern = "*.csv"
            file_chooser.use_dir_icons = True
            file_chooser.title = "Save spectral data to a CSV file"
            file_chooser.default_filename = "spectral_data.csv"
            file_chooser.show_hidden = False
            file_chooser.register_callback(chooser_callback)
            file_chooser_control = ipyleaflet.WidgetControl(
                widget=file_chooser, position="topright"
            )
            self._host_map.add(file_chooser_control)
            setattr(self._host_map, "_file_chooser", file_chooser)
            setattr(self._host_map, "_file_chooser_control", file_chooser_control)

        save_btn.on_click(save_btn_click)

        def close_widget(_):
            self.cleanup()

        close_btn.on_click(close_widget)

        super().__init__([layers_widget, stack_btn, reset_btn, save_btn, close_btn])

        output = widgets.Output()
        output_control = ipyleaflet.WidgetControl(widget=output, position="bottomright")
        self._output_widget = output
        self._output_control = output_control
        self._host_map.add(output_control)

        if not hasattr(self._host_map, "_spectral_data"):
            self._host_map._spectral_data = {}

        def handle_interaction(**kwargs):

            latlon = kwargs.get("coordinates")
            lat = latlon[0]
            lon = latlon[1]
            if kwargs.get("type") == "click" and self._host_map._layer_editor is None:
                layer_name = layers_widget.value

                if not hasattr(self._host_map, "_plot_markers"):
                    self._host_map._plot_markers = []
                markers = self._host_map._plot_markers
                marker_cluster = self._host_map._plot_marker_cluster
                markers.append(ipyleaflet.Marker(location=latlon, draggable=False))
                marker_cluster.markers = markers
                self._host_map._plot_marker_cluster = marker_cluster

                xlabel = "Wavelength (nm)"
                ylabel = "Reflectance"

                ds = self._host_map.cog_layer_dict[layer_name]["xds"]

                if self._host_map.cog_layer_dict[layer_name]["hyper"] == "PRISMA":
                    da = extract_prisma(ds, lat, lon)

                self._host_map._spectral_data[f"({lat:.4f} {lon:.4f})"] = da.values

                if self._host_map.cog_layer_dict[layer_name]["hyper"] != "XARRAY":
                    da[da < 0] = np.nan
                    x_axis_options = {"label_offset": "30px"}
                else:
                    x_axis_options = {
                        "label_offset": "30px",
                        "tick_format": "0d",
                        "num_ticks": da.sizes["band"],
                    }
                axes_options = {
                    "x": x_axis_options,
                    "y": {"label_offset": "35px"},
                }

                if not stack_btn.value:
                    plt.clear()
                    plt.plot(
                        da.coords[da.dims[0]].values,
                        da.values,
                        axes_options=axes_options,
                    )
                else:
                    color = np.random.rand(
                        3,
                    )
                    if "wavelength" in da.coords:
                        xlabel = "Wavelength (nm)"
                        x_values = da["wavelength"].values
                    else:
                        xlabel = "Band"
                        x_values = da.coords[da.dims[0]].values

                    plt.plot(
                        x_values,
                        da.values,
                        color=color,
                        axes_options=axes_options,
                    )
                    try:
                        if isinstance(self._fig.axes[0], bqplot.ColorAxis):
                            self._fig.axes = self._fig.axes[1:]
                        elif isinstance(self._fig.axes[-1], bqplot.ColorAxis):
                            self._fig.axes = self._fig.axes[:-1]
                    except Exception:
                        pass

                plt.xlabel(xlabel)
                plt.ylabel(ylabel)
                if xlim:
                    plt.xlim(xlim[0], xlim[1])
                if ylim:
                    plt.ylim(ylim[0], ylim[1])

                if not self._show_plot:
                    with self._output_widget:
                        plt.show()
                        self._show_plot = True

                self._host_map.default_style = {"cursor": "crosshair"}

        self._host_map.on_interaction(handle_interaction)
        self._on_map_interaction = handle_interaction

        self._spectral_widget = self
        self._spectral_control = ipyleaflet.WidgetControl(
            widget=self, position=position
        )
        self._host_map.add(self._spectral_control)

    def cleanup(self):
        """Removes the widget from the map and performs cleanup."""
        if self._host_map:
            self._host_map.default_style = {"cursor": "default"}
            self._host_map.on_interaction(self._on_map_interaction, remove=True)

            if self._output_control:
                self._host_map.remove_control(self._output_control)

                if self._output_widget:
                    self._output_widget.close()
                    self._output_widget = None

            if self._spectral_control:
                self._host_map.remove_control(self._spectral_control)
                self._spectral_control = None

                if self._spectral_widget:
                    self._spectral_widget.close()
                    self._spectral_widget = None

            if hasattr(self._host_map, "_plot_marker_cluster"):
                self._host_map._plot_marker_cluster.markers = []
                self._host_map._plot_markers = []

            if hasattr(self._host_map, "_spectral_data"):
                self._host_map._spectral_data = {}

            if hasattr(self, "_output_widget") and self._output_widget is not None:
                self._output_widget.clear_output()

        if self.on_close is not None:
            self.on_close()

__init__(self, host_map, stack=True, position='topright', xlim=None, ylim=None, **kwargs) special

Initializes a new instance of the SpectralWidget class.

Parameters:

Name Type Description Default
host_map Map

The map to host the widget.

required
stack bool

Whether to stack the plots. Defaults to True.

True
position str

The position of the widget on the map. Defaults to "topright".

'topright'
xlim tuple

The x-axis limits. Defaults to None.

None
ylim tuple

The y-axis limits. Defaults to None.

None
Source code in prismatools/gui.py
def __init__(
    self, host_map, stack=True, position="topright", xlim=None, ylim=None, **kwargs
):
    """
    Initializes a new instance of the SpectralWidget class.

    Args:
        host_map (Map): The map to host the widget.
        stack (bool, optional): Whether to stack the plots. Defaults to True.
        position (str, optional): The position of the widget on the map. Defaults to "topright".
        xlim (tuple, optional): The x-axis limits. Defaults to None.
        ylim (tuple, optional): The y-axis limits. Defaults to None.
    """
    self._host_map = host_map
    self.on_close = None
    self._stack = stack
    self._show_plot = False

    fig_margin = {"top": 20, "bottom": 35, "left": 50, "right": 20}
    fig = plt.figure(
        # title=None,
        fig_margin=fig_margin,
        layout={"width": "500px", "height": "300px"},
    )

    self._fig = fig
    self._host_map._fig = fig

    layer_names = list(host_map.cog_layer_dict.keys())
    layers_widget = widgets.Dropdown(options=layer_names)
    layers_widget.layout.width = "18ex"

    close_btn = widgets.Button(
        icon="times",
        tooltip="Close the widget",
        button_style="primary",
        layout=widgets.Layout(width="32px"),
    )

    reset_btn = widgets.Button(
        icon="trash",
        tooltip="Remove all markers",
        button_style="primary",
        layout=widgets.Layout(width="32px"),
    )

    stack_btn = widgets.ToggleButton(
        value=stack,
        icon="area-chart",
        tooltip="Stack spectral signatures",
        button_style="primary",
        layout=widgets.Layout(width="32px"),
    )

    def reset_btn_click(_):
        if hasattr(self._host_map, "_plot_marker_cluster"):
            self._host_map._plot_marker_cluster.markers = []
            self._host_map._plot_markers = []

        if hasattr(self._host_map, "_spectral_data"):
            self._host_map._spectral_data = {}

        self._output_widget.clear_output()
        self._show_plot = False
        plt.clear()

    reset_btn.on_click(reset_btn_click)

    save_btn = widgets.Button(
        icon="floppy-o",
        tooltip="Save the data to a CSV",
        button_style="primary",
        layout=widgets.Layout(width="32px"),
    )

    def chooser_callback(chooser):
        if chooser.selected:
            file_path = chooser.selected
            self._host_map.spectral_to_csv(file_path)
            if (
                hasattr(self._host_map, "_file_chooser_control")
                and self._host_map._file_chooser_control in self._host_map.controls
            ):
                self._host_map.remove_control(self._host_map._file_chooser_control)
                self._host_map._file_chooser.close()

    def save_btn_click(_):
        if not hasattr(self._host_map, "_spectral_data"):
            return

        self._output_widget.clear_output()
        file_chooser = FileChooser(
            os.getcwd(), layout=widgets.Layout(width="454px")
        )
        file_chooser.filter_pattern = "*.csv"
        file_chooser.use_dir_icons = True
        file_chooser.title = "Save spectral data to a CSV file"
        file_chooser.default_filename = "spectral_data.csv"
        file_chooser.show_hidden = False
        file_chooser.register_callback(chooser_callback)
        file_chooser_control = ipyleaflet.WidgetControl(
            widget=file_chooser, position="topright"
        )
        self._host_map.add(file_chooser_control)
        setattr(self._host_map, "_file_chooser", file_chooser)
        setattr(self._host_map, "_file_chooser_control", file_chooser_control)

    save_btn.on_click(save_btn_click)

    def close_widget(_):
        self.cleanup()

    close_btn.on_click(close_widget)

    super().__init__([layers_widget, stack_btn, reset_btn, save_btn, close_btn])

    output = widgets.Output()
    output_control = ipyleaflet.WidgetControl(widget=output, position="bottomright")
    self._output_widget = output
    self._output_control = output_control
    self._host_map.add(output_control)

    if not hasattr(self._host_map, "_spectral_data"):
        self._host_map._spectral_data = {}

    def handle_interaction(**kwargs):

        latlon = kwargs.get("coordinates")
        lat = latlon[0]
        lon = latlon[1]
        if kwargs.get("type") == "click" and self._host_map._layer_editor is None:
            layer_name = layers_widget.value

            if not hasattr(self._host_map, "_plot_markers"):
                self._host_map._plot_markers = []
            markers = self._host_map._plot_markers
            marker_cluster = self._host_map._plot_marker_cluster
            markers.append(ipyleaflet.Marker(location=latlon, draggable=False))
            marker_cluster.markers = markers
            self._host_map._plot_marker_cluster = marker_cluster

            xlabel = "Wavelength (nm)"
            ylabel = "Reflectance"

            ds = self._host_map.cog_layer_dict[layer_name]["xds"]

            if self._host_map.cog_layer_dict[layer_name]["hyper"] == "PRISMA":
                da = extract_prisma(ds, lat, lon)

            self._host_map._spectral_data[f"({lat:.4f} {lon:.4f})"] = da.values

            if self._host_map.cog_layer_dict[layer_name]["hyper"] != "XARRAY":
                da[da < 0] = np.nan
                x_axis_options = {"label_offset": "30px"}
            else:
                x_axis_options = {
                    "label_offset": "30px",
                    "tick_format": "0d",
                    "num_ticks": da.sizes["band"],
                }
            axes_options = {
                "x": x_axis_options,
                "y": {"label_offset": "35px"},
            }

            if not stack_btn.value:
                plt.clear()
                plt.plot(
                    da.coords[da.dims[0]].values,
                    da.values,
                    axes_options=axes_options,
                )
            else:
                color = np.random.rand(
                    3,
                )
                if "wavelength" in da.coords:
                    xlabel = "Wavelength (nm)"
                    x_values = da["wavelength"].values
                else:
                    xlabel = "Band"
                    x_values = da.coords[da.dims[0]].values

                plt.plot(
                    x_values,
                    da.values,
                    color=color,
                    axes_options=axes_options,
                )
                try:
                    if isinstance(self._fig.axes[0], bqplot.ColorAxis):
                        self._fig.axes = self._fig.axes[1:]
                    elif isinstance(self._fig.axes[-1], bqplot.ColorAxis):
                        self._fig.axes = self._fig.axes[:-1]
                except Exception:
                    pass

            plt.xlabel(xlabel)
            plt.ylabel(ylabel)
            if xlim:
                plt.xlim(xlim[0], xlim[1])
            if ylim:
                plt.ylim(ylim[0], ylim[1])

            if not self._show_plot:
                with self._output_widget:
                    plt.show()
                    self._show_plot = True

            self._host_map.default_style = {"cursor": "crosshair"}

    self._host_map.on_interaction(handle_interaction)
    self._on_map_interaction = handle_interaction

    self._spectral_widget = self
    self._spectral_control = ipyleaflet.WidgetControl(
        widget=self, position=position
    )
    self._host_map.add(self._spectral_control)

cleanup(self)

Removes the widget from the map and performs cleanup.

Source code in prismatools/gui.py
def cleanup(self):
    """Removes the widget from the map and performs cleanup."""
    if self._host_map:
        self._host_map.default_style = {"cursor": "default"}
        self._host_map.on_interaction(self._on_map_interaction, remove=True)

        if self._output_control:
            self._host_map.remove_control(self._output_control)

            if self._output_widget:
                self._output_widget.close()
                self._output_widget = None

        if self._spectral_control:
            self._host_map.remove_control(self._spectral_control)
            self._spectral_control = None

            if self._spectral_widget:
                self._spectral_widget.close()
                self._spectral_widget = None

        if hasattr(self._host_map, "_plot_marker_cluster"):
            self._host_map._plot_marker_cluster.markers = []
            self._host_map._plot_markers = []

        if hasattr(self._host_map, "_spectral_data"):
            self._host_map._spectral_data = {}

        if hasattr(self, "_output_widget") and self._output_widget is not None:
            self._output_widget.clear_output()

    if self.on_close is not None:
        self.on_close()

change_basemap(m, position='topright')

Widget for changing basemaps.

Parameters:

Name Type Description Default
m object

leafmap.Map.

required
Source code in prismatools/gui.py
def change_basemap(m, position: Optional[str] = "topright"):
    """Widget for changing basemaps.

    Args:
        m (object): leafmap.Map.
    """
    from leafmap.basemaps import get_xyz_dict
    from leafmap import basemaps, get_basemap

    xyz_dict = get_xyz_dict()

    value = "OpenStreetMap"

    dropdown = widgets.Dropdown(
        options=list(basemaps.keys()),
        value=value,
        layout=widgets.Layout(width="200px"),
    )

    close_btn = widgets.Button(
        icon="times",
        tooltip="Close the basemap widget",
        button_style="primary",
        layout=widgets.Layout(width="32px"),
    )

    basemap_widget = widgets.HBox([dropdown, close_btn])

    def on_click(change):
        if change["new"]:
            basemap_name = dropdown.value
            if basemap_name not in m.get_layer_names():
                m.add_basemap(basemap_name)
                if basemap_name in xyz_dict:
                    if "bounds" in xyz_dict[basemap_name]:
                        bounds = xyz_dict[basemap_name]["bounds"]
                        bounds = [
                            bounds[0][1],
                            bounds[0][0],
                            bounds[1][1],
                            bounds[1][0],
                        ]
                        m.zoom_to_bounds(bounds)

    dropdown.observe(on_click, "value")

    def close_click(change):
        m.toolbar_reset()
        if m.basemap_ctrl is not None and m.basemap_ctrl in m.controls:
            m.remove_control(m.basemap_ctrl)
        basemap_widget.close()

    close_btn.on_click(close_click)

    basemap_control = WidgetControl(widget=basemap_widget, position=position)
    m.add(basemap_control)
    m.basemap_ctrl = basemap_control

layer_manager_gui(m, position='topright', opened=True, return_widget=False)

Creates a layer manager widget.

Parameters:

Name Type Description Default
m geemap.Map

The geemap.Map object.

required
position str

The position of the widget. Defaults to "topright".

'topright'
return_widget bool

Whether to return the widget. Defaults to False.

False
Source code in prismatools/gui.py
def layer_manager_gui(
    m,
    position: Optional[str] = "topright",
    opened: Optional[bool] = True,
    return_widget: Optional[bool] = False,
):
    """Creates a layer manager widget.

    Args:
        m (geemap.Map): The geemap.Map object.
        position (str, optional): The position of the widget. Defaults to "topright".
        return_widget (bool, optional): Whether to return the widget. Defaults to False.
    """

    layers_button = widgets.ToggleButton(
        value=False,
        tooltip="Layer Manager",
        icon="server",
        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"),
    )

    toolbar_header = widgets.HBox()
    toolbar_header.children = [layers_button]
    toolbar_footer = widgets.VBox()
    toolbar_footer.children = []
    toolbar_widget = widgets.VBox()
    toolbar_widget.children = [toolbar_header]

    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 = [layers_button]

    layers_button.observe(toolbar_btn_click, "value")

    def close_btn_click(change):
        if change["new"]:
            layers_button.value = False
            m.toolbar_reset()
            if m.layer_manager is not None and m.layer_manager in m.controls:
                m.remove_control(m.layer_manager)
                m.layer_manager = None
            toolbar_widget.close()

    close_button.observe(close_btn_click, "value")

    def layers_btn_click(change):
        if change["new"]:
            layers_hbox = []
            all_layers_chk = widgets.Checkbox(
                value=False,
                description="All layers on/off",
                indent=False,
                layout=widgets.Layout(height="18px", padding="0px 8px 25px 8px"),
            )
            all_layers_chk.layout.width = "30ex"
            layers_hbox.append(all_layers_chk)

            def all_layers_chk_changed(change):
                if change["new"]:
                    for layer in m.layers:
                        if hasattr(layer, "visible"):
                            layer.visible = True
                else:
                    for layer in m.layers:
                        if hasattr(layer, "visible"):
                            layer.visible = False

            all_layers_chk.observe(all_layers_chk_changed, "value")

            layers = [lyr for lyr in m.layers if lyr.name]

            # if the layers contain unsupported layers (e.g., GeoJSON, GeoData), adds the ipyleaflet built-in LayerControl
            if len(layers) < (len(m.layers) - 1):
                if m.layer_control is None:
                    layer_control = LayersControl(position="topright")
                    m.layer_control = layer_control
                if m.layer_control not in m.controls:
                    m.add(m.layer_control)

            # for non-TileLayer, use layer.style={'opacity':0, 'fillOpacity': 0} to turn layer off.
            for layer in layers:
                visible = True
                if hasattr(layer, "visible"):
                    visible = layer.visible
                layer_chk = widgets.Checkbox(
                    value=visible,
                    description=layer.name,
                    indent=False,
                    layout=widgets.Layout(height="18px"),
                )
                layer_chk.layout.width = "25ex"

                if layer in m.geojson_layers:
                    try:
                        opacity = max(
                            layer.style["opacity"], layer.style["fillOpacity"]
                        )
                    except KeyError:
                        opacity = 1.0
                elif hasattr(layer, "opacity"):
                    opacity = layer.opacity
                else:
                    opacity = 1.0

                layer_opacity = widgets.FloatSlider(
                    value=opacity,
                    min=0,
                    max=1,
                    step=0.01,
                    readout=False,
                    layout=widgets.Layout(width="80px"),
                )
                layer_settings = widgets.Button(
                    icon="gear",
                    tooltip=layer.name,
                    layout=widgets.Layout(
                        width="25px", height="25px", padding="0px 0px 0px 0px"
                    ),
                )

                def layer_settings_click(b):
                    if b.tooltip in m.cog_layer_dict:
                        m._add_layer_editor(
                            position="topright",
                            layer_dict=m.cog_layer_dict[b.tooltip],
                        )

                layer_settings.on_click(layer_settings_click)

                def layer_opacity_changed(change):
                    if change["new"]:
                        layer.style = {
                            "opacity": change["new"],
                            "fillOpacity": change["new"],
                        }

                if hasattr(layer, "visible"):
                    widgets.jslink((layer_chk, "value"), (layer, "visible"))

                if layer in m.geojson_layers:
                    layer_opacity.observe(layer_opacity_changed, "value")
                elif hasattr(layer, "opacity"):
                    widgets.jsdlink((layer_opacity, "value"), (layer, "opacity"))

                hbox = widgets.HBox(
                    [layer_chk, layer_settings, layer_opacity],
                    layout=widgets.Layout(padding="0px 8px 0px 8px"),
                )
                layers_hbox.append(hbox)
                m.layer_widget = layers_hbox

            toolbar_header.children = [close_button, layers_button]
            toolbar_footer.children = layers_hbox

        else:
            toolbar_header.children = [layers_button]

    layers_button.observe(layers_btn_click, "value")
    layers_button.value = opened

    if not hasattr(m, "_layer_manager_widget"):
        m._layer_manager_widget = toolbar_footer

    if return_widget:
        return m.layer_widget
    else:
        layer_control = WidgetControl(widget=toolbar_widget, position=position)

        if layer_control not in m.controls:
            m.add_control(layer_control)
            m.layer_manager = layer_control

main_toolbar(m)

Creates the main toolbar and adds it to the map.

Parameters:

Name Type Description Default
m leafmap.Map

The leafmap Map object.

required
Source code in prismatools/gui.py
def main_toolbar(m):
    """Creates the main toolbar and adds it to the map.

    Args:
        m (leafmap.Map): The leafmap Map object.
    """
    # add here additional tools
    all_tools = {
        "map": {
            "name": "basemap",
            "tooltip": "Change basemap",
        },
    }

    tools = {}
    for tool in all_tools:
        if os.environ.get(all_tools[tool]["name"].upper(), "").upper() != "FALSE":
            tools[tool] = all_tools[tool]

    icons = list(tools.keys())
    tooltips = [item["tooltip"] for item in list(tools.values())]
    toolnames = [item["name"].upper() for item in list(all_tools.values())]
    toolnames.sort()
    setattr(m, "_ENV_VARS", toolnames)

    icon_width = "32px"
    icon_height = "32px"
    n_cols = 3
    n_rows = math.ceil(len(icons) / n_cols)

    toolbar_grid = widgets.GridBox(
        children=[
            widgets.ToggleButton(
                layout=widgets.Layout(
                    width="auto", height="auto", padding="0px 0px 0px 4px"
                ),
                button_style="primary",
                icon=icons[i],
                tooltip=tooltips[i],
            )
            for i in range(len(icons))
        ],
        layout=widgets.Layout(
            width="109px",
            grid_template_columns=(icon_width + " ") * n_cols,
            grid_template_rows=(icon_height + " ") * n_rows,
            grid_gap="1px 1px",
            padding="5px",
        ),
    )
    m.toolbar = toolbar_grid

    def tool_callback(change):
        if change["new"]:
            current_tool = change["owner"]
            for tool in toolbar_grid.children:
                if tool is not current_tool:
                    tool.value = False
            tool = change["owner"]
            tool_name = tools[tool.icon]["name"]

            if tool_name == "basemap":
                change_basemap(m)
        else:
            # tool = change["owner"]
            # tool_name = tools[tool.icon]["name"]
            pass

        m.toolbar_reset()

    for tool in toolbar_grid.children:
        tool.observe(tool_callback, "value")

    toolbar_button = widgets.ToggleButton(
        value=False,
        tooltip="Toolbar",
        icon="wrench",
        layout=widgets.Layout(width="28px", height="28px", padding="0px 0px 0px 4px"),
    )
    m.toolbar_button = toolbar_button

    layers_button = widgets.ToggleButton(
        value=False,
        tooltip="Layers",
        icon="server",
        layout=widgets.Layout(height="28px", width="72px"),
    )

    toolbar_widget = widgets.VBox()
    toolbar_widget.children = [toolbar_button]
    toolbar_header = widgets.HBox()
    toolbar_header.children = [layers_button, toolbar_button]
    toolbar_footer = widgets.VBox()
    toolbar_footer.children = [toolbar_grid]

    toolbar_event = ipyevents.Event(
        source=toolbar_widget, watched_events=["mouseenter", "mouseleave"]
    )

    def handle_toolbar_event(event):
        if event["type"] == "mouseenter":
            toolbar_widget.children = [toolbar_header, toolbar_footer]
        elif event["type"] == "mouseleave":
            if not toolbar_button.value:
                toolbar_widget.children = [toolbar_button]
                toolbar_button.value = False
                layers_button.value = False

    toolbar_event.on_dom_event(handle_toolbar_event)

    def toolbar_btn_click(change):
        if change["new"]:
            layers_button.value = False
            toolbar_widget.children = [toolbar_header, toolbar_footer]
        else:
            if not layers_button.value:
                toolbar_widget.children = [toolbar_button]

    toolbar_button.observe(toolbar_btn_click, "value")

    def layers_btn_click(change):
        if change["new"]:
            toolbar_footer.children = layer_manager_gui(m, return_widget=True)
            toolbar_button.value = False
        else:
            toolbar_footer.children = [toolbar_grid]

    layers_button.observe(layers_btn_click, "value")

    toolbar_control = WidgetControl(widget=toolbar_widget, position="topright")

    m.add(toolbar_control)