Dropdown Menus in Python/v3

How to add dropdowns to update Plotly chart attributes in Python.


Note: this page is part of the documentation for version 3 of Plotly.py, which is not the most recent version.
See our Version 4 Migration Guide for information about how to upgrade.
The version 4 version of this page is here.

New to Plotly?

Plotly's Python library is free and open source! Get started by dowloading the client and reading the primer.
You can set up Plotly to work in online or offline mode, or in jupyter notebooks.
We also have a quick-reference cheatsheet (new!) to help you get started!

Version Check

Note: Python Buttons are available in version 1.12.12+
Run pip install plotly --upgrade to update your Plotly version

In [7]:
import plotly
plotly.__version__
Out[7]:
'2.2.3'

Methods

The updatemenu method determines which plotly.js function will be used to modify the chart. There are 4 possible methods:

  • "restyle": modify data or data attributes
  • "relayout": modify layout attributes
  • "update": modify data and layout attributes
  • "animate": start or pause an animation)

Restyle Dropdown

The "restyle" method should be used when modifying the data and data attributes of the graph.
Update One Data Attribute
This example demonstrates how to update a single data attribute: chart type with the "restyle" method.

In [1]:
import plotly.plotly as py
import plotly.graph_objs as go
from plotly.tools import FigureFactory as FF

import json
import numpy as np
import pandas as pd

df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/volcano.csv')

data = [go.Surface(z=df.values.tolist(), colorscale='Viridis')]

layout = go.Layout(
    width=800,
    height=900,
    autosize=False,
    margin=dict(t=0, b=0, l=0, r=0),
    scene=dict(
        xaxis=dict(
            gridcolor='rgb(255, 255, 255)',
            zerolinecolor='rgb(255, 255, 255)',
            showbackground=True,
            backgroundcolor='rgb(230, 230,230)'
        ),
        yaxis=dict(
            gridcolor='rgb(255, 255, 255)',
            zerolinecolor='rgb(255, 255, 255)',
            showbackground=True,
            backgroundcolor='rgb(230, 230, 230)'
        ),
        zaxis=dict(
            gridcolor='rgb(255, 255, 255)',
            zerolinecolor='rgb(255, 255, 255)',
            showbackground=True,
            backgroundcolor='rgb(230, 230,230)'
        ),
        aspectratio = dict(x=1, y=1, z=0.7),
        aspectmode = 'manual'
    )
)

updatemenus=list([
    dict(
        buttons=list([
            dict(
                args=['type', 'surface'],
                label='3D Surface',
                method='restyle'
            ),
            dict(
                args=['type', 'heatmap'],
                label='Heatmap',
                method='restyle'
            )
        ]),
        direction = 'down',
        pad = {'r': 10, 't': 10},
        showactive = True,
        x = 0.1,
        xanchor = 'left',
        y = 1.1,
        yanchor = 'top'
    ),
])

annotations = list([
    dict(text='Trace type:', x=0, y=1.085, yref='paper', align='left', showarrow=False)
])
layout['updatemenus'] = updatemenus
layout['annotations'] = annotations

fig = dict(data=data, layout=layout)
py.iplot(fig, filename='cmocean-picker-one-dropdown')
Out[1]:

Update Several Data Attributes
This example demonstrates how to update several data attributes: colorscale, chart type, and line display with the "restyle" method. This example uses the cmocean python package. You can install this package with pip install cmocean.

In [9]:
import plotly.plotly as py
import plotly.graph_objs as go
from plotly.tools import FigureFactory as FF

import cmocean
import json
import numpy as np
import pandas as pd

def cmocean_to_plotly(cmap, pl_entries=100):
    h = 1.0/(pl_entries-1)
    pl_colorscale = []

    for k in range(pl_entries):
        C = map(np.uint8, np.array(cmap(k*h)[:3])*255)
        pl_colorscale.append([k*h, 'rgb'+str((C[0], C[1], C[2]))])

    return pl_colorscale

df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/volcano.csv')

data = [go.Surface(z=df.values.tolist(), colorscale='Viridis')]

button_layer_1_height = 1.12
button_layer_2_height = 1.065

layout = go.Layout(
    width=800,
    height=900,
    autosize=False,
    margin=dict(t=0, b=0, l=0, r=0),
    scene=dict(
        xaxis=dict(
            gridcolor='rgb(255, 255, 255)',
            zerolinecolor='rgb(255, 255, 255)',
            showbackground=True,
            backgroundcolor='rgb(230, 230,230)'
        ),
        yaxis=dict(
            gridcolor='rgb(255, 255, 255)',
            zerolinecolor='rgb(255, 255, 255)',
            showbackground=True,
            backgroundcolor='rgb(230, 230,230)'
        ),
        zaxis=dict(
            gridcolor='rgb(255, 255, 255)',
            zerolinecolor='rgb(255, 255, 255)',
            showbackground=True,
            backgroundcolor='rgb(230, 230,230)'
        ),
        aspectratio = dict(x=1, y=1, z=0.7 ),
        aspectmode = 'manual'
    )
)

updatemenus=list([
    dict(
        buttons=list([
            dict(
                args=['colorscale', json.dumps(cmocean_to_plotly(cmocean.cm.haline)) ],
                label='Haline',
                method='restyle'
            ),
            dict(
                args=['colorscale', json.dumps(cmocean_to_plotly(cmocean.cm.turbid))],
                label='Turbid',
                method='restyle'
            ),
            dict(
                args=['colorscale', json.dumps(cmocean_to_plotly(cmocean.cm.speed))],
                label='Speed',
                method='restyle'
            ),
            dict(
                args=['colorscale', json.dumps(cmocean_to_plotly(cmocean.cm.haline)) ],
                label='Tempo',
                method='restyle'
            ),
            dict(
                args=['colorscale', json.dumps(cmocean_to_plotly(cmocean.cm.gray))],
                label='Gray',
                method='restyle'
            ),
            dict(
                args=['colorscale', json.dumps(cmocean_to_plotly(cmocean.cm.phase))],
                label='Phase',
                method='restyle'
            ),
            dict(
                args=['colorscale', json.dumps(cmocean_to_plotly(cmocean.cm.balance)) ],
                label='Balance',
                method='restyle'
            ),
            dict(
                args=['colorscale', json.dumps(cmocean_to_plotly(cmocean.cm.delta))],
                label='Delta',
                method='restyle'
            ),
            dict(
                args=['colorscale', json.dumps(cmocean_to_plotly(cmocean.cm.curl))],
                label='Curl',
                method='restyle'
            ),
        ]),
        direction = 'down',
        pad = {'r': 10, 't': 10},
        showactive = True,
        x = 0.1,
        xanchor = 'left',
        y = button_layer_1_height,
        yanchor = 'top'
    ),
    dict(
        buttons=list([
            dict(
                args=['reversescale', True],
                label='Reverse',
                method='restyle'
            ),
            dict(
                args=['reversescale', False],
                label='Undo',
                method='restyle'
            )
        ]),
        direction = 'down',
        pad = {'r': 10, 't': 10},
        showactive = True,
        x = 0.55,
        xanchor = 'left',
        y = button_layer_1_height,
        yanchor = 'top'
    ),
    dict(
        buttons=list([
            dict(
                args=[{'contours.showlines':False, 'type':'contour'}],
                label='Hide lines',
                method='restyle'
            ),
            dict(
                args=[{'contours.showlines':True, 'type':'contour'}],
                label='Show lines',
                method='restyle'
            ),
        ]),
        direction = 'down',
        pad = {'r': 10, 't': 10},
        showactive = True,
        x = 0.775,
        xanchor = 'left',
        y = button_layer_1_height,
        yanchor = 'top'
    ),
    dict(
        buttons=list([
            dict(
                args=['type', 'surface'],
                label='3d Surface',
                method='restyle'
            ),
            dict(
                args=['type', 'heatmap'],
                label='Heatmap',
                method='restyle'
            ),
            dict(
                args=['type', 'contour'],
                label='Contour',
                method='restyle'
            )
        ]),
        direction = 'down',
        pad = {'r': 10, 't': 10},
        showactive = True,
        x = 0.3,
        xanchor = 'left',
        y = button_layer_1_height,
        yanchor = 'top'
    ),
])

annotations = list([
    dict(text='cmocean<br>scale', x=0, y=1.11, yref='paper', align='left', showarrow=False ),
    dict(text='Trace<br>type', x=0.25, y=1.11, yref='paper', showarrow=False ),
    dict(text="Colorscale", x=0.5, y=1.10, yref='paper', showarrow=False),
    dict(text="Lines", x=0.75, y=1.10, yref='paper', showarrow=False)
])
layout['updatemenus'] = updatemenus
layout['annotations'] = annotations

fig = dict(data=data, layout=layout)
py.iplot(fig, filename='cmocean-picker-dropdown')
Out[9]:

Relayout Dropdown

The "relayout" method should be used when modifying the layout attributes of the graph.
Update One Layout Attribute
This example demonstrates how to update a layout attribute: chart type with the "relayout" method.

In [10]:
import plotly.plotly as py
import plotly.graph_objs as go

import numpy as np

x0 = np.random.normal(2, 0.4, 400)
y0 = np.random.normal(2, 0.4, 400)
x1 = np.random.normal(3, 0.6, 600)
y1 = np.random.normal(6, 0.4, 400)
x2 = np.random.normal(4, 0.2, 200)
y2 = np.random.normal(4, 0.4, 200)

trace0 = go.Scatter(
    x=x0,
    y=y0,
    mode='markers',
    marker=dict(color='#835AF1')
)
trace1 = go.Scatter(
    x=x1,
    y=y1,
    mode='markers',
    marker=dict(color='#7FA6EE')
)
trace2 = go.Scatter(
    x=x2,
    y=y2,
    mode='markers',
    marker=dict(color='#B8F7D4')
)
data = [trace0, trace1, trace2]

cluster0 = [dict(type='circle',
                 xref='x', yref='y',
                 x0=min(x0), y0=min(y0),
                 x1=max(x0), y1=max(y0),
                 opacity=.25,
                 line=dict(color='#835AF1'),
                 fillcolor='#835AF1')]
cluster1 = [dict(type='circle',
                 xref='x', yref='y',
                 x0=min(x1), y0=min(y1),
                 x1=max(x1), y1=max(y1),
                 opacity=.25,
                 line=dict(color='#7FA6EE'),
                 fillcolor='#7FA6EE')]
cluster2 = [dict(type='circle',
                 xref='x', yref='y',
                 x0=min(x2), y0=min(y2),
                 x1=max(x2), y1=max(y2),
                 opacity=.25,
                 line=dict(color='#B8F7D4'),
                 fillcolor='#B8F7D4')]

updatemenus = list([
    dict(buttons=list([
            dict(label = 'None',
                 method = 'relayout',
                 args = ['shapes', []]),
            dict(label = 'Cluster 0',
                 method = 'relayout',
                 args = ['shapes', cluster0]),
            dict(label = 'Cluster 1',
                 method = 'relayout',
                 args = ['shapes', cluster1]),
            dict(label = 'Cluster 2',
                 method = 'relayout',
                 args = ['shapes', cluster2]),
            dict(label = 'All',
                 method = 'relayout',
                 args = ['shapes', cluster0+cluster1+cluster2])
        ]),
    )
])

layout = dict(title='Highlight Clusters', showlegend=False,
              updatemenus=updatemenus)

fig = dict(data=data, layout=layout)

py.iplot(fig, filename='relayout_option_dropdown')
Out[10]:

Update Dropdown

The "update" method should be used when modifying the data and layout sections of the graph.
This example demonstrates how to update which traces are displayed while simulaneously updating layout attributes such as the chart title and annotations.

In [2]:
import plotly.plotly as py
import plotly.graph_objs as go

from datetime import datetime
import pandas as pd

df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/finance-charts-apple.csv')
df.columns = [col.replace('AAPL.', '') for col in df.columns]

trace_high = go.Scatter(x=list(df.index),
                        y=list(df.High),
                        name='High',
                        line=dict(color='#33CFA5'))

trace_high_avg = go.Scatter(x=list(df.index),
                            y=[df.High.mean()]*len(df.index),
                            name='High Average',
                            visible=False,
                            line=dict(color='#33CFA5', dash='dash'))

trace_low = go.Scatter(x=list(df.index),
                       y=list(df.Low),
                       name='Low',
                       line=dict(color='#F06A6A'))

trace_low_avg = go.Scatter(x=list(df.index),
                           y=[df.Low.mean()]*len(df.index),
                           name='Low Average',
                           visible=False,
                           line=dict(color='#F06A6A', dash='dash'))

data = [trace_high, trace_high_avg, trace_low, trace_low_avg]

high_annotations=[dict(x='2016-03-01',
                       y=df.High.mean(),
                       xref='x', yref='y',
                       text='High Average:<br>'+str(df.High.mean()),
                       ax=0, ay=-40),
                  dict(x=df.High.idxmax(),
                       y=df.High.max(),
                       xref='x', yref='y',
                       text='High Max:<br>'+str(df.High.max()),
                       ax=0, ay=-40)]
low_annotations=[dict(x='2015-05-01',
                      y=df.Low.mean(),
                      xref='x', yref='y',
                      text='Low Average:<br>'+str(df.Low.mean()),
                      ax=0, ay=40),
                 dict(x=df.High.idxmin(),
                      y=df.Low.min(),
                      xref='x', yref='y',
                      text='Low Min:<br>'+str(df.Low.min()),
                      ax=0, ay=40)]

updatemenus = list([
    dict(active=-1,
         buttons=list([
            dict(label = 'High',
                 method = 'update',
                 args = [{'visible': [True, True, False, False]},
                         {'title': 'Yahoo High',
                          'annotations': high_annotations}]),
            dict(label = 'Low',
                 method = 'update',
                 args = [{'visible': [False, False, True, True]},
                         {'title': 'Yahoo Low',
                          'annotations': low_annotations}]),
            dict(label = 'Both',
                 method = 'update',
                 args = [{'visible': [True, True, True, True]},
                         {'title': 'Yahoo',
                          'annotations': high_annotations+low_annotations}]),
            dict(label = 'Reset',
                 method = 'update',
                 args = [{'visible': [True, False, True, False]},
                         {'title': 'Yahoo',
                          'annotations': []}])
        ]),
    )
])

layout = dict(title='Yahoo', showlegend=False,
              updatemenus=updatemenus)

fig = dict(data=data, layout=layout)
py.iplot(fig, filename='update_dropdown')
Out[2]:

Style Dropdown

When adding dropdowns to Plotly charts, users have the option of styling the color, font, padding, and position of the dropdown menus. The example below demonstrates how to apply different styling options. See all updatemenu styling attributes here: https://plotly.com/python/reference/#layout-updatemenus.

In [4]:
df_wind = pd.read_csv('https://plotly.com/~datasets/2805.csv')

df_known_capacity = df_wind[ df_wind['total_cpcy'] != -99999.000 ]
df_sum = df_known_capacity.groupby('manufac')['total_cpcy'].sum().sort_values(ascending=False).to_frame()

df_farms = pd.read_csv('https://plotly.com/~jackp/17256.csv')
df_farms.set_index('Wind Farm', inplace=True)

wind_farms=list([
    dict(
        args=[ {
            'mapbox.center.lat':38,
            'mapbox.center.lon':-94,
            'mapbox.zoom':3,
            'annotations[0].text':'All US wind turbines (scroll to zoom)'
        } ],
        label='USA',
        method='relayout'
    )
])

for farm, row in df_farms.iterrows():
    desc = []
    for col in df_farms.columns:
        if col not in ['DegMinSec','Latitude','Longitude']:
            if str(row[col]) not in ['None','nan','']:
                desc.append( col + ': ' + str(row[col]).strip("'") )
    desc.insert(0, farm)
    wind_farms.append(
        dict(
            args=[ {
                'mapbox.center.lat':row['Latitude'],
                'mapbox.center.lon':float(str(row['Longitude']).strip("'")),
                'mapbox.zoom':9,
                'annotations[0].text': '<br>'.join(desc)
            } ],
            label=' '.join(farm.split(' ')[0:2]),
            method='relayout'
        )
    )

data = []
for mfr in list(df_sum.index):
    if mfr != 'unknown':
        trace = dict(
            lat = df_wind[ df_wind['manufac'] == mfr ]['lat_DD'],
            lon = df_wind[ df_wind['manufac'] == mfr ]['long_DD'],
            name = mfr,
            marker = dict(size = 4),
            type = 'scattermapbox'
        )
    data.append(trace)

# mapbox_access_token = 'insert mapbox token here'

layout = dict(
    height = 800,
    margin = dict( t=0, b=0, l=0, r=0 ),
    font = dict( color='#FFFFFF', size=11 ),
    paper_bgcolor = '#000000',
    mapbox=dict(
        accesstoken=mapbox_access_token,
        bearing=0,
        center=dict(
            lat=38,
            lon=-94
        ),
        pitch=0,
        zoom=3,
        style='dark'
    ),
)

updatemenus=list([
    dict(
        buttons = wind_farms[0:10],
        pad = {'r': 0, 't': 10},
        x = 0.1,
        xanchor = 'left',
        y = 1.0,
        yanchor = 'top',
        bgcolor = '#AAAAAA',
        active = 99,
        bordercolor = '#FFFFFF',
        font = dict(size=11, color='#000000')
    ),
    dict(
        buttons=list([
            dict(
                args=['mapbox.style', 'dark'],
                label='Dark',
                method='relayout'
            ),
            dict(
                args=['mapbox.style', 'light'],
                label='Light',
                method='relayout'
            ),
            dict(
                args=['mapbox.style', 'satellite'],
                label='Satellite',
                method='relayout'
            ),
            dict(
                args=['mapbox.style', 'satellite-streets'],
                label='Satellite with Streets',
                method='relayout'
            )
        ]),
        direction = 'up',
        x = 0.75,
        xanchor = 'left',
        y = 0.05,
        yanchor = 'bottom',
        bgcolor = '#000000',
        bordercolor = '#FFFFFF',
        font = dict(size=11)
    ),
])

annotations = list([
    dict(text='All US wind turbines (scroll to zoom)', font=dict(color='magenta',size=14), borderpad=10,
         x=0.05, y=0.05, xref='paper', yref='paper', align='left', showarrow=False, bgcolor='black'),
    dict(text='Wind<br>Farms', x=0.01, y=0.99, yref='paper', align='left', showarrow=False,font=dict(size=14))
])

layout['updatemenus'] = updatemenus
layout['annotations'] = annotations

figure = dict(data=data, layout=layout)
py.iplot(figure, filename='wind-turbine-territory-dropdown')
Out[4]:

Reference

See https://plotly.com/python/reference/#layout-updatemenus for more information about updatemenu dropdowns.