Figure rendering twice when ui.input_switch state is changed

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)

Hello,

Your error is a logical one, and since this is a dummy example I'm sure it's more complex in reality :slight_smile:

The island_switch (Filter?) is changing another input plotted_features so this means that instead of filtering your data frame on island_switch it should do it on plotted_features as this endpoint is influenced by both island_switch or additional user selection.

Hope this helps,
PJ

1 Like

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.