From 4abf8f7c6feffbfec4ea6565a8e313856c2c166f Mon Sep 17 00:00:00 2001 From: Gordon Shotwell Date: Fri, 26 Jan 2024 13:19:54 -0400 Subject: [PATCH] Expressify reactive examples (#1078) Co-authored-by: Garrick Aden-Buie --- shiny/api-examples/Progress/app-express.py | 21 ++++++++++++ shiny/api-examples/Value/app-core.py | 14 ++++---- shiny/api-examples/Value/app-express.py | 28 ++++++++++++++++ shiny/api-examples/calc/app-core.py | 18 ++++++----- shiny/api-examples/calc/app-express.py | 32 +++++++++++++++++++ shiny/api-examples/effect/app-express.py | 15 +++++++++ .../api-examples/invalidate_later/app-core.py | 9 ++---- .../invalidate_later/app-express.py | 10 ++++++ shiny/api-examples/isolate/app-express.py | 23 +++++++++++++ shiny/api-examples/poll/app-core.py | 24 +++++++------- 10 files changed, 159 insertions(+), 35 deletions(-) create mode 100644 shiny/api-examples/Progress/app-express.py create mode 100644 shiny/api-examples/Value/app-express.py create mode 100644 shiny/api-examples/calc/app-express.py create mode 100644 shiny/api-examples/effect/app-express.py create mode 100644 shiny/api-examples/invalidate_later/app-express.py create mode 100644 shiny/api-examples/isolate/app-express.py diff --git a/shiny/api-examples/Progress/app-express.py b/shiny/api-examples/Progress/app-express.py new file mode 100644 index 000000000..b4bde03f6 --- /dev/null +++ b/shiny/api-examples/Progress/app-express.py @@ -0,0 +1,21 @@ +import asyncio + +from shiny import reactive +from shiny.express import input, render, ui + +ui.input_action_button("button", "Compute") + + +@render.text +@reactive.event(input.button) +async def compute(): + with ui.Progress(min=1, max=15) as p: + p.set(message="Calculation in progress", detail="This may take a while...") + + for i in range(1, 15): + p.set(i, message="Computing") + await asyncio.sleep(0.1) + # Normally use time.sleep() instead, but it doesn't yet work in Pyodide. + # https://github.com/pyodide/pyodide/issues/2354 + + return "Done computing!" diff --git a/shiny/api-examples/Value/app-core.py b/shiny/api-examples/Value/app-core.py index fe0112954..04479492a 100644 --- a/shiny/api-examples/Value/app-core.py +++ b/shiny/api-examples/Value/app-core.py @@ -1,10 +1,10 @@ from shiny import App, Inputs, Outputs, Session, reactive, render, ui -app_ui = ui.page_fluid( - ui.input_action_button("minus", "-1"), - " ", - ui.input_action_button("plus", "+1"), - ui.br(), +app_ui = ui.page_sidebar( + ui.sidebar( + ui.input_action_button("minus", "-1"), + ui.input_action_button("plus", "+1"), + ), ui.output_text("value"), ) @@ -12,13 +12,13 @@ def server(input: Inputs, output: Outputs, session: Session): val = reactive.Value(0) - @reactive.Effect + @reactive.effect @reactive.event(input.minus) def _(): newVal = val.get() - 1 val.set(newVal) - @reactive.Effect + @reactive.effect @reactive.event(input.plus) def _(): newVal = val.get() + 1 diff --git a/shiny/api-examples/Value/app-express.py b/shiny/api-examples/Value/app-express.py new file mode 100644 index 000000000..80a55e165 --- /dev/null +++ b/shiny/api-examples/Value/app-express.py @@ -0,0 +1,28 @@ +from shiny import reactive +from shiny.express import input, render, ui + +val = reactive.Value(0) + + +@reactive.effect +@reactive.event(input.minus) +def _(): + newVal = val.get() - 1 + val.set(newVal) + + +@reactive.effect +@reactive.event(input.plus) +def _(): + newVal = val.get() + 1 + val.set(newVal) + + +with ui.sidebar(): + ui.input_action_button("minus", "-1") + ui.input_action_button("plus", "+1") + + +@render.text +def value(): + return str(val.get()) diff --git a/shiny/api-examples/calc/app-core.py b/shiny/api-examples/calc/app-core.py index 603313593..fe2620253 100644 --- a/shiny/api-examples/calc/app-core.py +++ b/shiny/api-examples/calc/app-core.py @@ -4,16 +4,18 @@ from shiny import App, Inputs, Outputs, Session, reactive, render, ui app_ui = ui.page_fluid( - ui.input_action_button("first", "Invalidate first (slow) computation"), - " ", - ui.input_action_button("second", "Invalidate second (fast) computation"), - ui.br(), - ui.output_ui("result"), + ui.card( + ui.layout_columns( + ui.input_action_button("first", "Invalidate first (slow) computation"), + ui.input_action_button("second", "Invalidate second (fast) computation"), + ), + ui.output_text_verbatim("result"), + ) ) def server(input: Inputs, output: Outputs, session: Session): - @reactive.Calc + @reactive.calc def first(): input.first() p = ui.Progress() @@ -23,12 +25,12 @@ def first(): p.close() return random.randint(1, 1000) - @reactive.Calc + @reactive.calc def second(): input.second() return random.randint(1, 1000) - @render.ui + @render.text def result(): return first() + second() diff --git a/shiny/api-examples/calc/app-express.py b/shiny/api-examples/calc/app-express.py new file mode 100644 index 000000000..2361cea80 --- /dev/null +++ b/shiny/api-examples/calc/app-express.py @@ -0,0 +1,32 @@ +import random +import time + +from shiny import reactive +from shiny.express import input, render, ui + + +@reactive.calc +def first(): + input.first() + p = ui.Progress() + for i in range(30): + p.set(i / 30, message="Computing, please wait...") + time.sleep(0.1) + p.close() + return random.randint(1, 1000) + + +@reactive.calc +def second(): + input.second() + return random.randint(1, 1000) + + +with ui.card(): + with ui.layout_columns(): + ui.input_action_button("first", "Invalidate first (slow) computation") + ui.input_action_button("second", "Invalidate second (fast) computation") + + @render.text + def result(): + return first() + second() diff --git a/shiny/api-examples/effect/app-express.py b/shiny/api-examples/effect/app-express.py new file mode 100644 index 000000000..363ed50cd --- /dev/null +++ b/shiny/api-examples/effect/app-express.py @@ -0,0 +1,15 @@ +from shiny import reactive +from shiny.express import input, ui + +ui.input_action_button("show", "Show modal dialog") + + +@reactive.effect +@reactive.event(input.show) +def show_important_message(): + m = ui.modal( + "This is a somewhat important message.", + easy_close=True, + footer=None, + ) + ui.modal_show(m) diff --git a/shiny/api-examples/invalidate_later/app-core.py b/shiny/api-examples/invalidate_later/app-core.py index 7966d01f0..66de8233d 100644 --- a/shiny/api-examples/invalidate_later/app-core.py +++ b/shiny/api-examples/invalidate_later/app-core.py @@ -2,16 +2,11 @@ from shiny import App, Inputs, Outputs, Session, reactive, render, ui -app_ui = ui.page_fluid(ui.output_ui("value")) +app_ui = ui.page_fluid(ui.output_text("value")) def server(input: Inputs, output: Outputs, session: Session): - @reactive.Effect - def _(): - reactive.invalidate_later(0.5) - print("Random int: ", random.randint(0, 10000)) - - @render.ui + @render.text def value(): reactive.invalidate_later(0.5) return "Random int: " + str(random.randint(0, 10000)) diff --git a/shiny/api-examples/invalidate_later/app-express.py b/shiny/api-examples/invalidate_later/app-express.py new file mode 100644 index 000000000..270c5e889 --- /dev/null +++ b/shiny/api-examples/invalidate_later/app-express.py @@ -0,0 +1,10 @@ +import random + +from shiny import reactive +from shiny.express import render + + +@render.text +def value(): + reactive.invalidate_later(0.5) + return "Random int: " + str(random.randint(0, 10000)) diff --git a/shiny/api-examples/isolate/app-express.py b/shiny/api-examples/isolate/app-express.py new file mode 100644 index 000000000..52f8b9c38 --- /dev/null +++ b/shiny/api-examples/isolate/app-express.py @@ -0,0 +1,23 @@ +import matplotlib.pyplot as plt +import numpy as np + +from shiny import reactive +from shiny.express import input, render, ui + +ui.input_slider("n", "Number of observations", min=0, max=1000, value=500) +ui.input_action_button("go", "Go!", class_="btn-success") + + +@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 diff --git a/shiny/api-examples/poll/app-core.py b/shiny/api-examples/poll/app-core.py index c9411d28a..f6ab621b6 100644 --- a/shiny/api-examples/poll/app-core.py +++ b/shiny/api-examples/poll/app-core.py @@ -89,9 +89,8 @@ def stock_quotes() -> pd.DataFrame: # === Define the Shiny UI and server =============================== app_ui = ui.page_fluid( - ui.row( - ui.column( - 8, + ui.layout_columns( + ui.card( ui.markdown( """ # `shiny.reactive.poll` demo @@ -100,11 +99,14 @@ def stock_quotes() -> pd.DataFrame: case, an in-memory sqlite3) with the help of `shiny.reactive.poll`. """ ), - class_="mb-3", + ui.input_selectize( + "symbols", "Filter by symbol", [""] + SYMBOLS, multiple=True + ), + ui.output_data_frame("table"), + fill=False, ), - ), - ui.input_selectize("symbols", "Filter by symbol", [""] + SYMBOLS, multiple=True), - ui.output_ui("table"), + col_widths=[8, 4], + ) ) @@ -115,13 +117,9 @@ def filtered_quotes(): df = df[df["symbol"].isin(input.symbols())] return df - @render.ui + @render.data_frame def table(): - return ui.HTML( - filtered_quotes().to_html( - index=False, classes="table font-monospace w-auto" - ) - ) + return filtered_quotes() app = App(app_ui, server)