Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BUG] Dynamic update of Mapbox style not working #1152

Closed
bluenote10 opened this issue Mar 13, 2020 · 12 comments
Closed

[BUG] Dynamic update of Mapbox style not working #1152

bluenote10 opened this issue Mar 13, 2020 · 12 comments

Comments

@bluenote10
Copy link

bluenote10 commented Mar 13, 2020

Context
Please provide us your environment so we can easily reproduce the issue.

  • pip list | grep dash
dash                               1.9.1               
dash-bootstrap-components          0.9.1               
dash-core-components               1.8.1               
dash-html-components               1.0.2               
dash-renderer                      1.2.4               
dash-table                         4.6.1               
  • Browser versions (but most likely not a frontend issue):

    • OS: Ubuntu 16.04
    • Browser: Firefox
    • Version: 73.0.1

Describe the bug

I have a use case which requires to dynamically set the style of a Mapbox map, for instance to modify the underlying tile server. It looks like dynamic updates of mapbox styles do not lead to an update of the map. Minimal reproducing example:

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output

import plotly.graph_objects as go


def init_app():
    app = dash.Dash(__name__)

    graph = dcc.Graph(
        id='graph',
        style={
            'width': '100%',
            'height': '1000px',
        }
    )
    switch = dcc.RadioItems(
        id='switch',
        options=[
            {'label': 'Map A', 'value': 'A'},
            {'label': 'Map B', 'value': 'B'},
        ],
        value='A',
    )
    app.layout = html.Div(children=[
        html.Div(children=[switch]),
        html.Div(children=[graph]),
    ])

    @app.callback(
        Output('graph', 'figure'),
        [Input('switch', 'value')],
    )
    def update_figure(value):
        print("Update value: ", value)

        if value == "A":
            # The main OSM tile server
            tiles = ["https://a.tile.openstreetmap.org/{z}/{x}/{y}.png"]
        else:
            # Example of an alternative tile server
            tiles = ["http://a.tile.stamen.com/watercolor/{z}/{x}/{y}.jpg"]

        print("Using tiles: ", tiles)

        mapbox_style = {
            "version": 8,
            "sources": {
                "osm": {
                    "type": 'raster',
                    "tiles": tiles,
                    "maxZoom": 23,
                    "tileSize": 256,
                }
            },
            "layers": [{
                "id": 'osm',
                "type": 'raster',
                "source": 'osm',
            }],
        }

        return dict(
            data=[
                go.Scattermapbox()
            ],
            layout=dict(
                title="Using tile server: {}".format(tiles[0]),
                mapbox=dict(style=mapbox_style)
            ),
        )

    return app


if __name__ == '__main__':
    app = init_app()
    app.run_server(debug=True)

According to the logging output (and the title change) it is clear that the update from the radio button is working properly. However the map does not change accordingly. Only the initial setting is relevant (swapping the if condition simply shows the other tile server unconditionally).

It looks like the behavior is not specific to just the tile server settings -- other modifications also do not seem to update.

Expected behavior

I would have expected the map to change according to the changes.

@alexcjohnson
Copy link
Collaborator

Thanks @bluenote10
@archmoj could you investigate, and move this issue to plotly.js if you can reproduce in a codepen?

@archmoj
Copy link
Contributor

archmoj commented Apr 1, 2020

Plotly.react appears to be working fine in this demo.

@archmoj
Copy link
Contributor

archmoj commented Apr 1, 2020

Also using dash the example below works.

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output

import plotly.graph_objects as go


def init_app():
    app = dash.Dash(__name__)

    graph = dcc.Graph(
        id='graph',
        style={
            'width': '100%',
            'height': '1000px',
        }
    )
    switch = dcc.RadioItems(
        id='switch',
        options=[
            {'label': 'Map A', 'value': 'A'},
            {'label': 'Map B', 'value': 'B'},
        ],
        value='A',
    )
    app.layout = html.Div(children=[
        html.Div(children=[switch]),
        html.Div(children=[graph]),
    ])

    @app.callback(
        Output('graph', 'figure'),
        [Input('switch', 'value')],
    )
    def update_figure(value):
        if value == "A":
            mapbox_style = "stamen-terrain"
        else:
            mapbox_style = "stamen-watercolor"

        return dict(
            data=[
                go.Scattermapbox()
            ],
            layout=dict(
                mapbox=dict(style=mapbox_style)
            ),
        )

    return app


if __name__ == '__main__':
    app = init_app()
    app.run_server(debug=True)

