Scattermapbox cluster bug - "The layer does not exist in the map's style..."

Hi,

I’m trying to create a webapp which uses the cluster function within scattermapbox. However, every so often, when loading the webapp, I’m presented with the following console error (which prevents any further interaction with the map):

Uncaught (in promise) Error: Mapbox error.

followed by multiple errors of the type:

Error: The layer 'plotly-trace-layer-4f7f6d-circle' does not exist in the map's style and cannot be queried for features.

I’ve created the following minimal example which throws up the same errors (they occur once every ~10 times I reload the webapp making the issue hard to track down). The example creates a list of random points around the world and plots them on a map. The example includes a simple callback to print the location of a point when clicking on it. I’ve tracked the issue down to the use of the cluster option in the “map_data” list (i.e. if I disable the cluster option, the errors no longer appear). From other posts/the documentation, I’m aware that the cluster option is not expected to work with OpenStreetMaps tiles hence the example requires a Mapbox access token.

from dash import Dash, dcc, html
from dash import Input, Output
from random import randint, seed

# -- Fix the randomness
seed(10)

# -- Generate random data
npoints = 100
latitudes = [randint(-90, 90) for i in range(npoints)]
longitudes = [randint(-180, 180) for i in range(npoints)]
colors = ["green" for i in range(npoints)]

# -- Mapbox styles
mapbox_style = "streets"
mapbox_accesstoken = open(".mapbox_token").read().strip()

# -- Set map data
map_data = [
    {
        "type": "scattermapbox",
        "lat": latitudes,
        "lon": longitudes,
        "mode": "markers",
        "marker": {
            "size": 15,
            "color": colors,
        },
        "cluster": {
            "enabled": True,
            "color": "green",
            "type": "circle",
            "maxzoom": 10,
            "size": 25,
            "opacity": 0.7,
        },
    },
]


# -- Set map layout
map_layout = {
    "mapbox": {
        "style": mapbox_style,
        "accesstoken": mapbox_accesstoken,
    },
    "clickmode": "event",
    "margin": {"t": 0, "r": 0, "b": 0, "l": 0},
}

# -- Create div with map and a dummy div for the callback
layout = html.Div(
    children=[
        dcc.Graph(
            id="world-map",
            figure={"data": map_data, "layout": map_layout},
            config={"displayModeBar": False, "scrollZoom": True},
            style={"height": "100vh"},
        ),
        html.Div(id="dummy"),
    ],
)

# -- Create app
app = Dash(
    __name__,
)
app.layout = layout

# -- Simple callback to print click data
@app.callback(
    Output("dummy", "children"),
    Input("world-map", "clickData"),
    prevent_initial_call=True,
)
def print_click(
    clickData,
):
    lat = clickData["points"][0]["lat"]
    lon = clickData["points"][0]["lon"]
    print("Clicked on point at lat/lon {}/{}".format(lat, lon))
    return None


if __name__ == "__main__":
    app.run_server(debug=True, use_reloader=False, host="0.0.0.0", port=8081)

I have tested the code on multiple computers with different browsers and they all present the same issue. I’m using the following up-to-date versions of dash and plotly:

plotly==5.18.0
dash==2.14.1

The full console logs for the errors are:

