Callback not working for pie chart?

Hi all,
TL;DR Pie chart not updating with callback and can’t assign an id to update a table.
Here is my code:

# import libraries 

import pandas as pd
import plotly.express as px 
import time 
import json
import urllib
import urllib.request

# import dash libraries 

import dash
import dash_core_components as dcc

# import dash bootstrap components 

import dash_bootstrap_components as dbc
import dash_html_components as html
import dash_table

from dash.dependencies import Input, Output
from dash_bootstrap_templates import load_figure_template

#########################################

# data fetching and treatment starts here 

# read JSON file from Json at emergencias.pt by Tomahock 

url = "https://emergencias.pt/data"
response  = urllib.request.urlopen(url).read()

jsonResponse = json.loads(response.decode('utf-8'))

# Create dataframe with pandas from json response 

df = pd.json_normalize(jsonResponse['data'])

# Create new column that sums the values of men, vehicules, and planes/helicopters for each entry

df['total_meios'] = df['man'] + df['terrain']+df['aerial']

# Transform hour type to date/time format 

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

# sort values by date/time 

df.sort_values(by=['hour'])

# Create dataframe for table 

df_table=df[["hour", "freguesia","naturezaName","status","total_meios"]]


######################################## 

# start plotting visualizations

# Create dataframe with the last 10 values 

df_actual = df.tail(10)

# plot donut chart for the last 10 entries 

fig_actual= px.pie(df_actual,names='district',values='total_meios',hole=0.7, color_discrete_sequence=px.colors.sequential.RdBu)

# fig_actual layout changes 

fig_actual.update_layout(showlegend=False)

fig_actual.update_layout({
        'plot_bgcolor': '#282b2f',
        'paper_bgcolor': '#282b2f',
        })

fig_actual.update_layout(
    title="Recursos Alocados",
    legend_title="Tipo de Ocorrência",
    font=dict(
        color="white",
            size=12
    )
)
fig_actual.update_traces(textposition='outside', textinfo='percent+label')

######################################## 

# create dashboard elements 

table = dbc.Table.from_dataframe(df_table.tail(10), striped=True, bordered=True, hover=True)

# Get template for layout

load_figure_template("slate")

# design top navbar 

VOSTPT_LOGO =  "https://dash.vost.pt/wp-content/uploads/2020/11/cropped-VOSTPT_LOGO_PNG_TRANSP.png"

navbar = dbc.Navbar(
    [
        html.A(
            # Use row and col to control vertical alignment of logo / brand
            dbc.Row(
                [
                    dbc.Col(html.Img(src=VOSTPT_LOGO, height="15px")),
                    dbc.Col(dbc.NavbarBrand("VOSTPT - DASHBOARD OPERACIONAL", className="ml-2")),
                ],
                align="center",
                no_gutters=True,
            ),
            href="https://vost.pt",
        ),
    ],
    color="dark",
    dark=True,
)

# define Dash app 

app = dash.Dash(__name__, external_stylesheets=[dbc.themes.SLATE],title='VOST Portugal - DASHOARD',update_title=None,
                meta_tags=[{'name': 'viewport',
                           'content': 'width=device-width, initial-scale=1.0, maximum-scale=1.2, minimum-scale=0.5,'}]
        )
# start server 

server = app.server

# app layout 

app.layout = dbc.Container(
    [
        # set update intervals for the three graphs 
        dcc.Interval(
           id='interval-component',
           interval=30*1000, # in milliseconds
           n_intervals=0
        ),
    # insert navigation bar     
    navbar,
    html.Hr(),
    # create row
    dbc.Row(
        [
            dbc.Col(dcc.Graph(id='graph_actual',figure=fig_actual,animate=True, className="h-100"),lg=6),
            dbc.Col(table),
            
        
        ], 
        
    ),
   ],
    # set fluid to true to make the layout mobile ready
    fluid=True,
)

@app.callback(
    Output('graph_actual', 'figure'),
    [Input('interval-component', "n_intervals")]

)

