I can't seem to figure out the documentation. Basically I want to create a dropdown menu and each selection outputs a different chart. Here is an MRE. plotly.express is imported as px.
race = pd.read_csv('https://github.com/ngpsu22/Ed_Debt-vs.-UBI/raw/main/race_debt_ubi')
education = pd.read_csv('https://github.com/ngpsu22/Ed_Debt-vs.-UBI/raw/main/education_debt_ubi')
income = pd.read_csv('https://github.com/ngpsu22/Ed_Debt-vs.-UBI/raw/main/income_debt_ubi')
fig_race = px.bar(race, x='race', y='percent_has_debt', text='percent_has_debt')
fig_education = px.bar(education, y='percent_has_debt', text='percent_has_debt')
fig_income = px.bar(income, y='percent_has_debt', text='percent_has_debt')
Basically I want to create a dropdown menu of ['race', 'education', 'income'] that outputs the corresponding chart.
I've made your data into a graph that you can select in a drop-down with the 'go' in 'plotly'. The default is to show all the values. I modified it with the help of the official reference and this site.
import plotly.graph_objects as go
import pandas as pd
race = pd.read_csv('https://github.com/ngpsu22/Ed_Debt-vs.-UBI/raw/main/race_debt_ubi')
education = pd.read_csv('https://github.com/ngpsu22/Ed_Debt-vs.-UBI/raw/main/education_debt_ubi')
income = pd.read_csv('https://github.com/ngpsu22/Ed_Debt-vs.-UBI/raw/main/income_debt_ubi')
fig = go.Figure()
fig.add_trace(go.Bar(x=race['race'], y=race['percent_has_debt'], name='race'))
fig.add_trace(go.Bar(x=[0,1,2,3], y=education['percent_has_debt'], name='education'))
fig.add_trace(go.Bar(x=[0,1,2,3,4,5], y=income['percent_has_debt'], name='income'))
fig.update_layout(
updatemenus=[go.layout.Updatemenu(
active=0,
buttons=list([
dict(label="None",
method="update",
args=[{'visible':[False,False,False]},
{'title':'AL','showlegend':True}]),
dict(label="race",
method="update",
args=[{'visible':[True,False,False]},
{'title':'RACE','showlegend':True}]),
dict(label="education",
method="update",
args=[{'visible':[False,True,False]},
{'title':'EDUCATION','showlegend':True}]),
dict(label="income",
method="update",
args=[{'visible':[False,False,True]},
{'title':'INCOME','showlegend':True}]),
]
))])
fig.show()
Related
Hello guys i need help i have a piece of code that adds a list of horizontal lines to a Plotly figure in python. i want to change the code to were we will use a slider to add the horizontal lines to the figure and relayout it. As the slider moves right more horizontal lines will be added to the figure when the slider moves left the horizontal lines will be removed from the figure. Below is the bit of my code so far
for v in range(len(sortadlist)):
fig.add_hline(y=sortadlist[v][0], line_color='brown', line_width=1.5, row=1, col=1)
fig.add_shape(type="rect",
y0=round(sortadlist[v][0],2)-.3, y1=round(sortadlist[v][0],2)+.3, x0=-1, x1=len(df),
fillcolor="darkcyan",
opacity=0.15)
All the code above does is loop through a list of numbers and uses the fig.add_hline to add the horizontal line to the figure. I need help creating a slider that will add the horizontal lines to the figure
This is how the figure currently looks i want a slider to help with adding more horizontal lines to the figure and remove them also
Since the entire code is not available, the sample data was handled by obtaining the company's stock price. First of all, horizontal lines and shapes do not have a show/hide attribute, so they are not compatible with sliders. So I have created a code to draw a line according to the appropriate price list in the line chart of the scatter chart. Once the line chart is hidden, the first line chart is made visible.
The structure of the graph is a candlestick with 6 lines and the candlestick is always displayed. A loop process is used to create a list of lines to be shown or hidden.
import yfinance as yf
import plotly.graph_objects as go
import numpy as np
df = yf.download("AAPL", start="2022-01-01", end="2023-01-01", progress=False)
df.reset_index(inplace=True)
pricelist = np.arange(130,190,10)
fig = go.Figure()
fig.add_trace(go.Candlestick(x=df['Date'],
open=df['Open'],
high=df['High'],
low=df['Low'],
close=df['Close'],
name='AAPL'
)
)
fig.add_hrect(y0=df['Close'].median()-10,
y1=df['Close'].median()+10,
annotation_text="Median+-10",
annotation_position="top right",
fillcolor="darkcyan",
opacity=0.25,
line_width=0)
for p in pricelist:
fig.add_trace(go.Scatter(x=df['Date'],
y=[p]*len(df['Date']),
line_color='blue',
name=str(p),
showlegend=False,
visible=False,
)
)
fig.data[1].visible = True
steps = []
for i in np.arange(1,len(fig.data)):
step = dict(
method="update",
args=[{"visible": [False] * len(fig.data)},
{"title": "Price lines: " + str(pricelist[i-1])}],
label=str(pricelist[i-1])
)
step["args"][0]["visible"][0] = True
step["args"][0]["visible"][i] = True
steps.append(step)
sliders = [dict(
active=10,
currentvalue={"prefix": "Price: "},
pad={"t": 50},
steps=steps
)]
fig.update_layout(
sliders=sliders
)
fig.update_layout(height=600, xaxis_rangeslider_visible=False)
fig.show()
I am plotting chart using below code:
fig = px.line(df, x='Time', y=['one','two'], color= df.index)
fig['layout']['xaxis']['autorange'] = "reversed"
fig.update_layout(legend_title="Price")
fig.show()
Dataframe i am working with like is below:
Time one two
100 9:30 129 243
110 10:30 234 453
120 11:00 155 234
Want to add dropdown menu to select from index and show one row at a time in chart.
example if i select 110 from drop down it should only show chart for that row.
Is there any easy fix for it.
Thank you in adavance.
Here's my solution:
In order to set the proper options for the dropdown menu, it would be helpful to have a function that creates the list of options (shown below)
# Create proper buttons list
def makeButtonsList(idxs):
buttons = []
for i, idx in enumerate(idxs):
visibleArr = np.full((2*df.index.shape[0],),
False, dtype=bool) # 2x number of booleans since one/two vals are separate plots
visibleArr[2*i] = True # Set two booleans next to each other (representing one & two) to true
visibleArr[(2*i)+1] = True
buttons.append(dict(label=str(idx),
method='update',
args=[{'visible': list(visibleArr)}])) # 'Visible' arg determines which plots are shown
# depending on which dropdown is selected
return buttons
Next create the traces for the data (with your sample data, I created a bar chart but you could easily modify this)
traces = []
for i in range(df.Time.shape[0]):
rowData = df.iloc[i, :]
time = rowData.Time
one = rowData.one
two = rowData.two
traces.append(go.Bar(x=[time], y=[one], name='One'))
traces.append(go.Bar(x=[time], y=[two], name='Two'))
where df is the dataframe you are working with.
Finally put it all together and create the Plotly plot!
# Import packages
import pandas as pd
import numpy as np
import plotly.graph_objs as go
import plotly.express as px
# Create proper buttons list
def makeButtonsList(idxs):
buttons = []
for i, idx in enumerate(idxs):
visibleArr = np.full((2*df.index.shape[0],),
False, dtype=bool) # 2x number of booleans since one/two vals are separate plots
visibleArr[2*i] = True # Set two booleans next to each other (representing one & two) to true
visibleArr[(2*i)+1] = True
buttons.append(dict(label=str(idx),
method='update',
args=[{'visible': list(visibleArr)}])) # 'Visible' arg determines which plots are shown
# depending on which dropdown is selected
return buttons
# Create traces
traces = []
for i in range(df.Time.shape[0]):
rowData = df.iloc[i, :]
time = rowData.Time
one = rowData.one
two = rowData.two
traces.append(go.Bar(x=[time], y=[one], name='One'))
traces.append(go.Bar(x=[time], y=[two], name='Two'))
# Create figure
fig = go.Figure(data=traces)
# Add dropdown options
fig.update_layout(
updatemenus=[
dict(
buttons=makeButtonsList(df.index),
direction="down",
pad={"r": 10, "t": 10},
showactive=True,
x=0.55,
xanchor="left",
y=1.2,
yanchor="top"
),
]
)
# Add annotation for index selected
fig.update_layout(
annotations=[
dict(text="Index:", showarrow=False,
x=0, y=1.15, yref="paper", align="left")
],
xaxis_title = 'Time',
yaxis_title = 'Value',
)
# Show the plot
fig.show()
Here is a sample plot:
BONUS:
If you think this method is tedious, and a slider bar would do the job just fine, Plotly supports animation of bar charts. Here is the following code you could use:
fig = px.bar(df, x='Time', y=['one','two'], animation_frame=df.index)
fig.update_layout(title='Data', barmode='group')
fig.show()
Here is the resulting plot:
Say I have a function that returns a chart. I want a user to be able to select from a drop down menu and their selections become the inputs to the function. Here is an MRE, but the actual charts and data I'm using are much more complicated so I don't want to use shortcuts or change which data is passed into the chart.
I've already read this documentation. https://plotly.com/python/dropdowns/
Here is the MRE:
import plotly.express as px
data_canada = px.data.gapminder().query("country == 'Canada'")
def charts(input):
if input == 'A':
fig = px.bar(data_canada, x='year', y='pop')
if input == 'B':
fig = px.bar(data_canada, x='year', y='lifeExp')
fig.show()
So what I need from here is how to create drop down menus that is an input to this function.
One way to solve this is to use updatemenus, where you basically update the visibility of the two traces, based on the selection in the dropdown:
import plotly.express as px
data_canada = px.data.gapminder().query("country == 'Canada'")
fig = px.bar(data_frame=data_canada, x='year', y=['pop', 'lifeExp'], title="LifeExp") # Plotly 4.8 and above!
fig.update_layout(
showlegend=False, # hide the legend so the default is not confusing
updatemenus=[
dict(
active=0,
buttons=list([
dict(label="LifeExp",
method="update",
args=[{"visible": [False, True]},
{"title": "LifeExp"}]),
dict(label="Population",
method="update",
args=[{"visible": [True, False]},
{"title": "Population"}])
])
)]
)
This should give the following result with the Gapminder data example:
What happens here is the following: First, you generate the figure with 2 traces and a default legend. Then, you add the dropdown and you make it control the visibility of the traces. The first option in the dropdown will be the default.
Note: this support for "wide-format" selection of columns is only available from Plotly 4.8.2 and higher (all numeric types are considered "the same" in wide-format from that version on
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})
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.
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()
I'm trying to create a drop down menu using the following code:
import plotly.express as px
df = px.data.gapminder()
fig = px.line(df, x="year", y="lifeExp", color="country")
buttons = [
{'method' : 'update', 'label' : val, 'args' : df[df['continent'].eq(val)]['lifeExp']}
for val in df['continent'].unique()
]
# construct menus
updatemenus = [{'buttons': buttons,
'direction': 'down',
'showactive': True,}]
# update layout with buttons, and show the figure
fig.update_layout(updatemenus=updatemenus)
fig.show()
I've added the list comprehension to generate the y values, but I"m not sure what I'm currently doing wrong here.
I'm expecting to be able to select a different continent and have the plot update