Callback error with barchart – Plotly dash

Question:

I’m trying to insert an interactive bar-chart using values in a df. Using below, I’ve got the unique values from Type displayed as RadioItems. I’m aiming to link these to a bar chart within the dbc.Container. The first 5 rows of the df are displayed below. I’m hoping to group each unique value of Type as a total count to be displayed as a bar chart.

Ideally, I’d like to be able to add/remove as many unique values to bar chart through the RadioItems.

Eventually, I’d like to add a date slide where I can select

  Type                time       DATE      TIME
0    A 2022-01-01 07:30:00 2022-01-01  07:30:00
1    B 2022-01-01 23:01:00 2022-01-01  23:01:00
2    A 2022-01-01 21:28:00 2022-01-01  21:28:00
3    E 2022-01-01 18:21:00 2022-01-01  18:21:00
4    E 2022-01-01 16:48:00 2022-01-01  16:48:00

current code:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import plotly.express as px
import plotly.graph_objs as go
import dash
from dash import dcc
from dash import html
import dash_bootstrap_components as dbc
from dash.dependencies import Input, Output

df = pd.DataFrame({
           'Type': ['A','B','B','C','D','D','E','E','F']
           })

N = 50

df = pd.concat([df] * N, ignore_index=True)

df['time'] = pd.date_range(start='2022/01/01 07:30', end='2022/01/30 08:30', periods=len(df))

df['time'] = pd.to_datetime(df['time'], dayfirst = True).sort_values()

df['time'] = df['time'].dt.floor('1min')

df['DATE'], df['TIME'] = zip(*[(d.date(), d.time()) for d in df['time']])

df['DATE'] = pd.to_datetime(df['DATE'])

df = df.sort_values(by = 'DATE')

date_count = df.groupby(['DATE']).size().reset_index(name = 'Count').sort_values('Count', ascending = False)

date_count["DOW"] = date_count["DATE"].dt.weekday
date_count = date_count.sort_values("DOW").reset_index(drop=True)
date_count["DOW"] = date_count["DATE"].dt.day_name()


external_stylesheets = [dbc.themes.SPACELAB, dbc.icons.BOOTSTRAP]

app = dash.Dash(__name__, external_stylesheets = external_stylesheets)

radio_items =  html.Div([
    html.P("Type"),
    dcc.RadioItems(
       id='Type', 
       value='Type', 
       options=[{'value': x, 'label': x} 
                for x in ['A', 'B', 'C', 'D', 'E', 'F']],
   ),
])

vess_date_barfig = px.bar(data_frame = date_count,
                         x = 'DATE',
                         y = 'Count',
                         color = 'DOW',
                         opacity = 0.5,
                         title = 'Total Daily Count of Type'
                         )

app.layout = dbc.Container([
    dbc.Row([
        dbc.Col(html.Div(radio_items, className="bg-secondary h-100"), width=2),
        dbc.Col([
            dbc.Row([
                dbc.Col(),
            ]),
            dbc.Row([
                dbc.Col(dcc.Graph(figure = vess_date_barfig), style={
                        "padding-bottom": "10px",
                    }),
            ]),
            dbc.Row([
                dbc.Col(dcc.Graph(id = 'bar-chart')),
            ]),
        ], width=5),
        dbc.Col([
            dbc.Row([
                dbc.Col(),
            ]),
            dbc.Row([
                # insert bar chart
                dbc.Col(dcc.Graph()),
            ], className="h-100"),
        ], width=5),
    ])
 ], fluid=True)


@app.callback(
    [Output('bar-chart', 'figure')], 
    [Input("Type", "value")])


def generate_chart(value):

    bar_data = df[df['Type'] == value]
    count = bar_data['Type'].value_counts()
    data = go.Bar(x = count.index, y = count.values)
    layout = go.Layout(title = 'title')
    fig = go.Figure(data = data, layout = layout)  

    return fig

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

I’m currently getting this error:

Traceback (most recent call last):
  File "/Users/venv/lib/python3.9/site-packages/flask/app.py", line 1820, in full_dispatch_request
rv = self.dispatch_request()
  File "/Users/venv/lib/python3.9/site-packages/flask/app.py", line 1796, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
  File "/Users/venv/lib/python3.9/site-packages/dash/dash.py", line 1274, in dispatch
ctx.run(
  File "/Users/venv/lib/python3.9/site-packages/dash/_callback.py", line 455, in add_context
flat_output_values = flatten_grouping(output_value, output)
  File "/Users/venv/lib/python3.9/site-packages/dash/_grouping.py", line 35, in flatten_grouping
validate_grouping(grouping, schema)
  File "/Users/venv/lib/python3.9/site-packages/dash/_grouping.py", line 210, in validate_grouping
SchemaTypeValidationError.check(grouping, full_schema, path, (tuple, list))
  File "/Users/venv/lib/python3.9/site-packages/dash/_grouping.py", line 162, in check
raise SchemaTypeValidationError(value, full_schema, path, expected_type)
dash._grouping.SchemaTypeValidationError: Schema: [<Output `bar-chart.figure`>]
            Path: ()
            Expected type: (<class 'tuple'>, <class 'list'>)
            Received value of type <class 'plotly.graph_objs._figure.Figure'>:
                Figure({
'data': [{'type': 'bar', 'x': array([], dtype=object), 'y': array([], dtype=int64)}],
'layout': {'template': '...', 'title': {'text': 'title'}}
})
Asked By: Chopin

||

Answers:

Your Output in the @app.callback decorator shouldn’t be inside a list. If you change it to the following:

@app.callback(
    Output('bar-chart', 'figure'), 
    [Input("Type", "value")])

def generate_chart(value):

    bar_data = df[df['Type'] == value]
    count = bar_data['Type'].value_counts()
    data = go.Bar(x = count.index, y = count.values)
    layout = go.Layout(title = 'title')
    fig = go.Figure(data = data, layout = layout)  

    return fig

Then your app runs and responds correctly to radio item selection, as shown below.

enter image description here

Answered By: Derek O