Skip to content

geemap module

Main module for interactive mapping using Google Earth Engine Python API and ipyleaflet. Keep in mind that Earth Engine functions use both camel case and snake case, such as setOptions(), setCenter(), centerObject(), addLayer(). ipyleaflet functions use snake case, such as add_tile_layer(), add_wms_layer(), add_minimap().

Map

The Map class inherits from ipyleaflet.Map. The arguments you can pass to the Map can be found at https://ipyleaflet.readthedocs.io/en/latest/api_reference/map.html. By default, the Map will add Google Maps as the basemap. Set add_google_map = False to use OpenStreetMap as the basemap.

Returns:

Type Description
object

ipyleaflet map object.

add_basemap(self, basemap='HYBRID')

Adds a basemap to the map.

Parameters:

Name Type Description Default
basemap str

Can be one of string from ee_basemaps. Defaults to 'HYBRID'.

'HYBRID'
Source code in geemap/geemap.py
def add_basemap(self, basemap="HYBRID"):
    """Adds a basemap to the map.

    Args:
        basemap (str, optional): Can be one of string from ee_basemaps. Defaults to 'HYBRID'.
    """
    try:
        if (
            basemap in basemap_tiles.keys()
            and basemap_tiles[basemap] not in self.layers
        ):
            self.add_layer(basemap_tiles[basemap])

    except Exception:
        raise ValueError(
            "Basemap can only be one of the following:\n  {}".format(
                "\n  ".join(basemap_tiles.keys())
            )
        )

add_cog_layer(self, url, name='Untitled', attribution='', opacity=1.0, shown=True, titiler_endpoint='https://api.cogeo.xyz/', **kwargs)

Adds a COG TileLayer to the map.

Parameters:

Name Type Description Default
url str

The URL of the COG tile layer.

required
name str

The layer name to use for the layer. Defaults to 'Untitled'.

'Untitled'
attribution str

The attribution to use. Defaults to ''.

''
opacity float

The opacity of the layer. Defaults to 1.

1.0
shown bool

A flag indicating whether the layer should be on by default. Defaults to True.

True
titiler_endpoint str

Titiler endpoint. Defaults to "https://api.cogeo.xyz/".

'https://api.cogeo.xyz/'
Source code in geemap/geemap.py
def add_cog_layer(
    self,
    url,
    name="Untitled",
    attribution="",
    opacity=1.0,
    shown=True,
    titiler_endpoint="https://api.cogeo.xyz/",
    **kwargs,
):
    """Adds a COG TileLayer to the map.

    Args:
        url (str): The URL of the COG tile layer.
        name (str, optional): The layer name to use for the layer. Defaults to 'Untitled'.
        attribution (str, optional): The attribution to use. Defaults to ''.
        opacity (float, optional): The opacity of the layer. Defaults to 1.
        shown (bool, optional): A flag indicating whether the layer should be on by default. Defaults to True.
        titiler_endpoint (str, optional): Titiler endpoint. Defaults to "https://api.cogeo.xyz/".
    """
    tile_url = get_cog_tile(url, titiler_endpoint, **kwargs)
    center = get_cog_center(url, titiler_endpoint)  # (lon, lat)
    self.add_tile_layer(tile_url, name, attribution, opacity, shown)
    self.set_center(lon=center[0], lat=center[1], zoom=10)

add_cog_mosaic(self, links, name='Untitled', attribution='', opacity=1.0, shown=True, titiler_endpoint='https://api.cogeo.xyz/', username='anonymous', overwrite=False, show_footprints=False, verbose=True, **kwargs)

Add a virtual mosaic of COGs to the map.

Parameters:

Name Type Description Default
links list

A list of links pointing to COGs.

required
name str

The layer name to use for the layer. Defaults to 'Untitled'.

'Untitled'
attribution str

The attribution to use. Defaults to ''.

''
opacity float

The opacity of the layer. Defaults to 1.

1.0
shown bool

A flag indicating whether the layer should be on by default. Defaults to True.

True
titiler_endpoint str

Titiler endpoint. Defaults to "https://api.cogeo.xyz/".

'https://api.cogeo.xyz/'
username str

The username to create mosaic using the titiler endpoint. Defaults to 'anonymous'.

'anonymous'
overwrite bool

Whether or not to replace existing layer with the same layer name. Defaults to False.

False
show_footprints bool

Whether or not to show footprints of COGs. Defaults to False.

False
verbose bool

Whether or not to print descriptions. Defaults to True.

True
Source code in geemap/geemap.py
def add_cog_mosaic(
    self,
    links,
    name="Untitled",
    attribution="",
    opacity=1.0,
    shown=True,
    titiler_endpoint="https://api.cogeo.xyz/",
    username="anonymous",
    overwrite=False,
    show_footprints=False,
    verbose=True,
    **kwargs,
):
    """Add a virtual mosaic of COGs to the map.

    Args:
        links (list): A list of links pointing to COGs.
        name (str, optional): The layer name to use for the layer. Defaults to 'Untitled'.
        attribution (str, optional): The attribution to use. Defaults to ''.
        opacity (float, optional): The opacity of the layer. Defaults to 1.
        shown (bool, optional): A flag indicating whether the layer should be on by default. Defaults to True.
        titiler_endpoint (str, optional): Titiler endpoint. Defaults to "https://api.cogeo.xyz/".
        username (str, optional): The username to create mosaic using the titiler endpoint. Defaults to 'anonymous'.
        overwrite (bool, optional): Whether or not to replace existing layer with the same layer name. Defaults to False.
        show_footprints (bool, optional): Whether or not to show footprints of COGs. Defaults to False.
        verbose (bool, optional): Whether or not to print descriptions. Defaults to True.
    """
    layername = name.replace(" ", "_")
    tile = get_cog_mosaic(
        links,
        titiler_endpoint=titiler_endpoint,
        username=username,
        layername=layername,
        overwrite=overwrite,
        verbose=verbose,
    )
    self.add_tile_layer(tile, name, attribution, opacity, shown)

    if show_footprints:
        if verbose:
            print(
                f"Generating footprints of {len(links)} COGs. This might take a while ..."
            )
        coords = []
        for link in links:
            coord = get_cog_bounds(link)
            if coord is not None:
                coords.append(coord)
        fc = coords_to_geojson(coords)

        geo_json = ipyleaflet.GeoJSON(
            data=fc,
            style={
                "opacity": 1,
                "dashArray": "1",
                "fillOpacity": 0,
                "weight": 1,
            },
            name="Footprints",
        )

        self.add_layer(geo_json)
        center = get_center(fc)
        if verbose:
            print("The footprint layer has been added.")
    else:
        center = get_cog_center(links[0], titiler_endpoint)

    self.set_center(center[0], center[1], zoom=6)

add_colorbar(self, vis_params=None, cmap='gray', discrete=False, label=None, orientation='horizontal', position='bottomright', transparent_bg=False, layer_name=None, **kwargs)

Add a matplotlib colorbar to the map

Parameters:

Name Type Description Default
vis_params dict

Visualization parameters as a dictionary. See https://developers.google.com/earth-engine/guides/image_visualization for options.

None
cmap str

Matplotlib colormap. Defaults to "gray". See https://matplotlib.org/3.3.4/tutorials/colors/colormaps.html#sphx-glr-tutorials-colors-colormaps-py for options.

'gray'
discrete bool

Whether to create a discrete colorbar. Defaults to False.

False
label str

Label for the colorbar. Defaults to None.

None
orientation str

Orientation of the colorbar, such as "vertical" and "horizontal". Defaults to "horizontal".

'horizontal'
position str

Position of the colorbar on the map. It can be one of: topleft, topright, bottomleft, and bottomright. Defaults to "bottomright".

'bottomright'
transparent_bg bool

Whether to use transparent background. Defaults to False.

False
layer_name str

The layer name associated with the colorbar. Defaults to None.

None

Exceptions:

Type Description
TypeError

If the vis_params is not a dictionary.

ValueError

If the orientation is not either horizontal or vertical.

ValueError

If the provided min value is not scalar type.

ValueError

If the provided max value is not scalar type.

ValueError

If the provided opacity value is not scalar type.

ValueError

If cmap or palette is not provided.

Source code in geemap/geemap.py
def add_colorbar(
    self,
    vis_params=None,
    cmap="gray",
    discrete=False,
    label=None,
    orientation="horizontal",
    position="bottomright",
    transparent_bg=False,
    layer_name=None,
    **kwargs,
):
    """Add a matplotlib colorbar to the map

    Args:
        vis_params (dict): Visualization parameters as a dictionary. See https://developers.google.com/earth-engine/guides/image_visualization for options.
        cmap (str, optional): Matplotlib colormap. Defaults to "gray". See https://matplotlib.org/3.3.4/tutorials/colors/colormaps.html#sphx-glr-tutorials-colors-colormaps-py for options.
        discrete (bool, optional): Whether to create a discrete colorbar. Defaults to False.
        label (str, optional): Label for the colorbar. Defaults to None.
        orientation (str, optional): Orientation of the colorbar, such as "vertical" and "horizontal". Defaults to "horizontal".
        position (str, optional): Position of the colorbar on the map. It can be one of: topleft, topright, bottomleft, and bottomright. Defaults to "bottomright".
        transparent_bg (bool, optional): Whether to use transparent background. Defaults to False.
        layer_name (str, optional): The layer name associated with the colorbar. Defaults to None.

    Raises:
        TypeError: If the vis_params is not a dictionary.
        ValueError: If the orientation is not either horizontal or vertical.
        ValueError: If the provided min value is not scalar type.
        ValueError: If the provided max value is not scalar type.
        ValueError: If the provided opacity value is not scalar type.
        ValueError: If cmap or palette is not provided.
    """
    import matplotlib as mpl
    import matplotlib.pyplot as plt
    import numpy as np

    if isinstance(vis_params, list):
        vis_params = {"palette": vis_params}
    elif isinstance(vis_params, tuple):
        vis_params = {"palette": list(vis_params)}
    elif vis_params is None:
        vis_params = {}

    if "colors" in kwargs and isinstance(kwargs["colors"], list):
        vis_params["palette"] = kwargs["colors"]

    if "colors" in kwargs and isinstance(kwargs["colors"], tuple):
        vis_params["palette"] = list(kwargs["colors"])

    if "vmin" in kwargs:
        vis_params["min"] = kwargs["vmin"]
        del kwargs["vmin"]

    if "vmax" in kwargs:
        vis_params["max"] = kwargs["vmax"]
        del kwargs["vmax"]

    if "caption" in kwargs:
        label = kwargs["caption"]
        del kwargs["caption"]

    if not isinstance(vis_params, dict):
        raise TypeError("The vis_params must be a dictionary.")

    if orientation not in ["horizontal", "vertical"]:
        raise ValueError("The orientation must be either horizontal or vertical.")

    if orientation == "horizontal":
        width, height = 6.0, 0.4
    else:
        width, height = 0.4, 4.0

    if "width" in kwargs:
        width = kwargs["width"]
        kwargs.pop("width")

    if "height" in kwargs:
        height = kwargs["height"]
        kwargs.pop("height")

    vis_keys = list(vis_params.keys())

    if "min" in vis_params:
        vmin = vis_params["min"]
        if type(vmin) not in (int, float):
            raise ValueError("The provided min value must be scalar type.")
    else:
        vmin = 0

    if "max" in vis_params:
        vmax = vis_params["max"]
        if type(vmax) not in (int, float):
            raise ValueError("The provided max value must be scalar type.")
    else:
        vmax = 1

    if "opacity" in vis_params:
        alpha = vis_params["opacity"]
        if type(alpha) not in (int, float):
            raise ValueError("The provided opacity value must be type scalar.")
    elif "alpha" in kwargs:
        alpha = kwargs["alpha"]
    else:
        alpha = 1

    if cmap is not None:

        cmap = mpl.pyplot.get_cmap(cmap)
        norm = mpl.colors.Normalize(vmin=vmin, vmax=vmax)

    if "palette" in vis_keys:
        hexcodes = to_hex_colors(vis_params["palette"])
        if discrete:
            cmap = mpl.colors.ListedColormap(hexcodes)
            vals = np.linspace(vmin, vmax, cmap.N + 1)
            norm = mpl.colors.BoundaryNorm(vals, cmap.N)

        else:
            cmap = mpl.colors.LinearSegmentedColormap.from_list(
                "custom", hexcodes, N=256
            )
            norm = mpl.colors.Normalize(vmin=vmin, vmax=vmax)

    elif cmap is not None:

        cmap = mpl.pyplot.get_cmap(cmap)
        norm = mpl.colors.Normalize(vmin=vmin, vmax=vmax)

    else:
        raise ValueError(
            'cmap keyword or "palette" key in vis_params must be provided.'
        )

    _, ax = plt.subplots(figsize=(width, height))
    cb = mpl.colorbar.ColorbarBase(
        ax, norm=norm, alpha=alpha, cmap=cmap, orientation=orientation, **kwargs
    )

    if "bands" in vis_keys:
        cb.set_label(vis_params["bands"])
    elif label is not None:
        cb.set_label(label)

    output = widgets.Output()
    colormap_ctrl = ipyleaflet.WidgetControl(
        widget=output,
        position=position,
        transparent_bg=transparent_bg,
    )
    with output:
        output.clear_output()
        plt.show()

    self.colorbar = colormap_ctrl
    if layer_name in self.ee_layer_names:
        if "colorbar" in self.ee_layer_dict[layer_name]:
            self.remove_control(self.ee_layer_dict[layer_name]["colorbar"])
        self.ee_layer_dict[layer_name]["colorbar"] = colormap_ctrl

    self.add_control(colormap_ctrl)

add_colorbar_branca(self, colors, vmin=0, vmax=1.0, index=None, caption='', categorical=False, step=None, height='45px', transparent_bg=False, position='bottomright', layer_name=None, **kwargs)

Add a branca colorbar to the map.

Parameters:

Name Type Description Default
colors list

The set of colors to be used for interpolation. Colors can be provided in the form: * tuples of RGBA ints between 0 and 255 (e.g: (255, 255, 0) or (255, 255, 0, 255)) * tuples of RGBA floats between 0. and 1. (e.g: (1.,1.,0.) or (1., 1., 0., 1.)) * HTML-like string (e.g: “#ffff00) * a color name or shortcut (e.g: “y” or “yellow”)

required
vmin int

The minimal value for the colormap. Values lower than vmin will be bound directly to colors[0].. Defaults to 0.

0
vmax float

The maximal value for the colormap. Values higher than vmax will be bound directly to colors[-1]. Defaults to 1.0.

1.0
index list

The values corresponding to each color. It has to be sorted, and have the same length as colors. If None, a regular grid between vmin and vmax is created.. Defaults to None.

None
caption str

The caption for the colormap. Defaults to "".

''
categorical bool

Whether or not to create a categorical colormap. Defaults to False.

False
step int

The step to split the LinearColormap into a StepColormap. Defaults to None.

None
height str

The height of the colormap widget. Defaults to "45px".

'45px'
transparent_bg bool

Whether to use transparent background for the colormap widget. Defaults to True.

False
position str

The position for the colormap widget. Defaults to "bottomright".

'bottomright'
layer_name str

Layer name of the colorbar to be associated with. Defaults to None.

None
Source code in geemap/geemap.py
def add_colorbar_branca(
    self,
    colors,
    vmin=0,
    vmax=1.0,
    index=None,
    caption="",
    categorical=False,
    step=None,
    height="45px",
    transparent_bg=False,
    position="bottomright",
    layer_name=None,
    **kwargs,
):
    """Add a branca colorbar to the map.

    Args:
        colors (list): The set of colors to be used for interpolation. Colors can be provided in the form: * tuples of RGBA ints between 0 and 255 (e.g: (255, 255, 0) or (255, 255, 0, 255)) * tuples of RGBA floats between 0. and 1. (e.g: (1.,1.,0.) or (1., 1., 0., 1.)) * HTML-like string (e.g: “#ffff00) * a color name or shortcut (e.g: “y” or “yellow”)
        vmin (int, optional): The minimal value for the colormap. Values lower than vmin will be bound directly to colors[0].. Defaults to 0.
        vmax (float, optional): The maximal value for the colormap. Values higher than vmax will be bound directly to colors[-1]. Defaults to 1.0.
        index (list, optional):The values corresponding to each color. It has to be sorted, and have the same length as colors. If None, a regular grid between vmin and vmax is created.. Defaults to None.
        caption (str, optional): The caption for the colormap. Defaults to "".
        categorical (bool, optional): Whether or not to create a categorical colormap. Defaults to False.
        step (int, optional): The step to split the LinearColormap into a StepColormap. Defaults to None.
        height (str, optional): The height of the colormap widget. Defaults to "45px".
        transparent_bg (bool, optional): Whether to use transparent background for the colormap widget. Defaults to True.
        position (str, optional): The position for the colormap widget. Defaults to "bottomright".
        layer_name (str, optional): Layer name of the colorbar to be associated with. Defaults to None.

    """
    from box import Box
    from branca.colormap import LinearColormap

    output = widgets.Output()
    output.layout.height = height

    if "width" in kwargs.keys():
        output.layout.width = kwargs["width"]

    if isinstance(colors, Box):
        try:
            colors = list(colors["default"])
        except Exception as e:
            print("The provided color list is invalid.")
            raise Exception(e)

    if all(len(color) == 6 for color in colors):
        colors = ["#" + color for color in colors]

    colormap = LinearColormap(
        colors=colors, index=index, vmin=vmin, vmax=vmax, caption=caption
    )

    if categorical:
        if step is not None:
            colormap = colormap.to_step(step)
        elif index is not None:
            colormap = colormap.to_step(len(index) - 1)
        else:
            colormap = colormap.to_step(3)

    colormap_ctrl = ipyleaflet.WidgetControl(
        widget=output,
        position=position,
        transparent_bg=transparent_bg,
        **kwargs,
    )
    with output:
        output.clear_output()
        display(colormap)

    self.colorbar = colormap_ctrl
    self.add_control(colormap_ctrl)

    if layer_name in self.ee_layer_names:
        self.ee_layer_dict[layer_name]["colorbar"] = colormap_ctrl

add_ee_layer(self, ee_object, vis_params={}, name=None, shown=True, opacity=1.0)

Adds a given EE object to the map as a layer.

Parameters:

Name Type Description Default
ee_object Collection|Feature|Image|MapId

The object to add to the map.

required
vis_params dict

The visualization parameters. Defaults to {}.

{}
name str

The name of the layer. Defaults to 'Layer N'.

None
shown bool

A flag indicating whether the layer should be on by default. Defaults to True.

True
opacity float

The layer's opacity represented as a number between 0 and 1. Defaults to 1.

1.0
Source code in geemap/geemap.py
def add_ee_layer(
    self, ee_object, vis_params={}, name=None, shown=True, opacity=1.0
):
    """Adds a given EE object to the map as a layer.

    Args:
        ee_object (Collection|Feature|Image|MapId): The object to add to the map.
        vis_params (dict, optional): The visualization parameters. Defaults to {}.
        name (str, optional): The name of the layer. Defaults to 'Layer N'.
        shown (bool, optional): A flag indicating whether the layer should be on by default. Defaults to True.
        opacity (float, optional): The layer's opacity represented as a number between 0 and 1. Defaults to 1.
    """
    from box import Box

    image = None
    if name is None:
        layer_count = len(self.layers)
        name = "Layer " + str(layer_count + 1)

    if (
        not isinstance(ee_object, ee.Image)
        and not isinstance(ee_object, ee.ImageCollection)
        and not isinstance(ee_object, ee.FeatureCollection)
        and not isinstance(ee_object, ee.Feature)
        and not isinstance(ee_object, ee.Geometry)
    ):
        err_str = "\n\nThe image argument in 'addLayer' function must be an instance of one of ee.Image, ee.Geometry, ee.Feature or ee.FeatureCollection."
        raise AttributeError(err_str)

    if (
        isinstance(ee_object, ee.geometry.Geometry)
        or isinstance(ee_object, ee.feature.Feature)
        or isinstance(ee_object, ee.featurecollection.FeatureCollection)
    ):
        features = ee.FeatureCollection(ee_object)

        width = 2

        if "width" in vis_params:
            width = vis_params["width"]

        color = "000000"

        if "color" in vis_params:
            color = vis_params["color"]

        image_fill = features.style(**{"fillColor": color}).updateMask(
            ee.Image.constant(0.5)
        )
        image_outline = features.style(
            **{"color": color, "fillColor": "00000000", "width": width}
        )

        image = image_fill.blend(image_outline)
    elif isinstance(ee_object, ee.image.Image):
        image = ee_object
    elif isinstance(ee_object, ee.imagecollection.ImageCollection):
        image = ee_object.mosaic()

    if "palette" in vis_params and isinstance(vis_params["palette"], Box):
        try:
            vis_params["palette"] = vis_params["palette"]["default"]
        except Exception as e:
            print("The provided palette is invalid.")
            raise Exception(e)

    map_id_dict = ee.Image(image).getMapId(vis_params)
    tile_layer = ipyleaflet.TileLayer(
        url=map_id_dict["tile_fetcher"].url_format,
        attribution="Google Earth Engine",
        name=name,
        opacity=opacity,
        visible=shown,
    )

    layer = self.find_layer(name=name)
    if layer is not None:

        existing_object = self.ee_layer_dict[name]["ee_object"]

        if isinstance(existing_object, ee.Image) or isinstance(
            existing_object, ee.ImageCollection
        ):
            self.ee_raster_layers.remove(existing_object)
            self.ee_raster_layer_names.remove(name)
            if self.plot_dropdown_widget is not None:
                self.plot_dropdown_widget.options = list(self.ee_raster_layer_names)
        elif (
            isinstance(ee_object, ee.Geometry)
            or isinstance(ee_object, ee.Feature)
            or isinstance(ee_object, ee.FeatureCollection)
        ):
            self.ee_vector_layers.remove(existing_object)
            self.ee_vector_layer_names.remove(name)

        self.ee_layers.remove(existing_object)
        self.ee_layer_names.remove(name)
        self.remove_layer(layer)

    self.ee_layers.append(ee_object)
    if name not in self.ee_layer_names:
        self.ee_layer_names.append(name)
    self.ee_layer_dict[name] = {
        "ee_object": ee_object,
        "ee_layer": tile_layer,
        "vis_params": vis_params,
    }

    self.add_layer(tile_layer)
    self.last_ee_layer = self.ee_layer_dict[name]
    self.last_ee_data = self.ee_layer_dict[name]["ee_object"]

    if isinstance(ee_object, ee.Image) or isinstance(ee_object, ee.ImageCollection):
        self.ee_raster_layers.append(ee_object)
        self.ee_raster_layer_names.append(name)
        if self.plot_dropdown_widget is not None:
            self.plot_dropdown_widget.options = list(self.ee_raster_layer_names)
    elif (
        isinstance(ee_object, ee.Geometry)
        or isinstance(ee_object, ee.Feature)
        or isinstance(ee_object, ee.FeatureCollection)
    ):
        self.ee_vector_layers.append(ee_object)
        self.ee_vector_layer_names.append(name)

add_geojson(self, in_geojson, layer_name='Untitled', style={}, hover_style={}, style_callback=None, fill_colors=['black'], info_mode='on_hover')

Adds a GeoJSON file to the map.

Parameters:

Name Type Description Default
in_geojson str | dict

The file path or http URL to the input GeoJSON or a dictionary containing the geojson.

required
layer_name str

The layer name to be used.. Defaults to "Untitled".

'Untitled'
style dict

A dictionary specifying the style to be used. Defaults to {}.

{}
hover_style dict

Hover style dictionary. Defaults to {}.

{}
style_callback function

Styling function that is called for each feature, and should return the feature style. This styling function takes the feature as argument. Defaults to None.

None
fill_colors list

The random colors to use for filling polygons. Defaults to ["black"].

['black']
info_mode str

Displays the attributes by either on_hover or on_click. Any value other than "on_hover" or "on_click" will be treated as None. Defaults to "on_hover".

'on_hover'

Exceptions:

Type Description
FileNotFoundError

The provided GeoJSON file could not be found.

Source code in geemap/geemap.py
def add_geojson(
    self,
    in_geojson,
    layer_name="Untitled",
    style={},
    hover_style={},
    style_callback=None,
    fill_colors=["black"],
    info_mode="on_hover",
):
    """Adds a GeoJSON file to the map.

    Args:
        in_geojson (str | dict): The file path or http URL to the input GeoJSON or a dictionary containing the geojson.
        layer_name (str, optional): The layer name to be used.. Defaults to "Untitled".
        style (dict, optional): A dictionary specifying the style to be used. Defaults to {}.
        hover_style (dict, optional): Hover style dictionary. Defaults to {}.
        style_callback (function, optional): Styling function that is called for each feature, and should return the feature style. This styling function takes the feature as argument. Defaults to None.
        fill_colors (list, optional): The random colors to use for filling polygons. Defaults to ["black"].
        info_mode (str, optional): Displays the attributes by either on_hover or on_click. Any value other than "on_hover" or "on_click" will be treated as None. Defaults to "on_hover".
    Raises:
        FileNotFoundError: The provided GeoJSON file could not be found.
    """
    import json
    import random

    import requests

    try:

        if isinstance(in_geojson, str):

            if in_geojson.startswith("http"):
                data = requests.get(in_geojson).json()
            else:
                in_geojson = os.path.abspath(in_geojson)
                if not os.path.exists(in_geojson):
                    raise FileNotFoundError(
                        "The provided GeoJSON file could not be found."
                    )

                with open(in_geojson, encoding="utf-8") as f:
                    data = json.load(f)
        elif isinstance(in_geojson, dict):
            data = in_geojson
        else:
            raise TypeError("The input geojson must be a type of str or dict.")
    except Exception as e:
        raise Exception(e)

    if not style:
        style = {
            # "stroke": True,
            "color": "#000000",
            "weight": 1,
            "opacity": 1,
            # "fill": True,
            # "fillColor": "#ffffff",
            "fillOpacity": 0.1,
            # "dashArray": "9"
            # "clickable": True,
        }
    elif "weight" not in style:
        style["weight"] = 1

    if not hover_style:
        hover_style = {"weight": style["weight"] + 1, "fillOpacity": 0.5}

    def random_color(feature):
        return {
            "color": "black",
            "fillColor": random.choice(fill_colors),
        }

    toolbar_button = widgets.ToggleButton(
        value=True,
        tooltip="Toolbar",
        icon="info",
        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"
        ),
    )

    html = widgets.HTML()
    html.layout.margin = "0px 10px 0px 10px"
    html.layout.max_height = "250px"
    html.layout.max_width = "250px"

    output_widget = widgets.VBox(
        [widgets.HBox([toolbar_button, close_button]), html]
    )
    info_control = ipyleaflet.WidgetControl(
        widget=output_widget, position="bottomright"
    )

    if info_mode in ["on_hover", "on_click"]:
        self.add_control(info_control)

    def toolbar_btn_click(change):
        if change["new"]:
            close_button.value = False
            output_widget.children = [
                widgets.VBox([widgets.HBox([toolbar_button, close_button]), html])
            ]
        else:
            output_widget.children = [widgets.HBox([toolbar_button, close_button])]

    toolbar_button.observe(toolbar_btn_click, "value")

    def close_btn_click(change):
        if change["new"]:
            toolbar_button.value = False
            if info_control in self.controls:
                self.remove_control(info_control)
            output_widget.close()

    close_button.observe(close_btn_click, "value")

    def update_html(feature, **kwargs):

        value = [
            "<h5><b>{}: </b>{}</h5>".format(prop, feature["properties"][prop])
            for prop in feature["properties"].keys()
        ][:-1]

        value = """{}""".format("".join(value))
        html.value = value

    if style_callback is None:
        style_callback = random_color

    geojson = ipyleaflet.GeoJSON(
        data=data,
        style=style,
        hover_style=hover_style,
        style_callback=style_callback,
        name=layer_name,
    )

    if info_mode == "on_hover":
        geojson.on_hover(update_html)
    elif info_mode == "on_click":
        geojson.on_click(update_html)

    self.add_layer(geojson)

