Skip to content

[Bug]: ipyleaflet map becomes gray after reloading with a few hundreds points #215

@etiennebacher

Description

@etiennebacher

Component

Input/Output Bindings

Severity

P1 - High (major feature broken)

Shiny Version

1.5.0

Python Version

3.13.7

Minimal Reproducible Example

from shinywidgets import render_widget, output_widget
from ipyleaflet import (
    Map,
    CircleMarker,
    LayerGroup,
)
from shiny import App, reactive, ui
import geopandas as gpd

geo_str = """{
"type": "FeatureCollection",
"crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } },
"features": [
{ "type": "Feature", "properties": { "id": "ak16994521", "mag": 2.3, "time": 1507425650893, "felt": null, "tsunami": 0 }, "geometry": { "type": "Point", "coordinates": [ -151.5129, 63.1016, 0.0 ] } },
]}
"""
dat = gpd.read_file(geo_str, driver="GeoJSON")

app_ui = ui.page_fluid(ui.input_action_button("reload", "reload"), output_widget("map"))


def server(input, output, session):
    reactive_dat = reactive.Value(dat)

    @reactive.effect
    @reactive.event(input.reload)
    def _():
        reactive_dat.set(dat.sample(n=1000, replace=True))

    @render_widget
    def map():
        map = Map(zoom=1)
        markers = []
        for idx, row in reactive_dat().iterrows():
            marker = CircleMarker(location=(row.geometry.y, row.geometry.x), radius=3)
            markers.append(marker)

        map.add_layer(LayerGroup(layers=markers))
        return map


app = App(app_ui, server)

Behavior

On startup, the map renders fine.

If I press the "Reload" button to mimick some computations, then the entire map becomes gray and unusable. This only happens when the number of observations in sample() is high enough. In the example, there are 1,000 points on the same lat/lon.

Image

Error Messages (if any)

There are two kinds of error messages in the browser console:

  1. This happens at every "Reload" click but doesn't necessarily trigger the grey map:
Error during model cleanup: Error: Widget is not attached.
    detach libembed-amd.js:69
    dispose libembed-amd.js:69
    dispose libembed-amd.js:69
    remove libembed-amd.js:69
    g libembed-amd.js:1
    v libembed-amd.js:1
    h libembed-amd.js:1
    trigger libembed-amd.js:1
    close libembed-amd.js:69
    <anonymous> output.ts:227
    _sendMessagesToHandlers shinyapp.ts:695
    _init shinyapp.ts:860
    _sendMessagesToHandlers shinyapp.ts:695
    dispatchMessage shinyapp.ts:670
    onmessage shinyapp.ts:256
    startActionQueueLoop shinyapp.ts:285
    onopen shinyapp.ts:253
    createSocket shinyapp.ts:226
    connect shinyapp.ts:166
    initialize index.ts:672
    ShinyClass index.ts:144
    setTimeout handler*ShinyClass/< index.ts:142
    jQuery 13

2 . This is the cause of the grey map:

Uncaught (in promise) TypeError: t is undefined
    create_view libembed-amd.js:25
    create_child_view libembed-amd.js:69
    add_layer_model Map.js:186
    update libembed-amd.js:69
    render_leaflet Map.js:242
    promise callback*render_leaflet Map.js:240
    promise callback*render Map.js:236
    state_change libembed-amd.js:25
    promise callback*t.prototype.create_view/t.state_change< libembed-amd.js:25
    promise callback*t.prototype.create_view libembed-amd.js:25
    renderValue output.ts:94
    onValueChange outputBinding.ts:26
    onValueChange outputAdapter.ts:34
    receiveOutput shinyapp.ts:515
    _init shinyapp.ts:725
    _sendMessagesToHandlers shinyapp.ts:695
    dispatchMessage shinyapp.ts:670
    onmessage shinyapp.ts:256
    startActionQueueLoop shinyapp.ts:285
    onopen shinyapp.ts:253
    createSocket shinyapp.ts:226
    connect shinyapp.ts:166
    initialize index.ts:672
    ShinyClass index.ts:144
    setTimeout handler*ShinyClass/< index.ts:142
    jQuery 13

Clicking one the links to index.ts leads to this part:

$(() => {
      // Init Shiny a little later than document ready, so user code can
      // run first (i.e. to register bindings)
      setTimeout(async () => {
        try {
          await this.initialize();
        } catch (e) {
          showErrorInClientConsole(e);
          throw e;
        }
      }, 1);
    });

I could be wrong, but it seems to me that the map takes slightly too long to being ready and therefore shiny tries to register a binding that doesn't exist yet, hence the grey map. If this is correct, is there a way to manually set the timeout before triggering the shiny input registration?

Environment

Windows 10

Firefox 128.0 esr. Also observed with Chrome 140 but interestingly the second error message is a bit different:

libembed-amd.js:25 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'state_change')
    at t.create_view (libembed-amd.js:25:145526)
    at e.create_child_view (libembed-amd.js:69:155859)
    at ii.add_layer_model (Map.js:186:17)
    at t.update (libembed-amd.js:69:168796)
    at Map.js:242:24

Using uv with pyproject.toml:

[project]
name = "test-shiny-app"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.11"
dependencies = [
    "geopandas>=1.1.0",
    "ipykernel>=6.29.5",
    "ipyleaflet==0.17.3",
    "ipywidgets==8.1.7",
    "shiny==1.5.0",
    "shinywidgets>=0.7.0",
]

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions