Basic UI
Inputs
Common structure
All input functions have the same first two argument:
id: the identifier used to connect the frontend with the backend: if your UI has an input withid="name", the server function will access it withinput.name().label: human-readable label for the control to appear on a web browser.
Free Text
examples/basic-ui/inputs/app.py
app_ui = ui.page_fluid(
ui.input_text("name", "What's your name?"),
ui.input_password("password", "What's your password?"),
ui.input_text_area("story", "Tell me about yourself", rows=3),
)Numeric inputs
examples/basic-ui/inputs/app.py
app_ui = ui.page_fluid(
ui.input_numeric("num", "Number one", value=0, min=0, max=100),
ui.input_slider("num2", "Number two", value=50, min=0, max=100),
ui.input_slider("rng", "Range", value=(10, 20), min=0, max=100),
)For range slider, value argument can be a list (i.e. value=[10, 20]) instead of tuple, but in server function, input.rng() will be still return a tuple instead of a list.
Dates
examples/basic-ui/inputs/app.py
app_ui = ui.page_fluid(
ui.input_date("dob", "When were you born?"),
ui.input_date_range("holiday", "When do you want to go on vacation next?"),
)Limited choices
Input controls for limited choices require choices argument to allow the user to choose from.
examples/basic-ui/inputs/app.py
state_names=[
"Alabama", "Alaska", "Arizona", "Arkansas", "California", "Colorado",
"Connecticut", "Delaware", "Florida", "Georgia", "Hawaii", "Idaho",
"Illinois", "Indiana", "Iowa", "Kansas", "Kentucky", "Louisiana",
"Maine", "Maryland", "Massachusetts", "Michigan", "Minnesota",
"Mississippi", "Missouri", "Montana", "Nebraska", "Nevada",
"New Hampshire", "New Jersey", "New Mexico", "New York",
"North Carolina", "North Dakota", "Ohio", "Oklahoma", "Oregon",
"Pennsylvania", "Rhode Island", "South Carolina", "South Dakota",
"Tennessee", "Texas", "Utah", "Vermont", "Virginia", "Washington",
"West Virginia", "Wisconsin", "Wyoming"]
animals = ["dog", "cat", "mouse", "bird", "other", "I hate animals"]examples/basic-ui/inputs/app.py
app_ui = ui.page_fluid(
ui.input_select("state", "What's your favourite states?", choices=state_names,
ui.input_radio_buttons("animal", "What's your favourite animals?", choices=animals),
)choices can be a dictionary instead of a list. In such cases, value is displayed on a screen, but key is retrieved when the input is accessed from a server function.
For example to show icon on screen, let us use faicons package, which provides an interface to Font-Awesome for use in Shiny for Python.
examples/basic-ui/inputs/app.py
from faicons import icon_svg
app_ui = ui.page_fluid(
ui.input_radio_buttons("rb", "Choose one:", choices={
"angry": icon_svg("face-angry"), "happy": icon_svg("face-smile"), "sad": icon_svg("face-sad-tear")}),
)On app, icons appear on each radio button items. However, when you call input.rb() in a server, it returns key values "angry", "happy", or "sad" based on which item was chosen by a user.
ui.input_select() and ui.input_selectize() allow a user to select multiple items when multiple=True.
examples/basic-ui/inputs/app.py
app_ui = ui.page_fluid(
ui.input_selectize("states", "What's your favourite states?", choices=state_names, multiple=True),
)Radio button allows only a single item selection. Mutliple selection can be done through alternative control: ui.input_checkbox_group().
examples/basic-ui/inputs/app.py
app_ui = ui.page_fluid(
ui.input_checkbox_group("animals", "What animals do you like?", choices=animals),
)Single checkbox ui.input_checkbox() is for Yes/No questions.
examples/basic-ui/inputs/app.py
app_ui = ui.page_fluid(
ui.input_checkbox("cleanup", "Clean up?", value=True),
ui.input_checkbox("shutdown", "Shutdown?"),
)File uploads
examples/basic-ui/inputs/app.py
app_ui = ui.page_fluid(
ui.input_file("upload", None),
)Exercises
- Label text boxes using a placeholder that appears inside the text entry area.
solutions/basic-ui/inputs/placeholder/app.py
from shiny import App, ui
app_ui = ui.page_fluid(
ui.input_text("name", None, placeholder="Your name"),
)
def server(input, output, session):
...
app = App(app_ui, server)- Create a date slider.
solutions/basic-ui/inputs/dateslider/app.py
from shiny import App, ui
import datetime
app_ui = ui.page_fluid(
ui.input_slider("date", "When should we deliver?",
min=datetime.date(2020, 9, 16),
max=datetime.date(2020, 9, 23),
value=datetime.date(2020, 9, 17)),
)
def server(input, output, session):
...
app = App(app_ui, server)- Create a slider input to select values between 0 and 100 where the interval between each selectable value on the slider is 5. Then, add animation to the input widget so when the user presses play the input widget scrolls through the range automatically.
solutions/basic-ui/inputs/animateslider/app.py
from shiny import App, ui
app_ui = ui.page_fluid(
ui.input_slider("ani", None, min=0, max=100, value=0,
step=5, animate=True, ticks=True),
)
def server(input, output, session):
...
app = App(app_ui, server)ticks=True is not an essential argument for this exercise, but it guides a user to click a right position when selecting a number.
- Create sub-headings that break the list up into pieces.
solutions/basic-ui/inputs/subheading/app.py
from shiny import App, ui
grouped = {
"Group A": {"A1":"Item A1", "A2":"Item A2"},
"Group B": {"B1":"Item B1", "B2":"Item B2", "B3":"Item B3"},
"Group C": {"C1":"Item C1", "C2":"Item C2"}
}
app_ui = ui.page_fluid(
ui.input_select("long", "Choose:", choices=grouped),
)
def server(input, output, session):
...
app = App(app_ui, server)A dictionary of dictionaries used as choices argument. It would mean that server will use keys (e.g. "A1") as input values instead of appeared string (e.g. "Item A1"), so keys would need to be unique not only within a subgroup but also across subgroups.
Outputs
Text
examples/basic-ui/outputs/text/app.py
from shiny import App, ui, render
import pandas as pd
app_ui = ui.page_fluid(
ui.output_text("text"),
ui.output_text_verbatim("code"),
)
def server(input, output, session):
@output
@render.text
def text():
return "Hello friend!"
@output
@render.text
def code():
x = pd.Series(range(1, 11))
return x.describe()
app = App(app_ui, server)In R, text output uses render function renderText() and verbatim output uses render function renderPrint(). In Python, both text and verbatim outputs use the same render function render.text().
Tables
examples/basic-ui/outputs/tables/app.py
from shiny import App, ui, render
from pydataset import data
mtcars = data("mtcars")
app_ui = ui.page_fluid(
ui.output_table("static"),
ui.output_data_frame("dynamic"),
)
def server(input, output, session):
@output
@render.table
def static():
return mtcars
@output
@render.data_frame
def dynamic():
return render.DataTable(mtcars, filters=True)
app = App(app_ui, server)While you can return just mtcars in dynamic() for default interactive table, to enable filters, either render.DataGrid() or render.DataTable() needs to be returned with filter=True.
The dynamic table is somewhat different from R version. There may be more ways to render tables by using widgets.
Plots
examples/basic-ui/outputs/plots/app.py
from shiny import App, ui, render
from matplotlib import pyplot as plt
app_ui = ui.page_fluid(
ui.output_plot("plot", width="400px")
)
def server(input, output, session):
@output
@render.plot
def plot():
return plt.scatter([1, 2, 3, 4, 5], [1, 2, 3, 4, 5])
app = App(app_ui, server)Exercises
- Text outputs and verbatim outputs
from shiny import App, ui, render
from pydataset import data
from scipy.stats import ttest_ind
import statsmodels.formula.api as smf
mtcars = data("mtcars")
app_ui = ui.page_fluid(
ui.output_text_verbatim("summary"),
ui.output_text("greeting"),
ui.output_text_verbatim("ttest"),
ui.output_text_verbatim("regression"),
)
def server(input, output, session):
@output
@render.text
def summary():
return mtcars.describe()
@output
@render.text
def greeting():
return "Good morning!"
@output
@render.text
def ttest():
return ttest_ind([1, 2, 3, 4, 5], [2, 3, 4, 5, 6])
@output
@render.text
def regression():
reg = smf.ols("mpg ~ wt", data=mtcars).fit()
return reg.summary()
app = App(app_ui, server)Shiny for Python use render.text() for both text output and verbatim output.
mtcars.describe() returns pandas data frame. When render.text() is used, the output will look like a result of print(mtcars.describe()).
- Plot by seeting height to 300px, witdh to 700px, and “alt” text so that a visually impaired user can tell that its a scatterplot of five random numbers.
solutions/basic-ui/outputs/plots/app.py
from shiny import App, ui, render
from matplotlib import pyplot as plt
import numpy as np
app_ui = ui.page_fluid(
ui.output_plot("plot", width="700px", height="300px")
)
def server(input, output, session):
@output
@render.plot(alt="A scatterplot of five random numbers")
def plot():
return plt.scatter(np.random.uniform(size=5), np.random.uniform(size=5))
app = App(app_ui, server)- Dynamic data table without search, search, ordering, and filtering commands.
solutions/basic-ui/outputs/tables/app.py
from shiny import App, ui, render
from pydataset import data
mtcars = data("mtcars")
app_ui = ui.page_fluid(
ui.output_data_frame("dynamic"),
)
def server(input, output, session):
@output
@render.data_frame
def dynamic():
return render.DataTable(mtcars, filters=False, height='240px')
app = App(app_ui, server)The rendered table still provides ordering commands. I do not know how to disable the ordering command with built-in render functions in shiny python package.
- Use React Table.
I could not find a way to render React Table or any other interactive tables that are not included in shiny package.
I attemped to use ipywidgets via shinywidgets, but my attempt was not quite successful and satisfiable.
It looks there have been related discussions on github.
I hope to come back this exercise once I find a solution.