add_kml(self, in_kml, layer_name='Untitled', style={}, hover_style={}, style_callback=None, fill_colors=['black'], info_mode='on_hover')

Adds a GeoJSON file to the map.

Parameters:

Name Type Description Default
in_kml str

The input file path to the KML.

required
layer_name str

The layer name to be used.. Defaults to "Untitled".

'Untitled'
style dict

A dictionary specifying the style to be used. Defaults to {}.

{}
hover_style dict

Hover style dictionary. Defaults to {}.

{}
style_callback function

Styling function that is called for each feature, and should return the feature style. This styling function takes the feature as argument. Defaults to None.

None
fill_colors list

The random colors to use for filling polygons. Defaults to ["black"].

['black']
info_mode str

Displays the attributes by either on_hover or on_click. Any value other than "on_hover" or "on_click" will be treated as None. Defaults to "on_hover".

'on_hover'

Exceptions:

Type Description
FileNotFoundError

The provided KML file could not be found.

Source code in geemap/geemap.py
def add_kml(
    self,
    in_kml,
    layer_name="Untitled",
    style={},
    hover_style={},
    style_callback=None,
    fill_colors=["black"],
    info_mode="on_hover",
):
    """Adds a GeoJSON file to the map.

    Args:
        in_kml (str): The input file path to the KML.
        layer_name (str, optional): The layer name to be used.. Defaults to "Untitled".
        style (dict, optional): A dictionary specifying the style to be used. Defaults to {}.
        hover_style (dict, optional): Hover style dictionary. Defaults to {}.
        style_callback (function, optional): Styling function that is called for each feature, and should return the feature style. This styling function takes the feature as argument. Defaults to None.
        fill_colors (list, optional): The random colors to use for filling polygons. Defaults to ["black"].
        info_mode (str, optional): Displays the attributes by either on_hover or on_click. Any value other than "on_hover" or "on_click" will be treated as None. Defaults to "on_hover".

    Raises:
        FileNotFoundError: The provided KML file could not be found.
    """

    in_kml = os.path.abspath(in_kml)
    if not os.path.exists(in_kml):
        raise FileNotFoundError("The provided KML file could not be found.")
    self.add_vector(
        in_kml,
        layer_name,
        style=style,
        hover_style=hover_style,
        style_callback=style_callback,
        fill_colors=fill_colors,
        info_mode=info_mode,
    )

add_landsat_ts_gif(self, layer_name='Timelapse', roi=None, label=None, start_year=1984, end_year=2019, start_date='06-10', end_date='09-20', bands=['NIR', 'Red', 'Green'], vis_params=None, dimensions=768, frames_per_second=10, font_size=30, font_color='white', add_progress_bar=True, progress_bar_color='white', progress_bar_height=5, out_gif=None, download=False, apply_fmask=True, nd_bands=None, nd_threshold=0, nd_palette=['black', 'blue'])

Adds a Landsat timelapse to the map.

Parameters:

Name Type Description Default
layer_name str

Layer name to show under the layer control. Defaults to 'Timelapse'.

'Timelapse'
roi object

Region of interest to create the timelapse. Defaults to None.

None
label str

A label to shown on the GIF, such as place name. Defaults to None.

None
start_year int

Starting year for the timelapse. Defaults to 1984.

1984
end_year int

Ending year for the timelapse. Defaults to 2019.

2019
start_date str

Starting date (month-day) each year for filtering ImageCollection. Defaults to '06-10'.

'06-10'
end_date str

Ending date (month-day) each year for filtering ImageCollection. Defaults to '09-20'.

'09-20'
bands list

Three bands selected from ['Blue', 'Green', 'Red', 'NIR', 'SWIR1', 'SWIR2', 'pixel_qa']. Defaults to ['NIR', 'Red', 'Green'].

['NIR', 'Red', 'Green']
vis_params dict

Visualization parameters. Defaults to None.

None
dimensions int

a number or pair of numbers in format WIDTHxHEIGHT) Maximum dimensions of the thumbnail to render, in pixels. If only one number is passed, it is used as the maximum, and the other dimension is computed by proportional scaling. Defaults to 768.

768
frames_per_second int

Animation speed. Defaults to 10.

10
font_size int

Font size of the animated text and label. Defaults to 30.

30
font_color str

Font color of the animated text and label. Defaults to 'black'.

'white'
add_progress_bar bool

Whether to add a progress bar at the bottom of the GIF. Defaults to True.

True
progress_bar_color str

Color for the progress bar. Defaults to 'white'.

'white'
progress_bar_height int

Height of the progress bar. Defaults to 5.

5
out_gif str

File path to the output animated GIF. Defaults to None.

None
download bool

Whether to download the gif. Defaults to False.

False
apply_fmask bool

Whether to apply Fmask (Function of mask) for automated clouds, cloud shadows, snow, and water masking.

True
nd_bands list

A list of names specifying the bands to use, e.g., ['Green', 'SWIR1']. The normalized difference is computed as (first − second) / (first + second). Note that negative input values are forced to 0 so that the result is confined to the range (-1, 1).

None
nd_threshold float

The threshold for extacting pixels from the normalized difference band.

0
nd_palette str

The color palette to use for displaying the normalized difference band.

['black', 'blue']
Source code in geemap/geemap.py
def add_landsat_ts_gif(
    self,
    layer_name="Timelapse",
    roi=None,
    label=None,
    start_year=1984,
    end_year=2019,
    start_date="06-10",
    end_date="09-20",
    bands=["NIR", "Red", "Green"],
    vis_params=None,
    dimensions=768,
    frames_per_second=10,
    font_size=30,
    font_color="white",
    add_progress_bar=True,
    progress_bar_color="white",
    progress_bar_height=5,
    out_gif=None,
    download=False,
    apply_fmask=True,
    nd_bands=None,
    nd_threshold=0,
    nd_palette=["black", "blue"],
):
    """Adds a Landsat timelapse to the map.

    Args:
        layer_name (str, optional): Layer name to show under the layer control. Defaults to 'Timelapse'.
        roi (object, optional): Region of interest to create the timelapse. Defaults to None.
        label (str, optional): A label to shown on the GIF, such as place name. Defaults to None.
        start_year (int, optional): Starting year for the timelapse. Defaults to 1984.
        end_year (int, optional): Ending year for the timelapse. Defaults to 2019.
        start_date (str, optional): Starting date (month-day) each year for filtering ImageCollection. Defaults to '06-10'.
        end_date (str, optional): Ending date (month-day) each year for filtering ImageCollection. Defaults to '09-20'.
        bands (list, optional): Three bands selected from ['Blue', 'Green', 'Red', 'NIR', 'SWIR1', 'SWIR2', 'pixel_qa']. Defaults to ['NIR', 'Red', 'Green'].
        vis_params (dict, optional): Visualization parameters. Defaults to None.
        dimensions (int, optional): a number or pair of numbers in format WIDTHxHEIGHT) Maximum dimensions of the thumbnail to render, in pixels. If only one number is passed, it is used as the maximum, and the other dimension is computed by proportional scaling. Defaults to 768.
        frames_per_second (int, optional): Animation speed. Defaults to 10.
        font_size (int, optional): Font size of the animated text and label. Defaults to 30.
        font_color (str, optional): Font color of the animated text and label. Defaults to 'black'.
        add_progress_bar (bool, optional): Whether to add a progress bar at the bottom of the GIF. Defaults to True.
        progress_bar_color (str, optional): Color for the progress bar. Defaults to 'white'.
        progress_bar_height (int, optional): Height of the progress bar. Defaults to 5.
        out_gif (str, optional): File path to the output animated GIF. Defaults to None.
        download (bool, optional): Whether to download the gif. Defaults to False.
        apply_fmask (bool, optional): Whether to apply Fmask (Function of mask) for automated clouds, cloud shadows, snow, and water masking.
        nd_bands (list, optional): A list of names specifying the bands to use, e.g., ['Green', 'SWIR1']. The normalized difference is computed as (first − second) / (first + second). Note that negative input values are forced to 0 so that the result is confined to the range (-1, 1).
        nd_threshold (float, optional): The threshold for extacting pixels from the normalized difference band.
        nd_palette (str, optional): The color palette to use for displaying the normalized difference band.

    """
    try:

        if roi is None:
            if self.draw_last_feature is not None:
                feature = self.draw_last_feature
                roi = feature.geometry()
            else:
                roi = ee.Geometry.Polygon(
                    [
                        [
                            [-115.471773, 35.892718],
                            [-115.471773, 36.409454],
                            [-114.271283, 36.409454],
                            [-114.271283, 35.892718],
                            [-115.471773, 35.892718],
                        ]
                    ],
                    None,
                    False,
                )
        elif isinstance(roi, ee.Feature) or isinstance(roi, ee.FeatureCollection):
            roi = roi.geometry()
        elif isinstance(roi, ee.Geometry):
            pass
        else:
            print("The provided roi is invalid. It must be an ee.Geometry")
            return

        geojson = ee_to_geojson(roi)
        bounds = minimum_bounding_box(geojson)
        geojson = adjust_longitude(geojson)
        roi = ee.Geometry(geojson)

        in_gif = landsat_ts_gif(
            roi=roi,
            out_gif=out_gif,
            start_year=start_year,
            end_year=end_year,
            start_date=start_date,
            end_date=end_date,
            bands=bands,
            vis_params=vis_params,
            dimensions=dimensions,
            frames_per_second=frames_per_second,
            apply_fmask=apply_fmask,
            nd_bands=nd_bands,
            nd_threshold=nd_threshold,
            nd_palette=nd_palette,
        )
        in_nd_gif = in_gif.replace(".gif", "_nd.gif")

        print("Adding animated text to GIF ...")
        add_text_to_gif(
            in_gif,
            in_gif,
            xy=("2%", "2%"),
            text_sequence=start_year,
            font_size=font_size,
            font_color=font_color,
            duration=int(1000 / frames_per_second),
            add_progress_bar=add_progress_bar,
            progress_bar_color=progress_bar_color,
            progress_bar_height=progress_bar_height,
        )
        if nd_bands is not None:
            add_text_to_gif(
                in_nd_gif,
                in_nd_gif,
                xy=("2%", "2%"),
                text_sequence=start_year,
                font_size=font_size,
                font_color=font_color,
                duration=int(1000 / frames_per_second),
                add_progress_bar=add_progress_bar,
                progress_bar_color=progress_bar_color,
                progress_bar_height=progress_bar_height,
            )

        if label is not None:
            add_text_to_gif(
                in_gif,
                in_gif,
                xy=("2%", "90%"),
                text_sequence=label,
                font_size=font_size,
                font_color=font_color,
                duration=int(1000 / frames_per_second),
                add_progress_bar=add_progress_bar,
                progress_bar_color=progress_bar_color,
                progress_bar_height=progress_bar_height,
            )
            # if nd_bands is not None:
            #     add_text_to_gif(in_nd_gif, in_nd_gif, xy=('2%', '90%'), text_sequence=label,
            #                     font_size=font_size, font_color=font_color, duration=int(1000 / frames_per_second), add_progress_bar=add_progress_bar, progress_bar_color=progress_bar_color, progress_bar_height=progress_bar_height)

        if is_tool("ffmpeg"):
            reduce_gif_size(in_gif)
            if nd_bands is not None:
                reduce_gif_size(in_nd_gif)

        print("Adding GIF to the map ...")
        self.image_overlay(url=in_gif, bounds=bounds, name=layer_name)
        if nd_bands is not None:
            self.image_overlay(
                url=in_nd_gif, bounds=bounds, name=layer_name + " ND"
            )
        print("The timelapse has been added to the map.")

        if download:
            link = create_download_link(
                in_gif,
                title="Click here to download the Landsat timelapse: ",
            )
            display(link)
            if nd_bands is not None:
                link2 = create_download_link(
                    in_nd_gif,
                    title="Click here to download the Normalized Difference Index timelapse: ",
                )
                display(link2)

    except Exception as e:
        raise Exception(e)

add_layer_control(self)

Adds the layer control to the map.

Source code in geemap/geemap.py
def add_layer_control(self):
    """Adds the layer control to the map."""
    pass

add_legend(self, legend_title='Legend', legend_dict=None, legend_keys=None, legend_colors=None, position='bottomright', builtin_legend=None, layer_name=None, **kwargs)

Adds a customized basemap to the map.

Parameters:

Name Type Description Default
legend_title str

Title of the legend. Defaults to 'Legend'.

'Legend'
legend_dict dict

A dictionary containing legend items as keys and color as values. If provided, legend_keys and legend_colors will be ignored. Defaults to None.

None
legend_keys list

A list of legend keys. Defaults to None.

None
legend_colors list

A list of legend colors. Defaults to None.

None
position str

Position of the legend. Defaults to 'bottomright'.

'bottomright'
builtin_legend str

Name of the builtin legend to add to the map. Defaults to None.

None
layer_name str

Layer name of the legend to be associated with. Defaults to None.

None
Source code in geemap/geemap.py
def add_legend(
    self,
    legend_title="Legend",
    legend_dict=None,
    legend_keys=None,
    legend_colors=None,
    position="bottomright",
    builtin_legend=None,
    layer_name=None,
    **kwargs,
):
    """Adds a customized basemap to the map.

    Args:
        legend_title (str, optional): Title of the legend. Defaults to 'Legend'.
        legend_dict (dict, optional): A dictionary containing legend items as keys and color as values. If provided, legend_keys and legend_colors will be ignored. Defaults to None.
        legend_keys (list, optional): A list of legend keys. Defaults to None.
        legend_colors (list, optional): A list of legend colors. Defaults to None.
        position (str, optional): Position of the legend. Defaults to 'bottomright'.
        builtin_legend (str, optional): Name of the builtin legend to add to the map. Defaults to None.
        layer_name (str, optional): Layer name of the legend to be associated with. Defaults to None.

    """
    import pkg_resources
    from IPython.display import display

    pkg_dir = os.path.dirname(
        pkg_resources.resource_filename("geemap", "geemap.py")
    )
    legend_template = os.path.join(pkg_dir, "data/template/legend.html")

    if "min_width" not in kwargs.keys():
        min_width = None
    if "max_width" not in kwargs.keys():
        max_width = None
    else:
        max_width = kwargs["max_width"]
    if "min_height" not in kwargs.keys():
        min_height = None
    else:
        min_height = kwargs["min_height"]
    if "max_height" not in kwargs.keys():
        max_height = None
    else:
        max_height = kwargs["max_height"]
    if "height" not in kwargs.keys():
        height = None
    else:
        height = kwargs["height"]
    if "width" not in kwargs.keys():
        width = None
    else:
        width = kwargs["width"]

    if width is None:
        max_width = "300px"
    if height is None:
        max_height = "400px"

    if not os.path.exists(legend_template):
        print("The legend template does not exist.")
        return

    if legend_keys is not None:
        if not isinstance(legend_keys, list):
            print("The legend keys must be a list.")
            return
    else:
        legend_keys = ["One", "Two", "Three", "Four", "etc"]

    if legend_colors is not None:
        if not isinstance(legend_colors, list):
            print("The legend colors must be a list.")
            return
        elif all(isinstance(item, tuple) for item in legend_colors):
            try:
                legend_colors = [rgb_to_hex(x) for x in legend_colors]
            except Exception as e:
                print(e)
        elif all(
            (item.startswith("#") and len(item) == 7) for item in legend_colors
        ):
            pass
        elif all((len(item) == 6) for item in legend_colors):
            pass
        else:
            print("The legend colors must be a list of tuples.")
            return
    else:
        legend_colors = [
            "#8DD3C7",
            "#FFFFB3",
            "#BEBADA",
            "#FB8072",
            "#80B1D3",
        ]

    if len(legend_keys) != len(legend_colors):
        print("The legend keys and values must be the same length.")
        return

    allowed_builtin_legends = builtin_legends.keys()
    if builtin_legend is not None:
        if builtin_legend not in allowed_builtin_legends:
            print(
                "The builtin legend must be one of the following: {}".format(
                    ", ".join(allowed_builtin_legends)
                )
            )
            return
        else:
            legend_dict = builtin_legends[builtin_legend]
            legend_keys = list(legend_dict.keys())
            legend_colors = list(legend_dict.values())

    if legend_dict is not None:
        if not isinstance(legend_dict, dict):
            print("The legend dict must be a dictionary.")
            return
        else:
            legend_keys = list(legend_dict.keys())
            legend_colors = list(legend_dict.values())
            if all(isinstance(item, tuple) for item in legend_colors):
                try:
                    legend_colors = [rgb_to_hex(x) for x in legend_colors]
                except Exception as e:
                    print(e)

    allowed_positions = [
        "topleft",
        "topright",
        "bottomleft",
        "bottomright",
    ]
    if position not in allowed_positions:
        print(
            "The position must be one of the following: {}".format(
                ", ".join(allowed_positions)
            )
        )
        return

    header = []
    content = []
    footer = []

    with open(legend_template) as f:
        lines = f.readlines()
        lines[3] = lines[3].replace("Legend", legend_title)
        header = lines[:6]
        footer = lines[11:]

    for index, key in enumerate(legend_keys):
        color = legend_colors[index]
        if not color.startswith("#"):
            color = "#" + color
        item = "      <li><span style='background:{};'></span>{}</li>\n".format(
            color, key
        )
        content.append(item)

    legend_html = header + content + footer
    legend_text = "".join(legend_html)

    try:

        legend_output_widget = widgets.Output(
            layout={
                # "border": "1px solid black",
                "max_width": max_width,
                "min_width": min_width,
                "max_height": max_height,
                "min_height": min_height,
                "height": height,
                "width": width,
                "overflow": "scroll",
            }
        )
        legend_control = ipyleaflet.WidgetControl(
            widget=legend_output_widget, position=position
        )
        legend_widget = widgets.HTML(value=legend_text)
        with legend_output_widget:
            display(legend_widget)

        self.legend_widget = legend_output_widget
        self.legend_control = legend_control
        self.add_control(legend_control)

        if layer_name in self.ee_layer_names:
            self.ee_layer_dict[layer_name]["legend"] = legend_control

    except Exception as e:
        raise Exception(e)

add_maker_cluster(self, event='click', add_marker=True)

Captures user inputs and add markers to the map.

Parameters:

Name Type Description Default
event str

[description]. Defaults to 'click'.

'click'
add_marker bool

If True, add markers to the map. Defaults to True.

True

Returns:

Type Description
object

a marker cluster.

Source code in geemap/geemap.py
def add_maker_cluster(self, event="click", add_marker=True):
    """Captures user inputs and add markers to the map.

    Args:
        event (str, optional): [description]. Defaults to 'click'.
        add_marker (bool, optional): If True, add markers to the map. Defaults to True.

    Returns:
        object: a marker cluster.
    """
    coordinates = []
    markers = []
    marker_cluster = ipyleaflet.MarkerCluster(name="Marker Cluster")
    self.last_click = []
    self.all_clicks = []
    if add_marker:
        self.add_layer(marker_cluster)

    def handle_interaction(**kwargs):
        latlon = kwargs.get("coordinates")

        if event == "click" and kwargs.get("type") == "click":
            coordinates.append(latlon)
            self.last_click = latlon
            self.all_clicks = coordinates
            if add_marker:
                markers.append(ipyleaflet.Marker(location=latlon))
                marker_cluster.markers = markers
        elif kwargs.get("type") == "mousemove":
            pass

    # cursor style: https://www.w3schools.com/cssref/pr_class_cursor.asp
    self.default_style = {"cursor": "crosshair"}
    self.on_interaction(handle_interaction)

add_minimap(self, zoom=5, position='bottomright')

Adds a minimap (overview) to the ipyleaflet map.

Parameters:

Name Type Description Default
zoom int

Initial map zoom level. Defaults to 5.

5
position str

Position of the minimap. Defaults to "bottomright".

'bottomright'
Source code in geemap/geemap.py
def add_minimap(self, zoom=5, position="bottomright"):
    """Adds a minimap (overview) to the ipyleaflet map.

    Args:
        zoom (int, optional): Initial map zoom level. Defaults to 5.
        position (str, optional): Position of the minimap. Defaults to "bottomright".
    """
    minimap = ipyleaflet.Map(
        zoom_control=False,
        attribution_control=False,
        zoom=zoom,
        center=self.center,
        layers=[basemap_tiles["ROADMAP"]],
    )
    minimap.layout.width = "150px"
    minimap.layout.height = "150px"
    ipyleaflet.link((minimap, "center"), (self, "center"))
    minimap_control = ipyleaflet.WidgetControl(widget=minimap, position=position)
    self.add_control(minimap_control)

add_osm(self, query, layer_name='Untitled', style={}, hover_style={}, style_callback=None, fill_colors=['black'], info_mode='on_hover', which_result=None, by_osmid=False, buffer_dist=None, to_ee=False, geodesic=True)

Adds OSM data to the map.

Parameters:

Name Type Description Default
query str | dict | list

Query string(s) or structured dict(s) to geocode.

required
layer_name str

The layer name to be used.. Defaults to "Untitled".

'Untitled'
style dict

A dictionary specifying the style to be used. Defaults to {}.

{}
hover_style dict

Hover style dictionary. Defaults to {}.

{}
style_callback function

Styling function that is called for each feature, and should return the feature style. This styling function takes the feature as argument. Defaults to None.

None
fill_colors list

The random colors to use for filling polygons. Defaults to ["black"].

['black']
info_mode str

Displays the attributes by either on_hover or on_click. Any value other than "on_hover" or "on_click" will be treated as None. Defaults to "on_hover".

'on_hover'
which_result INT

Which geocoding result to use. if None, auto-select the first (Multi)Polygon or raise an error if OSM doesn't return one. to get the top match regardless of geometry type, set which_result=1. Defaults to None.

None
by_osmid bool

If True, handle query as an OSM ID for lookup rather than text search. Defaults to False.

False
buffer_dist float

Distance to buffer around the place geometry, in meters. Defaults to None.

None
to_ee bool

Whether to convert the csv to an ee.FeatureCollection.

False
geodesic bool

Whether line segments should be interpreted as spherical geodesics. If false, indicates that line segments should be interpreted as planar lines in the specified CRS. If absent, defaults to true if the CRS is geographic (including the default EPSG:4326), or to false if the CRS is projected.

True
Source code in geemap/geemap.py
def add_osm(
    self,
    query,
    layer_name="Untitled",
    style={},
    hover_style={},
    style_callback=None,
    fill_colors=["black"],
    info_mode="on_hover",
    which_result=None,
    by_osmid=False,
    buffer_dist=None,
    to_ee=False,
    geodesic=True,
):
    """Adds OSM data to the map.

    Args:
        query (str | dict | list): Query string(s) or structured dict(s) to geocode.
        layer_name (str, optional): The layer name to be used.. Defaults to "Untitled".
        style (dict, optional): A dictionary specifying the style to be used. Defaults to {}.
        hover_style (dict, optional): Hover style dictionary. Defaults to {}.
        style_callback (function, optional): Styling function that is called for each feature, and should return the feature style. This styling function takes the feature as argument. Defaults to None.
        fill_colors (list, optional): The random colors to use for filling polygons. Defaults to ["black"].
        info_mode (str, optional): Displays the attributes by either on_hover or on_click. Any value other than "on_hover" or "on_click" will be treated as None. Defaults to "on_hover".
        which_result (INT, optional): Which geocoding result to use. if None, auto-select the first (Multi)Polygon or raise an error if OSM doesn't return one. to get the top match regardless of geometry type, set which_result=1. Defaults to None.
        by_osmid (bool, optional): If True, handle query as an OSM ID for lookup rather than text search. Defaults to False.
        buffer_dist (float, optional): Distance to buffer around the place geometry, in meters. Defaults to None.
        to_ee (bool, optional): Whether to convert the csv to an ee.FeatureCollection.
        geodesic (bool, optional): Whether line segments should be interpreted as spherical geodesics. If false, indicates that line segments should be interpreted as planar lines in the specified CRS. If absent, defaults to true if the CRS is geographic (including the default EPSG:4326), or to false if the CRS is projected.

    """

    gdf = osm_to_geopandas(
        query, which_result=which_result, by_osmid=by_osmid, buffer_dist=buffer_dist
    )
    geojson = gdf.__geo_interface__

    if to_ee:
        fc = geojson_to_ee(geojson, geodesic=geodesic)
        self.addLayer(fc, {}, layer_name)
        self.zoomToObject(fc)
    else:
        self.add_geojson(
            geojson,
            layer_name=layer_name,
            style=style,
            hover_style=hover_style,
            style_callback=style_callback,
            fill_colors=fill_colors,
            info_mode=info_mode,
        )
        bounds = gdf.bounds.iloc[0]
        self.fit_bounds([[bounds[1], bounds[0]], [bounds[3], bounds[2]]])

add_planet_by_month(self, year=2016, month=1, name=None, api_key=None, token_name='PLANET_API_KEY')

Adds a Planet global mosaic by month to the map. To get a Planet API key, see https://developers.planet.com/quickstart/apis

Parameters:

Name Type Description Default
year int

The year of Planet global mosaic, must be >=2016. Defaults to 2016.

2016
month int

The month of Planet global mosaic, must be 1-12. Defaults to 1.

1
name str

The layer name to use. Defaults to None.

None
api_key str

The Planet API key. Defaults to None.

None
token_name str

The environment variable name of the API key. Defaults to "PLANET_API_KEY".

'PLANET_API_KEY'
Source code in geemap/geemap.py
def add_planet_by_month(
    self, year=2016, month=1, name=None, api_key=None, token_name="PLANET_API_KEY"
):
    """Adds a Planet global mosaic by month to the map. To get a Planet API key, see https://developers.planet.com/quickstart/apis

    Args:
        year (int, optional): The year of Planet global mosaic, must be >=2016. Defaults to 2016.
        month (int, optional): The month of Planet global mosaic, must be 1-12. Defaults to 1.
        name (str, optional): The layer name to use. Defaults to None.
        api_key (str, optional): The Planet API key. Defaults to None.
        token_name (str, optional): The environment variable name of the API key. Defaults to "PLANET_API_KEY".
    """
    layer = planet_tile_by_month(year, month, name, api_key, token_name)
    self.add_layer(layer)

add_planet_by_quarter(self, year=2016, quarter=1, name=None, api_key=None, token_name='PLANET_API_KEY')

Adds a Planet global mosaic by quarter to the map. To get a Planet API key, see https://developers.planet.com/quickstart/apis

Parameters:

Name Type Description Default
year int

The year of Planet global mosaic, must be >=2016. Defaults to 2016.

2016
quarter int

The quarter of Planet global mosaic, must be 1-12. Defaults to 1.

1
name str

The layer name to use. Defaults to None.

None
api_key str

The Planet API key. Defaults to None.

None
token_name str

The environment variable name of the API key. Defaults to "PLANET_API_KEY".

'PLANET_API_KEY'
Source code in geemap/geemap.py
def add_planet_by_quarter(
    self, year=2016, quarter=1, name=None, api_key=None, token_name="PLANET_API_KEY"
):
    """Adds a Planet global mosaic by quarter to the map. To get a Planet API key, see https://developers.planet.com/quickstart/apis

    Args:
        year (int, optional): The year of Planet global mosaic, must be >=2016. Defaults to 2016.
        quarter (int, optional): The quarter of Planet global mosaic, must be 1-12. Defaults to 1.
        name (str, optional): The layer name to use. Defaults to None.
        api_key (str, optional): The Planet API key. Defaults to None.
        token_name (str, optional): The environment variable name of the API key. Defaults to "PLANET_API_KEY".
    """
    layer = planet_tile_by_quarter(year, quarter, name, api_key, token_name)
    self.add_layer(layer)

add_raster(self, image, bands=None, layer_name=None, colormap=None, x_dim='x', y_dim='y')

Adds a local raster dataset to the map.

Parameters:

Name Type Description Default
image str

The image file path.

required
bands int or list

The image bands to use. It can be either a number (e.g., 1) or a list (e.g., [3, 2, 1]). Defaults to None.

None
layer_name str

The layer name to use for the raster. Defaults to None.

None
colormap str

The name of the colormap to use for the raster, such as 'gray' and 'terrain'. More can be found at https://matplotlib.org/3.1.0/tutorials/colors/colormaps.html. Defaults to None.

None
x_dim str

The x dimension. Defaults to 'x'.

'x'
y_dim str

The y dimension. Defaults to 'y'.

'y'
Source code in geemap/geemap.py
def add_raster(
    self,
    image,
    bands=None,
    layer_name=None,
    colormap=None,
    x_dim="x",
    y_dim="y",
):
    """Adds a local raster dataset to the map.

    Args:
        image (str): The image file path.
        bands (int or list, optional): The image bands to use. It can be either a number (e.g., 1) or a list (e.g., [3, 2, 1]). Defaults to None.
        layer_name (str, optional): The layer name to use for the raster. Defaults to None.
        colormap (str, optional): The name of the colormap to use for the raster, such as 'gray' and 'terrain'. More can be found at https://matplotlib.org/3.1.0/tutorials/colors/colormaps.html. Defaults to None.
        x_dim (str, optional): The x dimension. Defaults to 'x'.
        y_dim (str, optional): The y dimension. Defaults to 'y'.
    """
    try:
        import xarray_leaflet

    except Exception:
        # import platform
        # if platform.system() != "Windows":
        #     # install_from_github(
        #     #     url='https://github.com/davidbrochart/xarray_leaflet')
        #     check_install('xarray_leaflet')
        #     import xarray_leaflet
        # else:
        raise ImportError(
            "You need to install xarray_leaflet first. See https://github.com/davidbrochart/xarray_leaflet"
        )

    import warnings

    # import xarray as xr
    import matplotlib.pyplot as plt
    import numpy as np
    import rioxarray

    warnings.simplefilter("ignore")

    if not os.path.exists(image):
        print("The image file does not exist.")
        return

    if colormap is None:
        colormap = plt.cm.inferno

    if layer_name is None:
        layer_name = "Layer_" + random_string()

    if isinstance(colormap, str):
        colormap = plt.cm.get_cmap(name=colormap)

    da = rioxarray.open_rasterio(image, masked=True)

    # print(da.rio.nodata)

    multi_band = False
    if len(da.band) > 1:
        multi_band = True
        if bands is None:
            bands = [3, 2, 1]
    else:
        bands = 1

    if multi_band:
        da = da.rio.write_nodata(0)
    else:
        da = da.rio.write_nodata(np.nan)
    da = da.sel(band=bands)

    # crs = da.rio.crs
    # nan = da.attrs['nodatavals'][0]
    # da = da / da.max()
    # # if multi_band:
    # da = xr.where(da == nan, np.nan, da)
    # da = da.rio.write_nodata(0)
    # da = da.rio.write_crs(crs)

    if multi_band and type(bands) == list:
        layer = da.leaflet.plot(self, x_dim=x_dim, y_dim=y_dim, rgb_dim="band")
    else:
        layer = da.leaflet.plot(self, x_dim=x_dim, y_dim=y_dim, colormap=colormap)

    layer.name = layer_name

add_shapefile(self, in_shp, layer_name='Untitled', style={}, hover_style={}, style_callback=None, fill_colors=['black'], info_mode='on_hover')

Adds a shapefile to the map.

Parameters:

Name Type Description Default
in_shp str

The input file path to the shapefile.

required
layer_name str

The layer name to be used.. Defaults to "Untitled".

'Untitled'
style dict

A dictionary specifying the style to be used. Defaults to {}.

{}
hover_style dict

Hover style dictionary. Defaults to {}.

{}
style_callback function

Styling function that is called for each feature, and should return the feature style. This styling function takes the feature as argument. Defaults to None.

None
fill_colors list

The random colors to use for filling polygons. Defaults to ["black"].

['black']
info_mode str

Displays the attributes by either on_hover or on_click. Any value other than "on_hover" or "on_click" will be treated as None. Defaults to "on_hover".

'on_hover'

Exceptions:

Type Description
FileNotFoundError

The provided shapefile could not be found.

Source code in geemap/geemap.py
def add_shapefile(
    self,
    in_shp,
    layer_name="Untitled",
    style={},
    hover_style={},
    style_callback=None,
    fill_colors=["black"],
    info_mode="on_hover",
):
    """Adds a shapefile to the map.

    Args:
        in_shp (str): The input file path to the shapefile.
        layer_name (str, optional): The layer name to be used.. Defaults to "Untitled".
        style (dict, optional): A dictionary specifying the style to be used. Defaults to {}.
        hover_style (dict, optional): Hover style dictionary. Defaults to {}.
        style_callback (function, optional): Styling function that is called for each feature, and should return the feature style. This styling function takes the feature as argument. Defaults to None.
        fill_colors (list, optional): The random colors to use for filling polygons. Defaults to ["black"].
        info_mode (str, optional): Displays the attributes by either on_hover or on_click. Any value other than "on_hover" or "on_click" will be treated as None. Defaults to "on_hover".

    Raises:
        FileNotFoundError: The provided shapefile could not be found.
    """
    in_shp = os.path.abspath(in_shp)
    if not os.path.exists(in_shp):
        raise FileNotFoundError("The provided shapefile could not be found.")

    geojson = shp_to_geojson(in_shp)
    self.add_geojson(
        geojson,
        layer_name,
        style,
        hover_style,
        style_callback,
        fill_colors,
        info_mode,
    )

add_stac_layer(self, url, bands=None, name='Untitled', attribution='', opacity=1.0, shown=True, titiler_endpoint='https://api.cogeo.xyz/', **kwargs)

Adds a STAC TileLayer to the map.

Parameters:

Name Type Description Default
url str

The URL of the COG tile layer.

required
name str

The layer name to use for the layer. Defaults to 'Untitled'.

'Untitled'
attribution str

The attribution to use. Defaults to ''.

''
opacity float

The opacity of the layer. Defaults to 1.

1.0
shown bool

A flag indicating whether the layer should be on by default. Defaults to True.

True
titiler_endpoint str

Titiler endpoint. Defaults to "https://api.cogeo.xyz/".

'https://api.cogeo.xyz/'
Source code in geemap/geemap.py
def add_stac_layer(
    self,
    url,
    bands=None,
    name="Untitled",
    attribution="",
    opacity=1.0,
    shown=True,
    titiler_endpoint="https://api.cogeo.xyz/",
    **kwargs,
):
    """Adds a STAC TileLayer to the map.

    Args:
        url (str): The URL of the COG tile layer.
        name (str, optional): The layer name to use for the layer. Defaults to 'Untitled'.
        attribution (str, optional): The attribution to use. Defaults to ''.
        opacity (float, optional): The opacity of the layer. Defaults to 1.
        shown (bool, optional): A flag indicating whether the layer should be on by default. Defaults to True.
        titiler_endpoint (str, optional): Titiler endpoint. Defaults to "https://api.cogeo.xyz/".
    """
    tile_url = get_stac_tile(url, bands, titiler_endpoint, **kwargs)
    center = get_stac_center(url, titiler_endpoint)
    self.add_tile_layer(tile_url, name, attribution, opacity, shown)
    self.set_center(lon=center[0], lat=center[1], zoom=10)

add_styled_vector(self, ee_object, column, palette, layer_name='Untitled', **kwargs)

Adds a styled vector to the map.

Parameters:

Name Type Description Default
ee_object object

An ee.FeatureCollection.

required
column str

The column name to use for styling.

required
palette list | dict

The palette (e.g., list of colors or a dict containing label and color pairs) to use for styling.

required
layer_name str

The name to be used for the new layer. Defaults to "Untitled".

'Untitled'
Source code in geemap/geemap.py
def add_styled_vector(
    self, ee_object, column, palette, layer_name="Untitled", **kwargs
):
    """Adds a styled vector to the map.

    Args:
        ee_object (object): An ee.FeatureCollection.
        column (str): The column name to use for styling.
        palette (list | dict): The palette (e.g., list of colors or a dict containing label and color pairs) to use for styling.
        layer_name (str, optional): The name to be used for the new layer. Defaults to "Untitled".
    """
    styled_vector = vector_styling(ee_object, column, palette, **kwargs)
    self.addLayer(styled_vector.style(**{"styleProperty": "style"}), {}, layer_name)

add_tile_layer(self, url='https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', name='Untitled', attribution='', opacity=1.0, shown=True, **kwargs)

Adds a TileLayer to the map.

Parameters:

Name Type Description Default
url str

The URL of the tile layer. Defaults to 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'.

'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'
name str

The layer name to use for the layer. Defaults to 'Untitled'.

'Untitled'
attribution str

The attribution to use. Defaults to ''.

''
opacity float

The opacity of the layer. Defaults to 1.

1.0
shown bool

A flag indicating whether the layer should be on by default. Defaults to True.

True
Source code in geemap/geemap.py
def add_tile_layer(
    self,
    url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
    name="Untitled",
    attribution="",
    opacity=1.0,
    shown=True,
    **kwargs,
):
    """Adds a TileLayer to the map.

    Args:
        url (str, optional): The URL of the tile layer. Defaults to 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'.
        name (str, optional): The layer name to use for the layer. Defaults to 'Untitled'.
        attribution (str, optional): The attribution to use. Defaults to ''.
        opacity (float, optional): The opacity of the layer. Defaults to 1.
        shown (bool, optional): A flag indicating whether the layer should be on by default. Defaults to True.
    """
    try:
        tile_layer = ipyleaflet.TileLayer(
            url=url,
            name=name,
            attribution=attribution,
            opacity=opacity,
            visible=shown,
            **kwargs,
        )
        self.add_layer(tile_layer)

    except Exception as e:
        print("Failed to add the specified TileLayer.")
        raise Exception(e)

add_time_slider(self, ee_object, vis_params={}, region=None, layer_name='Time series', labels=None, time_interval=1, position='bottomright', slider_length='150px', date_format='YYYY-MM-dd')

Adds a time slider to the map.

Parameters:

Name Type Description Default
ee_object ee.Image | ee.ImageCollection

The Image or ImageCollection to visualize.

required
vis_params dict

Visualization parameters to use for visualizing image. Defaults to {}.

{}
region ee.Geometry | ee.FeatureCollection

The region to visualize.

None
layer_name str

The layer name to be used. Defaults to "Time series".

'Time series'
labels list

The list of labels to be used for the time series. Defaults to None.

None
time_interval int

Time interval in seconds. Defaults to 1.

1
position str

Position to place the time slider, can be any of ['topleft', 'topright', 'bottomleft', 'bottomright']. Defaults to "bottomright".

'bottomright'
slider_length str

Length of the time slider. Defaults to "150px".

'150px'
date_format str

The date format to use. Defaults to 'YYYY-MM-dd'.

'YYYY-MM-dd'

Exceptions:

Type Description
TypeError

If the ee_object is not ee.Image | ee.ImageCollection.

