Dash graph showing an output which is based on *previous* iteration of input

Hi,

I have a scatter plot like this, for which I have a multi dropdown input.

Everything loads fine initially, but then when I start to add further input values on the dropdown, the graph will only show the first N-1 text overlays when I have N inputs in the input box (like this - notice the text for Greece is not shown).

Any idea what could be causing it?
For reference, these are the snippets of code relevant:

def make_scatter_comp(in_df, var1, var2, x_log, y_log, names_list):

    overlays = in_df['country'].apply(lambda x: x if x in names_list else '').values

    fig = px.scatter(in_df, x=var1, y=var2, log_x=x_log, log_y=y_log, text=overlays,
                     title=data_labels[var1] + ' vs ' + data_labels[var2],
                     labels=data_labels,
                     color='continent', size="population", size_max=25,
                     color_discrete_map=cont_colours,
                     category_orders={'continent': cont_order},
                     template='plotly_white', hover_name='country')

    fig.update_traces(marker=dict(line=dict(width=1, color='Gray')), textposition='top center')
    fig.update_layout(font=dict(size=font_size, color='DarkSlateGray'), width=800, height=500)

...

    dbc.Row([
        dbc.Col([
            dbc.Badge("(Cosmetic) Show text for:", color="secondary", className="mr-1"),
            dbc.FormGroup([
                dcc.Dropdown(
                    id='scatter_name_overlay',
                    options=[{'label': k, 'value': k} for k in np.sort(df.country.unique())],
                    value=['China'],
                    multi=True,
                    style={'width': '100%'}
                )],
            )], md=6
        ),
    ]),

...

@app.callback(
    Output('scatter_one', 'figure'),
    [Input('scatter_xvar', 'value'), Input('scatter_yvar', 'value'),
     Input('scatter_x_log_radio', 'checked'), Input('scatter_y_log_radio', 'checked'),
     Input('scatter_name_overlay', 'value')]
)
def update_scatter(var1, var2, x_log, y_log, names):

    # if var1 != var2:
    if type(names) == list:
        names_list = names
    else:
        names_list = [names]

    fig = make_scatter_comp(df, var1, var2, x_log, y_log, names_list)

    return fig

Thanks!

Edit: When I look at the fig object contemporaneously, the text item contains the correct data, so it is being passed on correctly…

Hello,

can you please provide the code where you defined the scatter_one dcc.Graph , and make sure that you didn’t wrap it inside a Dcc.Loading, because i saw such behavior in a similar issue where the graph were wrapped inside it.

Best regards.

1 Like

Hi Timo!

That’s interesting.
It was wrapped in dcc.Loading (like this)

    dcc.Loading(
        id="loading-scatter_one",
        children=[
            dcc.Graph(
                'scatter_one',
                config={'displayModeBar': False}
            ),
        ],
        type="circle",
    ),

but changing it to just dcc.Graph doesn’t seem to have fixed it. Now the text is only changing on every second click?

    dcc.Graph(
        'scatter_one',
        config={'displayModeBar': False}
    ),

It’s deployed on Heroku here:
https://hosp-cap-data.herokuapp.com

And the git repo:

Just want to chime in. I am running into the dcc.Graph ghosting problem as well and can’t figure out what is wrong. The callback to dcc.Graph works fine, but when I wrapped dcc.Loading around the html.Div, it start to use graph from the previous state.

dcc.Loading(
  html.Div(
    dcc.Graph(id="us-map", style={"height": "44vh"},)
   ),
   id="map-loading"
),

And my callback header is:

@app.callback(
    Output("us-map", "figure"), [Input("input-id", "value")]
)
1 Like

@TimoDZ How did you resolve that behavior?

I think dcc.Loading is very cool feature and am trying to use it to show loading state for resource intensive callbacks, specifically, Graphs.

I tried your code, and while searching i think there is this open issue related to Loading state, you can check the last comment maybe the proposed solutions may work.

1 Like

Hi,
No i didn’t, i just removed the Loading part, but i said in the previous comment it may be an open issue about state management using Loading, which is the problem, some ppl just suggested to have a limited interval that will do the second call for you, which is not the best solution to have.

1 Like

Yes, it seems like state management is broken in dcc.Loading.

I’ve found that the map (scatter mapbox) and the scatter dots on the map is from the previous state, but the labels/hoverlabels are from the current state.

The sample code in the github issue is a “hack”, basically loading two different versions of the same website.

I wrapped WSGI/Flask around Dash with Werkzeug 1.0.0. I used the same DispatcherMiddleware to invoke the dash app with multiple callbacks. It does not fix the dcc.Loading ghosting issue, still using layers from previous state (but labels from current state).

import flask, dash
from werkzeug.serving import run_simple
from werkzeug.middleware.dispatcher import DispatcherMiddleware


server = flask.Flask(__name__)
app = dash.Dash(
    __name__,
    server=server,
    external_stylesheets=external_stylesheets,
    meta_tags=meta_tags,
    routes_pathname_prefix="/",
)

application = DispatcherMiddleware(server, {
    "": app.server,
})

if __name__ == "__main__":
    run_simple('127.0.0.1', 8050, application)

Hello @vitaminc @TimoDZ - Thank you for reporting these issues, we’re working on fixing them right now. Are the issues you are having just with scattermapbox or with all graph types? Could you share a simple, reproducible example that we could use to test with?

@jphwang - Thanks for reporting the issue, could you create a simple, reprodible example? I just tried to reproduce your issue and could not:

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

app = dash.Dash(__name__)

TEXT = ['A', 'B', 'C' ,'D','E']

app.layout = html.Div([
    dcc.Dropdown(
        options=[{'label': i, 'value': i} for i in TEXT],
        value=TEXT[0],
        id='text',
        multi=True
    ),
    dcc.Graph(id='graph')

])


@app.callback(Output('graph', 'figure'), [Input('text', 'value')])
def display_graph(text):
    return {
        'data': [{
            'x': list(range(len(text))),
            'text': text,
            'mode': 'markers+text',
            'textposition': 'top'
        }]
    }


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

Hello !
i believe that this issue is related to the same problem too, i didn’t check if there was a new release those days but the issue seams to appear whenever we wrap the graph inside the Loading, it gets always delayed by one step to update the screen. i will try to post an example later if the one linked to here or posted in this post didn’t work.

OK thanks, I’ll comment over there. This might be fixed tomorrow when we create a new release… we just merged one fix related to loading + maps & uirevision here: https://github.com/plotly/dash-core-components/pull/740

For any graph, or just the mapping types?

To be honest, i personally didn’t use Loading in my projects, i tried the examples given by other issues related to that presented by the other members (like this thread and the one i posted in the previous comment) in order to help them, so i don’t know if it is a global issue or just related to this type, maybe someone else may have tested it on something else.

btw, can we test the new release now ? or we should wait till tomorrow :smile:

You can try it out now @timodz, it was just released one hour ago: pip install dash==1.11.0 :smiley_cat:

1 Like