Putting it together
The basics of the user interface (UI) inputs and outputs enables you to start building dynamic dashboards and applications. On this page, we’ll walk through 2 examples.
example | covers |
---|---|
CSV parser | Enter text, see the resulting pandas DataFrame |
Plot traits for dog breeds (e.g. drooliness) | Select dog breeds and traits to compare |
Since the examples load the pandas
library, it may take some time to load the apps on this page.
Example 1: parsing and displaying CSV
In this example, we’ll parse CSV data users paste in, and display it as a table.
Note that to do this, we need to use a little bit of code to allow the pandas
to read a string of text:
#| components: [editor, cell]
import pandas as pd
from io import StringIO
csv_text = """
a,b,c
1,2,3
"""
pd.read_csv(StringIO(csv_text))
The key is that .read_csv()
expects a file. StringIO()
takes the text and makes it into something file-like that .read_csv()
understands.
Below, we include this snippet in a Shiny application, to allow users to input text.
#| standalone: true
#| components: [editor, viewer]
#| layout: vertical
#| viewerHeight: 200
## file: app.py
import pandas as pd
from io import StringIO
from shiny import App, render, ui
app_ui = ui.page_fluid(
ui.input_text_area("csv_text", "CSV Text", value="a, b\n1, 2"),
ui.output_table("parsed_data"),
)
def server(input, output, session):
@output
@render.table
def parsed_data():
file_text = StringIO(input.csv_text())
data = pd.read_csv(file_text)
return data
# This is a shiny.App object. It must be named `app`.
app = App(app_ui, server)
Notice that…
- We replaced the variable
csv_text
withinput.csv_text()
, to get the user’s input. - We are using
output_table()
to display a formatted table.
Try the following to see how pandas parses different CSVs:
Extra commas
a,b,,1,2
Raises a parsing error
a, b1, 2
,,,
Example 2: Visualizing dog traits
In this example, we’ll visualize dog traits by breed. For example, the drooling level of German Shepherds.
Viewers will be able to select the following:
- which dog breeds to see traits for.
- which traits to plot ratings for.
Here is a preview of the data:
breed | trait | rating |
---|---|---|
Retrievers (Labrador) | Affectionate With Family |
|
German Shepherd Dogs | Affectionate With Family |
|
Bulldogs | Affectionate With Family |
|
Retrievers (Labrador) | Good With Young Children |
|
German Shepherd Dogs | Good With Young Children |
|
Bulldogs | Good With Young Children |
|
We’ll take inputs for breed and trait, and use them to subset the data.
#| standalone: true
#| components: [editor, viewer]
#| layout: vertical
#| viewerHeight: 600
## file: app.py
from shiny import App, render, ui
import pandas as pd
import seaborn as sns
from pathlib import Path
sns.set_theme()
long_breeds = pd.read_csv(Path(__file__).parent / "dog_traits_long.csv")
options_traits = long_breeds["trait"].unique().tolist()
options_breeds = long_breeds["breed"].unique().tolist()
app_ui = ui.page_fluid(
ui.input_selectize("traits", "Traits", options_traits, multiple=True),
ui.input_selectize("breeds", "Breeds", options_breeds, multiple=True),
ui.output_plot("barchart")
)
def server(input, output, session):
@output
@render.plot
def barchart():
# note that input.traits() refers to the traits selected via the UI
indx_trait = long_breeds["trait"].isin(input.traits())
indx_breed = long_breeds["breed"].isin(input.breeds())
# subset data to keep only selected traits and breeds
sub_df = long_breeds[indx_trait & indx_breed]
sub_df["dummy"] = 1
# plot data. we use the same dummy value for x, and use hue to set
# the bars next to eachother
g = sns.catplot(
data=sub_df, kind="bar",
y="rating", x="dummy", hue="trait",
col="breed", col_wrap=3,
)
# remove labels on x-axis, which is on the legend anyway
g.set_xlabels("")
g.set_xticklabels("")
g.set_titles(col_template="{col_name}")
return g
app = App(app_ui, server)
## file: dog_traits_long.csv
breed,trait,rating
Retrievers (Labrador),Affectionate With Family,5
French Bulldogs,Affectionate With Family,5
German Shepherd Dogs,Affectionate With Family,5
Retrievers (Golden),Affectionate With Family,5
Bulldogs,Affectionate With Family,4
Poodles,Affectionate With Family,5
Beagles,Affectionate With Family,3
Rottweilers,Affectionate With Family,5
Retrievers (Labrador),Good With Young Children,5
French Bulldogs,Good With Young Children,5
German Shepherd Dogs,Good With Young Children,5
Retrievers (Golden),Good With Young Children,5
Bulldogs,Good With Young Children,3
Poodles,Good With Young Children,5
Beagles,Good With Young Children,5
Rottweilers,Good With Young Children,3
Retrievers (Labrador),Good With Other Dogs,5
French Bulldogs,Good With Other Dogs,4
German Shepherd Dogs,Good With Other Dogs,3
Retrievers (Golden),Good With Other Dogs,5
Bulldogs,Good With Other Dogs,3
Poodles,Good With Other Dogs,3
Beagles,Good With Other Dogs,5
Rottweilers,Good With Other Dogs,3
Retrievers (Labrador),Shedding Level,4
French Bulldogs,Shedding Level,3
German Shepherd Dogs,Shedding Level,4
Retrievers (Golden),Shedding Level,4
Bulldogs,Shedding Level,3
Poodles,Shedding Level,1
Beagles,Shedding Level,3
Rottweilers,Shedding Level,3
Retrievers (Labrador),Coat Grooming Frequency,2
French Bulldogs,Coat Grooming Frequency,1
German Shepherd Dogs,Coat Grooming Frequency,2
Retrievers (Golden),Coat Grooming Frequency,2
Bulldogs,Coat Grooming Frequency,3
Poodles,Coat Grooming Frequency,4
Beagles,Coat Grooming Frequency,2
Rottweilers,Coat Grooming Frequency,1
Retrievers (Labrador),Drooling Level,2
French Bulldogs,Drooling Level,3
German Shepherd Dogs,Drooling Level,2
Retrievers (Golden),Drooling Level,2
Bulldogs,Drooling Level,3
Poodles,Drooling Level,1
Beagles,Drooling Level,1
Rottweilers,Drooling Level,3
Retrievers (Labrador),Openness To Strangers,5
French Bulldogs,Openness To Strangers,5
German Shepherd Dogs,Openness To Strangers,3
Retrievers (Golden),Openness To Strangers,5
Bulldogs,Openness To Strangers,4
Poodles,Openness To Strangers,5
Beagles,Openness To Strangers,3
Rottweilers,Openness To Strangers,3
Retrievers (Labrador),Playfulness Level,5
French Bulldogs,Playfulness Level,5
German Shepherd Dogs,Playfulness Level,4
Retrievers (Golden),Playfulness Level,4
Bulldogs,Playfulness Level,4
Poodles,Playfulness Level,5
Beagles,Playfulness Level,4
Rottweilers,Playfulness Level,4
Retrievers (Labrador),Watchdog/Protective Nature,3
French Bulldogs,Watchdog/Protective Nature,3
German Shepherd Dogs,Watchdog/Protective Nature,5
Retrievers (Golden),Watchdog/Protective Nature,3
Bulldogs,Watchdog/Protective Nature,3
Poodles,Watchdog/Protective Nature,5
Beagles,Watchdog/Protective Nature,2
Rottweilers,Watchdog/Protective Nature,5
Retrievers (Labrador),Adaptability Level,5
French Bulldogs,Adaptability Level,5
German Shepherd Dogs,Adaptability Level,5
Retrievers (Golden),Adaptability Level,5
Bulldogs,Adaptability Level,3
Poodles,Adaptability Level,4
Beagles,Adaptability Level,4
Rottweilers,Adaptability Level,4
Retrievers (Labrador),Trainability Level,5
French Bulldogs,Trainability Level,4
German Shepherd Dogs,Trainability Level,5
Retrievers (Golden),Trainability Level,5
Bulldogs,Trainability Level,4
Poodles,Trainability Level,5
Beagles,Trainability Level,3
Rottweilers,Trainability Level,5
Retrievers (Labrador),Energy Level,5
French Bulldogs,Energy Level,3
German Shepherd Dogs,Energy Level,5
Retrievers (Golden),Energy Level,3
Bulldogs,Energy Level,3
Poodles,Energy Level,4
Beagles,Energy Level,4
Rottweilers,Energy Level,3
Retrievers (Labrador),Barking Level,3
French Bulldogs,Barking Level,1
German Shepherd Dogs,Barking Level,3
Retrievers (Golden),Barking Level,1
Bulldogs,Barking Level,2
Poodles,Barking Level,4
Beagles,Barking Level,4
Rottweilers,Barking Level,1
Retrievers (Labrador),Mental Stimulation Needs,4
French Bulldogs,Mental Stimulation Needs,3
German Shepherd Dogs,Mental Stimulation Needs,5
Retrievers (Golden),Mental Stimulation Needs,4
Bulldogs,Mental Stimulation Needs,3
Poodles,Mental Stimulation Needs,5
Beagles,Mental Stimulation Needs,4
Rottweilers,Mental Stimulation Needs,5
Note that:
- We use
input_selectize()
withmultiple=True
to let users select multiple options from a dropdown. - We figure out the options for each input before hand, using the pandas
.unique().tolist()
methods.
Next up
On this page, we’ve looked at two examples of simple applications that react to changes in inputs. This just scratches the surface of what Shiny can do. In the next section, we’ll go through more advanced tools for reactive programming in Shiny.