Source code in geemap/geemap.py
def add_time_slider(
    self,
    ee_object,
    vis_params={},
    region=None,
    layer_name="Time series",
    labels=None,
    time_interval=1,
    position="bottomright",
    slider_length="150px",
    date_format="YYYY-MM-dd",
):
    """Adds a time slider to the map.

    Args:
        ee_object (ee.Image | ee.ImageCollection): The Image or ImageCollection to visualize.
        vis_params (dict, optional): Visualization parameters to use for visualizing image. Defaults to {}.
        region (ee.Geometry | ee.FeatureCollection): The region to visualize.
        layer_name (str, optional): The layer name to be used. Defaults to "Time series".
        labels (list, optional): The list of labels to be used for the time series. Defaults to None.
        time_interval (int, optional): Time interval in seconds. Defaults to 1.
        position (str, optional): Position to place the time slider, can be any of ['topleft', 'topright', 'bottomleft', 'bottomright']. Defaults to "bottomright".
        slider_length (str, optional): Length of the time slider. Defaults to "150px".
        date_format (str, optional): The date format to use. Defaults to 'YYYY-MM-dd'.

    Raises:
        TypeError: If the ee_object is not ee.Image | ee.ImageCollection.
    """
    import threading

    if isinstance(ee_object, ee.Image):
        if region is not None:
            if isinstance(region, ee.Geometry):
                ee_object = ee_object.clip(region)
            elif isinstance(region, ee.FeatureCollection):
                ee_object = ee_object.clipToCollection(region)
        if layer_name not in self.ee_raster_layer_names:
            self.addLayer(ee_object, {}, layer_name, False)
        band_names = ee_object.bandNames()
        ee_object = ee.ImageCollection(
            ee_object.bandNames().map(lambda b: ee_object.select([b]))
        )

        if labels is not None:
            if len(labels) != int(ee_object.size().getInfo()):
                raise ValueError(
                    "The length of labels must be equal to the number of bands in the image."
                )
        else:
            labels = band_names.getInfo()

    elif isinstance(ee_object, ee.ImageCollection):
        if region is not None:
            if isinstance(region, ee.Geometry):
                ee_object = ee_object.map(lambda img: img.clip(region))
            elif isinstance(region, ee.FeatureCollection):
                ee_object = ee_object.map(lambda img: img.clipToCollection(region))

        if labels is not None:
            if len(labels) != int(ee_object.size().getInfo()):
                raise ValueError(
                    "The length of labels must be equal to the number of images in the ImageCollection."
                )
        else:
            labels = (
                ee_object.aggregate_array("system:time_start")
                .map(lambda d: ee.Date(d).format(date_format))
                .getInfo()
            )
    else:
        raise TypeError("The ee_object must be an ee.Image or ee.ImageCollection")

    # if labels is not None:
    #     size = len(labels)
    # else:
    #     size = ee_object.size().getInfo()
    #     labels = [str(i) for i in range(1, size + 1)]

    first = ee.Image(ee_object.first())

    if layer_name not in self.ee_raster_layer_names:
        self.addLayer(ee_object.toBands(), {}, layer_name, False)
    self.addLayer(first, vis_params, "Image X")

    slider = widgets.IntSlider(
        min=1,
        max=len(labels),
        readout=False,
        continuous_update=False,
        layout=widgets.Layout(width=slider_length),
    )
    label = widgets.Label(
        value=labels[0], layout=widgets.Layout(padding="0px 5px 0px 5px")
    )

    play_btn = widgets.Button(
        icon="play",
        tooltip="Play the time slider",
        button_style="primary",
        layout=widgets.Layout(width="32px"),
    )

    pause_btn = widgets.Button(
        icon="pause",
        tooltip="Pause the time slider",
        button_style="primary",
        layout=widgets.Layout(width="32px"),
    )

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

    play_chk = widgets.Checkbox(value=False)

    slider_widget = widgets.HBox([slider, label, play_btn, pause_btn, close_btn])

    def play_click(b):

        play_chk.value = True

        def work(slider):
            while play_chk.value:
                if slider.value < len(labels):
                    slider.value += 1
                else:
                    slider.value = 1
                time.sleep(time_interval)

        thread = threading.Thread(target=work, args=(slider,))
        thread.start()

    def pause_click(b):
        play_chk.value = False

    play_btn.on_click(play_click)
    pause_btn.on_click(pause_click)

    def slider_changed(change):
        self.default_style = {"cursor": "wait"}
        index = slider.value - 1
        label.value = labels[index]
        image = ee.Image(ee_object.toList(ee_object.size()).get(index))
        if layer_name not in self.ee_raster_layer_names:
            self.addLayer(ee_object.toBands(), {}, layer_name, False)
        self.addLayer(image, vis_params, "Image X")
        self.default_style = {"cursor": "default"}

    slider.observe(slider_changed, "value")

    def close_click(b):
        play_chk.value = False
        self.toolbar_reset()
        self.remove_ee_layer("Image X")
        self.remove_ee_layer(layer_name)

        if self.slider_ctrl is not None and self.slider_ctrl in self.controls:
            self.remove_control(self.slider_ctrl)
        slider_widget.close()

    close_btn.on_click(close_click)

    slider_ctrl = ipyleaflet.WidgetControl(widget=slider_widget, position=position)
    self.add_control(slider_ctrl)
    self.slider_ctrl = slider_ctrl

add_vector(self, filename, layer_name='Untitled', to_ee=False, bbox=None, mask=None, rows=None, style={}, hover_style={}, style_callback=None, fill_colors=['black'], info_mode='on_hover', **kwargs)

Adds any geopandas-supported vector dataset to the map.

Parameters:

Name Type Description Default
filename str

Either the absolute or relative path to the file or URL to be opened, or any object with a read() method (such as an open file or StringIO).

required
layer_name str

The layer name to use. Defaults to "Untitled".

'Untitled'
to_ee bool

Whether to convert the GeoJSON to ee.FeatureCollection. Defaults to False.

False
bbox tuple | GeoDataFrame or GeoSeries | shapely Geometry

Filter features by given bounding box, GeoSeries, GeoDataFrame or a shapely geometry. CRS mis-matches are resolved if given a GeoSeries or GeoDataFrame. Cannot be used with mask. Defaults to None.

None
mask dict | GeoDataFrame or GeoSeries | shapely Geometry

Filter for features that intersect with the given dict-like geojson geometry, GeoSeries, GeoDataFrame or shapely geometry. CRS mis-matches are resolved if given a GeoSeries or GeoDataFrame. Cannot be used with bbox. Defaults to None.

None
rows int or slice

Load in specific rows by passing an integer (first n rows) or a slice() object.. Defaults to None.

None
style dict

A dictionary specifying the style to be used. Defaults to {}.

{}
hover_style dict

Hover style dictionary. Defaults to {}.

{}
style_callback function

Styling function that is called for each feature, and should return the feature style. This styling function takes the feature as argument. Defaults to None.

None
fill_colors list

The random colors to use for filling polygons. Defaults to ["black"].

['black']
info_mode str

Displays the attributes by either on_hover or on_click. Any value other than "on_hover" or "on_click" will be treated as None. Defaults to "on_hover".

'on_hover'
Source code in geemap/geemap.py
def add_vector(
    self,
    filename,
    layer_name="Untitled",
    to_ee=False,
    bbox=None,
    mask=None,
    rows=None,
    style={},
    hover_style={},
    style_callback=None,
    fill_colors=["black"],
    info_mode="on_hover",
    **kwargs,
):
    """Adds any geopandas-supported vector dataset to the map.

    Args:
        filename (str): Either the absolute or relative path to the file or URL to be opened, or any object with a read() method (such as an open file or StringIO).
        layer_name (str, optional): The layer name to use. Defaults to "Untitled".
        to_ee (bool, optional): Whether to convert the GeoJSON to ee.FeatureCollection. Defaults to False.
        bbox (tuple | GeoDataFrame or GeoSeries | shapely Geometry, optional): Filter features by given bounding box, GeoSeries, GeoDataFrame or a shapely geometry. CRS mis-matches are resolved if given a GeoSeries or GeoDataFrame. Cannot be used with mask. Defaults to None.
        mask (dict | GeoDataFrame or GeoSeries | shapely Geometry, optional): Filter for features that intersect with the given dict-like geojson geometry, GeoSeries, GeoDataFrame or shapely geometry. CRS mis-matches are resolved if given a GeoSeries or GeoDataFrame. Cannot be used with bbox. Defaults to None.
        rows (int or slice, optional): Load in specific rows by passing an integer (first n rows) or a slice() object.. Defaults to None.
        style (dict, optional): A dictionary specifying the style to be used. Defaults to {}.
        hover_style (dict, optional): Hover style dictionary. Defaults to {}.
        style_callback (function, optional): Styling function that is called for each feature, and should return the feature style. This styling function takes the feature as argument. Defaults to None.
        fill_colors (list, optional): The random colors to use for filling polygons. Defaults to ["black"].
        info_mode (str, optional): Displays the attributes by either on_hover or on_click. Any value other than "on_hover" or "on_click" will be treated as None. Defaults to "on_hover".

    """
    if not filename.startswith("http"):
        filename = os.path.abspath(filename)
    if to_ee:

        fc = vector_to_ee(
            filename,
            bbox=bbox,
            mask=mask,
            rows=rows,
            geodesic=True,
            **kwargs,
        )

        self.addLayer(fc, {}, layer_name)
    else:

        ext = os.path.splitext(filename)[1].lower()
        if ext == ".shp":
            self.add_shapefile(
                filename,
                layer_name,
                style,
                hover_style,
                style_callback,
                fill_colors,
                info_mode,
            )
        elif ext in [".json", ".geojson"]:
            self.add_geojson(
                filename,
                layer_name,
                style,
                hover_style,
                style_callback,
                fill_colors,
                info_mode,
            )
        else:
            geojson = vector_to_geojson(
                filename,
                bbox=bbox,
                mask=mask,
                rows=rows,
                epsg="4326",
                **kwargs,
            )

            self.add_geojson(
                geojson,
                layer_name,
                style,
                hover_style,
                style_callback,
                fill_colors,
                info_mode,
            )

add_wms_layer(self, url, layers, name=None, attribution='', format='image/jpeg', transparent=False, opacity=1.0, shown=True, **kwargs)

Add a WMS layer to the map.

Parameters:

Name Type Description Default
url str

The URL of the WMS web service.

required
layers str

Comma-separated list of WMS layers to show.

required
name str

The layer name to use on the layer control. Defaults to None.

None
attribution str

The attribution of the data layer. Defaults to ''.

''
format str

WMS image format (use ‘image/png’ for layers with transparency). Defaults to 'image/jpeg'.

'image/jpeg'
transparent bool

If True, the WMS service will return images with transparency. Defaults to False.

False
opacity float

The opacity of the layer. Defaults to 1.0.

1.0
shown bool

A flag indicating whether the layer should be on by default. Defaults to True.

True
Source code in geemap/geemap.py
def add_wms_layer(
    self,
    url,
    layers,
    name=None,
    attribution="",
    format="image/jpeg",
    transparent=False,
    opacity=1.0,
    shown=True,
    **kwargs,
):
    """Add a WMS layer to the map.

    Args:
        url (str): The URL of the WMS web service.
        layers (str): Comma-separated list of WMS layers to show.
        name (str, optional): The layer name to use on the layer control. Defaults to None.
        attribution (str, optional): The attribution of the data layer. Defaults to ''.
        format (str, optional): WMS image format (use ‘image/png’ for layers with transparency). Defaults to 'image/jpeg'.
        transparent (bool, optional): If True, the WMS service will return images with transparency. Defaults to False.
        opacity (float, optional): The opacity of the layer. Defaults to 1.0.
        shown (bool, optional): A flag indicating whether the layer should be on by default. Defaults to True.
    """

    if name is None:
        name = str(layers)

    try:
        wms_layer = ipyleaflet.WMSLayer(
            url=url,
            layers=layers,
            name=name,
            attribution=attribution,
            format=format,
            transparent=transparent,
            opacity=opacity,
            visible=shown,
            **kwargs,
        )
        self.add_layer(wms_layer)

    except Exception as e:
        print("Failed to add the specified WMS TileLayer.")
        raise Exception(e)

add_xy_data(self, in_csv, x='longitude', y='latitude', label=None, layer_name='Marker cluster', to_ee=False)

Adds points from a CSV file containing lat/lon information and display data on the map.

Parameters:

Name Type Description Default
in_csv str

The file path to the input CSV file.

required
x str

The name of the column containing longitude coordinates. Defaults to "longitude".

'longitude'
y str

The name of the column containing latitude coordinates. Defaults to "latitude".

'latitude'
label str

The name of the column containing label information to used for marker popup. Defaults to None.

None
layer_name str

The layer name to use. Defaults to "Marker cluster".

'Marker cluster'
to_ee bool

Whether to convert the csv to an ee.FeatureCollection.

False

Exceptions:

Type Description
FileNotFoundError

The specified input csv does not exist.

ValueError

The specified x column does not exist.

ValueError

The specified y column does not exist.

ValueError

The specified label column does not exist.

Source code in geemap/geemap.py
def add_xy_data(
    self,
    in_csv,
    x="longitude",
    y="latitude",
    label=None,
    layer_name="Marker cluster",
    to_ee=False,
):
    """Adds points from a CSV file containing lat/lon information and display data on the map.

    Args:
        in_csv (str): The file path to the input CSV file.
        x (str, optional): The name of the column containing longitude coordinates. Defaults to "longitude".
        y (str, optional): The name of the column containing latitude coordinates. Defaults to "latitude".
        label (str, optional): The name of the column containing label information to used for marker popup. Defaults to None.
        layer_name (str, optional): The layer name to use. Defaults to "Marker cluster".
        to_ee (bool, optional): Whether to convert the csv to an ee.FeatureCollection.

    Raises:
        FileNotFoundError: The specified input csv does not exist.
        ValueError: The specified x column does not exist.
        ValueError: The specified y column does not exist.
        ValueError: The specified label column does not exist.
    """
    import pandas as pd

    if not in_csv.startswith("http") and (not os.path.exists(in_csv)):
        raise FileNotFoundError("The specified input csv does not exist.")

    df = pd.read_csv(in_csv)
    col_names = df.columns.values.tolist()

    if x not in col_names:
        raise ValueError(f"x must be one of the following: {', '.join(col_names)}")

    if y not in col_names:
        raise ValueError(f"y must be one of the following: {', '.join(col_names)}")

    if label is not None and (label not in col_names):
        raise ValueError(
            f"label must be one of the following: {', '.join(col_names)}"
        )

    self.default_style = {"cursor": "wait"}

    if to_ee:
        fc = csv_to_ee(in_csv, latitude=y, longitude=x)
        self.addLayer(fc, {}, layer_name)

    else:
        points = list(zip(df[y], df[x]))

        if label is not None:
            labels = df[label]
            markers = [
                ipyleaflet.Marker(
                    location=point,
                    draggable=False,
                    popup=widgets.HTML(str(labels[index])),
                )
                for index, point in enumerate(points)
            ]
        else:
            markers = [
                ipyleaflet.Marker(location=point, draggable=False)
                for point in points
            ]

        marker_cluster = ipyleaflet.MarkerCluster(markers=markers, name=layer_name)
        self.add_layer(marker_cluster)

    self.default_style = {"cursor": "default"}

addLayer(self, ee_object, vis_params={}, name=None, shown=True, opacity=1.0)

Adds a given EE object to the map as a layer.

Parameters:

Name Type Description Default
ee_object Collection|Feature|Image|MapId

The object to add to the map.

required
vis_params dict

The visualization parameters. Defaults to {}.

{}
name str

The name of the layer. Defaults to 'Layer N'.

None
shown bool

A flag indicating whether the layer should be on by default. Defaults to True.

True
opacity float

The layer's opacity represented as a number between 0 and 1. Defaults to 1.

1.0
Source code in geemap/geemap.py
def add_ee_layer(
    self, ee_object, vis_params={}, name=None, shown=True, opacity=1.0
):
    """Adds a given EE object to the map as a layer.

    Args:
        ee_object (Collection|Feature|Image|MapId): The object to add to the map.
        vis_params (dict, optional): The visualization parameters. Defaults to {}.
        name (str, optional): The name of the layer. Defaults to 'Layer N'.
        shown (bool, optional): A flag indicating whether the layer should be on by default. Defaults to True.
        opacity (float, optional): The layer's opacity represented as a number between 0 and 1. Defaults to 1.
    """
    from box import Box

    image = None
    if name is None:
        layer_count = len(self.layers)
        name = "Layer " + str(layer_count + 1)

    if (
        not isinstance(ee_object, ee.Image)
        and not isinstance(ee_object, ee.ImageCollection)
        and not isinstance(ee_object, ee.FeatureCollection)
        and not isinstance(ee_object, ee.Feature)
        and not isinstance(ee_object, ee.Geometry)
    ):
        err_str = "\n\nThe image argument in 'addLayer' function must be an instance of one of ee.Image, ee.Geometry, ee.Feature or ee.FeatureCollection."
        raise AttributeError(err_str)

    if (
        isinstance(ee_object, ee.geometry.Geometry)
        or isinstance(ee_object, ee.feature.Feature)
        or isinstance(ee_object, ee.featurecollection.FeatureCollection)
    ):
        features = ee.FeatureCollection(ee_object)

        width = 2

        if "width" in vis_params:
            width = vis_params["width"]

        color = "000000"

        if "color" in vis_params:
            color = vis_params["color"]

        image_fill = features.style(**{"fillColor": color}).updateMask(
            ee.Image.constant(0.5)
        )
        image_outline = features.style(
            **{"color": color, "fillColor": "00000000", "width": width}
        )

        image = image_fill.blend(image_outline)
    elif isinstance(ee_object, ee.image.Image):
        image = ee_object
    elif isinstance(ee_object, ee.imagecollection.ImageCollection):
        image = ee_object.mosaic()

    if "palette" in vis_params and isinstance(vis_params["palette"], Box):
        try:
            vis_params["palette"] = vis_params["palette"]["default"]
        except Exception as e:
            print("The provided palette is invalid.")
            raise Exception(e)

    map_id_dict = ee.Image(image).getMapId(vis_params)
    tile_layer = ipyleaflet.TileLayer(
        url=map_id_dict["tile_fetcher"].url_format,
        attribution="Google Earth Engine",
        name=name,
        opacity=opacity,
        visible=shown,
    )

    layer = self.find_layer(name=name)
    if layer is not None:

        existing_object = self.ee_layer_dict[name]["ee_object"]

        if isinstance(existing_object, ee.Image) or isinstance(
            existing_object, ee.ImageCollection
        ):
            self.ee_raster_layers.remove(existing_object)
            self.ee_raster_layer_names.remove(name)
            if self.plot_dropdown_widget is not None:
                self.plot_dropdown_widget.options = list(self.ee_raster_layer_names)
        elif (
            isinstance(ee_object, ee.Geometry)
            or isinstance(ee_object, ee.Feature)
            or isinstance(ee_object, ee.FeatureCollection)
        ):
            self.ee_vector_layers.remove(existing_object)
            self.ee_vector_layer_names.remove(name)

        self.ee_layers.remove(existing_object)
        self.ee_layer_names.remove(name)
        self.remove_layer(layer)

    self.ee_layers.append(ee_object)
    if name not in self.ee_layer_names:
        self.ee_layer_names.append(name)
    self.ee_layer_dict[name] = {
        "ee_object": ee_object,
        "ee_layer": tile_layer,
        "vis_params": vis_params,
    }

    self.add_layer(tile_layer)
    self.last_ee_layer = self.ee_layer_dict[name]
    self.last_ee_data = self.ee_layer_dict[name]["ee_object"]

    if isinstance(ee_object, ee.Image) or isinstance(ee_object, ee.ImageCollection):
        self.ee_raster_layers.append(ee_object)
        self.ee_raster_layer_names.append(name)
        if self.plot_dropdown_widget is not None:
            self.plot_dropdown_widget.options = list(self.ee_raster_layer_names)
    elif (
        isinstance(ee_object, ee.Geometry)
        or isinstance(ee_object, ee.Feature)
        or isinstance(ee_object, ee.FeatureCollection)
    ):
        self.ee_vector_layers.append(ee_object)
        self.ee_vector_layer_names.append(name)

addLayerControl(self)

Adds the layer control to the map.

Source code in geemap/geemap.py
def add_layer_control(self):
    """Adds the layer control to the map."""
    pass

basemap_demo(self)

A demo for using geemap basemaps.

Source code in geemap/geemap.py
def basemap_demo(self):
    """A demo for using geemap basemaps."""
    dropdown = widgets.Dropdown(
        options=list(basemap_tiles.keys()),
        value="HYBRID",
        description="Basemaps",
    )

    def on_click(change):
        basemap_name = change["new"]
        old_basemap = self.layers[-1]
        self.substitute_layer(old_basemap, basemap_tiles[basemap_name])

    dropdown.observe(on_click, "value")
    basemap_control = ipyleaflet.WidgetControl(widget=dropdown, position="topright")
    self.add_control(basemap_control)

center_object(self, ee_object, zoom=None)

Centers the map view on a given object.

Parameters:

Name Type Description Default
ee_object Element|Geometry

An Earth Engine object to center on a geometry, image or feature.

required
zoom int

The zoom level, from 1 to 24. Defaults to None.

None
Source code in geemap/geemap.py
def center_object(self, ee_object, zoom=None):
    """Centers the map view on a given object.

    Args:
        ee_object (Element|Geometry): An Earth Engine object to center on a geometry, image or feature.
        zoom (int, optional): The zoom level, from 1 to 24. Defaults to None.
    """
    if zoom is None and hasattr(self, "fit_bounds"):
        self.zoom_to_object(ee_object)
    else:
        lat = 0
        lon = 0
        if isinstance(ee_object, ee.geometry.Geometry):
            centroid = ee_object.centroid(1)
            lon, lat = centroid.getInfo()["coordinates"]
        else:
            try:
                centroid = ee_object.geometry().centroid(1)
                lon, lat = centroid.getInfo()["coordinates"]
            except Exception as e:
                print(e)
                raise Exception(e)

        self.setCenter(lon, lat, zoom)

centerObject(self, ee_object, zoom=None)

Centers the map view on a given object.

Parameters:

Name Type Description Default
ee_object Element|Geometry

An Earth Engine object to center on a geometry, image or feature.

required
zoom int

The zoom level, from 1 to 24. Defaults to None.

None
Source code in geemap/geemap.py
def center_object(self, ee_object, zoom=None):
    """Centers the map view on a given object.

    Args:
        ee_object (Element|Geometry): An Earth Engine object to center on a geometry, image or feature.
        zoom (int, optional): The zoom level, from 1 to 24. Defaults to None.
    """
    if zoom is None and hasattr(self, "fit_bounds"):
        self.zoom_to_object(ee_object)
    else:
        lat = 0
        lon = 0
        if isinstance(ee_object, ee.geometry.Geometry):
            centroid = ee_object.centroid(1)
            lon, lat = centroid.getInfo()["coordinates"]
        else:
            try:
                centroid = ee_object.geometry().centroid(1)
                lon, lat = centroid.getInfo()["coordinates"]
            except Exception as e:
                print(e)
                raise Exception(e)

        self.setCenter(lon, lat, zoom)

create_vis_widget(self, layer_dict)

Create a GUI for changing layer visualization parameters interactively.

Parameters:

Name Type Description Default
layer_dict dict

A dict containning information about the layer. It is an element from Map.ee_layer_dict.

required

Returns:

Type Description
object

An ipywidget.

