Basic Reactivity
Reactive programming
examples/basic-reactivity/greeting/app.py
from shiny import App, ui, render
app_ui = ui.page_fluid(
ui.input_text("name", "What's your name?"),
ui.output_text("greeting"),
)
def server(input, output, session):
@render.text
def greeting():
return f"Hello {input.name()}!"
app = App(app_ui, server)Reactive expressions
examples/basic-reactivity/reactive-expressions/app.py
from shiny import App, ui, render, reactive
app_ui = ui.page_fluid(
ui.input_text("name", "What's your name?"),
ui.output_text("greeting"),
)
def server(input, output, session):
@reactive.calc
def string():
return f"Hello {input.name()}!"
@render.text
def greeting():
return string()
app = App(app_ui, server)Execution order
examples/basic-reactivity/execution-order/app.py
from shiny import App, ui, render, reactive
app_ui = ui.page_fluid(
ui.input_text("name", "What's your name?"),
ui.output_text("greeting"),
)
def server(input, output, session):
@render.text
def greeting():
return string()
@reactive.calc
def string():
return f"Hello {input.name()}!"
app = App(app_ui, server)Reactive expressions
examples/basic-reactivity/two-distributions/app.py
from shiny import App, ui, render, reactive
import pandas as pd
from plotnine import ggplot, geom_freqpoly, aes, coord_cartesian
from scipy.stats import ttest_ind
import numpy as np
def freqpoly(x1, x2, binwidth=0.1, xlim=(-3, 3)):
df = pd.DataFrame({
"x": np.concatenate([x1, x2]),
"g": ["x1"] * len(x1) + ["x2"] * len(x2)
})
res = (ggplot(df, aes("x", colour="g"))
+ geom_freqpoly(binwidth=binwidth, size=1)
+ coord_cartesian(xlim=xlim))
return res
def t_test(x1, x2):
test = ttest_ind(x1, x2)
return f"p value: {test.pvalue:.3f}\n[{test.confidence_interval().low:.2f}, {test.confidence_interval().high:.2f}]"
app_ui = ui.page_fluid(
ui.row(
ui.column(4,
"Distribution 1",
ui.input_numeric("n1", label="n", value=1000, min=1),
ui.input_numeric("mean1", label="µ", value=0, step=0.1),
ui.input_numeric("sd1", label="σ", value=0.5, min=0.1, step=0.1),
),
ui.column(4,
"Distribution 2",
ui.input_numeric("n2", label="n", value=1000, min=1),
ui.input_numeric("mean2", label="µ", value=0, step=0.1),
ui.input_numeric("sd2", label="σ", value=0.5, min=0.1, step=0.1),
),
ui.column(4,
"Frequency polygon",
ui.input_numeric("binwidth", label="Bin Width", value=0.1, step=0.1),
ui.input_slider("range", label="range", value=(-3, 3), min=-5, max=5),
),
),
ui.row(
ui.column(9, ui.output_plot("hist")),
ui.column(3, ui.output_text_verbatim("ttest"))
),
)
def server(input, output, session):
@reactive.calc
def x1():
return np.random.normal(input.mean1(), input.sd1(), size=input.n1())
@reactive.calc
def x2():
return np.random.normal(input.mean2(), input.sd2(), size=input.n2())
@render.plot
def hist():
return freqpoly(x1(), x2(), binwidth=input.binwidth(), xlim=input.range())
@render.text
def ttest():
return t_test(x1(), x2())
app = App(app_ui, server)Controlling timing of evaluation
Time invalidation
examples/basic-reactivity/timed-invalidation/app.py
from shiny import App, ui, render, reactive
import pandas as pd
from plotnine import ggplot, geom_freqpoly, aes, coord_cartesian
import numpy as np
def freqpoly(x1, x2, binwidth=0.1, xlim=(-3, 3)):
df = pd.DataFrame({
"x": np.concatenate([x1, x2]),
"g": ["x1"] * len(x1) + ["x2"] * len(x2)
})
res = (ggplot(df, aes("x", colour="g"))
+ geom_freqpoly(binwidth=binwidth, size=1)
+ coord_cartesian(xlim=xlim))
return res
app_ui = ui.page_fluid(
ui.row(
ui.column(3,
ui.input_numeric("lambda1", "lambda1", value=3),
ui.input_numeric("lambda2", "lambda2", value=5),
ui.input_numeric("n", "n", value=int(1e4), min=0),
),
ui.column(9, ui.output_plot("hist"))
)
)
def server(input, output, session):
@reactive.calc()
def timer():
reactive.invalidate_later(0.5)
@reactive.calc
def x1():
timer()
return np.random.poisson(input.lambda1(), size=input.n())
@reactive.calc
def x2():
timer()
return np.random.poisson(input.lambda2(), size=input.n())
@render.plot
def hist():
return freqpoly(x1(), x2(), binwidth=1, xlim=(0, 40))
app = App(app_ui, server)On click
examples/basic-reactivity/on-click/app.py
from shiny import App, ui, render, reactive
import pandas as pd
from plotnine import ggplot, geom_freqpoly, aes, coord_cartesian
import numpy as np
def freqpoly(x1, x2, binwidth=0.1, xlim=(-3, 3)):
df = pd.DataFrame({
"x": np.concatenate([x1, x2]),
"g": ["x1"] * len(x1) + ["x2"] * len(x2)
})
res = (ggplot(df, aes("x", colour="g"))
+ geom_freqpoly(binwidth=binwidth, size=1)
+ coord_cartesian(xlim=xlim))
return res
app_ui = ui.page_fluid(
ui.row(
ui.column(3,
ui.input_numeric("lambda1", "lambda1", value=3),
ui.input_numeric("lambda2", "lambda2", value=5),
ui.input_numeric("n", "n", value=int(1e4), min=0),
ui.input_action_button("simulate", "Simulate!"),
),
ui.column(9, ui.output_plot("hist")),
),
)
def server(input, output, session):
@reactive.calc
@reactive.event(input.simulate, ignore_none=False)
def x1():
return np.random.poisson(input.lambda1(), size=input.n())
@reactive.calc
@reactive.event(input.simulate, ignore_none=False)
def x2():
return np.random.poisson(input.lambda2(), size=input.n())
@render.plot
def hist():
return freqpoly(x1(), x2(), binwidth=1, xlim=(0, 40))
app = App(app_ui, server)
Note
Set ignore_none=False to execute the computation before the very first click on the button.
Observers
examples/basic-reactivity/observers/app.py
from shiny import App, ui, render, reactive
app_ui = ui.page_fluid(
ui.input_text("name", "What's your name?"),
ui.output_text("greeting"),
)
def server(input, output, session):
@reactive.calc
def string():
return f"Hello {input.name()}!"
@render.text
def greeting():
return string()
@reactive.effect
@reactive.event(input.name)
def _():
print("Greeting performed")
app = App(app_ui, server)