user13747020
user13747020

Reputation:

Plotly: How to organize dropdown menu?

I have a drop down menu in plotly to display all graphs for every state in the country. I also have a graph that shows the whole US.

In my drop down menu I want to move the US to the top of the display and not in the alphabetical order.

Any suggestions? Really stuck and reorganizing the data frame doesn't work.

state_names = summary['state'].unique()
state_names.sort()
age_groups = summary['age_group'].unique()
x = summary['ca_monthly'].unique()

data_list = []
for state in state_names:
    state_list = []
    state_data = summary[summary['state']==state]
    for age in age_groups:
        state_list.append(
            state_data[state_data['age_group']==age]['poverty_rate'])
    data_list.append(state_list)

data = pd.DataFrame(data_list, columns=age_groups)
data['State'] = state_names
data = data.set_index('State')

fig = go.Figure()

legend_names = {'child': 'Child poverty',
                'adult': 'Adult poverty',
                'all': 'Overall poverty'}
default = state_names[0]
for age in age_groups:
    fig.add_trace(go.Scatter(
        x=x, 
        y=data[age][default],
        name=legend_names[age]
    ))

buttons = []
title = 'Poverty impact of a child allowance in '
for state in state_names:
    new_button = {'method': 'update',
                  'label': state,
                  'args': [{'y': data.loc[state]},
                           {'title.text': title + state}]}
    buttons.append(new_button)

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

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

fig.update_layout(
    title= title + default,
    xaxis_title='Monthly Child Allowance',
    yaxis_title='SPM poverty rate',
    yaxis_ticksuffix='%',
    font=dict(family='Roboto'),
    hovermode='x', 
    xaxis_tickprefix='$',
    xaxis_ticksuffix='',
    plot_bgcolor='white',
    legend_title_text='',
    legend=dict(yanchor='top', y=0.99, xanchor='right', x=0.99),
    xaxis=dict(tickmode='linear', dtick = 50),
    yaxis=dict(range=[0, summary.poverty_rate.max() * 1.05], dtick=2)
)

fig.update_traces(mode='markers+lines', hovertemplate=None,
                  marker=dict(size=4))

fig.show(config={'displayModeBar': False})

Upvotes: 2

Views: 2677

Answers (1)

vestland
vestland

Reputation: 61074

The answer:

Just add the buttons to the dropdown menu and each corresponding subset of your data to the button args in whatever order you prefer.

The details:

Regarding:

[...] reorganizing the data frame doesn't work.

Yes it would. But you don't have to. We seem to be talking about dropdown menus here. So just add the buttons in whatever order you'd like.

How it all turns out will depend entirely on your dataset and what you would in fact like to display. But you've not provided the former nor described the latter in full detail. But since you're using functions such as state_names = summary['state'].unique() I'm going to assume that your dataset is of a long format.

I'm also going to assume that you're only displaying one trace at a time here. Or else this approach wouldn't make much sense since you would obtain the very same functionality with the interactivity of plotlys default legend functionality.

I'll use the px.data.gapminder() dataset where running dfi['continent'].unique().tolist() will give ['Asia', 'Europe', 'Africa', 'Americas', 'Oceania']. I'm also going to throw in some aggregated data for the entire world, and define the order of the buttons to be ['World', 'Africa', 'Americas', 'Asia', 'Europe', 'Oceania'.

I hope this will reflect the structure of your real world data. And if it doesn't, then I strongly suggest that you take the time to learn how to efficiently build and share a pandas dataframe. The dataset also contains observations for individual countries. You'll just have to pretend that the world is USA and that the countries are states. But I suspect that won't be a problem.

Following the logic I've just described, the code snippet below will produce the following plot, with world defined to be placed at the top, and with the individual continents following in alphabetical order.

enter image description here

Complete code:

import plotly.graph_objects as go
import plotly.express as px
import pandas as pd

# dataframe, input
dfi = px.data.gapminder()

# dataframe, aggregated by continent
dfc = dfi.groupby( [ "continent", "year"] ).mean().reset_index()

# dataframe with calculated mean for all continents
dfw = dfc.groupby( ["year"] ).mean().reset_index()
dfw['continent']='World'
dfw = dfw.append(dfc)
dfw

# select a category (world),
# take it out of the categories,
# put it first in a list,
# and add the rest of the categories alphabetically
mainGeo = dfw['continent'].unique().tolist()
mainGeo
mainCat = 'World'
mainGeo.remove(mainCat)
mainGeo.sort()

order = [mainCat] + mainGeo
order

colors = px.colors.qualitative.Plotly

# plotly figure setup
fig=go.Figure()
fig.add_traces(go.Scatter(x=df['year'], y = df['lifeExp'], name=geo,
                          mode='lines', line=dict(color = colors[2], width = 1))
              )

# dropdown menu
updatemenu = []
buttons = []

# button with one option for each dataframe
for geo in order:
    buttons.append(dict(method='restyle',
                        label=geo,
                        visible=True,
                        args=[{'y':[dfw[dfw['continent']==geo]['lifeExp'].values],
                               'x':[dfw[dfw['continent']==geo]['year'].values],
                               'type':'scatter'}, ],
                        )
                  )

# some adjustments to the updatemenus
updatemenu = []
your_menu = dict()
updatemenu.append(your_menu)

updatemenu[0]['buttons'] = buttons
updatemenu[0]['direction'] = 'down'
updatemenu[0]['showactive'] = True

# add dropdown menus to the figure
fig.update_layout(showlegend=False, updatemenus=updatemenu)
fig.show()

Upvotes: 2

Related Questions