Source code in geemap/geemap.py
def create_vis_widget(self, layer_dict):
    """Create a GUI for changing layer visualization parameters interactively.

    Args:
        layer_dict (dict): A dict containning information about the layer. It is an element from Map.ee_layer_dict.

    Returns:
        object: An ipywidget.
    """

    import matplotlib as mpl
    import matplotlib.pyplot as plt

    ee_object = layer_dict["ee_object"]
    ee_layer = layer_dict["ee_layer"]
    vis_params = layer_dict["vis_params"]

    layer_name = ee_layer.name
    layer_opacity = ee_layer.opacity

    band_names = None
    min_value = 0
    max_value = 100
    sel_bands = None
    layer_palette = []
    layer_gamma = 1
    left_value = 0
    right_value = 10000

    self.colorbar_widget = widgets.Output(layout=widgets.Layout(height="60px"))
    self.colorbar_ctrl = ipyleaflet.WidgetControl(
        widget=self.colorbar_widget, position="bottomright"
    )
    self.add_control(self.colorbar_ctrl)

    # def vdir(obj):  # Get branca colormap list
    #     return [x for x in dir(obj) if not x.startswith("_")]

    if isinstance(ee_object, ee.Image):
        band_names = ee_object.bandNames().getInfo()
        band_count = len(band_names)

        if "min" in vis_params.keys():
            min_value = vis_params["min"]
            if min_value < left_value:
                left_value = min_value - max_value
        if "max" in vis_params.keys():
            max_value = vis_params["max"]
            right_value = 2 * max_value
        if "gamma" in vis_params.keys():
            layer_gamma = vis_params["gamma"]
        if "bands" in vis_params.keys():
            sel_bands = vis_params["bands"]
        if "palette" in vis_params.keys():
            layer_palette = [
                color.replace("#", "") for color in list(vis_params["palette"])
            ]

        vis_widget = widgets.VBox(
            layout=widgets.Layout(padding="5px 5px 5px 8px", width="330px")
        )
        label = widgets.Label(value=f"{layer_name} visualization parameters")

        radio1 = widgets.RadioButtons(
            options=["1 band (Grayscale)"], layout={"width": "max-content"}
        )
        radio2 = widgets.RadioButtons(
            options=["3 bands (RGB)"], layout={"width": "max-content"}
        )
        radio1.index = None
        radio2.index = None

        dropdown_width = "98px"
        band1_dropdown = widgets.Dropdown(
            options=band_names,
            value=band_names[0],
            layout=widgets.Layout(width=dropdown_width),
        )
        band2_dropdown = widgets.Dropdown(
            options=band_names,
            value=band_names[0],
            layout=widgets.Layout(width=dropdown_width),
        )
        band3_dropdown = widgets.Dropdown(
            options=band_names,
            value=band_names[0],
            layout=widgets.Layout(width=dropdown_width),
        )

        bands_hbox = widgets.HBox()

        legend_chk = widgets.Checkbox(
            value=False,
            description="Legend",
            indent=False,
            layout=widgets.Layout(width="70px"),
        )

        color_picker = widgets.ColorPicker(
            concise=False,
            value="#000000",
            layout=widgets.Layout(width="116px"),
            style={"description_width": "initial"},
        )

        add_color = widgets.Button(
            icon="plus",
            tooltip="Add a hex color string to the palette",
            layout=widgets.Layout(width="32px"),
        )

        del_color = widgets.Button(
            icon="minus",
            tooltip="Remove a hex color string from the palette",
            layout=widgets.Layout(width="32px"),
        )

        reset_color = widgets.Button(
            icon="eraser",
            tooltip="Remove all color strings from the palette",
            layout=widgets.Layout(width="34px"),
        )

        classes = widgets.Dropdown(
            options=["Any"] + [str(i) for i in range(3, 13)],
            description="Classes:",
            layout=widgets.Layout(width="115px"),
            style={"description_width": "initial"},
        )

        colormap = widgets.Dropdown(
            options=plt.colormaps(),
            value=None,
            description="Colormap:",
            layout=widgets.Layout(width="181px"),
            style={"description_width": "initial"},
        )

        def classes_changed(change):
            if change["new"]:
                selected = change["owner"].value
                if colormap.value is not None:

                    n_class = None
                    if selected != "Any":
                        n_class = int(classes.value)

                    colors = plt.cm.get_cmap(colormap.value, n_class)
                    cmap_colors = [
                        mpl.colors.rgb2hex(colors(i))[1:] for i in range(colors.N)
                    ]

                    _, ax = plt.subplots(figsize=(6, 0.4))
                    cmap = mpl.colors.LinearSegmentedColormap.from_list(
                        "custom", to_hex_colors(cmap_colors), N=256
                    )
                    norm = mpl.colors.Normalize(
                        vmin=value_range.value[0], vmax=value_range.value[1]
                    )
                    mpl.colorbar.ColorbarBase(
                        ax, norm=norm, cmap=cmap, orientation="horizontal"
                    )

                    palette.value = ", ".join([color for color in cmap_colors])

                    if self.colorbar_widget is None:
                        self.colorbar_widget = widgets.Output(
                            layout=widgets.Layout(height="60px")
                        )

                    if self.colorbar_ctrl is None:
                        self.colorbar_ctrl = ipyleaflet.WidgetControl(
                            widget=self.colorbar_widget, position="bottomright"
                        )
                        self.add_control(self.colorbar_ctrl)

                    colorbar_output = self.colorbar_widget
                    with colorbar_output:
                        colorbar_output.clear_output()
                        plt.show()

                    if len(palette.value) > 0 and "," in palette.value:
                        labels = [
                            f"Class {i+1}"
                            for i in range(len(palette.value.split(",")))
                        ]
                        legend_labels.value = ", ".join(labels)

        classes.observe(classes_changed, "value")

        palette = widgets.Text(
            value=", ".join(layer_palette),
            placeholder="List of hex color code (RRGGBB)",
            description="Palette:",
            tooltip="Enter a list of hex color code (RRGGBB)",
            layout=widgets.Layout(width="300px"),
            style={"description_width": "initial"},
        )

        def add_color_clicked(b):
            if color_picker.value is not None:
                if len(palette.value) == 0:
                    palette.value = color_picker.value[1:]
                else:
                    palette.value += ", " + color_picker.value[1:]

        def del_color_clicked(b):
            if "," in palette.value:
                items = [item.strip() for item in palette.value.split(",")]
                palette.value = ", ".join(items[:-1])
            else:
                palette.value = ""

        def reset_color_clicked(b):
            palette.value = ""

        add_color.on_click(add_color_clicked)
        del_color.on_click(del_color_clicked)
        reset_color.on_click(reset_color_clicked)

        spacer = widgets.Label(layout=widgets.Layout(width="5px"))
        v_spacer = widgets.Label(layout=widgets.Layout(height="5px"))
        radio_btn = widgets.HBox([radio1, spacer, spacer, spacer, radio2])

        value_range = widgets.FloatRangeSlider(
            value=[min_value, max_value],
            min=left_value,
            max=right_value,
            step=0.1,
            description="Range:",
            disabled=False,
            continuous_update=False,
            readout=True,
            readout_format=".1f",
            layout=widgets.Layout(width="300px"),
            style={"description_width": "45px"},
        )

        range_hbox = widgets.HBox([value_range, spacer])

        opacity = widgets.FloatSlider(
            value=layer_opacity,
            min=0,
            max=1,
            step=0.01,
            description="Opacity:",
            continuous_update=False,
            readout=True,
            readout_format=".2f",
            layout=widgets.Layout(width="320px"),
            style={"description_width": "50px"},
        )

        gamma = widgets.FloatSlider(
            value=layer_gamma,
            min=0.1,
            max=10,
            step=0.01,
            description="Gamma:",
            continuous_update=False,
            readout=True,
            readout_format=".2f",
            layout=widgets.Layout(width="320px"),
            style={"description_width": "50px"},
        )

        legend_chk = widgets.Checkbox(
            value=False,
            description="Legend",
            indent=False,
            layout=widgets.Layout(width="70px"),
        )

        linear_chk = widgets.Checkbox(
            value=True,
            description="Linear colormap",
            indent=False,
            layout=widgets.Layout(width="150px"),
        )

        step_chk = widgets.Checkbox(
            value=False,
            description="Step colormap",
            indent=False,
            layout=widgets.Layout(width="140px"),
        )

        legend_title = widgets.Text(
            value="Legend",
            description="Legend title:",
            tooltip="Enter a title for the legend",
            layout=widgets.Layout(width="300px"),
            style={"description_width": "initial"},
        )

        legend_labels = widgets.Text(
            value="Class 1, Class 2, Class 3",
            description="Legend labels:",
            tooltip="Enter a a list of labels for the legend",
            layout=widgets.Layout(width="300px"),
            style={"description_width": "initial"},
        )

        colormap_hbox = widgets.HBox([linear_chk, step_chk])
        legend_vbox = widgets.VBox()

        def linear_chk_changed(change):

            if change["new"]:
                step_chk.value = False
                legend_vbox.children = [colormap_hbox]
            else:
                step_chk.value = True

        def step_chk_changed(change):

            if change["new"]:
                linear_chk.value = False
                if len(layer_palette) > 0:
                    legend_labels.value = ",".join(
                        [
                            "Class " + str(i)
                            for i in range(1, len(layer_palette) + 1)
                        ]
                    )
                legend_vbox.children = [
                    colormap_hbox,
                    legend_title,
                    legend_labels,
                ]
            else:
                linear_chk.value = True

        linear_chk.observe(linear_chk_changed, "value")
        step_chk.observe(step_chk_changed, "value")

        def colormap_changed(change):
            if change["new"]:

                n_class = None
                if classes.value != "Any":
                    n_class = int(classes.value)

                colors = plt.cm.get_cmap(colormap.value, n_class)
                cmap_colors = [
                    mpl.colors.rgb2hex(colors(i))[1:] for i in range(colors.N)
                ]

                _, ax = plt.subplots(figsize=(6, 0.4))
                cmap = mpl.colors.LinearSegmentedColormap.from_list(
                    "custom", to_hex_colors(cmap_colors), N=256
                )
                norm = mpl.colors.Normalize(
                    vmin=value_range.value[0], vmax=value_range.value[1]
                )
                mpl.colorbar.ColorbarBase(
                    ax, norm=norm, cmap=cmap, orientation="horizontal"
                )

                palette.value = ", ".join(cmap_colors)

                if self.colorbar_widget is None:
                    self.colorbar_widget = widgets.Output(
                        layout=widgets.Layout(height="60px")
                    )

                if self.colorbar_ctrl is None:
                    self.colorbar_ctrl = ipyleaflet.WidgetControl(
                        widget=self.colorbar_widget, position="bottomright"
                    )
                    self.add_control(self.colorbar_ctrl)

                colorbar_output = self.colorbar_widget
                with colorbar_output:
                    colorbar_output.clear_output()
                    plt.show()
                    # display(colorbar)

                if len(palette.value) > 0 and "," in palette.value:
                    labels = [
                        f"Class {i+1}" for i in range(len(palette.value.split(",")))
                    ]
                    legend_labels.value = ", ".join(labels)

        colormap.observe(colormap_changed, "value")

        btn_width = "97.5px"
        import_btn = widgets.Button(
            description="Import",
            button_style="primary",
            tooltip="Import vis params to notebook",
            layout=widgets.Layout(width=btn_width),
        )

        apply_btn = widgets.Button(
            description="Apply",
            tooltip="Apply vis params to the layer",
            layout=widgets.Layout(width=btn_width),
        )

        close_btn = widgets.Button(
            description="Close",
            tooltip="Close vis params diaglog",
            layout=widgets.Layout(width=btn_width),
        )

        def import_btn_clicked(b):

            vis = {}
            if radio1.index == 0:
                vis["bands"] = [band1_dropdown.value]
                if len(palette.value) > 0:
                    vis["palette"] = palette.value.split(",")
            else:
                vis["bands"] = [
                    band1_dropdown.value,
                    band2_dropdown.value,
                    band3_dropdown.value,
                ]

            vis["min"] = value_range.value[0]
            vis["max"] = value_range.value[1]
            vis["opacity"] = opacity.value
            vis["gamma"] = gamma.value

            create_code_cell(f"vis_params = {str(vis)}")

        def apply_btn_clicked(b):

            vis = {}
            if radio1.index == 0:
                vis["bands"] = [band1_dropdown.value]
                if len(palette.value) > 0:
                    vis["palette"] = [c.strip() for c in palette.value.split(",")]
            else:
                vis["bands"] = [
                    band1_dropdown.value,
                    band2_dropdown.value,
                    band3_dropdown.value,
                ]
                vis["gamma"] = gamma.value

            vis["min"] = value_range.value[0]
            vis["max"] = value_range.value[1]

            self.addLayer(ee_object, vis, layer_name, True, opacity.value)
            ee_layer.visible = False

            if legend_chk.value:
                if (
                    self.colorbar_ctrl is not None
                    and self.colorbar_ctrl in self.controls
                ):
                    self.remove_control(self.colorbar_ctrl)
                    self.colorbar_ctrl.close()
                    self.colorbar_widget.close()

                if (
                    "colorbar" in layer_dict.keys()
                    and layer_dict["colorbar"] in self.controls
                ):
                    self.remove_control(layer_dict["colorbar"])
                    layer_dict["colorbar"] = None

                if linear_chk.value:
                    if (
                        "legend" in layer_dict.keys()
                        and layer_dict["legend"] in self.controls
                    ):
                        self.remove_control(layer_dict["legend"])
                        layer_dict["legend"] = None

                    if len(palette.value) > 0 and "," in palette.value:
                        colors = to_hex_colors(
                            [color.strip() for color in palette.value.split(",")]
                        )

                        self.add_colorbar(
                            vis_params={
                                "palette": colors,
                                "min": value_range.value[0],
                                "max": value_range.value[1],
                            },
                            layer_name=layer_name,
                        )
                elif step_chk.value:

                    if len(palette.value) > 0 and "," in palette.value:
                        colors = to_hex_colors(
                            [color.strip() for color in palette.value.split(",")]
                        )
                        labels = [
                            label.strip()
                            for label in legend_labels.value.split(",")
                        ]

                        self.add_legend(
                            legend_title=legend_title.value,
                            legend_keys=labels,
                            legend_colors=colors,
                            layer_name=layer_name,
                        )
            else:
                if radio1.index == 0 and "palette" in vis:
                    self.colorbar_widget.clear_output()
                    with self.colorbar_widget:
                        _, ax = plt.subplots(figsize=(6, 0.4))
                        colors = to_hex_colors(vis["palette"])
                        cmap = mpl.colors.LinearSegmentedColormap.from_list(
                            "custom", colors, N=256
                        )
                        norm = mpl.colors.Normalize(
                            vmin=vis["min"], vmax=vis["max"]
                        )
                        mpl.colorbar.ColorbarBase(
                            ax, norm=norm, cmap=cmap, orientation="horizontal"
                        )
                        plt.show()

                    if (
                        "colorbar" in layer_dict.keys()
                        and layer_dict["colorbar"] in self.controls
                    ):
                        self.remove_control(layer_dict["colorbar"])
                        layer_dict["colorbar"] = None
                    if (
                        "legend" in layer_dict.keys()
                        and layer_dict["legend"] in self.controls
                    ):
                        self.remove_control(layer_dict["legend"])
                        layer_dict["legend"] = None

        def close_btn_clicked(b):
            if self.vis_control in self.controls:
                self.remove_control(self.vis_control)
                self.vis_control = None
                self.vis_widget.close()

            if (
                self.colorbar_ctrl is not None
                and self.colorbar_ctrl in self.controls
            ):
                self.remove_control(self.colorbar_ctrl)
                self.colorbar_ctrl = None
                self.colorbar_widget.close()

        import_btn.on_click(import_btn_clicked)
        apply_btn.on_click(apply_btn_clicked)
        close_btn.on_click(close_btn_clicked)

        color_hbox = widgets.HBox(
            [legend_chk, color_picker, add_color, del_color, reset_color]
        )
        btn_hbox = widgets.HBox([import_btn, apply_btn, close_btn])

        gray_box = [
            label,
            radio_btn,
            bands_hbox,
            v_spacer,
            range_hbox,
            opacity,
            gamma,
            widgets.HBox([classes, colormap]),
            palette,
            color_hbox,
            legend_vbox,
            btn_hbox,
        ]

        rgb_box = [
            label,
            radio_btn,
            bands_hbox,
            v_spacer,
            range_hbox,
            opacity,
            gamma,
            btn_hbox,
        ]

        def legend_chk_changed(change):

            if change["new"]:
                linear_chk.value = True
                legend_vbox.children = [
                    widgets.HBox([linear_chk, step_chk]),
                    # legend_title,
                    # legend_labels,
                ]
            else:
                legend_vbox.children = []

        legend_chk.observe(legend_chk_changed, "value")

        if band_count < 3:
            radio1.index = 0
            band1_dropdown.layout.width = "300px"
            bands_hbox.children = [band1_dropdown]
            vis_widget.children = gray_box
            legend_chk.value = False

            if len(palette.value) > 0 and "," in palette.value:
                import matplotlib as mpl
                import matplotlib.pyplot as plt

                colors = to_hex_colors(
                    [color.strip() for color in palette.value.split(",")]
                )

                self.colorbar_widget.clear_output()
                with self.colorbar_widget:
                    _, ax = plt.subplots(figsize=(6, 0.4))
                    cmap = mpl.colors.LinearSegmentedColormap.from_list(
                        "custom", colors, N=256
                    )
                    norm = mpl.colors.Normalize(
                        vmin=value_range.value[0], vmax=value_range.value[1]
                    )
                    mpl.colorbar.ColorbarBase(
                        ax, norm=norm, cmap=cmap, orientation="horizontal"
                    )
                    plt.show()

        else:
            radio2.index = 0
            if (sel_bands is None) or (len(sel_bands) < 2):
                sel_bands = band_names[0:3]
            band1_dropdown.value = sel_bands[0]
            band2_dropdown.value = sel_bands[1]
            band3_dropdown.value = sel_bands[2]
            bands_hbox.children = [
                band1_dropdown,
                band2_dropdown,
                band3_dropdown,
            ]
            vis_widget.children = rgb_box

        def radio1_observer(sender):
            radio2.unobserve(radio2_observer, names=["value"])
            radio2.index = None
            radio2.observe(radio2_observer, names=["value"])
            band1_dropdown.layout.width = "300px"
            bands_hbox.children = [band1_dropdown]
            palette.value = ", ".join(layer_palette)
            palette.disabled = False
            color_picker.disabled = False
            add_color.disabled = False
            del_color.disabled = False
            reset_color.disabled = False
            vis_widget.children = gray_box

            if len(palette.value) > 0 and "," in palette.value:
                colors = [color.strip() for color in palette.value.split(",")]

                _, ax = plt.subplots(figsize=(6, 0.4))
                cmap = mpl.colors.LinearSegmentedColormap.from_list(
                    "custom", to_hex_colors(colors), N=256
                )
                norm = mpl.colors.Normalize(vmin=0, vmax=1)
                mpl.colorbar.ColorbarBase(
                    ax, norm=norm, cmap=cmap, orientation="horizontal"
                )

                self.colorbar_widget = widgets.Output(
                    layout=widgets.Layout(height="60px")
                )
                self.colorbar_ctrl = ipyleaflet.WidgetControl(
                    widget=self.colorbar_widget, position="bottomright"
                )

                if self.colorbar_ctrl not in self.controls:
                    self.add_control(self.colorbar_ctrl)

                self.colorbar_widget.clear_output()
                with self.colorbar_widget:
                    plt.show()

        def radio2_observer(sender):
            radio1.unobserve(radio1_observer, names=["value"])
            radio1.index = None
            radio1.observe(radio1_observer, names=["value"])
            band1_dropdown.layout.width = dropdown_width
            bands_hbox.children = [
                band1_dropdown,
                band2_dropdown,
                band3_dropdown,
            ]
            palette.value = ""
            palette.disabled = True
            color_picker.disabled = True
            add_color.disabled = True
            del_color.disabled = True
            reset_color.disabled = True
            vis_widget.children = rgb_box

            if (
                self.colorbar_ctrl is not None
                and self.colorbar_ctrl in self.controls
            ):
                self.remove_control(self.colorbar_ctrl)
                self.colorbar_ctrl.close()
                self.colorbar_widget.close()

        radio1.observe(radio1_observer, names=["value"])
        radio2.observe(radio2_observer, names=["value"])

        return vis_widget

    elif isinstance(ee_object, ee.FeatureCollection):

        vis_widget = widgets.VBox(
            layout=widgets.Layout(padding="5px 5px 5px 8px", width="330px")
        )
        label = widgets.Label(value=f"{layer_name} visualization parameters")

        new_layer_name = widgets.Text(
            value=f"{layer_name} style",
            description="New layer name:",
            style={"description_width": "initial"},
        )

        color = widgets.ColorPicker(
            concise=False,
            value="#000000",
            description="Color:",
            layout=widgets.Layout(width="140px"),
            style={"description_width": "initial"},
        )

        color_opacity = widgets.FloatSlider(
            value=layer_opacity,
            min=0,
            max=1,
            step=0.01,
            description="Opacity:",
            continuous_update=True,
            readout=False,
            #             readout_format=".2f",
            layout=widgets.Layout(width="130px"),
            style={"description_width": "50px"},
        )

        color_opacity_label = widgets.Label(
            style={"description_width": "initial"},
            layout=widgets.Layout(padding="0px"),
        )
        widgets.jslink((color_opacity, "value"), (color_opacity_label, "value"))

        point_size = widgets.IntText(
            value=3,
            description="Point size:",
            layout=widgets.Layout(width="110px"),
            style={"description_width": "initial"},
        )

        point_shape_options = [
            "circle",
            "square",
            "diamond",
            "cross",
            "plus",
            "pentagram",
            "hexagram",
            "triangle",
            "triangle_up",
            "triangle_down",
            "triangle_left",
            "triangle_right",
            "pentagon",
            "hexagon",
            "star5",
            "star6",
        ]
        point_shape = widgets.Dropdown(
            options=point_shape_options,
            value="circle",
            description="Point shape:",
            layout=widgets.Layout(width="185px"),
            style={"description_width": "initial"},
        )

        line_width = widgets.IntText(
            value=2,
            description="Line width:",
            layout=widgets.Layout(width="110px"),
            style={"description_width": "initial"},
        )

        line_type = widgets.Dropdown(
            options=["solid", "dotted", "dashed"],
            value="solid",
            description="Line type:",
            layout=widgets.Layout(width="185px"),
            style={"description_width": "initial"},
        )

        fill_color = widgets.ColorPicker(
            concise=False,
            value="#000000",
            description="Fill Color:",
            layout=widgets.Layout(width="160px"),
            style={"description_width": "initial"},
        )

        fill_color_opacity = widgets.FloatSlider(
            value=0.66,
            min=0,
            max=1,
            step=0.01,
            description="Opacity:",
            continuous_update=True,
            readout=False,
            #             readout_format=".2f",
            layout=widgets.Layout(width="110px"),
            style={"description_width": "50px"},
        )

        fill_color_opacity_label = widgets.Label(
            style={"description_width": "initial"},
            layout=widgets.Layout(padding="0px"),
        )
        widgets.jslink(
            (fill_color_opacity, "value"),
            (fill_color_opacity_label, "value"),
        )

        color_picker = widgets.ColorPicker(
            concise=False,
            value="#000000",
            layout=widgets.Layout(width="116px"),
            style={"description_width": "initial"},
        )
        add_color = widgets.Button(
            icon="plus",
            tooltip="Add a hex color string to the palette",
            layout=widgets.Layout(width="32px"),
        )
        del_color = widgets.Button(
            icon="minus",
            tooltip="Remove a hex color string from the palette",
            layout=widgets.Layout(width="32px"),
        )
        reset_color = widgets.Button(
            icon="eraser",
            tooltip="Remove all color strings from the palette",
            layout=widgets.Layout(width="34px"),
        )

        palette = widgets.Text(
            value="",
            placeholder="List of hex code (RRGGBB) separated by comma",
            description="Palette:",
            tooltip="Enter a list of hex code (RRGGBB) separated by comma",
            layout=widgets.Layout(width="300px"),
            style={"description_width": "initial"},
        )

        legend_title = widgets.Text(
            value="Legend",
            description="Legend title:",
            tooltip="Enter a title for the legend",
            layout=widgets.Layout(width="300px"),
            style={"description_width": "initial"},
        )

        legend_labels = widgets.Text(
            value="Labels",
            description="Legend labels:",
            tooltip="Enter a a list of labels for the legend",
            layout=widgets.Layout(width="300px"),
            style={"description_width": "initial"},
        )

        def add_color_clicked(b):
            if color_picker.value is not None:
                if len(palette.value) == 0:
                    palette.value = color_picker.value[1:]
                else:
                    palette.value += ", " + color_picker.value[1:]

        def del_color_clicked(b):
            if "," in palette.value:
                items = [item.strip() for item in palette.value.split(",")]
                palette.value = ", ".join(items[:-1])
            else:
                palette.value = ""

        def reset_color_clicked(b):
            palette.value = ""

        add_color.on_click(add_color_clicked)
        del_color.on_click(del_color_clicked)
        reset_color.on_click(reset_color_clicked)

        field = widgets.Dropdown(
            options=[],
            value=None,
            description="Field:",
            layout=widgets.Layout(width="140px"),
            style={"description_width": "initial"},
        )

        field_values = widgets.Dropdown(
            options=[],
            value=None,
            description="Values:",
            layout=widgets.Layout(width="156px"),
            style={"description_width": "initial"},
        )

        classes = widgets.Dropdown(
            options=["Any"] + [str(i) for i in range(3, 13)],
            description="Classes:",
            layout=widgets.Layout(width="115px"),
            style={"description_width": "initial"},
        )

        colormap = widgets.Dropdown(
            options=["viridis"],
            value="viridis",
            description="Colormap:",
            layout=widgets.Layout(width="181px"),
            style={"description_width": "initial"},
        )

        def classes_changed(change):
            if change["new"]:
                selected = change["owner"].value
                if colormap.value is not None:

                    n_class = None
                    if selected != "Any":
                        n_class = int(classes.value)

                    colors = plt.cm.get_cmap(colormap.value, n_class)
                    cmap_colors = [
                        mpl.colors.rgb2hex(colors(i))[1:] for i in range(colors.N)
                    ]

                    _, ax = plt.subplots(figsize=(6, 0.4))
                    cmap = mpl.colors.LinearSegmentedColormap.from_list(
                        "custom", to_hex_colors(cmap_colors), N=256
                    )
                    norm = mpl.colors.Normalize(vmin=0, vmax=1)
                    mpl.colorbar.ColorbarBase(
                        ax, norm=norm, cmap=cmap, orientation="horizontal"
                    )

                    palette.value = ", ".join([color for color in cmap_colors])

                    if self.colorbar_widget is None:
                        self.colorbar_widget = widgets.Output(
                            layout=widgets.Layout(height="60px")
                        )

                    if self.colorbar_ctrl is None:
                        self.colorbar_ctrl = ipyleaflet.WidgetControl(
                            widget=self.colorbar_widget, position="bottomright"
                        )
                        self.add_control(self.colorbar_ctrl)

                    colorbar_output = self.colorbar_widget
                    with colorbar_output:
                        colorbar_output.clear_output()
                        plt.show()

                    if len(palette.value) > 0 and "," in palette.value:
                        labels = [
                            f"Class {i+1}"
                            for i in range(len(palette.value.split(",")))
                        ]
                        legend_labels.value = ", ".join(labels)

        classes.observe(classes_changed, "value")

        def colormap_changed(change):
            if change["new"]:

                n_class = None
                if classes.value != "Any":
                    n_class = int(classes.value)

                colors = plt.cm.get_cmap(colormap.value, n_class)
                cmap_colors = [
                    mpl.colors.rgb2hex(colors(i))[1:] for i in range(colors.N)
                ]

                _, ax = plt.subplots(figsize=(6, 0.4))
                cmap = mpl.colors.LinearSegmentedColormap.from_list(
                    "custom", to_hex_colors(cmap_colors), N=256
                )
                norm = mpl.colors.Normalize(vmin=0, vmax=1)
                mpl.colorbar.ColorbarBase(
                    ax, norm=norm, cmap=cmap, orientation="horizontal"
                )

                palette.value = ", ".join(cmap_colors)

                if self.colorbar_widget is None:
                    self.colorbar_widget = widgets.Output(
                        layout=widgets.Layout(height="60px")
                    )

                if self.colorbar_ctrl is None:
                    self.colorbar_ctrl = ipyleaflet.WidgetControl(
                        widget=self.colorbar_widget, position="bottomright"
                    )
                    self.add_control(self.colorbar_ctrl)

                colorbar_output = self.colorbar_widget
                with colorbar_output:
                    colorbar_output.clear_output()
                    plt.show()
                    # display(colorbar)

                if len(palette.value) > 0 and "," in palette.value:
                    labels = [
                        f"Class {i+1}" for i in range(len(palette.value.split(",")))
                    ]
                    legend_labels.value = ", ".join(labels)

        colormap.observe(colormap_changed, "value")

        btn_width = "97.5px"
        import_btn = widgets.Button(
            description="Import",
            button_style="primary",
            tooltip="Import vis params to notebook",
            layout=widgets.Layout(width=btn_width),
        )

        apply_btn = widgets.Button(
            description="Apply",
            tooltip="Apply vis params to the layer",
            layout=widgets.Layout(width=btn_width),
        )

        close_btn = widgets.Button(
            description="Close",
            tooltip="Close vis params diaglog",
            layout=widgets.Layout(width=btn_width),
        )

        style_chk = widgets.Checkbox(
            value=False,
            description="Style by attribute",
            indent=False,
            layout=widgets.Layout(width="140px"),
        )

        legend_chk = widgets.Checkbox(
            value=False,
            description="Legend",
            indent=False,
            layout=widgets.Layout(width="70px"),
        )
        compute_label = widgets.Label(value="")

        style_vbox = widgets.VBox([widgets.HBox([style_chk, compute_label])])

        def style_chk_changed(change):

            if change["new"]:

                if (
                    self.colorbar_ctrl is not None
                    and self.colorbar_ctrl in self.controls
                ):
                    self.remove_control(self.colorbar_ctrl)
                    self.colorbar_ctrl.close()
                    self.colorbar_widget.close()

                self.colorbar_widget = widgets.Output(
                    layout=widgets.Layout(height="60px")
                )
                self.colorbar_ctrl = ipyleaflet.WidgetControl(
                    widget=self.colorbar_widget, position="bottomright"
                )
                self.add_control(self.colorbar_ctrl)
                fill_color.disabled = True
                colormap.options = plt.colormaps()
                colormap.value = "viridis"
                style_vbox.children = [
                    widgets.HBox([style_chk, compute_label]),
                    widgets.HBox([field, field_values]),
                    widgets.HBox([classes, colormap]),
                    palette,
                    widgets.HBox(
                        [
                            legend_chk,
                            color_picker,
                            add_color,
                            del_color,
                            reset_color,
                        ]
                    ),
                ]
                compute_label.value = "Computing ..."

                field.options = (
                    ee.Feature(ee_object.first()).propertyNames().getInfo()
                )
                compute_label.value = ""
                classes.value = "Any"
                legend_chk.value = False

            else:
                fill_color.disabled = False
                style_vbox.children = [widgets.HBox([style_chk, compute_label])]
                compute_label.value = ""
                if (
                    self.colorbar_ctrl is not None
                    and self.colorbar_ctrl in self.controls
                ):
                    self.remove_control(self.colorbar_ctrl)
                    self.colorbar_ctrl = None
                    self.colorbar_widget = None
                # legend_chk.value = False

        style_chk.observe(style_chk_changed, "value")

        def legend_chk_changed(change):
            if change["new"]:
                style_vbox.children = list(style_vbox.children) + [
                    widgets.VBox([legend_title, legend_labels])
                ]

                if len(palette.value) > 0 and "," in palette.value:
                    labels = [
                        f"Class {i+1}" for i in range(len(palette.value.split(",")))
                    ]
                    legend_labels.value = ", ".join(labels)

            else:
                style_vbox.children = [
                    widgets.HBox([style_chk, compute_label]),
                    widgets.HBox([field, field_values]),
                    widgets.HBox([classes, colormap]),
                    palette,
                    widgets.HBox(
                        [
                            legend_chk,
                            color_picker,
                            add_color,
                            del_color,
                            reset_color,
                        ]
                    ),
                ]

        legend_chk.observe(legend_chk_changed, "value")

        def field_changed(change):

            if change["new"]:
                compute_label.value = "Computing ..."
                options = ee_object.aggregate_array(field.value).getInfo()
                if options is not None:
                    options = list(set(options))
                    options.sort()

                field_values.options = options
                compute_label.value = ""

        field.observe(field_changed, "value")

        def get_vis_params():

            vis = {}
            vis["color"] = color.value[1:] + str(
                hex(int(color_opacity.value * 255))
            )[2:].zfill(2)
            if geometry_type(ee_object) in ["Point", "MultiPoint"]:
                vis["pointSize"] = point_size.value
                vis["pointShape"] = point_shape.value
            vis["width"] = line_width.value
            vis["lineType"] = line_type.value
            vis["fillColor"] = fill_color.value[1:] + str(
                hex(int(fill_color_opacity.value * 255))
            )[2:].zfill(2)

            return vis

        def import_btn_clicked(b):

            vis = get_vis_params()
            create_code_cell(f"vis_params = {str(vis)}")

        def apply_btn_clicked(b):

            compute_label.value = "Computing ..."

            if new_layer_name.value in self.ee_layer_names:
                old_layer = new_layer_name.value

                if "legend" in self.ee_layer_dict[old_layer].keys():
                    legend = self.ee_layer_dict[old_layer]["legend"]
                    if legend in self.controls:
                        self.remove_control(legend)
                    legend.close()
                if "colorbar" in self.ee_layer_dict[old_layer].keys():
                    colorbar = self.ee_layer_dict[old_layer]["colorbar"]
                    if colorbar in self.controls:
                        self.remove_control(colorbar)
                    colorbar.close()

            if not style_chk.value:
                vis = get_vis_params()
                self.addLayer(ee_object.style(**vis), {}, new_layer_name.value)
                ee_layer.visible = False

            elif (
                style_chk.value and len(palette.value) > 0 and "," in palette.value
            ):
                colors = ee.List(
                    [
                        color.strip()
                        + str(hex(int(fill_color_opacity.value * 255)))[2:].zfill(2)
                        for color in palette.value.split(",")
                    ]
                )
                arr = ee_object.aggregate_array(field.value).distinct().sort()
                fc = ee_object.map(
                    lambda f: f.set({"styleIndex": arr.indexOf(f.get(field.value))})
                )
                step = arr.size().divide(colors.size()).ceil()
                fc = fc.map(
                    lambda f: f.set(
                        {
                            "style": {
                                "color": color.value[1:]
                                + str(hex(int(color_opacity.value * 255)))[
                                    2:
                                ].zfill(2),
                                "pointSize": point_size.value,
                                "pointShape": point_shape.value,
                                "width": line_width.value,
                                "lineType": line_type.value,
                                "fillColor": colors.get(
                                    ee.Number(
                                        ee.Number(f.get("styleIndex")).divide(step)
                                    ).floor()
                                ),
                            }
                        }
                    )
                )

                self.addLayer(
                    fc.style(**{"styleProperty": "style"}),
                    {},
                    f"{new_layer_name.value}",
                )

                if (
                    len(palette.value)
                    and legend_chk.value
                    and len(legend_labels.value) > 0
                ):
                    legend_colors = [
                        color.strip() for color in palette.value.split(",")
                    ]
                    legend_keys = [
                        label.strip() for label in legend_labels.value.split(",")
                    ]
                    self.add_legend(
                        legend_title=legend_title.value,
                        legend_keys=legend_keys,
                        legend_colors=legend_colors,
                        layer_name=new_layer_name.value,
                    )
            ee_layer.visible = False
            compute_label.value = ""

        def close_btn_clicked(b):
            self.remove_control(self.vis_control)
            self.vis_control.close()
            self.vis_widget.close()

            if (
                self.colorbar_ctrl is not None
                and self.colorbar_ctrl in self.controls
            ):
                self.remove_control(self.colorbar_ctrl)
                self.colorbar_ctrl.close()
                self.colorbar_widget.close()

        import_btn.on_click(import_btn_clicked)
        apply_btn.on_click(apply_btn_clicked)
        close_btn.on_click(close_btn_clicked)

        vis_widget.children = [
            label,
            new_layer_name,
            widgets.HBox([color, color_opacity, color_opacity_label]),
            widgets.HBox([point_size, point_shape]),
            widgets.HBox([line_width, line_type]),
            widgets.HBox(
                [fill_color, fill_color_opacity, fill_color_opacity_label]
            ),
            style_vbox,
            widgets.HBox([import_btn, apply_btn, close_btn]),
        ]

        if geometry_type(ee_object) in ["Point", "MultiPoint"]:
            point_size.disabled = False
            point_shape.disabled = False
        else:
            point_size.disabled = True
            point_shape.disabled = True

        return vis_widget

