When I am making a graph on plotly, my first graph (All) is working great. It has the 5 categories and, when you hover, adds up to 100%. first graph. When I move onto the second graph, this is where I start running into issues. When you click the 20 buttons, it comes up with this The second graph. Now it has the 5 corresponding categories to the age group of 20 but it also includes the some categories for the 30s age group. How can I set it up so that it only shows the 5 categories for each corresponding age group?
Entire Code:
p_info = pd.read_csv('PatientInfo.csv',parse_dates=['symptom_onset_date', 'confirmed_date', 'released_date', 'deceased_date'])
p_info = p_info.dropna(subset=['age'])
p_info = p_info.dropna(subset=['infection_case'])
#Lets Group these together to make analysis easier
def group(x):
if "Shincheonji Church" in x:
x="Church"
return x
if "Onchun Church" in x:
x="Church"
return x
if "Dongan Church" in x:
x="Church"
return x
if "Geochang Church" in x:
x="Church"
return x
if "SMR Newly Planted Churches Group" in x:
x="Church"
return x
if "Pilgrimage to Israel" in x:
x="Church"
return x
if "River of Grace Community Church" in x:
x="Church"
return x
if "Biblical Language study meeting" in x:
x="Church"
return x
if "etc" in x:
x="etc"
return x
if "contact with patient" in x:
x="Direct Contact with Patient"
return x
if "overseas inflow" in x:
x="Overseas"
return x
else:
x="Group"
return x
p_info['infection_type'] = p_info['infection_case'].apply(group)
p_info['week'] = p_info['confirmed_date'].dt.weekofyear
type_by_time = p_info.groupby(['week', 'infection_type']).size().unstack().fillna(0)
# type_by_time = type_by_time.div(type_by_time.sum(axis=1), axis=0) * 100
type_by_time
type_by_time_age = []
# df = PatientRoute.merge(PatientInfo, on='patient_id')
df = p_info
for age_group in ['20','30','40','50','60','70','80']:
new_type_by_time = df.groupby(['week', 'infection_type']).size().unstack().fillna(0)
type_by_time_age.append(new_type_by_time)
colors = px.colors.qualitative.Light24
x = type_by_time.index.tolist()
categories = ['Church', 'Direct Contact with Patient', 'Group', 'Overseas', 'etc']
fig = go.Figure()
for i, cat in enumerate(categories):
fig.add_trace(go.Scatter(x=x, y=type_by_time[cat],
hoverinfo='x+y',
mode='lines',
line=dict(width=0.5, color=colors[i]),
name=cat,
stackgroup='one',
groupnorm='percent'
))
for age, df in enumerate(type_by_time_age):
for i, cat in enumerate(categories):
fig.add_trace(go.Scatter(x=df.index.tolist(), y=df[cat],
hoverinfo='y',
mode='lines',
line=dict(width=0.5, color=colors[i]),
name=cat,
stackgroup=age,
groupnorm='percent',
visible=False))
fig.update_layout(
title='Where do most people get infected?',
showlegend=True,
xaxis=dict(
range=[4, 19],
ticksuffix=' week'
),
yaxis=dict(
type='linear',
range=[1, 100],
ticksuffix='%'))
menus = []
for i, name in enumerate(['All','20','30','40','50','60','70','80']):
d = dict(label=name,
method="update",
args=[{"visible": [False]*i*9 + [True]*9 + [False]*(8-i-1)*9},
{"title": f"Where do most people get infected? (Age: {name})"}])
menus.append(d)
fig.update_layout(
updatemenus=[
dict(
type="buttons",
direction="right",
active=0,
x=1,
y=1.2,
buttons=menus,
)
],
xaxis_title="weeks",
yaxis_title="% in group of people who get infected",
)
fig.show()
Here is the link to the kaggle dataset: https://www.kaggle.com/kimjihoo/coronavirusdataset
Related
I am revisiting an old Plotly-Dash app and a bubble chart is not properly ordering the axis'. I tried 'categoryorder':'total ascending' under go.Layout but this didn't help.
The application uses an old version of Dash and Plotly. Using the most recent version breaks the app so I'd like to make it work with the below versions:
def initial_bubble_chart(data):
bubble_tickers, energy_value_change, energy_pct_change, industry, market_cap = [], [], [], [], []
for t, _ in data.items():
try:
if bool(data[t][resource_consumption_q][energy_consumption_bucket_q][energy_consumption_q][value_change_q]) == True:
energy_value_change.append(data[t][resource_consumption_q][energy_consumption_bucket_q][energy_consumption_q][value_change_q])
energy_pct_change.append(data[t][resource_consumption_q][energy_consumption_bucket_q][energy_consumption_q][pct_change_q])
industry.append(data[t][financials_topic_q][descriptive_bucket_q][industry_q][value_2017_q])
market_cap.append(data[t][financials_topic_q][company_valuation_bucket_q][market_cap_q][value_2017_q])
bubble_tickers.append(t)
else:
continue
except:
pass
x = list(zip(bubble_tickers, energy_value_change, energy_pct_change, market_cap, industry))
y_test = pd.DataFrame(x)
y_test.columns = ['Tickers', 'Energy Value Change', 'Energy percent change', 'market cap', 'industry']
traces = []
for industry_name in y_test['industry'].unique():
df_by_industry = y_test[y_test['industry']==industry_name].sort_values(by=['Energy Value Change'])
traces.append(go.Scatter(
x = df_by_industry['Energy Value Change'].apply(pd.to_numeric),
y = df_by_industry['Energy percent change'].apply(pd.to_numeric),
#makes this a scatter plot
mode ='markers',
opacity = 0.7,
marker = dict(size = y_test['market cap'].astype(str).astype(float)/1000000000),
#doesn't show proper ticker
hovertext=bubble_tickers,
name = industry_name,
#template= {'template':'seaborn'}
))
return {'data':traces,
#remember that the graph dictionary takes two parameters:
#1: 'data': traces
#2: 'layout':go.Layout(), where the xaxis takes a dict
'layout':go.Layout(
title='Energy Consumption (MwH) 2012-2017 vs. 2017 Market Cap',
xaxis={'title':'Energy Consumption Value Change', 'categoryorder':'total ascending'},
yaxis={'title': 'Energy Consumption Percent Change', 'categoryorder':'total ascending'},
hovermode = 'closest',
template = 'plotly_white',
)}
Calling the function:
html.Div([
dcc.Graph(id='bubble-graph',
figure = go.Figure(initial_bubble_chart(data)))
],style={'display':'inline-block',
'width':'80%',
'border':{'width':'2px', 'color':'black'},
'marginLeft':350,
'marginTop':10,
'marginBottom':50},
className = 'six columns'
),
I would like to have the x and y axis' ordered and reformat the axis'. Graph:
Bubble Chart
I'm trying to move away from iterows due to it's poor proformance. I can't however find another solution to comparing each row of one dataframe with each row from another dataframe.
I have two dataframes each containing a latitude and a longitude. Previously I have used these two functions to make a distance calculation between the two coordinates shown here:
def find_matches(first_HL, second_HL, N, M):
program_start = time.time()
matched_sites_df = pd.DataFrame()
for i_WP, r_WP in first_HL.iterrows():
series = pd.Series(dtype=float)
if r_WP['PL Name'] is not None and r_WP['PL Latitude'] is not None and r_WP['PL Longitude'] is not None:
series = name_and_distance_match(i_WP, r_WP, second_HL, N, M)
if series is not None:
series = pd.DataFrame(series.to_frame().T)
matched_sites_df = pd.concat([matched_sites_df, series], axis=0, ignore_index=True)
now = time.time()
print("------ MATCH FOUND ------ ", r_WP['PL Name'], "------", round(now - program_start, 2), "seconds")
return matched_sites_df
def calc_distance(r_WP, r_HL):
coords_1 = (r_WP['PL Latitude'], r_WP['PL Longitude'])
coords_2 = (r_HL['Latitude'], r_HL['Longitude'])
distance_km = round(geopy.distance.geodesic(coords_1, coords_2).km, 2)
return distance_km
def name_and_distance_match(i_WP, r_WP, second_HL, N, M):
for i_HL, r_HL in second_HL.iterrows():
if pd.isnull(r_HL['Site Name']) or pd.isnull(r_WP['PL Name']) == True:
pass
elif abs(r_WP['PL Latitude'] - r_HL['Latitude']) > 0.1:
pass
elif abs(r_WP['PL Longitude'] - r_HL['Longitude']) > 0.1:
pass
else:
distance_km = r_WP['Distance (km)'] = calc_distance(r_WP, r_HL)
if distance_km < M:
r_HL = filter_town(r_WP, r_HL)
score = r_WP['Name Similarity'] = np.vectorize(fuzzy)(r_HL["HL Site Short"], r_WP['PL Name'])
if score > N:
r_WP["HL Site Short"] = r_HL["HL Site Short"]
return r_WP
Is there a way I can do this without iterows?
The solution I'm working on at the moment looks like this:
def distance_check(first_HL, second_WPHL):
first_lat = first_HL["Latitude"]
first_long = second_WPHL["PL Longitude"]
second_lat = first_HL["Latitude"]
second_long = second_WPHL["PL Longitude"]
if abs(first_lat - second_lat) + abs(first_long - second_long) > 0.2:
return False
else:
COMBINED_HOUSELIST["WHATPUB Site Name"] = PUBMATCH_WHATPUB_SITES["Site Name"]
return True
PUBMATCH_WHATPUB_SITES
COMBINED_HOUSELIST["Distance Check"] = COMBINED_HOUSELIST.apply(distance_check(PUBMATCH_WHATPUB_SITES, COMBINED_HOUSELIST), axis=1)
Any help would be greatly appreciated, thank you.
EDIT: Example Dataframes
COMBINED_HOUSELIST = pd.DataFrame(np.array([["12345", "Wrexham Cwtch", "52.10", "-2.06"], ["12354", "Horse & Hound", "52.21", "-1.95"], ["12435", "Round Of Gras Badsey", "52.33", "-1.99"]]),
columns=['Site Number', 'Site Name', 'Longitude', 'Latitude'])
PUBMATCH_WHATPUB_SITES= pd.DataFrame(np.array([["52938", "Valkyrie Café Bar", "53.22", "-3.00"], ["12435", "Round Of Badsey", "52.33", "-1.99"], ["12345", "Cwtch", "52.11", "-2.00"]]),
columns=['Site Number', 'Site Name', 'Longitude', 'Latitude'])
Desired output
matched_sites = pd.DataFrame(np.array([["12345", "Wrexham Cwtch", "52.10", "-2.06"], ["12354", "Horse & Hound", "52.21", "-1.95"], ["12435", "Round Of Gras Badsey", "52.33", "-1.99"]]),
columns=['Site Number', 'Site Name', 'Longitude', 'Latitude'])
One way or another, I fear that you will have to resort to some form of iteration, but doing it outside of Pandas might speed things up.
So, here is one way to do it with map and partial functions from Python standard library.
First, define two helper functions:
from functools import partial
def calc_distance(coo1, coo2):
return abs(coo1[0] - coo2[0]) + abs(coo1[1] - coo2[1])
def find_matches(one_list, another_list, threshold):
idx = []
for coo in one_list:
func = partial(calc_distance, coo)
results = [result for result in map(func, another_list)]
idx.append([results.index(result) for result in results if result <= threshold])
return idx
Then, with the following toy dataframes:
import pandas as pd
import numpy as np
COMBINED_HOUSELIST = pd.DataFrame(
np.array(
[
["12345", "Wrexham Cwtch", "52.10", "-2.06"],
["12354", "Horse & Hound", "52.21", "-1.95"],
["12435", "Round Of Gras Badsey", "52.33", "-1.99"],
]
),
columns=["Site Number", "Site Name", "Longitude", "Latitude"],
)
PUBMATCH_WHATPUB_SITES = pd.DataFrame(
np.array(
[
["52938", "Valkyrie Café Bar", "53.22", "-3.00"],
["54999", "New Café Bar", "52.10", "-2.1"],
["12435", "Round Of Badsey", "52.33", "-1.99"],
["12345", "Cwtch", "52.11", "-2.00"],
]
),
columns=["Site Number", "Site Name", "Longitude", "Latitude"],
)
You can proceed like this:
# Setup
for col in ["Latitude", "Longitude"]:
for df in [COMBINED_HOUSELIST, PUBMATCH_WHATPUB_SITES]:
df[col] = pd.to_numeric(df[col])
# Get two lists of coordinates looking like [[lat, long], [lat, long],...]
CH_COO = COMBINED_HOUSELIST.loc[:, ["Latitude", "Longitude"]].to_dict("split")["data"]
PW_COO = PUBMATCH_WHATPUB_SITES.loc[:, ["Latitude", "Longitude"]].to_dict("split")[
"data"
]
# Look for matches
COMBINED_HOUSELIST = COMBINED_HOUSELIST.assign(match=find_matches(CH_COO, PW_COO, 0.1))
# Get site names
COMBINED_HOUSELIST["match"] = COMBINED_HOUSELIST.apply(
lambda x: [PUBMATCH_WHATPUB_SITES.loc[idx, "Site Name"] for idx in x["match"]],
axis=1,
)
Finally, print(COMBINED_HOUSELIST):
Below is the starting code, dataframes and TA indicator. Using plotly to make all my graphs. The dataframes are 'df' and 'd15'. I do have others but will keep it simple for the help.
import yfinance as yf
import plotly.graph_objs as go
#Importing my data
df = yf.download(tickers='EURUSD=X', period='1d', interval='5m')
d15 = yf.download(tickers='EURUSD=X', period='3d',interval='15m')
def Supertrend(df, atr_period, multiplier):
high = df['High']
low = df['Low']
close = df['Close']
# calculate ATR
price_diffs = [high - low,
high - close.shift(),
close.shift() - low]
true_range = pd.concat(price_diffs, axis=1)
true_range = true_range.abs().max(axis=1)
# default ATR calculation in supertrend indicator
atr = true_range.ewm(alpha=1/atr_period,min_periods=atr_period).mean()
# df['atr'] = df['tr'].rolling(atr_period).mean()
# HL2 is simply the average of high and low prices
hl2 = (high + low) / 2
# upperband and lowerband calculation
# notice that final bands are set to be equal to the respective bands
final_upperband = upperband = hl2 + (multiplier * atr)
final_lowerband = lowerband = hl2 - (multiplier * atr)
# initialize Supertrend column to True
supertrend = [True] * len(df)
for i in range(1, len(df.index)):
curr, prev = i, i-1
# if current close price crosses above upperband
if close[curr] > final_upperband[prev]:
supertrend[curr] = True
# if current close price crosses below lowerband
elif close[curr] < final_lowerband[prev]:
supertrend[curr] = False
# else, the trend continues
else:
supertrend[curr] = supertrend[prev]
# adjustment to the final bands
if supertrend[curr] == True and final_lowerband[curr] < final_lowerband[prev]:
final_lowerband[curr] = final_lowerband[prev]
if supertrend[curr] == False and final_upperband[curr] > final_upperband[prev]:
final_upperband[curr] = final_upperband[prev]
# to remove bands according to the trend direction
if supertrend[curr] == True:
final_upperband[curr] = np.nan
else:
final_lowerband[curr] = np.nan
return pd.DataFrame({
'Supertrend': supertrend,
'Final Lowerband': final_lowerband,
'Final Upperband': final_upperband
}, index=df.index)
atr_period = 10
atr_multiplier = 6.0
df = yf.download(tickers='EURUSD=X', period='1d', interval='5m')
supertrend = Supertrend(df, atr_period, atr_multiplier)
df = df.join(supertrend)
#15 Minute Indicator
def Supertrend(df, atr_period, multiplier):
high = df['High']
low = df['Low']
close = df['Close']
# calculate ATR
price_diffs = [high - low,
high - close.shift(),
close.shift() - low]
true_range = pd.concat(price_diffs, axis=1)
true_range = true_range.abs().max(axis=1)
# default ATR calculation in supertrend indicator
atr = true_range.ewm(alpha=1/atr_period,min_periods=atr_period).mean()
# df['atr'] = df['tr'].rolling(atr_period).mean()
# HL2 is simply the average of high and low prices
hl2 = (high + low) / 2
# upperband and lowerband calculation
# notice that final bands are set to be equal to the respective bands
final_upperband = upperband = hl2 + (multiplier * atr)
final_lowerband = lowerband = hl2 - (multiplier * atr)
# initialize Supertrend column to True
supertrend = [True] * len(df)
for i in range(1, len(df.index)):
curr, prev = i, i-1
# if current close price crosses above upperband
if close[curr] > final_upperband[prev]:
supertrend[curr] = True
# if current close price crosses below lowerband
elif close[curr] < final_lowerband[prev]:
supertrend[curr] = False
# else, the trend continues
else:
supertrend[curr] = supertrend[prev]
# adjustment to the final bands
if supertrend[curr] == True and final_lowerband[curr] < final_lowerband[prev]:
final_lowerband[curr] = final_lowerband[prev]
if supertrend[curr] == False and final_upperband[curr] > final_upperband[prev]:
final_upperband[curr] = final_upperband[prev]
# to remove bands according to the trend direction
if supertrend[curr] == True:
final_upperband[curr] = np.nan
else:
final_lowerband[curr] = np.nan
return pd.DataFrame({
'Supertrend': supertrend,
'Final Lowerband': final_lowerband,
'Final Upperband': final_upperband
}, index=df.index)
atr_period = 10
atr_multiplier = 6.0
df = yf.download(tickers='EURUSD=X', period='1d', interval='5m')
supertrend = Supertrend(df, atr_period, atr_multiplier)
df = df.join(supertrend)
This next part is the plot which I think is where I need the help. I need to add 2 buttons and add these 2 charts to each other?
Button 1: 5m (Shows 05m TF Plot)
Button 2: 15m (Shows 15m TF Plot)
#5 Minute TF plot
fig = go.Figure()
fig.add_trace(go.Candlestick(x=df.index,
open=df['Open'],
high=df['High'],
low=df['Low'],
close=df['Close'],
increasing_line_color= '#04b29b',
decreasing_line_color= '#ff2d5d',
increasing_fillcolor = '#04b29b',
decreasing_fillcolor = '#ff2d5d',
name='EURUSD'
))
fig.add_trace(go.Scatter(x=df.index,
y=df['Final Lowerband'],
mode='lines',
line=dict(color='#04b29b'),
name='Bullish'
))
fig.add_trace(go.Scatter(x=df.index,
y=df['Final Upperband'],
mode='lines',
line=dict(color='#ff2d5d'),
name='Bearish'
))
fig.update_layout(xaxis_rangeslider_visible=False,
plot_bgcolor = 'black', showlegend = False,
margin = dict(l=10, r=10,t=10,b=10),
paper_bgcolor='black',
xaxis=dict(showgrid=False, zerolinecolor = 'white',
color='white'),
yaxis=dict(showticklabels=False, showgrid=False))
fig.update_xaxes(
rangebreaks=[
dict(bounds=["sat", "mon"]), #hide weekends
dict(values=["2015-12-25", "2016-01-01"]) # hide Christmas
and New Year's
]
)
fig.show()
This is the 15 minute tf
15 Minute TF Plot
fig15 = go.Figure()
fig15.add_trace(go.Candlestick(x=d15.index,
open=d15['Open'],
high=d15['High'],
low=d15['Low'],
close=d15['Close'],
increasing_line_color= '#04b29b',
decreasing_line_color= '#ff2d5d',
increasing_fillcolor = '#04b29b',
decreasing_fillcolor = '#ff2d5d',
name='EURUSD'
))
fig15.add_trace(go.Scatter(x=d15.index,
y=d15['Final Lowerband'],
mode='lines',
line=dict(color='#04b29b'),
name='Bullish'
))
fig15.add_trace(go.Scatter(x=d15.index,
y=d15['Final Upperband'],
mode='lines',
line=dict(color='#ff2d5d'),
name='Bearish'
))
fig15.update_layout(xaxis_rangeslider_visible=False,
plot_bgcolor = 'black', showlegend = False,
margin = dict(l=10, r=10,t=10,b=10),
paper_bgcolor='black',
xaxis=dict(showgrid=False, zerolinecolor = 'white',
color='white'),
yaxis=dict(showticklabels=False, showgrid=False))
fig15.update_xaxes(
rangebreaks=[
dict(bounds=["sat", "mon"]), #hide weekends
dict(values=["2015-12-25", "2016-01-01"]) # hide Christmas
and New Year's
]
)
fig15.show()
If you want to get an answer quickly, you will get a quicker answer if you put a more simplified code on it. Or, if you create a reproducible situation with sample data and code for graphs, you will have a better chance of getting an answer. To answer the main question of how to make each graph a button, you can use the stock price data from the official reference, draw three different stocks, and set the show/hide control for each to show For example, if you only have AAPL, set the others to False to hide them. That is simply the only setting.
import plotly.graph_objects as go
import plotly.express as px
df = px.data.stocks()
fig = go.Figure()
fig.add_trace(go.Scatter(x=df['date'], y=df['AAPL'], name='AAPL'))
fig.add_trace(go.Scatter(x=df['date'], y=df['GOOG'], name='GOOG'))
fig.add_trace(go.Scatter(x=df['date'], y=df['AMZN'], name='AMZN'))
fig.update_layout(
updatemenus=[
dict(
type="buttons",
direction="right",
active=0,
x=0.25,
y=1.2,
buttons=list([
dict(label="All",
method="update",
args=[{"visible": [True, True, True]},
{"title": "All"}
]),
dict(label="AAPL",
method="update",
args=[{"visible": [True, False, False]},
{"title": "AAPL"}
]),
dict(label="GOOG",
method="update",
args=[{"visible": [False, True, False]},
{"title": "GOOG"}
]),
dict(label="AMZN",
method="update",
args=[{"visible": [False, False, True]},
{"title": "AMZN"}
]),
]),
)
])
fig.show()
I have a task and I'm done.
I've dataframe and I need to save it for the users - it can't be an excel file, but it should be something with filtering button - dropdown list. Something user friendly..
Do you have any idea how to do it?
I tried to join this:
def multi_plot(df, title, addAll = True):
fig = go.Figure()
for column in df.columns.to_list():
fig.add_trace(
go.Scatter(
x = df.index,
y = df[column],
name = column
)
)
button_all = dict(label = 'All',
method = 'update',
args = [{'visible': df.columns.isin(df.columns),
'title': 'All',
'showlegend':True}])
def create_layout_button(column):
return dict(label = column,
method = 'update',
args = [{'visible': df.columns.isin([column]),
'title': column,
'showlegend': True}])
fig.update_layout(
updatemenus=[go.layout.Updatemenu(
active = 0,
buttons = ([button_all] * addAll) + list(df.columns.map(lambda column: create_layout_button(column)))
)
],
yaxis_type="log"
)
But i'm lost :/
Should I add this to html table?
I want to change the dropdown button with an input box so I can search for the item by starting to type the name and then select. So far I have a drop down box where you can select either one item or all of them at the same time. However, I want the user to be able to start typing the name of the item and then click and select the item they want to display their graph.
As I am new to plotly, any suggestion is very welcome and appreciated :)
Here is what the plot looks like so far:
My code:
def interactive_multi_plot(actual, forecast_1, forecast_2, title, addAll = True):
fig = go.Figure()
for column in forecast_1.columns.to_list():
fig.add_trace(
go.Scatter(
x = forecast_1.index,
y = forecast_1[column],
name = "Forecast_SI"
)
)
button_all = dict(label = 'All',
method = 'update',
args = [{'visible': forecast_1.columns.isin(forecast_1.columns),
'title': 'All',
'showlegend':True}])
for column in forecast_2.columns.to_list():
fig.add_trace(
go.Scatter(
x = forecast_2.index,
y = forecast_2[column],
name = "Forecast_LSTM"
)
)
button_all = dict(label = 'All',
method = 'update',
args = [{'visible': forecast_2.columns.isin(forecast_2.columns),
'title': 'All',
'showlegend':True}])
for column in actual.columns.to_list():
fig.add_trace(
go.Scatter(
x = actual.index,
y = actual[column],
name = "True values"
)
)
button_all = dict(label = 'All',
method = 'update',
args = [{'visible': actual.columns.isin(actual.columns),
'title': 'All',
'showlegend':True}])
fig.layout.plot_bgcolor = '#010028'
fig.layout.paper_bgcolor = '#010028'
def create_layout_button(column):
return dict(label = column,
method = 'update',
args = [{'visible': actual.columns.isin([column]),
'title': column,
'showlegend': True}])
fig.update_layout(
updatemenus=[go.layout.Updatemenu(
active = 0,
buttons = ([button_all] * addAll) + list(actual.columns.map(lambda column: create_layout_button(column)))
)
]
)
# Update remaining layout properties
fig.update_layout(
title_text=title,
height=800,
font = dict(color='#fff', size=12)
)
fig.show()
This is the error I receive:
small changes to interactive_multi_plot().
for all three add_trace() add meta = column for each of the scatter creations
change to return fig instead of fig.show()
simulate some data and call interactive_multi_plot(). I have assumed all three data frames have the same columns
S = 100
C = 10
actual = pd.DataFrame(
{
c: np.sort(np.random.uniform(0, 600, S))
for c in [
f"{a}{b}-{c}"
for a, b, c in zip(
np.random.randint(100, 200, C),
np.random.choice(list("ABCDEF"), C),
np.random.randint(300, 400, C),
)
]
}
)
f1 = actual.assign(**{c:actual[c]*1.1 for c in actual.columns})
f2 = actual.assign(**{c:actual[c]*1.2 for c in actual.columns})
fig = interactive_multi_plot(actual, f1, f2, "Orders")
solution
use dash this does support interactive drop downs
simple case of show figure and define a callback on item selected from dash drop down
it could be considered that updatemenus is now redundant. I have not considered sync of updatemenus back to dash drop down
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
from jupyter_dash import JupyterDash
# Build App
app = JupyterDash(__name__)
app.layout = html.Div(
[
dcc.Dropdown(
id="lines",
options=[{"label": c, "value": c} for c in ["All"] + actual.columns.tolist()],
value="All",
),
dcc.Graph(id="interactive-multiplot", figure=fig),
]
)
#app.callback(
Output("interactive-multiplot", "figure"),
Input("lines", "value"),
State("interactive-multiplot", "figure"),
)
def updateGraphCB(line, fig):
# filter traces...
fig = go.Figure(fig).update_traces(visible=False).update_traces(visible=True, selector={"meta":line} if line!="All" else {})
# syn button to dash drop down
fig = fig.update_layout(updatemenus=[{"active":0 if line=="All" else actual.columns.get_loc(line)+1}])
return fig
app.run_server(mode="inline")