def UpdateFigActual(value):
    global df_actual
    
    url = "https://emergencias.pt/data"
    response  = urllib.request.urlopen(url).read()

    jsonResponse = json.loads(response.decode('utf-8'))

    df_new_actual = pd.json_normalize(jsonResponse['data'])

    df_new_actual['DateAndTime'] = df_new_actual['date'].str.cat(df_new_actual['hour'],sep=" ")

    df_new_actual.sort_values(by=['DateAndTime'])

    df_new_actual['total_meios'] = df_new_actual['man'] + df_new_actual['terrain']+df_new_actual['aerial']

    df_now_actual=df_new_actual.tail(10)

    print(df_now_actual)

    # Plot 
    fig_actual=px.pie(df_now_actual,names='district',values='district',hole=0.7, color_discrete_sequence=px.colors.sequential.Electric)

    fig_actual.update_layout({
        'plot_bgcolor': '#282b2f',
        'paper_bgcolor': '#282b2f',
        })
    

    return fig_actual

# launch app 

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

What I have is a pie chart and a table. As you can see I choose, on purpose, two different color sequences, to test.
When I run the app it plots the graph the first time and on the terminal the dataframe updates.

However the chart doesn’t.

I’m also having troubles in creating a callback that updates the table with the last entries.

Anyone has any idea how to solve this? I’ve trying for the last hours but can’t come up with a solution for this.
Thank you in advance!

Note: This project is for a NGO, and not a commercial project. All code will be open source.

Hi @jgomes_eu

It would be helpful if you could post a minimal example with some sample data. More info on how to do that here

In the meantime, this might be part of the problem: “Why global variables will break your app”

To update a dash-bootstrap-components Table in a callback, the whole table needs to be re-created with the new data. (Unlike the Dash DataTable that has a data prop that can be updated in a callback)

Here is a MWE:

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import dash_bootstrap_components as dbc
import plotly.express as px

df = px.data.tips()

app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])


dropdown = html.Div(
    dcc.Dropdown(
        id="dropdown",
        options=[{"label": i, "value": i} for i in df["day"].unique()],
        multi=True,
        value=[],
    ),
    className="m-4",
)

app.layout = dbc.Container(
    [
        html.H1("Table with a Dropdown"),
        html.Hr(),
        dbc.Row(dbc.Col(dropdown)),
        dbc.Row(dbc.Col(id="dbc-table")),
    ],
    fluid=True,
)


@app.callback(Output("dbc-table", "children"), Input("dropdown", "value"))
def update_table(days):
    dff = df.copy() if days == [] else df[df["day"].isin(days)]
    return dbc.Table.from_dataframe(dff, striped=True, bordered=True, hover=True)

Hi @AnnMarieW, thank you for your comments.

I went ahead and tried to change the graph type to bar, line, and scatter and all of them update with the code that I have.
When I change it to a pie chart then it stops updating, which is a really weird behaviour.

My dataset is updated every few minutes and so it’s easy to track the changes
This is a screenshot taken at 10:31h


This is a screenshot taken at 10:37h

As you can see the bar chart updates.

Changing to a pie chart this no longer applies. The dataset changes (I use print(df_now_actualto monitor the changes on the dataset) but the graph doesn’t update accordingly.

Here’s a link to a sample of my dataset

I’m really lost as to why this is not working

In this GIST I posted the code that I’m using. As you can see I first plot a pie chart and then on callback it changes to bar a graph. I did this for testing purposes.

When I change, inside the callback, to a pie chart the the callback doesn’t work at all.

Any help would be appreciated.

Hi @jgomes_eu

You initial pie chart (that works) is defined as:

fig_actual= px.pie(df_actual,names='district',values='total_meios',hole=0.7, color_discrete_sequence=px.colors.sequential.RdBu)

In the callback (that doesn’t work) its’ defined as:

fig_actual=px.pie(df_now_actual,names='district',values='district',hole=0.7, color_discrete_sequence=px.colors.sequential.Electric)

Do you think it might have something to do with the way values is defined?

Hi @AnnMarieW,
Actually the values, in this case, they don’t make a difference. Basically the pie chart should return the district with most occurrences in the dataset.
However I started from scratch gist here and the values are updating as they should.

Taken at 17:25h


Taken at 17:26h

Again thank you for your help and care for trying to sort this out.

As for having the table update I cant’ seem to assign an id to it, but I will open a new issue for this.

dbc.Col(id='table_one', table),
                                 ^
SyntaxError: positional argument follows keyword argument

Hi @jgomes_eu

You can fix that error by

dbc.Col(table, id='table_one'),

OR

dbc.Col(id='table_one', children=table),
2 Likes

@AnnMarieW thank you so much for your help!

2 Likes