draw_layer_on_top(self)

Move user-drawn feature layer to the top of all layers.

Source code in geemap/geemap.py
def draw_layer_on_top(self):
    """Move user-drawn feature layer to the top of all layers."""
    draw_layer_index = self.find_layer_index(name="Drawn Features")
    if draw_layer_index > -1 and draw_layer_index < (len(self.layers) - 1):
        layers = list(self.layers)
        layers = (
            layers[0:draw_layer_index]
            + layers[(draw_layer_index + 1) :]
            + [layers[draw_layer_index]]
        )
        self.layers = layers

extract_values_to_points(self, filename)

Exports pixel values to a csv file based on user-drawn geometries.

Parameters:

Name Type Description Default
filename str

The output file path to the csv file or shapefile.

required
Source code in geemap/geemap.py
def extract_values_to_points(self, filename):
    """Exports pixel values to a csv file based on user-drawn geometries.

    Args:
        filename (str): The output file path to the csv file or shapefile.
    """
    import csv

    filename = os.path.abspath(filename)
    allowed_formats = ["csv", "shp"]
    ext = filename[-3:]

    if ext not in allowed_formats:
        print(
            "The output file must be one of the following: {}".format(
                ", ".join(allowed_formats)
            )
        )
        return

    out_dir = os.path.dirname(filename)
    out_csv = filename[:-3] + "csv"
    out_shp = filename[:-3] + "shp"
    if not os.path.exists(out_dir):
        os.makedirs(out_dir)

    count = len(self.chart_points)
    out_list = []
    if count > 0:
        header = ["id", "longitude", "latitude"] + self.chart_labels
        out_list.append(header)

        for i in range(0, count):
            id = i + 1
            line = [id] + self.chart_points[i] + self.chart_values[i]
            out_list.append(line)

        with open(out_csv, "w", newline="") as f:
            writer = csv.writer(f)
            writer.writerows(out_list)

        if ext == "csv":
            print(f"The csv file has been saved to: {out_csv}")
        else:
            csv_to_shp(out_csv, out_shp)
            print(f"The shapefile has been saved to: {out_shp}")

find_layer(self, name)

Finds layer by name

Parameters:

Name Type Description Default
name str

Name of the layer to find.

required

Returns:

Type Description
object

ipyleaflet layer object.

Source code in geemap/geemap.py
def find_layer(self, name):
    """Finds layer by name

    Args:
        name (str): Name of the layer to find.

    Returns:
        object: ipyleaflet layer object.
    """
    layers = self.layers

    for layer in layers:
        if layer.name == name:
            return layer

    return None

find_layer_index(self, name)

Finds layer index by name

Parameters:

Name Type Description Default
name str

Name of the layer to find.

required

Returns:

Type Description
int

Index of the layer with the specified name

Source code in geemap/geemap.py
def find_layer_index(self, name):
    """Finds layer index by name

    Args:
        name (str): Name of the layer to find.

    Returns:
        int: Index of the layer with the specified name
    """
    layers = self.layers

    for index, layer in enumerate(layers):
        if layer.name == name:
            return index

    return -1

get_scale(self)

Returns the approximate pixel scale of the current map view, in meters.

Returns:

Type Description
float

Map resolution in meters.

Source code in geemap/geemap.py
def get_scale(self):
    """Returns the approximate pixel scale of the current map view, in meters.

    Returns:
        float: Map resolution in meters.
    """
    zoom_level = self.zoom
    # Reference: https://blogs.bing.com/maps/2006/02/25/map-control-zoom-levels-gt-resolution
    resolution = 156543.04 * math.cos(0) / math.pow(2, zoom_level)
    return resolution

getScale(self)

Returns the approximate pixel scale of the current map view, in meters.

Returns:

Type Description
float

Map resolution in meters.

Source code in geemap/geemap.py
def get_scale(self):
    """Returns the approximate pixel scale of the current map view, in meters.

    Returns:
        float: Map resolution in meters.
    """
    zoom_level = self.zoom
    # Reference: https://blogs.bing.com/maps/2006/02/25/map-control-zoom-levels-gt-resolution
    resolution = 156543.04 * math.cos(0) / math.pow(2, zoom_level)
    return resolution

image_overlay(self, url, bounds, name)

Overlays an image from the Internet or locally on the map.

Parameters:

Name Type Description Default
url str

http URL or local file path to the image.

required
bounds tuple

bounding box of the image in the format of (lower_left(lat, lon), upper_right(lat, lon)), such as ((13, -130), (32, -100)).

required
name str

name of the layer to show on the layer control.

required
Source code in geemap/geemap.py
def image_overlay(self, url, bounds, name):
    """Overlays an image from the Internet or locally on the map.

    Args:
        url (str): http URL or local file path to the image.
        bounds (tuple): bounding box of the image in the format of (lower_left(lat, lon), upper_right(lat, lon)), such as ((13, -130), (32, -100)).
        name (str): name of the layer to show on the layer control.
    """
    from base64 import b64encode
    from io import BytesIO

    from PIL import Image, ImageSequence

    try:
        if not url.startswith("http"):

            if not os.path.exists(url):
                print("The provided file does not exist.")
                return

            ext = os.path.splitext(url)[1][1:]  # file extension
            image = Image.open(url)

            f = BytesIO()
            if ext.lower() == "gif":
                frames = []
                # Loop over each frame in the animated image
                for frame in ImageSequence.Iterator(image):
                    frame = frame.convert("RGBA")
                    b = BytesIO()
                    frame.save(b, format="gif")
                    frame = Image.open(b)
                    frames.append(frame)
                frames[0].save(
                    f,
                    format="GIF",
                    save_all=True,
                    append_images=frames[1:],
                    loop=0,
                )
            else:
                image.save(f, ext)

            data = b64encode(f.getvalue())
            data = data.decode("ascii")
            url = "data:image/{};base64,".format(ext) + data
        img = ipyleaflet.ImageOverlay(url=url, bounds=bounds, name=name)
        self.add_layer(img)
    except Exception as e:
        print(e)

layer_opacity(self, name, value=1.0)

Changes layer opacity.

Parameters:

Name Type Description Default
name str

The name of the layer to change opacity.

required
value float

The opacity value to set. Defaults to 1.0.

1.0
Source code in geemap/geemap.py
def layer_opacity(self, name, value=1.0):
    """Changes layer opacity.

    Args:
        name (str): The name of the layer to change opacity.
        value (float, optional): The opacity value to set. Defaults to 1.0.
    """
    layer = self.find_layer(name)
    try:
        layer.opacity = value
    except Exception as e:
        raise Exception(e)

marker_cluster(self)

Adds a marker cluster to the map and returns a list of ee.Feature, which can be accessed using Map.ee_marker_cluster.

Returns:

Type Description
object

a list of ee.Feature

Source code in geemap/geemap.py
def marker_cluster(self):
    """Adds a marker cluster to the map and returns a list of ee.Feature, which can be accessed using Map.ee_marker_cluster.

    Returns:
        object: a list of ee.Feature
    """
    coordinates = []
    markers = []
    marker_cluster = ipyleaflet.MarkerCluster(name="Marker Cluster")
    self.last_click = []
    self.all_clicks = []
    self.ee_markers = []
    self.add_layer(marker_cluster)

    def handle_interaction(**kwargs):
        latlon = kwargs.get("coordinates")
        if kwargs.get("type") == "click":
            coordinates.append(latlon)
            geom = ee.Geometry.Point(latlon[1], latlon[0])
            feature = ee.Feature(geom)
            self.ee_markers.append(feature)
            self.last_click = latlon
            self.all_clicks = coordinates
            markers.append(ipyleaflet.Marker(location=latlon))
            marker_cluster.markers = markers
        elif kwargs.get("type") == "mousemove":
            pass

    # cursor style: https://www.w3schools.com/cssref/pr_class_cursor.asp
    self.default_style = {"cursor": "crosshair"}
    self.on_interaction(handle_interaction)

plot(self, x, y, plot_type=None, overlay=False, position='bottomright', min_width=None, max_width=None, min_height=None, max_height=None, **kwargs)

Creates a plot based on x-array and y-array data.

Parameters:

Name Type Description Default
x numpy.ndarray or list

The x-coordinates of the plotted line.

required
y numpy.ndarray or list

The y-coordinates of the plotted line.

required
plot_type str

The plot type can be one of "None", "bar", "scatter" or "hist". Defaults to None.

None
overlay bool

Whether to overlay plotted lines on the figure. Defaults to False.

False
position str

Position of the control, can be ‘bottomleft’, ‘bottomright’, ‘topleft’, or ‘topright’. Defaults to 'bottomright'.

'bottomright'
min_width int

Min width of the widget (in pixels), if None it will respect the content size. Defaults to None.

None
max_width int

Max width of the widget (in pixels), if None it will respect the content size. Defaults to None.

None
min_height int

Min height of the widget (in pixels), if None it will respect the content size. Defaults to None.

None
max_height int

Max height of the widget (in pixels), if None it will respect the content size. Defaults to None.

