Search code examples
pythonplotly

How to plot bar graph with button for multiple categories?


For a given dataframe, I am trying to create plotly plot a comparative bar graph with q1,q2.. on the x-axis, and barline for each stockname and the figures on y-axis.

Additionally, a button should have [Sales, Net Profit] selectors so that when an option is picked it should plot a comparative graph of those stocks (maximum 6 stocks).

import pandas as pd
import numpy as np
import plotly.graph_objects as go

my_dict = dict({
    'quarterly_result' : ['Sales','Net Profit', 'Sales', 'Net Profit'],
    'stockname' : ['Stock1', 'Stock1','Stock2', 'Stock2'],
    'q1' : [100,10,np.nan,np.nan],
    'q2' : [110,20.6,570,120],
    'q3' : [67,-2.0,620,125.7],
    'q4' : [125,40.5,np.nan,np.nan],
    'q5' : [np.nan,np.nan,660,105.9],
    'q6' : [np.nan,np.nan,636,140]
})

df = pd.DataFrame(my_dict)

fig = go.Figure()

x = df.columns[2:]
y1 = df.loc[0][2:]
y2 = df.loc[2][2:]

fig.add_traces(go.Bar(x=x, y=y1))
fig.add_traces(go.Bar(x=x, y=y2))

buttons = [{'method': 'update', 'label': col, 'args': [{'y': [df[col]]}]} 
           for col in df.iloc[:, 1:]]

updatemenus = [{'buttons': buttons,
                'direction': 'down',
                'showactive': True,}]

# update layout with buttons, and show the figure
fig.update_layout(updatemenus=updatemenus)
fig.show()

I am unsure how to plot this multi-categorical dataframe. Below snippet is not working. How do I fix this?

Incorrect outcome:

enter image description here

Expected:

enter image description here


Solution

  • You can add traces for each stock with the respective metric. Then add buttons to toggle between the metrics:

    import pandas as pd
    import numpy as np
    import plotly.graph_objects as go
    
    my_dict = {
        'quarterly_result': ['Sales', 'Net Profit', 'Sales', 'Net Profit'],
        'stockname': ['Stock1', 'Stock1', 'Stock2', 'Stock2'],
        'q1': [100, 10, np.nan, np.nan],
        'q2': [110, 20.6, 570, 120],
        'q3': [67, -2.0, 620, 125.7],
        'q4': [125, 40.5, np.nan, np.nan],
        'q5': [np.nan, np.nan, 660, 105.9],
        'q6': [np.nan, np.nan, 636, 140]
    }
    
    df = pd.DataFrame(my_dict)
    
    fig = go.Figure()
    
    # List of quarters
    x = df.columns[2:]
    
    # Add traces for each metric
    for result in df['quarterly_result'].unique():
        for stock in df['stockname'].unique():
            fig.add_trace(go.Bar(
                x=x,
                y=df[(df['stockname'] == stock) & (df['quarterly_result'] == result)].iloc[0, 2:],
                name=f'{stock} {result}'
            ))
    
    # Add buttons to toggle the visibility
    buttons = [{'label': label, 'method': 'update',
                'args': [{'visible': [label in trace.name for trace in fig.data]}]}
               for label in df['quarterly_result'].unique()]
    
    updatemenus = [{'buttons': buttons,
                    'direction': "down",
                    'showactive': True, }]
    
    # update layout with buttons, and show the figure
    fig.update_layout(updatemenus=updatemenus)
    fig.show()
    

    Results:

    Initial plot, both are visible: Sales and NP plot

    Sales: Sales plot

    Net profit: NP results