Search code examples
pythoncallbackbar-chartplotly-dashdashboard

Plot Bar Chart based on unique values in Python Dash


I'm trying to visualize the weighting scheme of different financial benchmarks (A, X) in an interactive bar chart embedded in Python Dash. Each benchmark is composed of different indices with different weights. The bar chart should change accordingly when switching or unselecting the benchmark. Somehow, I fail in adjusting the callback part of the code properly, as I'm not able to create the bar chart. Is anyone familiar with this issue?

I'm using Jupyter Notebook. Here's my code with a data sample:

Packages and data:

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

data = [['A', 'B', 0.4], ['A', 'C', 0.5], ['A', 'D', 0.1], ['X', 'Y', 0.15], ['X', 'Z', 0.85]]
df = pd.DataFrame(data, columns = ['BM_NAME', 'INDEX_NAME', 'WEIGHT'])
df

Bar chart. In dash, the idea is to have a single bar chart visible for a single selected benchmark (hence 'multi' is set to 'false'):

barchart = px.bar(
    data_frame=df,
    x="BM_NAME",
    y="WEIGHT",
    color="INDEX_NAME",
    opacity=0.9,
    barmode='group')
barchart

Dash code:

# create the Dash app
app = dash.Dash()

# set up app layout
app.layout = html.Div(children=[
    html.H1(children='BM Composition'),
    dcc.Dropdown(id='BM-dropdown',
                options=[{'label': x, 'value': x}
                        for x in df.BM_NAME.unique()],
                 value='A',
                 multi=False, clearable=True),
    dcc.Graph(id='bar-chart')
])


# set up the callback function
@app.callback(
    Output(component_id="bar-chart", component_property="figure"),
    [Input(component_id="BM-dropdown", component_property="value")],
)
def display_BM_composition(selected_BM):
    dff = df.BM_NAME.unique()  # Only use unique values in column "BM_NAME" selected in dropdown

    barchart = px.bar(
        data_frame=df,
        x=filtered_BM,
        y="WEIGHT",
        color="INDEX_NAME",
        opacity=0.9,
        barmode='group')

    return barchart

# Run local server
if __name__ == '__main__':
    app.run_server(debug=True, use_reloader=False)

Any help or suggestion for improvement is much appreciated!


Solution

  • EDIT After some trying, I found the following solution, which works perfectly for me:

    @app.callback(
        Output(component_id="bar-chart", component_property="figure"),
        [Input(component_id="BM-dropdown", component_property="value")],
    )
    def display_BM_composition(selected_BM):
        filtered_BM = df[df.BM_NAME == selected_BM]  # Only use unique values in column "BM_NAME" selected in dropdown
    
        barchart = px.bar(
            data_frame=filtered_BM,
            x="BM_NAME",
            y="WEIGHT",
            color="INDEX_NAME",
            opacity=0.9,
            barmode='group')
    
        return barchart