None
Source code in geemap/geemap.py
def plot(
    self,
    x,
    y,
    plot_type=None,
    overlay=False,
    position="bottomright",
    min_width=None,
    max_width=None,
    min_height=None,
    max_height=None,
    **kwargs,
):
    """Creates a plot based on x-array and y-array data.

    Args:
        x (numpy.ndarray or list): The x-coordinates of the plotted line.
        y (numpy.ndarray or list): The y-coordinates of the plotted line.
        plot_type (str, optional): The plot type can be one of "None", "bar", "scatter" or "hist". Defaults to None.
        overlay (bool, optional): Whether to overlay plotted lines on the figure. Defaults to False.
        position (str, optional): Position of the control, can be ‘bottomleft’, ‘bottomright’, ‘topleft’, or ‘topright’. Defaults to 'bottomright'.
        min_width (int, optional): Min width of the widget (in pixels), if None it will respect the content size. Defaults to None.
        max_width (int, optional): Max width of the widget (in pixels), if None it will respect the content size. Defaults to None.
        min_height (int, optional): Min height of the widget (in pixels), if None it will respect the content size. Defaults to None.
        max_height (int, optional): Max height of the widget (in pixels), if None it will respect the content size. Defaults to None.

    """
    if self.plot_widget is not None:
        plot_widget = self.plot_widget
    else:
        plot_widget = widgets.Output(layout={"border": "1px solid black"})
        plot_control = ipyleaflet.WidgetControl(
            widget=plot_widget,
            position=position,
            min_width=min_width,
            max_width=max_width,
            min_height=min_height,
            max_height=max_height,
        )
        self.plot_widget = plot_widget
        self.plot_control = plot_control
        self.add_control(plot_control)

    if max_width is None:
        max_width = 500
    if max_height is None:
        max_height = 300

    if (plot_type is None) and ("markers" not in kwargs.keys()):
        kwargs["markers"] = "circle"

    with plot_widget:
        try:
            fig = plt.figure(1, **kwargs)
            if max_width is not None:
                fig.layout.width = str(max_width) + "px"
            if max_height is not None:
                fig.layout.height = str(max_height) + "px"

            plot_widget.clear_output(wait=True)
            if not overlay:
                plt.clear()

            if plot_type is None:
                if "marker" not in kwargs.keys():
                    kwargs["marker"] = "circle"
                plt.plot(x, y, **kwargs)
            elif plot_type == "bar":
                plt.bar(x, y, **kwargs)
            elif plot_type == "scatter":
                plt.scatter(x, y, **kwargs)
            elif plot_type == "hist":
                plt.hist(y, **kwargs)
            plt.show()

        except Exception as e:
            print("Failed to create plot.")
            raise Exception(e)

plot_demo(self, iterations=20, plot_type=None, overlay=False, position='bottomright', min_width=None, max_width=None, min_height=None, max_height=None, **kwargs)

A demo of interactive plotting using random pixel coordinates.

Parameters:

Name Type Description Default
iterations int

How many iterations to run for the demo. Defaults to 20.

20
plot_type str

The plot type can be one of "None", "bar", "scatter" or "hist". Defaults to None.

None
overlay bool

Whether to overlay plotted lines on the figure. Defaults to False.

False
position str

Position of the control, can be ‘bottomleft’, ‘bottomright’, ‘topleft’, or ‘topright’. Defaults to 'bottomright'.

'bottomright'
min_width int

Min width of the widget (in pixels), if None it will respect the content size. Defaults to None.

None
max_width int

Max width of the widget (in pixels), if None it will respect the content size. Defaults to None.

None
min_height int

Min height of the widget (in pixels), if None it will respect the content size. Defaults to None.

None
max_height int

Max height of the widget (in pixels), if None it will respect the content size. Defaults to None.

None
Source code in geemap/geemap.py
def plot_demo(
    self,
    iterations=20,
    plot_type=None,
    overlay=False,
    position="bottomright",
    min_width=None,
    max_width=None,
    min_height=None,
    max_height=None,
    **kwargs,
):
    """A demo of interactive plotting using random pixel coordinates.

    Args:
        iterations (int, optional): How many iterations to run for the demo. Defaults to 20.
        plot_type (str, optional): The plot type can be one of "None", "bar", "scatter" or "hist". Defaults to None.
        overlay (bool, optional): Whether to overlay plotted lines on the figure. Defaults to False.
        position (str, optional): Position of the control, can be ‘bottomleft’, ‘bottomright’, ‘topleft’, or ‘topright’. Defaults to 'bottomright'.
        min_width (int, optional): Min width of the widget (in pixels), if None it will respect the content size. Defaults to None.
        max_width (int, optional): Max width of the widget (in pixels), if None it will respect the content size. Defaults to None.
        min_height (int, optional): Min height of the widget (in pixels), if None it will respect the content size. Defaults to None.
        max_height (int, optional): Max height of the widget (in pixels), if None it will respect the content size. Defaults to None.
    """

    import numpy as np

    if self.random_marker is not None:
        self.remove_layer(self.random_marker)

    image = ee.Image("LE7_TOA_5YEAR/1999_2003").select([0, 1, 2, 3, 4, 6])
    self.addLayer(
        image,
        {"bands": ["B4", "B3", "B2"], "gamma": 1.4},
        "LE7_TOA_5YEAR/1999_2003",
    )
    self.setCenter(-50.078877, 25.190030, 3)
    band_names = image.bandNames().getInfo()
    # band_count = len(band_names)

    latitudes = np.random.uniform(30, 48, size=iterations)
    longitudes = np.random.uniform(-121, -76, size=iterations)

    marker = ipyleaflet.Marker(location=(0, 0))
    self.random_marker = marker
    self.add_layer(marker)

    for i in range(iterations):
        try:
            coordinate = ee.Geometry.Point([longitudes[i], latitudes[i]])
            dict_values = image.sample(coordinate).first().toDictionary().getInfo()
            band_values = list(dict_values.values())
            title = "{}/{}: Spectral signature at ({}, {})".format(
                i + 1,
                iterations,
                round(latitudes[i], 2),
                round(longitudes[i], 2),
            )
            marker.location = (latitudes[i], longitudes[i])
            self.plot(
                band_names,
                band_values,
                plot_type=plot_type,
                overlay=overlay,
                min_width=min_width,
                max_width=max_width,
                min_height=min_height,
                max_height=max_height,
                title=title,
                **kwargs,
            )
            time.sleep(0.3)
        except Exception as e:
            raise Exception(e)

plot_raster(self, ee_object=None, sample_scale=None, plot_type=None, overlay=False, position='bottomright', min_width=None, max_width=None, min_height=None, max_height=None, **kwargs)

Interactive plotting of Earth Engine data by clicking on the map.

Parameters:

Name Type Description Default
ee_object object

The ee.Image or ee.ImageCollection to sample. Defaults to None.

None
sample_scale float

A nominal scale in meters of the projection to sample in. Defaults to None.

None
plot_type str

The plot type can be one of "None", "bar", "scatter" or "hist". Defaults to None.

None
overlay bool

Whether to overlay plotted lines on the figure. Defaults to False.

False
position str

Position of the control, can be ‘bottomleft’, ‘bottomright’, ‘topleft’, or ‘topright’. Defaults to 'bottomright'.

'bottomright'
min_width int

Min width of the widget (in pixels), if None it will respect the content size. Defaults to None.

None
max_width int

Max width of the widget (in pixels), if None it will respect the content size. Defaults to None.

None
min_height int

Min height of the widget (in pixels), if None it will respect the content size. Defaults to None.

None
max_height int

Max height of the widget (in pixels), if None it will respect the content size. Defaults to None.

None
Source code in geemap/geemap.py
def plot_raster(
    self,
    ee_object=None,
    sample_scale=None,
    plot_type=None,
    overlay=False,
    position="bottomright",
    min_width=None,
    max_width=None,
    min_height=None,
    max_height=None,
    **kwargs,
):
    """Interactive plotting of Earth Engine data by clicking on the map.

    Args:
        ee_object (object, optional): The ee.Image or ee.ImageCollection to sample. Defaults to None.
        sample_scale (float, optional): A nominal scale in meters of the projection to sample in. Defaults to None.
        plot_type (str, optional): The plot type can be one of "None", "bar", "scatter" or "hist". Defaults to None.
        overlay (bool, optional): Whether to overlay plotted lines on the figure. Defaults to False.
        position (str, optional): Position of the control, can be ‘bottomleft’, ‘bottomright’, ‘topleft’, or ‘topright’. Defaults to 'bottomright'.
        min_width (int, optional): Min width of the widget (in pixels), if None it will respect the content size. Defaults to None.
        max_width (int, optional): Max width of the widget (in pixels), if None it will respect the content size. Defaults to None.
        min_height (int, optional): Min height of the widget (in pixels), if None it will respect the content size. Defaults to None.
        max_height (int, optional): Max height of the widget (in pixels), if None it will respect the content size. Defaults to None.

    """
    if self.plot_control is not None:
        del self.plot_widget
        if self.plot_control in self.controls:
            self.remove_control(self.plot_control)

    if self.random_marker is not None:
        self.remove_layer(self.random_marker)

    plot_widget = widgets.Output(layout={"border": "1px solid black"})
    plot_control = ipyleaflet.WidgetControl(
        widget=plot_widget,
        position=position,
        min_width=min_width,
        max_width=max_width,
        min_height=min_height,
        max_height=max_height,
    )
    self.plot_widget = plot_widget
    self.plot_control = plot_control
    self.add_control(plot_control)

    self.default_style = {"cursor": "crosshair"}
    msg = "The plot function can only be used on ee.Image or ee.ImageCollection with more than one band."
    if (ee_object is None) and len(self.ee_raster_layers) > 0:
        ee_object = self.ee_raster_layers[-1]
        if isinstance(ee_object, ee.ImageCollection):
            ee_object = ee_object.mosaic()
    elif isinstance(ee_object, ee.ImageCollection):
        ee_object = ee_object.mosaic()
    elif not isinstance(ee_object, ee.Image):
        print(msg)
        return

    if sample_scale is None:
        sample_scale = self.getScale()

    if max_width is None:
        max_width = 500

    band_names = ee_object.bandNames().getInfo()

    coordinates = []
    markers = []
    marker_cluster = ipyleaflet.MarkerCluster(name="Marker Cluster")
    self.last_click = []
    self.all_clicks = []
    self.add_layer(marker_cluster)

    def handle_interaction(**kwargs2):
        latlon = kwargs2.get("coordinates")

        if kwargs2.get("type") == "click":
            try:
                coordinates.append(latlon)
                self.last_click = latlon
                self.all_clicks = coordinates
                markers.append(ipyleaflet.Marker(location=latlon))
                marker_cluster.markers = markers
                self.default_style = {"cursor": "wait"}
                xy = ee.Geometry.Point(latlon[::-1])
                dict_values = (
                    ee_object.sample(xy, scale=sample_scale)
                    .first()
                    .toDictionary()
                    .getInfo()
                )
                band_values = list(dict_values.values())
                self.plot(
                    band_names,
                    band_values,
                    plot_type=plot_type,
                    overlay=overlay,
                    min_width=min_width,
                    max_width=max_width,
                    min_height=min_height,
                    max_height=max_height,
                    **kwargs,
                )
                self.default_style = {"cursor": "crosshair"}
            except Exception as e:
                if self.plot_widget is not None:
                    with self.plot_widget:
                        self.plot_widget.clear_output()
                        print("No data for the clicked location.")
                else:
                    print(e)
                self.default_style = {"cursor": "crosshair"}

    self.on_interaction(handle_interaction)

remove_colorbar(self)

Remove colorbar from the map.

Source code in geemap/geemap.py
def remove_colorbar(self):
    """Remove colorbar from the map."""
    if self.colorbar is not None:
        self.remove_control(self.colorbar)

remove_drawn_features(self)

Removes user-drawn geometries from the map

Source code in geemap/geemap.py
def remove_drawn_features(self):
    """Removes user-drawn geometries from the map"""
    if self.draw_layer is not None:
        self.remove_layer(self.draw_layer)
        self.draw_count = 0
        self.draw_features = []
        self.draw_last_feature = None
        self.draw_layer = None
        self.draw_last_json = None
        self.draw_last_bounds = None
        self.user_roi = None
        self.user_rois = None
        self.chart_values = []
        self.chart_points = []
        self.chart_labels = None
    if self.draw_control is not None:
        self.draw_control.clear()

remove_ee_layer(self, name)

Removes an Earth Engine layer.

Parameters:

Name Type Description Default
name str

The name of the Earth Engine layer to remove.

required
Source code in geemap/geemap.py
def remove_ee_layer(self, name):
    """Removes an Earth Engine layer.

    Args:
        name (str): The name of the Earth Engine layer to remove.
    """
    if name in self.ee_layer_dict:
        ee_object = self.ee_layer_dict[name]["ee_object"]
        ee_layer = self.ee_layer_dict[name]["ee_layer"]
        if name in self.ee_raster_layer_names:
            self.ee_raster_layer_names.remove(name)
            self.ee_raster_layers.remove(ee_object)
        elif name in self.ee_vector_layer_names:
            self.ee_vector_layer_names.remove(name)
            self.ee_vector_layers.remove(ee_object)
        self.ee_layers.remove(ee_object)
        self.ee_layer_names.remove(name)
        if ee_layer in self.layers:
            self.remove_layer(ee_layer)

remove_last_drawn(self)

Removes user-drawn geometries from the map

Source code in geemap/geemap.py
def remove_last_drawn(self):
    """Removes user-drawn geometries from the map"""
    if self.draw_layer is not None:
        collection = ee.FeatureCollection(self.draw_features[:-1])
        ee_draw_layer = ee_tile_layer(
            collection, {"color": "blue"}, "Drawn Features", True, 0.5
        )
        if self.draw_count == 1:
            self.remove_drawn_features()
        else:
            self.substitute_layer(self.draw_layer, ee_draw_layer)
            self.draw_layer = ee_draw_layer
            self.draw_count -= 1
            self.draw_features = self.draw_features[:-1]
            self.draw_last_feature = self.draw_features[-1]
            self.draw_layer = ee_draw_layer
            self.draw_last_json = None
            self.draw_last_bounds = None
            self.user_roi = ee.Feature(
                collection.toList(collection.size()).get(
                    collection.size().subtract(1)
                )
            ).geometry()
            self.user_rois = collection
            self.chart_values = self.chart_values[:-1]
            self.chart_points = self.chart_points[:-1]
            # self.chart_labels = None

set_center(self, lon, lat, zoom=None)

Centers the map view at a given coordinates with the given zoom level.

Parameters:

Name Type Description Default
lon float

The longitude of the center, in degrees.

required
lat float

The latitude of the center, in degrees.

required
zoom int

The zoom level, from 1 to 24. Defaults to None.

None
Source code in geemap/geemap.py
def set_center(self, lon, lat, zoom=None):
    """Centers the map view at a given coordinates with the given zoom level.

    Args:
        lon (float): The longitude of the center, in degrees.
        lat (float): The latitude of the center, in degrees.
        zoom (int, optional): The zoom level, from 1 to 24. Defaults to None.
    """
    self.center = (lat, lon)
    if zoom is not None:
        self.zoom = zoom

set_control_visibility(self, layerControl=True, fullscreenControl=True, latLngPopup=True)

Sets the visibility of the controls on the map.

Parameters:

Name Type Description Default
layerControl bool

Whether to show the control that allows the user to toggle layers on/off. Defaults to True.

True
fullscreenControl bool

Whether to show the control that allows the user to make the map full-screen. Defaults to True.

True
latLngPopup bool

Whether to show the control that pops up the Lat/lon when the user clicks on the map. Defaults to True.

True
Source code in geemap/geemap.py
def set_control_visibility(
    self, layerControl=True, fullscreenControl=True, latLngPopup=True
):
    """Sets the visibility of the controls on the map.

    Args:
        layerControl (bool, optional): Whether to show the control that allows the user to toggle layers on/off. Defaults to True.
        fullscreenControl (bool, optional): Whether to show the control that allows the user to make the map full-screen. Defaults to True.
        latLngPopup (bool, optional): Whether to show the control that pops up the Lat/lon when the user clicks on the map. Defaults to True.
    """
    pass

set_options(self, mapTypeId='HYBRID', styles=None, types=None)

Adds Google basemap and controls to the ipyleaflet map.

Parameters:

Name Type Description Default
mapTypeId str

A mapTypeId to set the basemap to. Can be one of "ROADMAP", "SATELLITE", "HYBRID" or "TERRAIN" to select one of the standard Google Maps API map types. Defaults to 'HYBRID'.

'HYBRID'
styles object

A dictionary of custom MapTypeStyle objects keyed with a name that will appear in the map's Map Type Controls. Defaults to None.

None
types list

A list of mapTypeIds to make available. If omitted, but opt_styles is specified, appends all of the style keys to the standard Google Maps API map types.. Defaults to None.

None
Source code in geemap/geemap.py
def set_options(self, mapTypeId="HYBRID", styles=None, types=None):
    """Adds Google basemap and controls to the ipyleaflet map.

    Args:
        mapTypeId (str, optional): A mapTypeId to set the basemap to. Can be one of "ROADMAP", "SATELLITE", "HYBRID" or "TERRAIN" to select one of the standard Google Maps API map types. Defaults to 'HYBRID'.
        styles (object, optional): A dictionary of custom MapTypeStyle objects keyed with a name that will appear in the map's Map Type Controls. Defaults to None.
        types (list, optional): A list of mapTypeIds to make available. If omitted, but opt_styles is specified, appends all of the style keys to the standard Google Maps API map types.. Defaults to None.
    """
    self.clear_layers()
    self.clear_controls()
    self.scroll_wheel_zoom = True
    self.add_control(ipyleaflet.ZoomControl(position="topleft"))
    self.add_control(ipyleaflet.LayersControl(position="topright"))
    self.add_control(ipyleaflet.ScaleControl(position="bottomleft"))
    self.add_control(ipyleaflet.FullScreenControl())
    self.add_control(ipyleaflet.DrawControl())

    measure = ipyleaflet.MeasureControl(
        position="bottomleft",
        active_color="orange",
        primary_length_unit="kilometers",
    )
    self.add_control(measure)

    try:
        self.add_layer(basemap_tiles[mapTypeId])
    except Exception:
        raise ValueError(
            'Google basemaps can only be one of "ROADMAP", "SATELLITE", "HYBRID" or "TERRAIN".'
        )

set_plot_options(self, add_marker_cluster=False, sample_scale=None, plot_type=None, overlay=False, position='bottomright', min_width=None, max_width=None, min_height=None, max_height=None, **kwargs)

Sets plotting options.

Parameters:

Name Type Description Default
add_marker_cluster bool

Whether to add a marker cluster. Defaults to False.

False
sample_scale float

A nominal scale in meters of the projection to sample in . Defaults to None.

None
plot_type str

The plot type can be one of "None", "bar", "scatter" or "hist". Defaults to None.

None
overlay bool

Whether to overlay plotted lines on the figure. Defaults to False.

False
position str

Position of the control, can be ‘bottomleft’, ‘bottomright’, ‘topleft’, or ‘topright’. Defaults to 'bottomright'.

'bottomright'
min_width int

Min width of the widget (in pixels), if None it will respect the content size. Defaults to None.

None
max_width int

Max width of the widget (in pixels), if None it will respect the content size. Defaults to None.

None
min_height int

Min height of the widget (in pixels), if None it will respect the content size. Defaults to None.

None
max_height int

Max height of the widget (in pixels), if None it will respect the content size. Defaults to None.

None
Source code in geemap/geemap.py
def set_plot_options(
    self,
    add_marker_cluster=False,
    sample_scale=None,
    plot_type=None,
    overlay=False,
    position="bottomright",
    min_width=None,
    max_width=None,
    min_height=None,
    max_height=None,
    **kwargs,
):
    """Sets plotting options.

    Args:
        add_marker_cluster (bool, optional): Whether to add a marker cluster. Defaults to False.
        sample_scale (float, optional):  A nominal scale in meters of the projection to sample in . Defaults to None.
        plot_type (str, optional): The plot type can be one of "None", "bar", "scatter" or "hist". Defaults to None.
        overlay (bool, optional): Whether to overlay plotted lines on the figure. Defaults to False.
        position (str, optional): Position of the control, can be ‘bottomleft’, ‘bottomright’, ‘topleft’, or ‘topright’. Defaults to 'bottomright'.
        min_width (int, optional): Min width of the widget (in pixels), if None it will respect the content size. Defaults to None.
        max_width (int, optional): Max width of the widget (in pixels), if None it will respect the content size. Defaults to None.
        min_height (int, optional): Min height of the widget (in pixels), if None it will respect the content size. Defaults to None.
        max_height (int, optional): Max height of the widget (in pixels), if None it will respect the content size. Defaults to None.

    """
    plot_options_dict = {}
    plot_options_dict["add_marker_cluster"] = add_marker_cluster
    plot_options_dict["sample_scale"] = sample_scale
    plot_options_dict["plot_type"] = plot_type
    plot_options_dict["overlay"] = overlay
    plot_options_dict["position"] = position
    plot_options_dict["min_width"] = min_width
    plot_options_dict["max_width"] = max_width
    plot_options_dict["min_height"] = min_height
    plot_options_dict["max_height"] = max_height

    for key in kwargs.keys():
        plot_options_dict[key] = kwargs[key]

    self.plot_options = plot_options_dict

    if add_marker_cluster and (self.plot_marker_cluster not in self.layers):
        self.add_layer(self.plot_marker_cluster)

setCenter(self, lon, lat, zoom=None)

Centers the map view at a given coordinates with the given zoom level.

Parameters:

Name Type Description Default
lon float

The longitude of the center, in degrees.

required
lat float

The latitude of the center, in degrees.

required
zoom int

The zoom level, from 1 to 24. Defaults to None.

None
Source code in geemap/geemap.py
def set_center(self, lon, lat, zoom=None):
    """Centers the map view at a given coordinates with the given zoom level.

    Args:
        lon (float): The longitude of the center, in degrees.
        lat (float): The latitude of the center, in degrees.
        zoom (int, optional): The zoom level, from 1 to 24. Defaults to None.
    """
    self.center = (lat, lon)
    if zoom is not None:
        self.zoom = zoom

setControlVisibility(self, layerControl=True, fullscreenControl=True, latLngPopup=True)

Sets the visibility of the controls on the map.

Parameters:

Name Type Description Default
layerControl bool

Whether to show the control that allows the user to toggle layers on/off. Defaults to True.

True
fullscreenControl bool

Whether to show the control that allows the user to make the map full-screen. Defaults to True.

True
latLngPopup bool

Whether to show the control that pops up the Lat/lon when the user clicks on the map. Defaults to True.

True
Source code in geemap/geemap.py
def set_control_visibility(
    self, layerControl=True, fullscreenControl=True, latLngPopup=True
):
    """Sets the visibility of the controls on the map.

    Args:
        layerControl (bool, optional): Whether to show the control that allows the user to toggle layers on/off. Defaults to True.
        fullscreenControl (bool, optional): Whether to show the control that allows the user to make the map full-screen. Defaults to True.
        latLngPopup (bool, optional): Whether to show the control that pops up the Lat/lon when the user clicks on the map. Defaults to True.
    """
    pass

setOptions(self, mapTypeId='HYBRID', styles=None, types=None)

