Related
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:
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()
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 have made a graph using time axis on the X axis, however I want to show only today's data. (i.e restrict the date to current date)
Here is the code I used to produce those graphs :
fig = go.Figure()
fig = make_subplots(rows=2,cols=1,shared_xaxes=True,vertical_spacing=0.02)
fig.add_trace(go.Scatter(x=data['time'],y=data['x_last_recorded'],name='xyz',mode='lines+markers'),row=2,col=1)
fig.add_trace(go.Scatter(x=predict_data['time'],y=predict_data['x1_last_recorded'],name='x1yz',mode='lines'),row=2,col=1)
fig.update_layout(height=800,width=1500,title='first_graph',yaxis_title='Values')
This has got me a graph of how I want, but it is showing all the dates present in the dataframe. How do I fetch only the current date's data?
Structure of time : dd-mm-yyyy hh:mm
We can solve your challenge by subsetting your dataframe using an approach such as df_current = df[df.index.date==df.index.date[-1]], and then restyle your figure by letting different subsets be represented by different options in a dropdown menu.
Here's the resulting figure for the different subsets / selection options:
All dates
Current date
Complete code:
# imports
import plotly.graph_objects as go
import pandas as pd
import numpy as np
# sample data in the form of an hourlt
np.random.seed(1234)
tseries = pd.date_range("01.01.2020", "01.04.2020", freq="H")
data = np.random.randint(-10, 12, size=(len(tseries), 2))
df = pd.DataFrame(index=tseries, data=data)
df.drop(df.tail(1).index,inplace=True)
df.columns=list('AB')
df.iloc[0]=0
df=df.cumsum()
# subset method
df_current = df[df.index.date==df.index.date[-1]]
# plotly setup
fig = go.Figure()
# set up a trace for each column in a dataframe
for col in df.columns:
fig.add_trace(go.Scatter(x=df.index, y =df[col], name=col))
# container for updatemenus and buttons
updatemenu = []
buttons = []
# button 1
buttons.append(dict(method='restyle',
label='All',
visible=True,
args=[{'y':[df[col].values for col in df.columns],
'x':[df.index],
'type':'scatter'}, ],))
# button 2
buttons.append(dict(method='restyle',
label='Current',
visible=True,
args=[{'y':[df_current[col].values for col in df_current.columns],
'x':[df_current.index],
'type':'scatter'}, ],))
# menu setup
your_menu = dict()
updatemenu.append(your_menu)
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()