Hi Everyone,
I want to create a multi-select checkbox function in my Plotly charts that allows users to toggle the visibility of multiple traces simultaneously. My charts have more than two curves and each of them is composed of numerous traces. Still, now the code I have done so far only allows to show a single curve in the chart or all the curves. Is there any way to achieve such functionality? Any advice will be appreciated. :)))
My code:
import streamlit as st
import pandas as pd # is used to plot specific eis only!
import numpy as np
import itertools
import plotly.graph_objs as go
import plotly as px
import plotly.colors as pc
from plotly.subplots import make_subplots
from t_libraries_modules import start
import time as time
# Plot Settings
bg_color = '#F0F0F0' # it's a hexadecimal color code! (16進位制)
@st.cache_data()
# This function is decorated with '@st.cache_data' to cache the data loading process and avoid reloading data on each interaction.
def load_data(file_folder):
return start(file_folder)
def ncols_plot_calculate(ax):
numitems = len(list(ax.get_legend_handles_labels()[0]))
nrows = 40
ncols = int(np.ceil(numitems / float(nrows)))
return ncols
#%%
@st.cache_data()
def plotly(title, results_to_use, cell_area, new_legend=False, label_files='filenr', time_scale='absolute'):
start_time = time.time()
raw_df = results_to_use['Raw_data']
rawoper_df = raw_df['Oper_conditions']
ivanalysis = results_to_use['Analysed_data']
#%% Function to update visibility
def get_visibility_status(selected_columns):
return [trace.name in selected_columns for trace in fig.data]
#%% Temperature
if title == 'Temperature':
fig = go.Figure()
traces = []
color_map = {}
for file, data in rawoper_df.items():
if 'Temp' in file:
x_data = data['Time']
y_data = data[data.columns.difference(['Date and Time', 'Time'])]
for col in y_data.columns:
# Assign color based on name
if col not in color_map:
color_map[col] = f"rgba({np.random.randint(0, 256)}, {np.random.randint(0, 256)}, {np.random.randint(0, 256)}, 1)"
trace = go.Scattergl(
x=x_data,
y=y_data[col],
#mode='lines+markers',
mode='lines',
name=col,
marker=dict(color=color_map[col]),
showlegend=False # Hide all legends initially
)
traces.append(trace)
fig.add_trace(trace)
# Now handle the legend to avoid duplicate entries
legend_items = set() # A set is used because it automatically handles uniqueness, meaning it will not allow duplicate entries.
color_legend_map = {}
for trace in fig.data: # iterates over each trace (data series) in the 'fig.data'
if trace.marker.color not in color_legend_map:
trace.showlegend = True
color_legend_map[trace.marker.color] = trace.name # 'trace.name' is set to 'col, which represents' name of each column in the dataframe 'y_data'. This name is used in the legend to identify the diff data series in the plot
legend_items.add(trace.name)
else:
trace.showlegend = False
#%% create button
# Generate buttons for each trace (as checkboxes)
buttons = []
# Add a button to show all traces
all_button = dict(
label='Show All',
method='update',
args=[{'visible': [True] * len(fig.data)},
{'title': title}],
execute=True # Use execute instead of showactive
)
buttons.append(all_button)
for col in y_data.columns:
button = dict(
label=col,
#method='update',
method='restyle',
args=[{'visible': get_visibility_status([col])},
{'title': title}],
args2=[{'visible': get_visibility_status([])}, # Reset to hide all when unchecked
{'title': title}],
execute=True # Use execute instead of showactive ( Bad property path: showactive ^^)
)
buttons.append(button)
#%%
# Update layout to include the checkboxes
fig.update_layout(
updatemenus=[
{
'buttons': buttons,
'direction': 'down',
'showactive': True,
'type': 'buttons',
'x': 1.5, # Align horizontally with legend
'y': 0, # Align vertically with legend
'xanchor': 'left',
'yanchor': 'bottom',
'font': {'size': 10}, # Smaller font size for buttons
'pad': {'r': 10, 't': 10}, # Padding around buttons
}
],
title=title,
title_font=dict(size=14, family="Arial", color="black"),
xaxis=dict(title='Time [date h]', title_font=dict(size=14, family="Arial, bold", color="black")),
yaxis=dict(title='Temperature [°C]', title_font=dict(size=14, family="Arial, bold", color="black")),
legend=dict(title=None, font=dict(size=10), x=1.05, y=1),
plot_bgcolor='white',
xaxis_showgrid=True, yaxis_showgrid=True,
xaxis_gridcolor='black', yaxis_gridcolor='black',
)
# Ensure the figure is responsive
fig.update_layout(autosize=True)
# Add responsive config
config = {
'responsive': True
}
fig.update_xaxes(tickangle=30, tickfont=dict(size=10))
st.plotly_chart(fig, theme="streamlit", use_container_width=True, config=config)