Search code examples
pythonplotlyplotly-dash

Unable to update Figure via Dash callback (IncorrectTypeException)


I have the following code that displays a histogram, and I want to use a RangeSlider to update the figure to only show the year range that the user specifies. I followed the standard template of using a callback to update the figure with the values in the slider but I am getting the following error on the callback function:

IncorrectTypeException: component_id must be a string or dict, found Figure

I saw someone else with this same error but they were passing a matplotlib figure. I am using a Plotly figure that otherwise displays normally. I saw someone else mention that the types in the source dataframe might matter, but I changed mine from 'object' to 'string' and it did not fix it. Anyone have any insight? Or does anyone know what component_id is supposed to represent? Thanks!!

Here is the similar question I referenced: returned a value having type `Figure` which is not JSON serializable

fig = px.histogram(df, y = 'Procedure', color = 'LOE')
app = JupyterDash(__name__)
app.layout = html.Div([
   dcc.Graph(figure=fig),
   dcc.RangeSlider(min = 2000, max = 2020, value = [2000,2020], step = 1,
                   marks={i: str(i) for i in range(2000,2020,1)}, id = 'range-slider')
])

@app.callback(
Output(fig, 'data'),
Input('range-slider', 'value'),
)
def update_table(slider_value):
   if not slider_value:
       return dash.no_update
   new_df = #modify df here
   return px.histogram(new_df, y = 'Procedure', color = 'LOE')

if __name__ == '__main__'
   app.run_server(mode = 'inline')

Solution

  • The error is pointing to this line:

    Output(fig, 'data'),

    It looks like you're trying the new way of passing a component in here, but the error makes it sound like you don't have the right version of Dash for that. You may need to pass in the dcc.Graph component instead of the histogram, though.

    You can always use a string ID here, which would look like this:

    app.layout = html.Div([
       dcc.Graph(id='my-output', figure=fig),
       dcc.RangeSlider(min = 2000, max = 2020, value = [2000,2020], step = 1,
                       marks={i: str(i) for i in range(2000,2020,1)}, id = 'range-slider')
    ])
    
    @app.callback(
    Output('my-output', 'figure'),
    Input('range-slider', 'value'),
    )
    def update_table(slider_value):
       if not slider_value:
           return dash.no_update
       new_df = #modify df here
       return px.histogram(new_df, y = 'Procedure', color = 'LOE')