Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update examples to use bslib #3963

Merged
merged 20 commits into from
Mar 20, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## Breaking changes

* Both `conditionalPanel()` and `uiOutput()` are now styled with `display: contents` by default in Shiny apps that use Bootstrap 5. This means that the elements they contain are positioned as if they were direct children of the parent container holding the `conditionalPanel()` or `uiOutput()`. This is probably what most users intend when they use these functions, but it may break apps that applied styles directly to the container elements created by these two functions. In that case, you may include CSS rules to set `display: block` for the `.shiny-panel-conditional` or `.shiny-html-output` classes. (#3957, #3960)
* The examples behind `runExample()` now use `{bslib}` to generate a better looking result. To instead run the "legacy" examples, set `options(shiny.legacy.examples = TRUE)` before calling `runExample()`. (#3963)
cpsievert marked this conversation as resolved.
Show resolved Hide resolved

## New features and improvements

Expand Down
4 changes: 3 additions & 1 deletion R/runapp.R
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,9 @@ runExample <- function(example=NA,
launch.browser = getOption('shiny.launch.browser', interactive()),
host=getOption('shiny.host', '127.0.0.1'),
display.mode=c("auto", "normal", "showcase")) {
examplesDir <- system_file('examples', package='shiny')
legacy <- getOption('shiny.legacy.examples', FALSE)
examplesDir <- if (isTRUE(legacy)) 'examples' else 'shiny'
examplesDir <- system_file(examplesDir, package='shiny')
Comment on lines +470 to +472
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@karangattu started working on extending runExample() to other packages in #3917.

That said, while we're here, I think we should do a very light-weight version of that work and add package = "shiny" to runExample()'s parameters.

I'll take that in a follow-up PR.

dir <- resolve(examplesDir, example)
if (is.null(dir)) {
if (is.na(example)) {
Expand Down
7 changes: 7 additions & 0 deletions inst/shiny/01_hello/DESCRIPTION
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Title: Hello Shiny!
Author: RStudio, Inc.
AuthorUrl: http://www.rstudio.com/
License: MIT
DisplayMode: Showcase
Tags: getting-started
Type: Shiny
3 changes: 3 additions & 0 deletions inst/shiny/01_hello/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
This small Shiny application demonstrates Shiny's automatic UI updates.

Move the *Number of bins* slider and notice how the `renderPlot` expression is automatically re-evaluated when its dependant, `input$bins`, changes, causing a histogram with a new number of bins to be rendered.
48 changes: 48 additions & 0 deletions inst/shiny/01_hello/app.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
library(shiny)
library(bslib)

# Define UI for app that draws a histogram ----
ui <- page_sidebar(

cpsievert marked this conversation as resolved.
Show resolved Hide resolved
# App title ----
title = "Hello Shiny!",
# Sidebar panel for inputs ----
sidebar =
sidebar(
# Input: Slider for the number of bins ----
sliderInput(inputId = "bins",
label = "Number of bins:",
min = 1,
max = 50,
value = 30)
),
# Output: Histogram ----
plotOutput(outputId = "distPlot")
)

# Define server logic required to draw a histogram ----
server <- function(input, output) {

# Histogram of the Old Faithful Geyser Data ----
# with requested number of bins
# This expression that generates a histogram is wrapped in a call
# to renderPlot to indicate that:
#
# 1. It is "reactive" and therefore should be automatically
# re-executed when inputs (input$bins) change
# 2. Its output type is a plot
output$distPlot <- renderPlot({

x <- faithful$waiting
bins <- seq(min(x), max(x), length.out = input$bins + 1)

hist(x, breaks = bins, col = "#75AADB", border = "white",
xlab = "Waiting time to next eruption (in mins)",
main = "Histogram of waiting times")

})

}

# Create Shiny app ----
shinyApp(ui = ui, server = server)
8 changes: 8 additions & 0 deletions inst/shiny/02_text/DESCRIPTION
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Title: Shiny Text
Author: RStudio, Inc.
AuthorUrl: http://www.rstudio.com/
License: MIT
DisplayMode: Showcase
Tags: getting-started
Type: Shiny

1 change: 1 addition & 0 deletions inst/shiny/02_text/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This example demonstrates output of raw text from R using the `renderPrint` function in `server` and the `verbatimTextOutput` function in `ui`. In this case, a textual summary of the data is shown using R's built-in `summary` function.
55 changes: 55 additions & 0 deletions inst/shiny/02_text/app.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
library(shiny)
library(bslib)

# Define UI for dataset viewer app ----
ui <- page_sidebar(

# App title ----
title = "Shiny Text",

# Sidebar panel for inputs ----
sidebar =
sidebar(
# Input: Selector for choosing dataset ----
selectInput(inputId = "dataset",
label = "Choose a dataset:",
choices = c("rock", "pressure", "cars")),

# Input: Numeric entry for number of obs to view ----
numericInput(inputId = "obs",
label = "Number of observations to view:",
value = 10)
),
# Output: Verbatim text for data summary ----
verbatimTextOutput("summary"),

# Output: HTML table with requested number of observations ----
tableOutput("view")
)

# Define server logic to summarize and view selected dataset ----
server <- function(input, output) {

# Return the requested dataset ----
datasetInput <- reactive({
switch(input$dataset,
"rock" = rock,
"pressure" = pressure,
"cars" = cars)
})

# Generate a summary of the dataset ----
output$summary <- renderPrint({
dataset <- datasetInput()
summary(dataset)
})

# Show the first "n" observations ----
output$view <- renderTable({
head(datasetInput(), n = input$obs)
})

}

# Create Shiny app ----
shinyApp(ui = ui, server = server)
7 changes: 7 additions & 0 deletions inst/shiny/03_reactivity/DESCRIPTION
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Title: Reactivity
Author: RStudio, Inc.
AuthorUrl: http://www.rstudio.com/
License: MIT
DisplayMode: Showcase
Tags: getting-started
Type: Shiny
5 changes: 5 additions & 0 deletions inst/shiny/03_reactivity/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
This example demonstrates a core feature of Shiny: **reactivity**. In the `server` function, a reactive called `datasetInput` is declared.

Notice that the reactive expression depends on the input expression `input$dataset`, and that it's used by two output expressions: `output$summary` and `output$view`. Try changing the dataset (using *Choose a dataset*) while looking at the reactive and then at the outputs; you will see first the reactive and then its dependencies flash.

Notice also that the reactive expression doesn't just update whenever anything changes--only the inputs it depends on will trigger an update. Change the "Caption" field and notice how only the `output$caption` expression is re-evaluated; the reactive and its dependents are left alone.
94 changes: 94 additions & 0 deletions inst/shiny/03_reactivity/app.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
library(shiny)
library(bslib)

# Define UI for dataset viewer app ----
ui <- page_sidebar(

# App title ----
title = "Reactivity",
# Sidebar panel for inputs ----
sidebar =
sidebar(

# Input: Text for providing a caption ----
# Note: Changes made to the caption in the textInput control
# are updated in the output area immediately as you type
textInput(inputId = "caption",
label = "Caption:",
value = "Data Summary"),

# Input: Selector for choosing dataset ----
selectInput(inputId = "dataset",
label = "Choose a dataset:",
choices = c("rock", "pressure", "cars")),

# Input: Numeric entry for number of obs to view ----
numericInput(inputId = "obs",
label = "Number of observations to view:",
value = 10)

),

# Output: Formatted text for caption ----
h3(textOutput("caption", container = span)),

# Output: Verbatim text for data summary ----
verbatimTextOutput("summary"),

# Output: HTML table with requested number of observations ----
tableOutput("view")
)

# Define server logic to summarize and view selected dataset ----
server <- function(input, output) {

# Return the requested dataset ----
# By declaring datasetInput as a reactive expression we ensure
# that:
#
# 1. It is only called when the inputs it depends on changes
# 2. The computation and result are shared by all the callers,
# i.e. it only executes a single time
datasetInput <- reactive({
switch(input$dataset,
"rock" = rock,
"pressure" = pressure,
"cars" = cars)
})

# Create caption ----
# The output$caption is computed based on a reactive expression
# that returns input$caption. When the user changes the
# "caption" field:
#
# 1. This function is automatically called to recompute the output
# 2. New caption is pushed back to the browser for re-display
#
# Note that because the data-oriented reactive expressions
# below don't depend on input$caption, those expressions are
# NOT called when input$caption changes
output$caption <- renderText({
input$caption
})

# Generate a summary of the dataset ----
# The output$summary depends on the datasetInput reactive
# expression, so will be re-executed whenever datasetInput is
# invalidated, i.e. whenever the input$dataset changes
output$summary <- renderPrint({
dataset <- datasetInput()
summary(dataset)
})

# Show the first "n" observations ----
# The output$view depends on both the databaseInput reactive
# expression and input$obs, so it will be re-executed whenever
# input$dataset or input$obs is changed
output$view <- renderTable({
head(datasetInput(), n = input$obs)
})

}

# Create Shiny app ----
shinyApp(ui, server)
7 changes: 7 additions & 0 deletions inst/shiny/04_mpg/DESCRIPTION
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Title: Miles Per Gallon
Author: RStudio, Inc.
AuthorUrl: http://www.rstudio.com/
License: MIT
DisplayMode: Showcase
Tags: getting-started
Type: Shiny
4 changes: 4 additions & 0 deletions inst/shiny/04_mpg/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
This example demonstrates the following concepts:

- **Global variables**: The `mpgData` variable is declared outside of the `ui` and `server` function definitions. This makes it available anywhere inside `app.R`. The code in `app.R` outside of `ui` and `server` function definitions is only run once when the app starts up, so it can't contain user input.
- **Reactive expressions**: `formulaText` is a reactive expression. Note how it re-evaluates when the Variable field is changed, but not when the Show Outliers box is unchecked.
67 changes: 67 additions & 0 deletions inst/shiny/04_mpg/app.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
library(shiny)
library(bslib)
library(datasets)

# Data pre-processing ----
# Tweak the "am" variable to have nicer factor labels -- since this
# doesn't rely on any user inputs, we can do this once at startup
# and then use the value throughout the lifetime of the app
mpgData <- mtcars
mpgData$am <- factor(mpgData$am, labels = c("Automatic", "Manual"))


# Define UI for miles per gallon app ----
ui <- page_sidebar(

# App title ----
title = "Miles Per Gallon",
# Sidebar panel for inputs ----
sidebar =
sidebarPanel(
cpsievert marked this conversation as resolved.
Show resolved Hide resolved

# Input: Selector for variable to plot against mpg ----
selectInput("variable", "Variable:",
c("Cylinders" = "cyl",
"Transmission" = "am",
"Gears" = "gear")),

# Input: Checkbox for whether outliers should be included ----
checkboxInput("outliers", "Show outliers", TRUE)

),

# Output: Formatted text for caption ----
h3(textOutput("caption")),

# Output: Plot of the requested variable against mpg ----
plotOutput("mpgPlot")
)

# Define server logic to plot various variables against mpg ----
server <- function(input, output) {

# Compute the formula text ----
# This is in a reactive expression since it is shared by the
# output$caption and output$mpgPlot functions
formulaText <- reactive({
paste("mpg ~", input$variable)
})

# Return the formula text for printing as a caption ----
output$caption <- renderText({
formulaText()
})

# Generate a plot of the requested variable against mpg ----
# and only exclude outliers if requested
output$mpgPlot <- renderPlot({
boxplot(as.formula(formulaText()),
data = mpgData,
outline = input$outliers,
col = "#75AADB", pch = 19)
})

}

# Create Shiny app ----
shinyApp(ui, server)
7 changes: 7 additions & 0 deletions inst/shiny/05_sliders/DESCRIPTION
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Title: Sliders
Author: RStudio, Inc.
AuthorUrl: http://www.rstudio.com/
License: MIT
DisplayMode: Showcase
Tags: getting-started
Type: Shiny
3 changes: 3 additions & 0 deletions inst/shiny/05_sliders/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
This example demonstrates Shiny's versatile `sliderInput` widget.

Slider inputs can be used to select single values, to select a continuous range of values, and even to animate over a range.
Loading
Loading