Uncaught (in promise) Error: Mapbox error.
    r plotly.min.js:8
    fire plotly.min.js:8
    fire plotly.min.js:8
    queryRenderedFeatures plotly.min.js:8
    queryRenderedFeatures plotly.min.js:8
    hoverPoints plotly.min.js:8
    ht plotly.min.js:8
    hover plotly.min.js:8
    hover plotly.min.js:8
    l plotly.min.js:8
    throttle plotly.min.js:8
    hover plotly.min.js:8
    initFx plotly.min.js:8
    fire plotly.min.js:8
    mousemove plotly.min.js:8
    handleEvent plotly.min.js:8
    addEventListener plotly.min.js:8
    ki plotly.min.js:8
    i plotly.min.js:8
    createMap plotly.min.js:8
    n plotly.min.js:8
    plot plotly.min.js:8
    plot plotly.min.js:8
    drawData plotly.min.js:8
    syncOrAsync plotly.min.js:8
    _doPlot plotly.min.js:8
    newPlot plotly.min.js:8
    react plotly.min.js:8
    React 3
    commitLifeCycles react-dom@16.v2_14_1m1699425702.14.0.js:19949
    commitLayoutEffects react-dom@16.v2_14_1m1699425702.14.0.js:22938
    callCallback react-dom@16.v2_14_1m1699425702.14.0.js:182
    invokeGuardedCallbackDev react-dom@16.v2_14_1m1699425702.14.0.js:231
    invokeGuardedCallback react-dom@16.v2_14_1m1699425702.14.0.js:286
    commitRootImpl react-dom@16.v2_14_1m1699425702.14.0.js:22676
    unstable_runWithPriority react@16.v2_14_1m1699425702.14.0.js:2685
    runWithPriority$1 react-dom@16.v2_14_1m1699425702.14.0.js:11174
    commitRoot react-dom@16.v2_14_1m1699425702.14.0.js:22516
    finishSyncRender react-dom@16.v2_14_1m1699425702.14.0.js:21942
    performSyncWorkOnRoot react-dom@16.v2_14_1m1699425702.14.0.js:21928
    flushSyncCallbackQueueImpl react-dom@16.v2_14_1m1699425702.14.0.js:11224
    unstable_runWithPriority react@16.v2_14_1m1699425702.14.0.js:2685
    runWithPriority$1 react-dom@16.v2_14_1m1699425702.14.0.js:11174
    flushSyncCallbackQueueImpl react-dom@16.v2_14_1m1699425702.14.0.js:11219
    workLoop react@16.v2_14_1m1699425702.14.0.js:2629
    flushWork react@16.v2_14_1m1699425702.14.0.js:2584
    performWorkUntilDeadline react@16.v2_14_1m1699425702.14.0.js:2196
    EventHandlerNonNull* react@16.v2_14_1m1699425702.14.0.js:2219
    <anonymous> react@16.v2_14_1m1699425702.14.0.js:15
    <anonymous> react@16.v2_14_1m1699425702.14.0.js:16

and

Error: The layer 'plotly-trace-layer-4f7f6d-circle' does not exist in the map's style and cannot be queried for features.
    queryRenderedFeatures plotly.min.js:8
    queryRenderedFeatures plotly.min.js:8
    hoverPoints plotly.min.js:8
    ht plotly.min.js:8
    hover plotly.min.js:8
    hover plotly.min.js:8
    l plotly.min.js:8
    throttle plotly.min.js:8
    hover plotly.min.js:8
    initFx plotly.min.js:8
    fire plotly.min.js:8
    mousemove plotly.min.js:8
    handleEvent plotly.min.js:8
    addEventListener plotly.min.js:8
    ki plotly.min.js:8
    i plotly.min.js:8
    createMap plotly.min.js:8
    n plotly.min.js:8
    plot plotly.min.js:8
    plot plotly.min.js:8
    drawData plotly.min.js:8
    syncOrAsync plotly.min.js:8
    _doPlot plotly.min.js:8
    newPlot plotly.min.js:8
    react plotly.min.js:8
    React 3
    commitLifeCycles react-dom@16.v2_14_1m1699425702.14.0.js:19949
    commitLayoutEffects react-dom@16.v2_14_1m1699425702.14.0.js:22938
    callCallback react-dom@16.v2_14_1m1699425702.14.0.js:182
    invokeGuardedCallbackDev react-dom@16.v2_14_1m1699425702.14.0.js:231
    invokeGuardedCallback react-dom@16.v2_14_1m1699425702.14.0.js:286
    commitRootImpl react-dom@16.v2_14_1m1699425702.14.0.js:22676
    unstable_runWithPriority react@16.v2_14_1m1699425702.14.0.js:2685
    runWithPriority$1 react-dom@16.v2_14_1m1699425702.14.0.js:11174
    commitRoot react-dom@16.v2_14_1m1699425702.14.0.js:22516
    finishSyncRender react-dom@16.v2_14_1m1699425702.14.0.js:21942
    performSyncWorkOnRoot react-dom@16.v2_14_1m1699425702.14.0.js:21928
    flushSyncCallbackQueueImpl react-dom@16.v2_14_1m1699425702.14.0.js:11224
    unstable_runWithPriority react@16.v2_14_1m1699425702.14.0.js:2685
    runWithPriority$1 react-dom@16.v2_14_1m1699425702.14.0.js:11174
    flushSyncCallbackQueueImpl react-dom@16.v2_14_1m1699425702.14.0.js:11219
    workLoop react@16.v2_14_1m1699425702.14.0.js:2629
    flushWork react@16.v2_14_1m1699425702.14.0.js:2584
    performWorkUntilDeadline react@16.v2_14_1m1699425702.14.0.js:2196
    EventHandlerNonNull* react@16.v2_14_1m1699425702.14.0.js:2219
    <anonymous> react@16.v2_14_1m1699425702.14.0.js:15
    <anonymous> react@16.v2_14_1m1699425702.14.0.js:16