Adds Google basemap and controls to the ipyleaflet map.

Parameters:

Name Type Description Default
mapTypeId str

A mapTypeId to set the basemap to. Can be one of "ROADMAP", "SATELLITE", "HYBRID" or "TERRAIN" to select one of the standard Google Maps API map types. Defaults to 'HYBRID'.

'HYBRID'
styles object

A dictionary of custom MapTypeStyle objects keyed with a name that will appear in the map's Map Type Controls. Defaults to None.

None
types list

A list of mapTypeIds to make available. If omitted, but opt_styles is specified, appends all of the style keys to the standard Google Maps API map types.. Defaults to None.

None
Source code in geemap/geemap.py
def set_options(self, mapTypeId="HYBRID", styles=None, types=None):
    """Adds Google basemap and controls to the ipyleaflet map.

    Args:
        mapTypeId (str, optional): A mapTypeId to set the basemap to. Can be one of "ROADMAP", "SATELLITE", "HYBRID" or "TERRAIN" to select one of the standard Google Maps API map types. Defaults to 'HYBRID'.
        styles (object, optional): A dictionary of custom MapTypeStyle objects keyed with a name that will appear in the map's Map Type Controls. Defaults to None.
        types (list, optional): A list of mapTypeIds to make available. If omitted, but opt_styles is specified, appends all of the style keys to the standard Google Maps API map types.. Defaults to None.
    """
    self.clear_layers()
    self.clear_controls()
    self.scroll_wheel_zoom = True
    self.add_control(ipyleaflet.ZoomControl(position="topleft"))
    self.add_control(ipyleaflet.LayersControl(position="topright"))
    self.add_control(ipyleaflet.ScaleControl(position="bottomleft"))
    self.add_control(ipyleaflet.FullScreenControl())
    self.add_control(ipyleaflet.DrawControl())

    measure = ipyleaflet.MeasureControl(
        position="bottomleft",
        active_color="orange",
        primary_length_unit="kilometers",
    )
    self.add_control(measure)

    try:
        self.add_layer(basemap_tiles[mapTypeId])
    except Exception:
        raise ValueError(
            'Google basemaps can only be one of "ROADMAP", "SATELLITE", "HYBRID" or "TERRAIN".'
        )

split_map(self, left_layer='HYBRID', right_layer='ESRI')

Adds split map.

Parameters:

Name Type Description Default
left_layer str

The layer tile layer. Defaults to 'HYBRID'.

'HYBRID'
right_layer str

The right tile layer. Defaults to 'ESRI'.

'ESRI'
Source code in geemap/geemap.py
def split_map(self, left_layer="HYBRID", right_layer="ESRI"):
    """Adds split map.

    Args:
        left_layer (str, optional): The layer tile layer. Defaults to 'HYBRID'.
        right_layer (str, optional): The right tile layer. Defaults to 'ESRI'.
    """
    try:
        controls = self.controls
        layers = self.layers
        self.clear_controls()

        self.add_control(ipyleaflet.ZoomControl())
        self.add_control(ipyleaflet.FullScreenControl())
        if left_layer in basemap_tiles.keys():
            left_layer = basemap_tiles[left_layer]

        if right_layer in basemap_tiles.keys():
            right_layer = basemap_tiles[right_layer]

        control = ipyleaflet.SplitMapControl(
            left_layer=left_layer, right_layer=right_layer
        )

        close_button = widgets.ToggleButton(
            value=False,
            tooltip="Close split-panel map",
            icon="times",
            layout=widgets.Layout(
                height="28px", width="28px", padding="0px 0px 0px 4px"
            ),
        )

        def close_btn_click(change):
            if change["new"]:
                self.controls = controls
                self.layers = layers[:-1]
                self.add_layer(layers[-1])

        close_button.observe(close_btn_click, "value")
        close_control = ipyleaflet.WidgetControl(
            widget=close_button, position="bottomright"
        )

        self.add_control(control)
        self.add_control(close_control)

    except Exception as e:
        print("The provided layers are invalid!")
        raise ValueError(e)

to_html(self, outfile, title='My Map', width='100%', height='880px', add_layer_control=True)

Saves the map as a HTML file.

Parameters:

Name Type Description Default
outfile str

The output file path to the HTML file.

required
title str

The title of the HTML file. Defaults to 'My Map'.

'My Map'
width str

The width of the map in pixels or percentage. Defaults to '100%'.

'100%'
height str

The height of the map in pixels. Defaults to '880px'.

'880px'
add_layer_control bool

Whether to add the LayersControl. Defaults to True.

True
Source code in geemap/geemap.py
def to_html(
    self,
    outfile,
    title="My Map",
    width="100%",
    height="880px",
    add_layer_control=True,
):
    """Saves the map as a HTML file.

    Args:
        outfile (str): The output file path to the HTML file.
        title (str, optional): The title of the HTML file. Defaults to 'My Map'.
        width (str, optional): The width of the map in pixels or percentage. Defaults to '100%'.
        height (str, optional): The height of the map in pixels. Defaults to '880px'.
        add_layer_control (bool, optional): Whether to add the LayersControl. Defaults to True.

    """
    try:

        if not outfile.endswith(".html"):
            print("The output file must end with .html")
            return

        out_dir = os.path.dirname(outfile)
        if not os.path.exists(out_dir):
            os.makedirs(out_dir)

        if add_layer_control and self.layer_control is None:
            layer_control = ipyleaflet.LayersControl(position="topright")
            self.layer_control = layer_control
            self.add_control(layer_control)

        before_width = self.layout.width
        before_height = self.layout.height

        if not isinstance(width, str):
            print("width must be a string.")
            return
        elif width.endswith("px") or width.endswith("%"):
            pass
        else:
            print("width must end with px or %")
            return

        if not isinstance(height, str):
            print("height must be a string.")
            return
        elif not height.endswith("px"):
            print("height must end with px")
            return

        self.layout.width = width
        self.layout.height = height

        self.save(outfile, title=title)

        self.layout.width = before_width
        self.layout.height = before_height

    except Exception as e:
        raise Exception(e)

to_image(self, outfile=None, monitor=1)

Saves the map as a PNG or JPG image.

Parameters:

Name Type Description Default
outfile str

The output file path to the image. Defaults to None.

None
monitor int

The monitor to take the screenshot. Defaults to 1.

1
Source code in geemap/geemap.py
def to_image(self, outfile=None, monitor=1):
    """Saves the map as a PNG or JPG image.

    Args:
        outfile (str, optional): The output file path to the image. Defaults to None.
        monitor (int, optional): The monitor to take the screenshot. Defaults to 1.
    """
    if outfile is None:
        outfile = os.path.join(os.getcwd(), "my_map.png")

    if outfile.endswith(".png") or outfile.endswith(".jpg"):
        pass
    else:
        print("The output file must be a PNG or JPG image.")
        return

    work_dir = os.path.dirname(outfile)
    if not os.path.exists(work_dir):
        os.makedirs(work_dir)

    screenshot = screen_capture(outfile, monitor)
    self.screenshot = screenshot

toolbar_reset(self)

Reset the toolbar so that no tool is selected.

Source code in geemap/geemap.py
def toolbar_reset(self):
    """Reset the toolbar so that no tool is selected."""
    toolbar_grid = self.toolbar
    for tool in toolbar_grid.children:
        tool.value = False

ts_inspector(self, left_ts, right_ts, left_names, right_names, left_vis={}, right_vis={})

Creates a split-panel map for inspecting timeseries images.

Parameters:

Name Type Description Default
left_ts object

An ee.ImageCollection to show on the left panel.

required
right_ts object

An ee.ImageCollection to show on the right panel.

required
left_names list

A list of names to show under the left dropdown.

required
right_names list

A list of names to show under the right dropdown.

required
left_vis dict

Visualization parameters for the left layer. Defaults to {}.

{}
right_vis dict

Visualization parameters for the right layer. Defaults to {}.

{}
Source code in geemap/geemap.py
def ts_inspector(
    self,
    left_ts,
    right_ts,
    left_names,
    right_names,
    left_vis={},
    right_vis={},
):
    """Creates a split-panel map for inspecting timeseries images.

    Args:
        left_ts (object): An ee.ImageCollection to show on the left panel.
        right_ts (object): An ee.ImageCollection to show on the right panel.
        left_names (list): A list of names to show under the left dropdown.
        right_names (list): A list of names to show under the right dropdown.
        left_vis (dict, optional): Visualization parameters for the left layer. Defaults to {}.
        right_vis (dict, optional): Visualization parameters for the right layer. Defaults to {}.
    """
    left_count = int(left_ts.size().getInfo())
    right_count = int(right_ts.size().getInfo())

    if left_count != len(left_names):
        print(
            "The number of images in left_ts must match the number of layer names in left_names."
        )
        return
    if right_count != len(right_names):
        print(
            "The number of images in right_ts must match the number of layer names in right_names."
        )
        return

    left_layer = ipyleaflet.TileLayer(
        url="https://mt1.google.com/vt/lyrs=m&x={x}&y={y}&z={z}",
        attribution="Google",
        name="Google Maps",
    )
    right_layer = ipyleaflet.TileLayer(
        url="https://mt1.google.com/vt/lyrs=m&x={x}&y={y}&z={z}",
        attribution="Google",
        name="Google Maps",
    )

    self.clear_controls()
    left_dropdown = widgets.Dropdown(options=left_names, value=None)
    right_dropdown = widgets.Dropdown(options=right_names, value=None)
    left_dropdown.layout.max_width = "130px"
    right_dropdown.layout.max_width = "130px"

    left_control = ipyleaflet.WidgetControl(
        widget=left_dropdown, position="topleft"
    )
    right_control = ipyleaflet.WidgetControl(
        widget=right_dropdown, position="topright"
    )

    self.add_control(control=left_control)
    self.add_control(control=right_control)

    self.add_control(ipyleaflet.ZoomControl(position="topleft"))
    self.add_control(ipyleaflet.ScaleControl(position="bottomleft"))
    self.add_control(ipyleaflet.FullScreenControl())

    def left_dropdown_change(change):
        left_dropdown_index = left_dropdown.index
        if left_dropdown_index is not None and left_dropdown_index >= 0:
            try:
                if isinstance(left_ts, ee.ImageCollection):
                    left_image = left_ts.toList(left_ts.size()).get(
                        left_dropdown_index
                    )
                elif isinstance(left_ts, ee.List):
                    left_image = left_ts.get(left_dropdown_index)
                else:
                    print("The left_ts argument must be an ImageCollection.")
                    return

                if isinstance(left_image, ee.ImageCollection):
                    left_image = ee.Image(left_image.mosaic())
                elif isinstance(left_image, ee.Image):
                    pass
                else:
                    left_image = ee.Image(left_image)

                left_image = ee_tile_layer(
                    left_image, left_vis, left_names[left_dropdown_index]
                )
                left_layer.url = left_image.url
            except Exception as e:
                print(e)
                return

    left_dropdown.observe(left_dropdown_change, names="value")

    def right_dropdown_change(change):
        right_dropdown_index = right_dropdown.index
        if right_dropdown_index is not None and right_dropdown_index >= 0:
            try:
                if isinstance(right_ts, ee.ImageCollection):
                    right_image = right_ts.toList(left_ts.size()).get(
                        right_dropdown_index
                    )
                elif isinstance(right_ts, ee.List):
                    right_image = right_ts.get(right_dropdown_index)
                else:
                    print("The left_ts argument must be an ImageCollection.")
                    return

                if isinstance(right_image, ee.ImageCollection):
                    right_image = ee.Image(right_image.mosaic())
                elif isinstance(right_image, ee.Image):
                    pass
                else:
                    right_image = ee.Image(right_image)

                right_image = ee_tile_layer(
                    right_image,
                    right_vis,
                    right_names[right_dropdown_index],
                )
                right_layer.url = right_image.url
            except Exception as e:
                print(e)
                return

    right_dropdown.observe(right_dropdown_change, names="value")

    try:

        split_control = ipyleaflet.SplitMapControl(
            left_layer=left_layer, right_layer=right_layer
        )
        self.add_control(split_control)

    except Exception as e:
        raise Exception(e)

video_overlay(self, url, bounds, name)

Overlays a video from the Internet on the map.

Parameters:

Name Type Description Default
url str

http URL of the video, such as "https://www.mapbox.com/bites/00188/patricia_nasa.webm"

required
bounds tuple

bounding box of the video in the format of (lower_left(lat, lon), upper_right(lat, lon)), such as ((13, -130), (32, -100)).

required
name str

name of the layer to show on the layer control.

required
Source code in geemap/geemap.py
def video_overlay(self, url, bounds, name):
    """Overlays a video from the Internet on the map.

    Args:
        url (str): http URL of the video, such as "https://www.mapbox.com/bites/00188/patricia_nasa.webm"
        bounds (tuple): bounding box of the video in the format of (lower_left(lat, lon), upper_right(lat, lon)), such as ((13, -130), (32, -100)).
        name (str): name of the layer to show on the layer control.
    """
    try:
        video = ipyleaflet.VideoOverlay(url=url, bounds=bounds, name=name)
        self.add_layer(video)
    except Exception as e:
        print(e)

zoom_to_me(self, zoom=14, add_marker=True)

Zoom to the current device location.

Parameters:

Name Type Description Default
zoom int

Zoom level. Defaults to 14.

14
add_marker bool

Whether to add a marker of the current device location. Defaults to True.

True
Source code in geemap/geemap.py
def zoom_to_me(self, zoom=14, add_marker=True):
    """Zoom to the current device location.

    Args:
        zoom (int, optional): Zoom level. Defaults to 14.
        add_marker (bool, optional): Whether to add a marker of the current device location. Defaults to True.
    """
    lat, lon = get_current_latlon()
    self.set_center(lon, lat, zoom)

    if add_marker:
        marker = ipyleaflet.Marker(
            location=(lat, lon),
            draggable=False,
            name="Device location",
        )
        self.add_layer(marker)

zoom_to_object(self, ee_object)

Zoom to the full extent of an Earth Engine object.

Parameters:

Name Type Description Default
ee_object object

An Earth Engine object, such as Image, ImageCollection, Geometry, Feature, FeatureCollection.

required

Exceptions:

Type Description
Exception

Error getting geometry.

Source code in geemap/geemap.py
def zoom_to_object(self, ee_object):
    """Zoom to the full extent of an Earth Engine object.

    Args:
        ee_object (object): An Earth Engine object, such as Image, ImageCollection, Geometry, Feature, FeatureCollection.

    Raises:
        Exception: Error getting geometry.
    """
    coordinates = None
    if isinstance(ee_object, ee.geometry.Geometry):
        bounds = ee_object.bounds()
        coordinates = bounds.getInfo()["coordinates"][0]

    else:
        try:
            bounds = ee_object.geometry().bounds()
            coordinates = bounds.getInfo()["coordinates"][0]

        except Exception as e:
            print(e)
            raise Exception(e)

    if coordinates is not None:
        south = coordinates[0][1]
        west = coordinates[0][0]
        north = coordinates[2][1]
        east = coordinates[2][0]
        self.fit_bounds([[south, east], [north, west]])

zoomToObject(self, ee_object)

Zoom to the full extent of an Earth Engine object.

Parameters:

Name Type Description Default
ee_object object

An Earth Engine object, such as Image, ImageCollection, Geometry, Feature, FeatureCollection.

required

Exceptions:

Type Description
Exception

Error getting geometry.

Source code in geemap/geemap.py
def zoom_to_object(self, ee_object):
    """Zoom to the full extent of an Earth Engine object.

    Args:
        ee_object (object): An Earth Engine object, such as Image, ImageCollection, Geometry, Feature, FeatureCollection.

    Raises:
        Exception: Error getting geometry.
    """
    coordinates = None
    if isinstance(ee_object, ee.geometry.Geometry):
        bounds = ee_object.bounds()
        coordinates = bounds.getInfo()["coordinates"][0]

    else:
        try:
            bounds = ee_object.geometry().bounds()
            coordinates = bounds.getInfo()["coordinates"][0]

        except Exception as e:
            print(e)
            raise Exception(e)

    if coordinates is not None:
        south = coordinates[0][1]
        west = coordinates[0][0]
        north = coordinates[2][1]
        east = coordinates[2][0]
        self.fit_bounds([[south, east], [north, west]])

ee_tile_layer(ee_object, vis_params={}, name='Layer untitled', shown=True, opacity=1.0)

Converts and Earth Engine layer to ipyleaflet TileLayer.

Parameters:

Name Type Description Default
ee_object Collection|Feature|Image|MapId

The object to add to the map.

required
vis_params dict

The visualization parameters. Defaults to {}.

{}
name str

The name of the layer. Defaults to 'Layer untitled'.

'Layer untitled'
shown bool

A flag indicating whether the layer should be on by default. Defaults to True.

True
opacity float

The layer's opacity represented as a number between 0 and 1. Defaults to 1.

1.0
Source code in geemap/geemap.py
def ee_tile_layer(
    ee_object, vis_params={}, name="Layer untitled", shown=True, opacity=1.0
):
    """Converts and Earth Engine layer to ipyleaflet TileLayer.

    Args:
        ee_object (Collection|Feature|Image|MapId): The object to add to the map.
        vis_params (dict, optional): The visualization parameters. Defaults to {}.
        name (str, optional): The name of the layer. Defaults to 'Layer untitled'.
        shown (bool, optional): A flag indicating whether the layer should be on by default. Defaults to True.
        opacity (float, optional): The layer's opacity represented as a number between 0 and 1. Defaults to 1.
    """

    image = None

    if (
        not isinstance(ee_object, ee.Image)
        and not isinstance(ee_object, ee.ImageCollection)
        and not isinstance(ee_object, ee.FeatureCollection)
        and not isinstance(ee_object, ee.Feature)
        and not isinstance(ee_object, ee.Geometry)
    ):
        err_str = "\n\nThe image argument in 'addLayer' function must be an instance of one of ee.Image, ee.Geometry, ee.Feature or ee.FeatureCollection."
        raise AttributeError(err_str)

    if (
        isinstance(ee_object, ee.geometry.Geometry)
        or isinstance(ee_object, ee.feature.Feature)
        or isinstance(ee_object, ee.featurecollection.FeatureCollection)
    ):
        features = ee.FeatureCollection(ee_object)

        width = 2

        if "width" in vis_params:
            width = vis_params["width"]

        color = "000000"

        if "color" in vis_params:
            color = vis_params["color"]

        image_fill = features.style(**{"fillColor": color}).updateMask(
            ee.Image.constant(0.5)
        )
        image_outline = features.style(
            **{"color": color, "fillColor": "00000000", "width": width}
        )

        image = image_fill.blend(image_outline)
    elif isinstance(ee_object, ee.image.Image):
        image = ee_object
    elif isinstance(ee_object, ee.imagecollection.ImageCollection):
        image = ee_object.mosaic()

    map_id_dict = ee.Image(image).getMapId(vis_params)
    tile_layer = ipyleaflet.TileLayer(
        url=map_id_dict["tile_fetcher"].url_format,
        attribution="Google Earth Engine",
        name=name,
        opacity=opacity,
        visible=shown,
    )
    return tile_layer

linked_maps(rows=2, cols=2, height='400px', ee_objects=[], vis_params=[], labels=[], label_position='topright', **kwargs)

Create linked maps of Earth Engine data layers.

Parameters:

Name Type Description Default
rows int

The number of rows of maps to create. Defaults to 2.

2
cols int

The number of columns of maps to create. Defaults to 2.

2
height str

The height of each map in pixels. Defaults to "400px".

'400px'
ee_objects list

The list of Earth Engine objects to use for each map. Defaults to [].

[]
vis_params list

The list of visualization parameters to use for each map. Defaults to [].

[]
labels list

The list of labels to show on the map. Defaults to [].

[]
label_position str

The position of the label, can be [topleft, topright, bottomleft, bottomright]. Defaults to "topright".

'topright'

Exceptions:

Type Description
ValueError

If the length of ee_objects is not equal to rows*cols.

ValueError

If the length of vis_params is not equal to rows*cols.

ValueError

If the length of labels is not equal to rows*cols.

Returns:

Type Description
ipywidget

A GridspecLayout widget.

Source code in geemap/geemap.py
def linked_maps(
    rows=2,
    cols=2,
    height="400px",
    ee_objects=[],
    vis_params=[],
    labels=[],
    label_position="topright",
    **kwargs,
):
    """Create linked maps of Earth Engine data layers.

    Args:
        rows (int, optional): The number of rows of maps to create. Defaults to 2.
        cols (int, optional): The number of columns of maps to create. Defaults to 2.
        height (str, optional): The height of each map in pixels. Defaults to "400px".
        ee_objects (list, optional): The list of Earth Engine objects to use for each map. Defaults to [].
        vis_params (list, optional): The list of visualization parameters to use for each map. Defaults to [].
        labels (list, optional): The list of labels to show on the map. Defaults to [].
        label_position (str, optional): The position of the label, can be [topleft, topright, bottomleft, bottomright]. Defaults to "topright".

    Raises:
        ValueError: If the length of ee_objects is not equal to rows*cols.
        ValueError: If the length of vis_params is not equal to rows*cols.
        ValueError: If the length of labels is not equal to rows*cols.

    Returns:
        ipywidget: A GridspecLayout widget.
    """
    grid = widgets.GridspecLayout(rows, cols, grid_gap="0px")
    count = rows * cols

    maps = []

    if len(ee_objects) > 0:
        if len(ee_objects) == 1:
            ee_objects = ee_objects * count
        elif len(ee_objects) < count:
            raise ValueError(f"The length of ee_objects must be equal to {count}.")

    if len(vis_params) > 0:
        if len(vis_params) == 1:
            vis_params = vis_params * count
        elif len(vis_params) < count:
            raise ValueError(f"The length of vis_params must be equal to {count}.")

    if len(labels) > 0:
        if len(labels) == 1:
            labels = labels * count
        elif len(labels) < count:
            raise ValueError(f"The length of labels must be equal to {count}.")

    for i in range(rows):
        for j in range(cols):
            index = i * rows + j
            m = Map(
                height=height,
                lite_mode=True,
                add_google_map=False,
                layout=widgets.Layout(margin="0px", padding="0px"),
                **kwargs,
            )

            if len(ee_objects) > 0:
                m.addLayer(ee_objects[index], vis_params[index], labels[index])

            if len(labels) > 0:
                label = widgets.Label(
                    labels[index], layout=widgets.Layout(padding="0px 5px 0px 5px")
                )
                control = ipyleaflet.WidgetControl(
                    widget=label, position=label_position
                )
                m.add_control(control)

            maps.append(m)
            widgets.jslink((maps[0], "center"), (m, "center"))
            widgets.jslink((maps[0], "zoom"), (m, "zoom"))

            output = widgets.Output()
            with output:
                display(m)
            grid[i, j] = output

    return grid

Last update: 2021-09-18