Inconsistent Callback Error Updating Scatter Plot

Hey everyone,

I’m having a hard time determining the source of a callback error as it only occurs a small percentage of times during app initialization. The error can occur for any of my graphs but I’ve shared the relevant code for the simplest callback below.

import dash
import dash_html_components as html
import pandas as pd
import dash_core_components as dcc
import dash_html_components as html
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output, State
from dash.exceptions import PreventUpdate
import numpy as np
import plotly_express as px


# =Set color scheme for all plots=
plot_color = "plotly"


app = dash.Dash(
    __name__,
    # external_stylesheets=external_stylesheets,
    # suppress_callback_exceptions=True,
)

app.layout = html.Div(
    html.Div(
        id="simulator-graph-zone",
        className="six columns",
        children=[
            html.H6(
                html.Span(
                    "Range Simulator",
                    id="simulator-tooltip-target",
                    style={"textDecoration": "underline", "cursor": "pointer",},
                ),
                className="graph-title",
            ),
            dbc.Tooltip("Test", target="simulator-tooltip-target", placement="right",),
            html.Div(
                [
                    html.P("Input nameplate battery capacity in kWh:",),
                    dcc.Input(
                        id="simulator-graph-input",
                        type="number",
                        placeholder="Nameplate Capacity (kWh)",
                        value=350,
                        min=10,
                        max=1000,
                        step=5,
                        style={"width": 220},
                    ),
                ],
                id="simulator-header",
                # className="seven columns",
            ),
            html.Br([]),
            html.Div(id="simulator-graph-container", className="pretty_container",),
        ],
    ),
)


def range_simulator(batt_capacity):
    # Makes range projections based on capacity and efficiency on a scatterplot
    nameplate_energy_capacity = batt_capacity
    usable_energy_capacity = (
        0.8 * nameplate_energy_capacity
    )  # assuming 80% usable energy
    set_efficiencies = np.linspace(1, 4, 7)
    vehicle_range = usable_energy_capacity / set_efficiencies
    vehicle_range_df = pd.DataFrame(vehicle_range, columns=["Range"])
    vehicle_range_df.insert(1, "Efficiency", set_efficiencies)
    range_graph = px.scatter(
        vehicle_range_df,
        x="Range",
        y="Efficiency",
        title=f"Vehicle Range Simulator ({usable_energy_capacity} kWh Usable)",
        labels={
            "Range": "Range (miles)",
            "Efficiency": "Vehicle Efficiency (kWh/mile)",
        },
        template=plot_color,
    )

    return range_graph


@app.callback(
    Output("simulator-graph-container", "children"),
    [Input("simulator-graph-input", "value"),],
)
def input_to_simulator(batt_capacity):
    if batt_capacity == None:
        raise PreventUpdate
    else:
        range_graph = range_simulator(batt_capacity)

    return dcc.Graph(id="simulator-graph", figure=range_graph)


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

Here is the traceback:

Traceback (most recent call last):
File “/Users/fieldmichael/projects/cte/dashboards/zebra/app.py”, line 1053, in input_to_simulator
range_graph = range_simulator(batt_capacity)
File “/Users/fieldmichael/projects/cte/dashboards/zebra/app.py”, line 363, in range_simulator
range_graph = px.scatter(
File “/Users/fieldmichael/projects/cte/dashboards/zebra/conda-env/lib/python3.8/site-packages/plotly/express/_chart_types.py”, line 64, in scatter
return make_figure(args=locals(), constructor=go.Scatter)
File “/Users/fieldmichael/projects/cte/dashboards/zebra/conda-env/lib/python3.8/site-packages/plotly/express/_core.py”, line 1824, in make_figure
apply_default_cascade(args)
File “/Users/fieldmichael/projects/cte/dashboards/zebra/conda-env/lib/python3.8/site-packages/plotly/express/_core.py”, line 906, in apply_default_cascade
args[“symbol_sequence”] = [
File “/Users/fieldmichael/projects/cte/dashboards/zebra/conda-env/lib/python3.8/site-packages/plotly/express/_core.py”, line 907, in
scatter.marker.symbol for scatter in args[“template”].data.scatter
File “/Users/fieldmichael/projects/cte/dashboards/zebra/conda-env/lib/python3.8/site-packages/plotly/graph_objs/scatter/_marker.py”, line 1032, in symbol
return self[“symbol”]
File “/Users/fieldmichael/projects/cte/dashboards/zebra/conda-env/lib/python3.8/site-packages/plotly/basedatatypes.py”, line 3896, in getitem
elif self._props is not None and prop in self._props:
File “/Users/fieldmichael/projects/cte/dashboards/zebra/conda-env/lib/python3.8/site-packages/plotly/basedatatypes.py”, line 3595, in _props
return self.parent._get_child_props(self)
File “/Users/fieldmichael/projects/cte/dashboards/zebra/conda-env/lib/python3.8/site-packages/plotly/basedatatypes.py”, line 3609, in _get_child_props
if self._props is None:
File “/Users/fieldmichael/projects/cte/dashboards/zebra/conda-env/lib/python3.8/site-packages/plotly/basedatatypes.py”, line 3595, in _props
return self.parent._get_child_props(self)
File “/Users/fieldmichael/projects/cte/dashboards/zebra/conda-env/lib/python3.8/site-packages/plotly/basedatatypes.py”, line 3629, in _get_child_props
child_ind = BaseFigure._index_is(children, child)
File “/Users/fieldmichael/projects/cte/dashboards/zebra/conda-env/lib/python3.8/site-packages/plotly/basedatatypes.py”, line 3410, in _index_is
raise ValueError(“Invalid value”)
ValueError: Invalid value

The function is always passed an initial value of 350 so I can not figure out what could be causing the seemingly random ValueError. It occurs roughly 1/20 times during app initialization and does not seem to have any relation to the order in which the callbacks are fired. Any help is greatly appreciated, thank you!

Hi @bigmike did you manage to resolve?
Facing the same issue

Looking back, I’m still not entirely sure what caused the issue as I ended up making some major changes to the structure of my app. I believe it has something to do with the initialization of the app, how default values are passed to your callbacks, and the order in which callbacks are fired on load. This link goes into some of the complexities of callback initialization.

I ended up setting prevent_initial_call=True and triggering this callback with the output of a separate callback. Sorry I could not be of more help!

HI @Math did you manage to find any solutions to this? I am struggling with the same problem.

Hi @lutherrichards I did not find the source of the issue, I settled for a simple try and except logic to catch the error and try again once more. For me it always works on second trial so I left it as such

Ahh okay that’s smart. Mine has similar behaviour, so I will give it a go. Thanks @Math

1 Like

Hi everyone!
I am struggling with this issue too. Anybody found any resolution or at least any causes of that error?

Hi,

I might have found a hack :

try:
    fig = px.scatter(...)
except Exception:
    fig = px.scatter(...)  # Exact same line as previously
return fig

It works in for me in development, and I’ll try later in production.

The idea behind is that it works randomly at the first attempt but always works on the second (e.g. when refreshing the page). Here I don’t wait for a refresh and force the second attempt in the except part.

On my trials to fix it, I also added prevent_initial_callback=True to some of the @app.callback(...) because callbacks producing plotly figures are called whenever a dcc.Store data attribute changes. Thus I make sure that callbacks for plotting figures are not triggered before data is maid available.

Let me know if it’s working for you.

1 Like

This worked for me as well. I wish I knew what was causing the initial ‘invalid value’ error, but this hack will work for now.

Someone on StackOverflow had a similar issue so I pointed him/her to your solution.