I have an input switch that I want to do two things: (1) I want it to change the choices that are selected in the checkbox_group (update_selected_features
) and (2) I want it to filter a dataset (filt_df
) when it's selected. I have the input switch in these two places and I believe that because is causing my figure (parcat_plot
) to be rendered twice. This is causing performance issues with my application and real data. Below is an example using the palmerpenguins
dataset that demonstrates this.
from shiny import App, reactive, render, ui
import pandas as pd
import numpy as np
from shinywidgets import render_widget, output_widget, render_plotly
import plotly.graph_objects as go
import palmerpenguins
df = palmerpenguins.load_penguins()
df_cols = df.columns.to_list()
df_cols.sort()
df.dropna(inplace=True)
## ------------------------------------
## Setting up the sidebar functions
## ------------------------------------
def center_shelf():
return ui.card(
ui.card_header(
'Species',
align='center'
),
ui.input_select(
"species",
"",
choices = list(pd.Series(df['species'].unique()).sort_values()))
)
def supply_chain_shelf():
return ui.card(
ui.card_header(
"Island",
align="center"
),
ui.input_switch(
"island_switch",
"Filter?",
True)
)
def features_shelf():
return ui.card(
ui.card_header(
'Features to Plot',
align='center'
),
ui.input_switch("show_features",
"Plot other features?"),
ui.panel_conditional("input.show_features",
ui.input_checkbox_group(
"plotted_features",
"",
choices=df_cols,
selected=['sex', 'species', 'body_mass_g'])
)
)
app_ui = ui.page_fluid(
ui.layout_sidebar(
ui.sidebar(
center_shelf(),
supply_chain_shelf(),
features_shelf()
),
ui.card(
output_widget('parcat_plot')
)
),
)
def server (input, output, session):
## update the selected features based on state of supply chain switch
@reactive.effect
def update_selected_features():
if input.island_switch():
ui.update_checkbox_group(
"plotted_features",
selected = ['sex', 'species', 'body_mass_g'])
else:
ui.update_checkbox_group(
"plotted_features",
selected=['sex', 'species', 'year', 'island'])
@reactive.calc
def filt_df():
df_tmp = df.loc[df['species'].eq(input.species())]
if input.island_switch(): ## this is the problem!!!
df_sub = df_tmp.iloc[0:20,]
return df_sub
else:
return df_tmp
@render_plotly
def parcat_plot():
model_df = filt_df()
vars_to_plot = input.plotted_features()
categorical_dimensions = list(vars_to_plot);
dimensions = [dict(values=model_df[label], label=label) for label in categorical_dimensions]
# Build colorscale
color = np.where(model_df['sex'].eq('male'), 1.0, 0.0)
colorscale = [[0.0, '#2166ac'], [1.0, '#b2182b']]
fig = go.FigureWidget(
data=[
go.Parcats(
arrangement='freeform',
domain={'y': [0.25, 1]},
dimensions=dimensions,
line={'colorscale': colorscale,
'color': color,
'shape': 'hspline'})
])
return fig
app = App(app_ui, server)