plotly.min.js:8:2494743
    fire plotly.min.js:8
    queryRenderedFeatures plotly.min.js:8
    queryRenderedFeatures plotly.min.js:8
    hoverPoints plotly.min.js:8
    ht plotly.min.js:8
    hover plotly.min.js:8
    hover plotly.min.js:8
    l plotly.min.js:8
    throttle plotly.min.js:8
    hover plotly.min.js:8
    initFx plotly.min.js:8
    fire plotly.min.js:8
    mousemove plotly.min.js:8
    handleEvent plotly.min.js:8
    (Async: EventListener.handleEvent)
    addEventListener plotly.min.js:8
    ki plotly.min.js:8
    i plotly.min.js:8
    createMap plotly.min.js:8
    n plotly.min.js:8
    plot plotly.min.js:8
    plot plotly.min.js:8
    drawData plotly.min.js:8
    syncOrAsync plotly.min.js:8
    _doPlot plotly.min.js:8
    newPlot plotly.min.js:8
    react plotly.min.js:8
    React 3
    commitLifeCycles react-dom@16.v2_14_1m1699425702.14.0.js:19949
    commitLayoutEffects react-dom@16.v2_14_1m1699425702.14.0.js:22938
    callCallback react-dom@16.v2_14_1m1699425702.14.0.js:182
    invokeGuardedCallbackDev react-dom@16.v2_14_1m1699425702.14.0.js:231
    invokeGuardedCallback react-dom@16.v2_14_1m1699425702.14.0.js:286
    commitRootImpl react-dom@16.v2_14_1m1699425702.14.0.js:22676
    unstable_runWithPriority react@16.v2_14_1m1699425702.14.0.js:2685
    runWithPriority$1 react-dom@16.v2_14_1m1699425702.14.0.js:11174
    commitRoot react-dom@16.v2_14_1m1699425702.14.0.js:22516
    finishSyncRender react-dom@16.v2_14_1m1699425702.14.0.js:21942
    performSyncWorkOnRoot react-dom@16.v2_14_1m1699425702.14.0.js:21928
    flushSyncCallbackQueueImpl react-dom@16.v2_14_1m1699425702.14.0.js:11224
    unstable_runWithPriority react@16.v2_14_1m1699425702.14.0.js:2685
    runWithPriority$1 react-dom@16.v2_14_1m1699425702.14.0.js:11174
    flushSyncCallbackQueueImpl react-dom@16.v2_14_1m1699425702.14.0.js:11219
    workLoop react@16.v2_14_1m1699425702.14.0.js:2629
    flushWork react@16.v2_14_1m1699425702.14.0.js:2584
    performWorkUntilDeadline react@16.v2_14_1m1699425702.14.0.js:2196
    (Async: EventHandlerNonNull)
    <anonymous> react@16.v2_14_1m1699425702.14.0.js:2219
    <anonymous> react@16.v2_14_1m1699425702.14.0.js:15
    <anonymous> react@16.v2_14_1m1699425702.14.0.js:16

Any help on understanding the source of the issue and a way to remedy it would be greatly appreciated!

I see some similarity with the following threads which seem unresolved:

To anyone looking into this issue, is there anything more I can provide to help pinpoint the source?

Uncaught (in promise) Error: Mapbox error.

I can confirm this error in my console as well.

I also get a similar error to the one reported:

Error: The layer ‘plotly-trace-layer-2c1bdd-circle’ does not exist in the map’s style and cannot be queried for features.

Right. I had stopped searching for a solution to this up until now but I’m happy to explore some options if you have any ideas. I had opened a thread on the plotly/dash GitHub repo https://github.com/plotly/dash/issues/2706 which you had commented on at the time if that is a better forum for discussion.

After much time banging my head against the keyboard trying to get a good cluster to work in leaflet, this is the approach I came up with.

Its a little more complicated than what you where exactly looking for, in this example I created a custom cluster style for a random progress ring and custom icon render for icons within the cluster.

The cluster can be simplified if you remove the variable cluster_to_layer from pages/market_cluster and you’ll render the default cluster.

Also if anyone can figure out how to replace the javascript’s random progress ring for real data from a dataframe, I’d be very much grateful.

ezgif.com-optimize

1 Like