Resetting input values and subsequent tables/plots to their initial state in Python Shiny

63 Views Asked by At

I want to implement a "reset" function activated by a "reset" button in a Shiny app, that would set all input variables back to their initial status (as they were when launching the app), and update any subsequent functions/plots depending on these inputs.

A reproducible example is the one provided on Shiny for Python website using the function reactive.isolate, showing a histogram which updates upon the user selecting observation values and then clicking on "GO".

import matplotlib.pyplot as plt
import numpy as np

from shiny import App, Inputs, Outputs, Session, reactive, render, ui

app_ui = ui.page_fluid(
    ui.input_slider("n", "Number of observations", min=0, max=1000, value=500),
    ui.input_action_button("go", "Go!", class_="btn-success"),
    ui.output_plot("plot"),
)


def server(input: Inputs, output: Outputs, session: Session):
    @output
    @render.plot(alt="A histogram")
    def plot():
        # Take a reactive dependency on the action button...
        input.go()

        # ...but don't take a reactive dependency on the slider
        with reactive.isolate():
            np.random.seed(19680801)
            x = 100 + 15 * np.random.randn(input.n())

        fig, ax = plt.subplots()
        ax.hist(x, bins=30, density=True)
        return fig


app = App(app_ui, server)

I want to create a "Reset" button which, upon clicking, would return the "Number of Observations" back to 500 and would update the histogram back to its original state when launching the app.

Upon creating the button,

app_ui = ui.page_fluid(
    ui.input_slider("n", "Number of observations", min=0, max=1000, value=500),
    ui.input_action_button("go", "Go!", class_="btn-success"),
    ui.input_action_button("reset", "Reset", class_="btn-success"),
    ui.output_plot("plot"),
)

I tried to use the input.reset() status in a separate function and tag the def plot() with @reactive.Effect (tried as well with @reactive.Calc or @reactive.event(input.reset) but without success. Clicking on the Reset button will set back the field "number of observations" to 500, but the histogram will not update automatically, unless I then click on "Go". IDeally, clicking "Reset" would update both the value and the plot without the extra "Go" click

def server(input: Inputs, output: Outputs, session: Session):
    
    @reactive.Effect
    @output
    @render.plot(alt="A histogram")
    def plot():
        # Take a reactive dependency on the action button...
        input.go()

        # ...but don't take a reactive dependency on the slider
        with reactive.isolate():
            np.random.seed(19680801)
            x = 100 + 15 * np.random.randn(input.n())

        fig, ax = plt.subplots()
        ax.hist(x, bins=30, density=True)
        return fig
    

    @reactive.Effect
    @reactive.event(input.reset )
    def _():
        ui.update_slider( "n" , value = 500 )


app = App(app_ui, server)

Truly grateful for any help !

2

There are 2 best solutions below

0
Eaque Arcana On

I found the answer in the meanwhile so posting here for anyone who may face the same problem.

The key is to create a reactive.value() at the very beginning to save the number of observations (500) and use it then in two separate functions for "go" and "reset" respectively.

import matplotlib.pyplot as plt
import numpy as np

from shiny import App, Inputs, Outputs, Session, reactive, render, ui

app_ui = ui.page_fluid(
    ui.input_slider("n", "Number of observations", min=0, max=1000, value=500),
    ui.input_action_button("go", "Go!", class_="btn-success"),
    ui.input_action_button("reset", "Reset", class_="btn-success"),
    ui.output_plot("plot"),
)

def server(input: Inputs, output: Outputs, session: Session):
    # Create a reactive value to store the number of observations
    num_observations = reactive.Value(500)

    @output
    @render.plot(alt="A histogram")
    def plot():
        # Plot the histogram based on the current value of num_observations
        np.random.seed(19680801)
        x = 100 + 15 * np.random.randn(num_observations())

        fig, ax = plt.subplots()
        ax.hist(x, bins=30, density=True)
        return fig

    @reactive.Effect
    @reactive.event(input.go)
    def on_go_click():
        # Update num_observations when 'Go' is clicked
        num_observations.set(input.n())

    @reactive.Effect
    @reactive.event(input.reset)
    def on_reset_click():
        # Reset num_observations to 500 when 'Reset' is clicked
        num_observations.set(500)
        ui.update_slider("n", value=500)


app = App(app_ui, server)
0
user23442514 On

I also wanted to create a reset/clear button, and so I did so as such:

    @render.ui
    @reactive.event(s_input.clear_button)
    def clear():
        return ui.HTML("""<script>location.reload();</script>""")```