I have been trying to update the timeline as per the selected item from dropdown but it is not getting plotted as per the selected option.
For example, in attached image i have selected B1 but C1 is extra here. I have tried printing x list too, for B1
it gives [False True False False False False False False False False]
. Only 1 true at 2nd location, I am not sure where this C1 is coming from. Results get worst when I chose the options below B1.
The current result:
With the following dataframe used: Dataframe used
def multi_plot2(df, addAll = True):
grp=df['Group1'].unique()
button_all = dict(label = 'All',
method = 'update',
args = [{'visible': df.columns.isin(df.columns),
'title': 'All',
'showlegend':True}])
def create_layout_button(column):
labels=np.array(df['Label'])
x=np.zeros(labels.size)
i=0
for s in labels:
if column in s:
print (s)
x[i]=1
i=i+1
x=x.astype(np.bool)
print(x)
return dict(label = column,
method = 'restyle',
args = [{'visible': x,
'showlegend': True}])
fig2.update_layout(
updatemenus=[go.layout.Updatemenu(
active = 0,
buttons = ([button_all] * addAll) + list(df['Combined'].map(lambda column: create_layout_button(column)))
)
])
fig2.show()
An sample of the dataframe used (that can be copy and pasted)
{'ID': {0: 1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10},
'Company': {0: 'Joes',
1: 'Mary',
2: 'Georgia',
3: 'France',
4: 'Butter',
5: 'Player',
6: 'Fish',
7: 'Cattle',
8: 'Swim',
9: 'Seabass'},
'Label': {0: 'Product_A-1',
1: 'Product_B-1',
2: 'Product_C-1',
3: 'Product_A-2',
4: 'Product_A-2',
5: 'Product_B-2',
6: 'Product_C-3',
7: 'Product_D-3',
8: 'Product_A-3',
9: 'Product_D-3'},
'Start': {0: '2021-10-31',
1: '2021-05-31',
2: '2021-10-01',
3: '2021-08-21',
4: '2021-10-01',
5: '2021-08-21',
6: '2021-04-18',
7: '2021-10-31',
8: '2021-08-30',
9: '2021-03-31'},
'End': {0: '2022-10-31',
1: '2022-05-31',
2: '2022-10-01',
3: '2022-08-21',
4: '2022-10-01',
5: '2022-08-21',
6: '2022-04-18',
7: '2022-10-31',
8: '2022-08-30',
9: '2022-03-31'},
'Group1': {0: 'A',
1: 'B',
2: 'C',
3: 'A',
4: 'A',
5: 'B',
6: 'C',
7: 'D',
8: 'A',
9: 'D'},
'Group2': {0: 1, 1: 1, 2: 1, 3: 2, 4: 2, 5: 2, 6: 3, 7: 3, 8: 3, 9: 3},
'Color': {0: 'Blue',
1: 'Red',
2: 'Green',
3: 'Yellow',
4: 'Green',
5: 'Yellow',
6: 'Red',
7: 'Green',
8: 'Green',
9: 'Yellow'},
'Review': {0: 'Excellent',
1: 'Good',
2: 'Bad',
3: 'Fair',
4: 'Good',
5: 'Bad',
6: 'Fair',
7: 'Excellent',
8: 'Good',
9: 'Bad'},
'url': {0: 'https://www.10xgenomics.com/',
1: 'http://www.3d-medicines.com',
2: 'https://www.89bio.com/',
3: 'https://www.acimmune.com/',
4: 'https://www.acastipharma.com',
5: 'https://acceleratediagnostics.com',
6: 'http://acceleronpharma.com/',
7: 'https://www.acell.com/',
8: 'https://www.acelrx.com',
9: 'https://achievelifesciences.com/'},
'Combined': {0: 'A-1',
1: 'B-1',
2: 'C-1',
3: 'A-2',
4: 'A-2',
5: 'B-2',
6: 'C-3',
7: 'D-3',
8: 'A-3',
9: 'D-3'}}
As far as I can tell, px.timeline
produces a figure with one trace. This means that when you pass a boolean array to the visible
argument for your buttons, clicking on these buttons these buttons won't correctly update the figure.
Although it's not a very elegant solution, my suggestion would be that you recreate the px.timeline figure using multiple go.Bar
traces – one trace for each product label. Then when you pass boolean array to the 'visible' argument as you did in your original code, the buttons should function correctly.
It's not perfect because the horizontal bars don't quite align with the labels (not sure why - any improvements would be greatly appreciated), but here is an example of what you can accomplish:
import numpy as np
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
df = pd.DataFrame(
{'ID': {0: 1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10},
'Company': {0: 'Joes',
1: 'Mary',
2: 'Georgia',
3: 'France',
4: 'Butter',
5: 'Player',
6: 'Fish',
7: 'Cattle',
8: 'Swim',
9: 'Seabass'},
'Label': {0: 'Product_A-1',
1: 'Product_B-1',
2: 'Product_C-1',
3: 'Product_A-2',
4: 'Product_A-2',
5: 'Product_B-2',
6: 'Product_C-3',
7: 'Product_D-3',
8: 'Product_A-3',
9: 'Product_D-3'},
'Start': {0: '2021-10-31',
1: '2021-05-31',
2: '2021-10-01',
3: '2021-08-21',
4: '2021-10-01',
5: '2021-08-21',
6: '2021-04-18',
7: '2021-10-31',
8: '2021-08-30',
9: '2021-03-31'},
'End': {0: '2022-10-31',
1: '2022-05-31',
2: '2022-10-01',
3: '2022-08-21',
4: '2022-10-01',
5: '2022-08-21',
6: '2022-04-18',
7: '2022-10-31',
8: '2022-08-30',
9: '2022-03-31'},
'Group1': {0: 'A',
1: 'B',
2: 'C',
3: 'A',
4: 'A',
5: 'B',
6: 'C',
7: 'D',
8: 'A',
9: 'D'},
'Group2': {0: 1, 1: 1, 2: 1, 3: 2, 4: 2, 5: 2, 6: 3, 7: 3, 8: 3, 9: 3},
'Color': {0: 'Blue',
1: 'Red',
2: 'Green',
3: 'Yellow',
4: 'Green',
5: 'Yellow',
6: 'Red',
7: 'Green',
8: 'Green',
9: 'Yellow'},
'Review': {0: 'Excellent',
1: 'Good',
2: 'Bad',
3: 'Fair',
4: 'Good',
5: 'Bad',
6: 'Fair',
7: 'Excellent',
8: 'Good',
9: 'Bad'},
'url': {0: 'https://www.10xgenomics.com/',
1: 'http://www.3d-medicines.com',
2: 'https://www.89bio.com/',
3: 'https://www.acimmune.com/',
4: 'https://www.acastipharma.com',
5: 'https://acceleratediagnostics.com',
6: 'http://acceleronpharma.com/',
7: 'https://www.acell.com/',
8: 'https://www.acelrx.com',
9: 'https://achievelifesciences.com/'},
'Combined': {0: 'A-1',
1: 'B-1',
2: 'C-1',
3: 'A-2',
4: 'A-2',
5: 'B-2',
6: 'C-3',
7: 'D-3',
8: 'B-1',
9: 'D-3'}}
)
# fig2 = px.timeline(
# df, x_start='Start', x_end='End', y='Label'
# )
fig2 = go.Figure()
df['Start'] = pd.to_datetime(df['Start'], format="%Y-%m-%d")
df['End'] = pd.to_datetime(df['End'], format="%Y-%m-%d")
button_all = [
dict(label="All",
method="update",
args = [{'visible': [True]*len(df)}])
]
button_labels = []
for label in df['Combined'].unique():
df_label = df.loc[df['Combined'] == label, ['Start','End','Label']]
# extract milliseconds
df_label['Diff'] = [d.total_seconds()*10**3 for d in (
df_label['End'] - df_label['Start']
)]
fig2.add_trace(go.Bar(
base=df_label['Start'].tolist(),
x=df_label['Diff'].tolist(),
y=df_label['Label'].tolist(),
xcalendar='gregorian',
orientation='h'
))
all_trace_labels = [trace['y'][0] for trace in fig2.data]
for trace in fig2.data:
label = trace['y'][0]
visible_array = [t == label for t in all_trace_labels]
button_labels.append(
dict(label=label,
method="update",
args = [{'visible': visible_array}])
)
fig2.update_layout(
updatemenus=[
dict(
type="dropdown",
direction="down",
buttons=button_all + button_labels,
)
],
xaxis = {
'anchor': 'y',
'automargin': True,
'autorange': True,
'autotypenumbers': 'strict',
'calendar': 'gregorian',
'domain': [0, 1],
'dtick': 'M3',
'tick0': '2000-01-01',
'type': 'date'
},
yaxis = {
'anchor': 'x',
'automargin': True,
'autorange': True,
'autotypenumbers': 'strict',
'categoryorder': 'trace',
'domain': [0, 1],
'dtick': 1,
'side': 'left',
'tick0': 0,
'type': 'category'
}
)
fig2.show()