Search code examples
pythondrop-down-menuplotlydropdownpie-chart

Piechart dropdown in plotly Python


I have large df like this (those data is just an example):

|Category|Sign|
|-       |-|
|One     |-|
|Two     |+|
|One     |-|
|Two     |-|
|One     |+|

I have to do pie charts with plotly - for each category I have to count '+' and '-' (it's easy and I done it) and then insert a dropdown to choose which one of these (in this case 2) pie plots will be shown. I have something like this:

cat = set(data['Category'])
for c in cat:
    t = data[data['Category'] == c]
    c = t['Sign'].value_counts()
    fig = px.pie(t, values = c.values, names = c.index)
    fig.show()

And now I have no idea how to do this dropdown - could someone help me, please? :) or just guide me how to do it?


Solution

    • core concept: all traces need to be part of same figure to control with updatemenus
    • have generated data as it's simpler to test concept (more categories)
    • have created figures for each category in what is the same way you did. However it's more convenient to have them in a dict
    • integrate all the figures in the dict into a consolidate figure
    • finally build updatemenus to achieve your requirement
    import numpy as np
    import plotly.express as px
    
    # generate data matching definition in question
    data = pd.DataFrame(
        {
            "Category": np.random.choice(["One", "Two", "Three"], 100),
            "Sign": np.random.choice(list("+-"), 100),
        }
    )
    
    # simplify - use value_counts() on whole dataframe
    df_vc = data.value_counts()
    # create a figure for each category
    figs = {
        c: px.pie(df_vc.loc[c].reset_index(), values=0, names="Sign").update_traces(
            name=c, visible=False
        )
        for c in df_vc.index.get_level_values("Category").unique()
    }
    
    # integrate figures per category into one figure
    defaultcat = df_vc.index.get_level_values("Category").unique()[0]
    fig = figs[defaultcat].update_traces(visible=True)
    for k in figs.keys():
        if k != defaultcat:
            fig.add_traces(figs[k].data)
    
    # finally build dropdown menu
    fig.update_layout(
        updatemenus=[
            {
                "buttons": [
                    {
                        "label": k,
                        "method": "update",
                        # list comprehension for which traces are visible
                        "args": [{"visible": [kk == k for kk in figs.keys()]}],
                    }
                    for k in figs.keys()
                ]
            }
        ]
    )
    

    enter image description here

    supplementary update

    • include Categrory combinations in drop down
    • extend building of dict to include combinations
    import itertools
    figs = {
        **{
            c: px.pie(df_vc.loc[c].reset_index(), values=0, names="Sign").update_traces(
                name=c, visible=False
            )
            for c in df_vc.index.get_level_values("Category").unique()
        },
        **{
            f"{a}-{b}": px.pie(
                df_vc.loc[[a, b]].reset_index(), values=0, names="Sign"
            ).update_traces(name=f"{a}-{b}", visible=False)
            for a, b in itertools.combinations(
                df_vc.index.get_level_values("Category").unique(), 2
            )
        },
    }