@archmoj
Copy link
Contributor

archmoj commented Apr 1, 2020

But it seems to be a problem when the style type is an object.

@archmoj
Copy link
Contributor

archmoj commented Apr 1, 2020

Tracked in plotly/plotly.js#4719.

@Concretely
Copy link

Is there any update on this? I'm having the same issue.

@archmoj
Copy link
Contributor

archmoj commented Oct 20, 2020

Is there any update on this? I'm having the same issue.

Which version are you using?
This should have been fixed.

@Concretely
Copy link

Yes, thank you. I figured out the problem. Animate=True was preventing the update for some reason.

@gaumarjos
Copy link

gaumarjos commented Nov 13, 2022

I'm having a similar problem today with

dash==2.7.0
dash-core-components==2.0.0
dash-html-components==2.0.0
dash-table==5.0.0
plotly==5.11.0

I have an app that, among other things, displays a trace on a map. The trace shall be updated based on a selection or when a different trace is loaded. When the callback is called, everything but the trace on the map is updated as expected: the centre (the map re-centres based on the new coordinates) and the datapoints (see image below).

In other words, the old "painted trace" remains and the new one is not painted while all the "data" (map centre, datapoints) are updated.

If I replace go.Scattermapbox with go.Scatter everything works fine so I'm inclined to think that the rest of my code works as expected.

image

The layout:

dcc.Graph(id='map_graph', animate=False),

The callback and an external function that generates the fig. I believe that generating the figure in an external function is not the issue because I do that for another map in the app and that works just fine.

@app.callback(
    Output('map_graph', 'figure'),
    Input('store_df', 'data'),
    Input('elevation_graph', 'selectedData'),
    Input('map_trace_color', 'value')
)
def update_map(jsonified_df, selected_points, map_trace_color):
    df = pd.read_json(jsonified_df, orient='split')
    if selected_points is not None:
        selected_indexes = [d['pointIndex'] for d in selected_points['points']]
        fig = geppetto.plot_map2(df=df,
                                 map_trace_color_param=map_trace_color,
                                 interval_unit="i",
                                 interval=[min(selected_indexes), max(selected_indexes)] if len(
                                     selected_indexes) > 0 else [0, 0])
    else:
        fig = geppetto.plot_map2(df=df,
                                 map_trace_color_param=map_trace_color,
                                 interval_unit="i",
                                 interval=[0, 0])

    return fig
def plot_map2(df, map_trace_color_param='elev', interval_unit="m", interval=(0, 0)):
    """

    :param df: dataframe to operate on
    :param map_trace_color_param: parameter to control the trace color
    :param interval_unit: 'm'=meters or 'i'=index
    :param interval: the interval of interest
    :return:
    """
    assert map_trace_color_param in ('elev', 'c_dist_geo2d', 'c_speed')
    df_selection = copy_segment(df,
                                columns=["lon", "lat", "c_dist_geo2d", "elev", 'c_speed'],
                                interval_unit=interval_unit,
                                interval=interval)

    data = [go.Scattermapbox(lat=df_selection["lat"],
                             lon=df_selection["lon"],
                             mode='lines+markers',
                             marker=go.scattermapbox.Marker(size=6,
                                                            color=df_selection[map_trace_color_param],
                                                            colorscale=px.colors.sequential.Bluered),
                             hovertext=df_selection['c_dist_geo2d'],
                             )]
    layout = go.Layout(autosize=False,
                       hovermode='closest',
                       mapbox=dict(style="open-street-map",
                                   # accesstoken=map_token,
                                   bearing=0,
                                   pitch=0,
                                   zoom=10,
                                   center=go.layout.mapbox.Center(lat=np.mean(df_selection["lat"]),
                                                                  lon=np.mean(df_selection["lon"])),

                                   ),
                       margin={'l': 10, 'b': 10, 't': 10, 'r': 10},
                       )
    return go.Figure(data=data, layout=layout)

@celia-lm
Copy link

Hi @gaumarjos , it's an open issue with plotly.js, you have a workaround in its thread: plotly/plotly.js#6363

@ciskoh
Copy link

ciskoh commented Jan 27, 2023

Hi I have a similar problem where my tiles do not update after a callback unless I refresh the page. See here . Can someone guide me towards a solution /workaround in python?

@alexcjohnson
Copy link
Collaborator

Let's continue this discussion in plotly/plotly.js#6444 - the original issue here was fixed a long time ago, then some related issues popped up again, so this issue is not helpful anymore.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants