Skip to content

'Can't access property "state_change", t is undefined' when adding to a LayerGroup - ipyleaflet map embedded in Shiny app #1271

@shawnboltz

Description

@shawnboltz

Hello,

I am fairly new to using ipyleaflet and am trying to create a test app using Shiny Express that 'selects' a marker and highlights it on a map. I have a Shiny input_select with a list of locations and the locations are displayed as markers on the map in a LayerGroup. When I select a city in the dropdown I have a reactive effect that should replace the marker for the selected location with a new one with a different icon (note: I've tried just changing the icon on the existing marker, but that doesn't correctly update on the map). I'm doing this using the .add and .remove methods on the LayerGroup. I've also tried just adding the markers to the map directly instead of using a LayerGroup and get the same result.

I'm getting some odd behavior where the marker for the currently selected location just disappears from the map and then re-appears after selecting a different city. I think I've tracked this down to what appears to be a bug in the logic that gets triggered by the .add method. Looking in the developer console in Firefox, I noticed that there is an error that triggers: 'Uncaught (in promise) TypeError: can't access property "state_change", t is undefined'. The behavior is the same in Edge.

I'm not sure if this is actually a problem with ipyleaflet or if it's something with shinywidgets or ipywidgets and unfortunately don't know where to begin to track down the issue. Does anyone know what I might be able to do as a workaround?

Version info:
Windows 11
Python 3.12
ipyleaflet 0.20.0
shinywidgets 0.7.0
ipywidgets 8.1.7

Example:

from shiny import reactive
from shiny.express import ui, input
from ipyleaflet import Map, Marker, LayerGroup, AwesomeIcon
from shinywidgets import render_widget

capital_cities = [
    {"city": "Dublin", "lat": 53.35, "lon": -6.26, "population": 1.30},
    {"city": "London", "lat": 51.51, "lon": -0.13, "population": 9.84},
    {"city": "Edinburgh", "lat": 55.95, "lon": -3.19, "population": 0.56},
    {"city": "Belfast", "lat": 54.60, "lon": -5.93, "population": 0.35},
    {"city": "Cardiff", "lat": 51.48, "lon": -3.17, "population": 0.50},
]

ui.page_opts(title="Map")

_cities = [x["city"] for x in capital_cities]
_cities.sort()
ui.input_select(
    "selected_city",
    "Select a city:",
    _cities,
)

@render_widget
def display_map():
    map_ = Map(center=(51, 0), zoom=5)
    map_.layout.height = '600px'

    # Create markers first
    markers = []
    for city in capital_cities:
        m = Marker(location=(city["lat"], city["lon"]), name=city["city"], title=city["city"])
        m.icon = AwesomeIcon(name="hand-spock-o", marker_color="red")
        markers.append(m)

    # Put the markers in a layergroup and plot
    group = LayerGroup(layers=markers)
    map_.add(group)

    return map_


@reactive.effect
def change_selected_city_marker():
    city = input.selected_city.get()
    print(city)

    marker_group = display_map.widget.layers[1]  # I have confirmed that this is the correct LayerGroup
    markers = marker_group.layers
    print("Number of markers before update:", len(markers))

    for m in markers:
        if m.name == city:
            print(f"Old Marker:\n{m}")
            updated_marker = Marker(
                location=m.location,
                name=m.name,
                title=m.title,
                icon=AwesomeIcon(name="hand-spock-o", marker_color="green")
            )
            print(f"New Marker:\n{updated_marker}")
            marker_group.remove(m)
            marker_group.add(updated_marker)
            break

    print("Number of markers after update:", len(marker_group.layers))
Image

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions