diff --git a/NEWS.md b/NEWS.md index c9e2c2d793..b074017cf5 100644 --- a/NEWS.md +++ b/NEWS.md @@ -6,6 +6,8 @@ * 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) + ## New features and improvements * Added an console that shows some errors in the browser. Also provide better error messages for duplicate input and output bindings. (#3931) diff --git a/R/runapp.R b/R/runapp.R index f6cc86ff00..af3103d053 100644 --- a/R/runapp.R +++ b/R/runapp.R @@ -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') dir <- resolve(examplesDir, example) if (is.null(dir)) { if (is.na(example)) { diff --git a/inst/shiny/01_hello/DESCRIPTION b/inst/shiny/01_hello/DESCRIPTION new file mode 100644 index 0000000000..62734b6047 --- /dev/null +++ b/inst/shiny/01_hello/DESCRIPTION @@ -0,0 +1,6 @@ +Title: Hello Shiny! +Author: RStudio, Inc. +AuthorUrl: http://www.rstudio.com/ +License: MIT +Tags: getting-started +Type: Shiny diff --git a/inst/shiny/01_hello/Readme.md b/inst/shiny/01_hello/Readme.md new file mode 100644 index 0000000000..a2450acc16 --- /dev/null +++ b/inst/shiny/01_hello/Readme.md @@ -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. diff --git a/inst/shiny/01_hello/app.R b/inst/shiny/01_hello/app.R new file mode 100644 index 0000000000..4765171f6e --- /dev/null +++ b/inst/shiny/01_hello/app.R @@ -0,0 +1,53 @@ +library(shiny) +library(bslib) + +# Define UI for app that draws a histogram ---- +ui <- page_sidebar( + + # 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) diff --git a/inst/shiny/02_text/DESCRIPTION b/inst/shiny/02_text/DESCRIPTION new file mode 100644 index 0000000000..519d8790d8 --- /dev/null +++ b/inst/shiny/02_text/DESCRIPTION @@ -0,0 +1,6 @@ +Title: Shiny Text +Author: RStudio, Inc. +AuthorUrl: http://www.rstudio.com/ +License: MIT +Tags: getting-started +Type: Shiny diff --git a/inst/shiny/02_text/Readme.md b/inst/shiny/02_text/Readme.md new file mode 100644 index 0000000000..7aa04e5ed9 --- /dev/null +++ b/inst/shiny/02_text/Readme.md @@ -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. diff --git a/inst/shiny/02_text/app.R b/inst/shiny/02_text/app.R new file mode 100644 index 0000000000..d69b092e2d --- /dev/null +++ b/inst/shiny/02_text/app.R @@ -0,0 +1,61 @@ +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) diff --git a/inst/shiny/03_reactivity/DESCRIPTION b/inst/shiny/03_reactivity/DESCRIPTION new file mode 100644 index 0000000000..623d270ecf --- /dev/null +++ b/inst/shiny/03_reactivity/DESCRIPTION @@ -0,0 +1,6 @@ +Title: Reactivity +Author: RStudio, Inc. +AuthorUrl: http://www.rstudio.com/ +License: MIT +Tags: getting-started +Type: Shiny diff --git a/inst/shiny/03_reactivity/Readme.md b/inst/shiny/03_reactivity/Readme.md new file mode 100644 index 0000000000..8eaee27ef6 --- /dev/null +++ b/inst/shiny/03_reactivity/Readme.md @@ -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. diff --git a/inst/shiny/03_reactivity/app.R b/inst/shiny/03_reactivity/app.R new file mode 100644 index 0000000000..789c0ddba5 --- /dev/null +++ b/inst/shiny/03_reactivity/app.R @@ -0,0 +1,93 @@ +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) diff --git a/inst/shiny/04_mpg/DESCRIPTION b/inst/shiny/04_mpg/DESCRIPTION new file mode 100644 index 0000000000..e8d46b3990 --- /dev/null +++ b/inst/shiny/04_mpg/DESCRIPTION @@ -0,0 +1,6 @@ +Title: Miles Per Gallon +Author: RStudio, Inc. +AuthorUrl: http://www.rstudio.com/ +License: MIT +Tags: getting-started +Type: Shiny diff --git a/inst/shiny/04_mpg/Readme.md b/inst/shiny/04_mpg/Readme.md new file mode 100644 index 0000000000..33c0fe096f --- /dev/null +++ b/inst/shiny/04_mpg/Readme.md @@ -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. diff --git a/inst/shiny/04_mpg/app.R b/inst/shiny/04_mpg/app.R new file mode 100644 index 0000000000..6b86ddacbd --- /dev/null +++ b/inst/shiny/04_mpg/app.R @@ -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 = sidebar( + + # 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) diff --git a/inst/shiny/05_sliders/DESCRIPTION b/inst/shiny/05_sliders/DESCRIPTION new file mode 100644 index 0000000000..ee1ab9cb0c --- /dev/null +++ b/inst/shiny/05_sliders/DESCRIPTION @@ -0,0 +1,6 @@ +Title: Sliders +Author: RStudio, Inc. +AuthorUrl: http://www.rstudio.com/ +License: MIT +Tags: getting-started +Type: Shiny diff --git a/inst/shiny/05_sliders/Readme.md b/inst/shiny/05_sliders/Readme.md new file mode 100644 index 0000000000..1b0cf572d0 --- /dev/null +++ b/inst/shiny/05_sliders/Readme.md @@ -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. diff --git a/inst/shiny/05_sliders/app.R b/inst/shiny/05_sliders/app.R new file mode 100644 index 0000000000..14b5d278ac --- /dev/null +++ b/inst/shiny/05_sliders/app.R @@ -0,0 +1,78 @@ +library(shiny) +library(bslib) + +# Define UI for slider demo app ---- +ui <- page_sidebar( + + # App title ---- + title = "Sliders", + + # Sidebar panel for inputs ---- + sidebar = sidebar( + + # Input: Simple integer interval ---- + sliderInput("integer", "Integer:", + min = 0, max = 1000, + value = 500), + + # Input: Decimal interval with step value ---- + sliderInput("decimal", "Decimal:", + min = 0, max = 1, + value = 0.5, step = 0.1), + + # Input: Specification of range within an interval ---- + sliderInput("range", "Range:", + min = 1, max = 1000, + value = c(200,500)), + + # Input: Custom currency format for with basic animation ---- + sliderInput("format", "Custom Format:", + min = 0, max = 10000, + value = 0, step = 2500, + pre = "$", sep = ",", + animate = TRUE), + + # Input: Animation with custom interval (in ms) ---- + # to control speed, plus looping + sliderInput("animation", "Looping Animation:", + min = 1, max = 2000, + value = 1, step = 10, + animate = + animationOptions(interval = 300, loop = TRUE)) + + ), + + # Output: Table summarizing the values entered ---- + tableOutput("values") +) + +# Define server logic for slider examples ---- +server <- function(input, output) { + + # Reactive expression to create data frame of all input values ---- + sliderValues <- reactive({ + + data.frame( + Name = c("Integer", + "Decimal", + "Range", + "Custom Format", + "Animation"), + Value = as.character(c(input$integer, + input$decimal, + paste(input$range, collapse = " "), + input$format, + input$animation)), + stringsAsFactors = FALSE) + + }) + + # Show the values in an HTML table ---- + output$values <- renderTable({ + sliderValues() + }) + +} + +# Create Shiny app ---- +shinyApp(ui, server) diff --git a/inst/shiny/06_tabsets/DESCRIPTION b/inst/shiny/06_tabsets/DESCRIPTION new file mode 100644 index 0000000000..71bed385be --- /dev/null +++ b/inst/shiny/06_tabsets/DESCRIPTION @@ -0,0 +1,6 @@ +Title: Tabsets +Author: RStudio, Inc. +AuthorUrl: http://www.rstudio.com/ +License: MIT +Tags: getting-started +Type: Shiny diff --git a/inst/shiny/06_tabsets/Readme.md b/inst/shiny/06_tabsets/Readme.md new file mode 100644 index 0000000000..5dac839728 --- /dev/null +++ b/inst/shiny/06_tabsets/Readme.md @@ -0,0 +1,9 @@ +This example demonstrates the `navset_*` and `nav_panel` widgets from the `bslib` package. + +Notice that outputs that are not visible are not re-evaluated until they become visible. Try this: + +1. Scroll to the bottom of the `server` function. You might need to use the *show with app* option so you can easily view the code and interact with the app at the same time. +2. Change the number of observations, and observe that only `output$plot` is evaluated. +3. Click the Summary tab, and observe that `output$summary` is evaluated. +4. Change the number of observations again, and observe that now only `output$summary` is evaluated. + diff --git a/inst/shiny/06_tabsets/app.R b/inst/shiny/06_tabsets/app.R new file mode 100644 index 0000000000..63e8f9f0e3 --- /dev/null +++ b/inst/shiny/06_tabsets/app.R @@ -0,0 +1,89 @@ +library(shiny) +library(bslib) + +# Define UI for random distribution app ---- +# Sidebar layout with input and output definitions ---- +ui <- page_sidebar( + + # App title ---- + title = "Tabsets", + + # Sidebar panel for inputs ---- + sidebar = sidebar( + + # Input: Select the random distribution type ---- + radioButtons("dist", "Distribution type:", + c("Normal" = "norm", + "Uniform" = "unif", + "Log-normal" = "lnorm", + "Exponential" = "exp")), + # br() element to introduce extra vertical spacing ---- + br(), + # Input: Slider for the number of observations to generate ---- + sliderInput("n", + "Number of observations:", + value = 500, + min = 1, + max = 1000) + ), + + # Main panel for displaying outputs ---- + # Output: A tabset that combines three panels ---- + navset_card_underline( + + # Panel with plot ---- + nav_panel("Plot", plotOutput("plot")), + + # Panel with summary ---- + nav_panel("Summary", verbatimTextOutput("summary")), + + # Panel with table ---- + nav_panel("Table", tableOutput("table")) + ) +) + +# Define server logic for random distribution app ---- +server <- function(input, output) { + + # Reactive expression to generate the requested distribution ---- + # This is called whenever the inputs change. The output functions + # defined below then use the value computed from this expression + d <- reactive({ + dist <- switch(input$dist, + norm = rnorm, + unif = runif, + lnorm = rlnorm, + exp = rexp, + rnorm) + + dist(input$n) + }) + + # Generate a plot of the data ---- + # Also uses the inputs to build the plot label. Note that the + # dependencies on the inputs and the data reactive expression are + # both tracked, and all expressions are called in the sequence + # implied by the dependency graph. + output$plot <- renderPlot({ + dist <- input$dist + n <- input$n + + hist(d(), + main = paste("r", dist, "(", n, ")", sep = ""), + col = "#75AADB", border = "white") + }) + + # Generate a summary of the data ---- + output$summary <- renderPrint({ + summary(d()) + }) + + # Generate an HTML table view of the data ---- + output$table <- renderTable({ + d() + }) + +} + +# Create Shiny app ---- +shinyApp(ui, server) diff --git a/inst/shiny/07_widgets/DESCRIPTION b/inst/shiny/07_widgets/DESCRIPTION new file mode 100644 index 0000000000..d66a2255ee --- /dev/null +++ b/inst/shiny/07_widgets/DESCRIPTION @@ -0,0 +1,6 @@ +Title: Widgets +Author: RStudio, Inc. +AuthorUrl: http://www.rstudio.com/ +License: MIT +Tags: getting-started +Type: Shiny diff --git a/inst/shiny/07_widgets/Readme.md b/inst/shiny/07_widgets/Readme.md new file mode 100644 index 0000000000..25a4ad02cd --- /dev/null +++ b/inst/shiny/07_widgets/Readme.md @@ -0,0 +1 @@ +This example demonstrates some additional widgets included in Shiny, such as `helpText` and `actionButton`. The latter is used to delay rendering output until the user explicitly requests it (a construct which also introduces two important server functions, `eventReactive` and `isolate`). diff --git a/inst/shiny/07_widgets/app.R b/inst/shiny/07_widgets/app.R new file mode 100644 index 0000000000..66d337c3be --- /dev/null +++ b/inst/shiny/07_widgets/app.R @@ -0,0 +1,74 @@ +library(shiny) +library(bslib) + +# Define UI for slider demo app ---- +ui <- page_sidebar( + + # App title ---- + title = "More Widgets", + + # Sidebar panel for inputs ---- + sidebar = sidebar( + + # Input: Select a dataset ---- + selectInput("dataset", "Choose a dataset:", + choices = c("rock", "pressure", "cars")), + + # Input: Specify the number of observations to view ---- + numericInput("obs", "Number of observations to view:", 10), + + # Include clarifying text ---- + helpText("Note: while the data view will show only the specified", + "number of observations, the summary will still be based", + "on the full dataset."), + + # Input: actionButton() to defer the rendering of output ---- + # until the user explicitly clicks the button (rather than + # doing it immediately when inputs change). This is useful if + # the computations required to render output are inordinately + # time-consuming. + actionButton("update", "Update View") + + ), + + # Output: Header + summary of distribution ---- + h4("Summary"), + verbatimTextOutput("summary"), + + # Output: Header + table of distribution ---- + h4("Observations"), + tableOutput("view") +) + +# Define server logic to summarize and view selected dataset ---- +server <- function(input, output) { + + # Return the requested dataset ---- + # Note that we use eventReactive() here, which depends on + # input$update (the action button), so that the output is only + # updated when the user clicks the button + datasetInput <- eventReactive(input$update, { + switch(input$dataset, + "rock" = rock, + "pressure" = pressure, + "cars" = cars) + }, ignoreNULL = FALSE) + + # Generate a summary of the dataset ---- + output$summary <- renderPrint({ + dataset <- datasetInput() + summary(dataset) + }) + + # Show the first "n" observations ---- + # The use of isolate() is necessary because we don't want the table + # to update whenever input$obs changes (only when the user clicks + # the action button) + output$view <- renderTable({ + head(datasetInput(), n = isolate(input$obs)) + }) + +} + +# Create Shiny app ---- +shinyApp(ui, server) diff --git a/inst/examples/08_html/DESCRIPTION b/inst/shiny/08_html/DESCRIPTION similarity index 85% rename from inst/examples/08_html/DESCRIPTION rename to inst/shiny/08_html/DESCRIPTION index 76a9c2187c..3cf00e3490 100644 --- a/inst/examples/08_html/DESCRIPTION +++ b/inst/shiny/08_html/DESCRIPTION @@ -2,6 +2,5 @@ Title: Custom HTML UI Author: RStudio, Inc. AuthorUrl: http://www.rstudio.com/ License: MIT -DisplayMode: Showcase Tags: getting-started Type: Shiny diff --git a/inst/examples/08_html/Readme.md b/inst/shiny/08_html/Readme.md similarity index 100% rename from inst/examples/08_html/Readme.md rename to inst/shiny/08_html/Readme.md diff --git a/inst/examples/08_html/app.R b/inst/shiny/08_html/app.R similarity index 100% rename from inst/examples/08_html/app.R rename to inst/shiny/08_html/app.R diff --git a/inst/examples/08_html/www/index.html b/inst/shiny/08_html/www/index.html similarity index 100% rename from inst/examples/08_html/www/index.html rename to inst/shiny/08_html/www/index.html diff --git a/inst/shiny/09_upload/DESCRIPTION b/inst/shiny/09_upload/DESCRIPTION new file mode 100644 index 0000000000..a92e716b27 --- /dev/null +++ b/inst/shiny/09_upload/DESCRIPTION @@ -0,0 +1,6 @@ +Title: File Upload +Author: RStudio, Inc. +AuthorUrl: http://www.rstudio.com/ +License: MIT +Tags: getting-started +Type: Shiny diff --git a/inst/shiny/09_upload/Readme.md b/inst/shiny/09_upload/Readme.md new file mode 100644 index 0000000000..3c45f363d5 --- /dev/null +++ b/inst/shiny/09_upload/Readme.md @@ -0,0 +1,3 @@ +We can add a file upload input in the UI using the function `fileInput()`, +e.g. `fileInput('foo')`. In the `server` function, we can access the +uploaded files via `input$foo`. diff --git a/inst/shiny/09_upload/app.R b/inst/shiny/09_upload/app.R new file mode 100644 index 0000000000..d4cbfad459 --- /dev/null +++ b/inst/shiny/09_upload/app.R @@ -0,0 +1,83 @@ +library(shiny) +library(bslib) + +# Define UI for slider demo app ---- +ui <- page_sidebar( + + # App title ---- + title = "Uploading Files", + + # Sidebar panel for inputs ---- + sidebar = sidebar( + + # Input: Select a file ---- + fileInput("file1", "Choose CSV File", + multiple = TRUE, + accept = c("text/csv", + "text/comma-separated-values,text/plain", + ".csv")), + + # Horizontal line ---- + tags$hr(), + + # Input: Checkbox if file has header ---- + checkboxInput("header", "Header", TRUE), + + # Input: Select separator ---- + radioButtons("sep", "Separator", + choices = c(Comma = ",", + Semicolon = ";", + Tab = "\t"), + selected = ","), + + # Input: Select quotes ---- + radioButtons("quote", "Quote", + choices = c(None = "", + "Double Quote" = '"', + "Single Quote" = "'"), + selected = '"'), + + # Horizontal line ---- + tags$hr(), + + # Input: Select number of rows to display ---- + radioButtons("disp", "Display", + choices = c(Head = "head", + All = "all"), + selected = "head") + + ), + + # Output: Data file ---- + tableOutput("contents") +) + +# Define server logic to read selected file ---- +server <- function(input, output) { + + output$contents <- renderTable({ + + # input$file1 will be NULL initially. After the user selects + # and uploads a file, head of that data file by default, + # or all rows if selected, will be shown. + + req(input$file1) + + df <- read.csv(input$file1$datapath, + header = input$header, + sep = input$sep, + quote = input$quote) + + if(input$disp == "head") { + return(head(df)) + } + else { + return(df) + } + + }) + +} + +# Create Shiny app ---- +shinyApp(ui, server) diff --git a/inst/shiny/10_download/DESCRIPTION b/inst/shiny/10_download/DESCRIPTION new file mode 100644 index 0000000000..30eaae74ce --- /dev/null +++ b/inst/shiny/10_download/DESCRIPTION @@ -0,0 +1,6 @@ +Title: File Download +Author: RStudio, Inc. +AuthorUrl: http://www.rstudio.com/ +License: MIT +Tags: getting-started +Type: Shiny diff --git a/inst/shiny/10_download/Readme.md b/inst/shiny/10_download/Readme.md new file mode 100644 index 0000000000..fceb331ab7 --- /dev/null +++ b/inst/shiny/10_download/Readme.md @@ -0,0 +1,2 @@ +We can add a download button to the UI using `downloadButton()`, and write +the content of the file in `downloadHandler()` in the `server` function. diff --git a/inst/shiny/10_download/app.R b/inst/shiny/10_download/app.R new file mode 100644 index 0000000000..641e16f6a1 --- /dev/null +++ b/inst/shiny/10_download/app.R @@ -0,0 +1,54 @@ +library(shiny) +library(bslib) + +# Define UI for slider demo app ---- +ui <- page_sidebar( + + # App title ---- + title = "Downloading Data", + + # Sidebar panel for inputs ---- + sidebar = sidebar( + + # Input: Choose dataset ---- + selectInput("dataset", "Choose a dataset:", + choices = c("rock", "pressure", "cars")), + + # Button + downloadButton("downloadData", "Download") + + ), + + tableOutput("table") +) + +# Define server logic to display and download selected file ---- +server <- function(input, output) { + + # Reactive value for selected dataset ---- + datasetInput <- reactive({ + switch(input$dataset, + "rock" = rock, + "pressure" = pressure, + "cars" = cars) + }) + + # Table of selected dataset ---- + output$table <- renderTable({ + datasetInput() + }) + + # Downloadable csv of selected dataset ---- + output$downloadData <- downloadHandler( + filename = function() { + paste(input$dataset, ".csv", sep = "") + }, + content = function(file) { + write.csv(datasetInput(), file, row.names = FALSE) + } + ) + +} + +# Create Shiny app ---- +shinyApp(ui, server) diff --git a/inst/shiny/11_timer/DESCRIPTION b/inst/shiny/11_timer/DESCRIPTION new file mode 100644 index 0000000000..4fe2244e91 --- /dev/null +++ b/inst/shiny/11_timer/DESCRIPTION @@ -0,0 +1,6 @@ +Title: Timer +Author: RStudio, Inc. +AuthorUrl: http://www.rstudio.com/ +License: MIT +Tags: getting-started +Type: Shiny diff --git a/inst/shiny/11_timer/Readme.md b/inst/shiny/11_timer/Readme.md new file mode 100644 index 0000000000..b9a617389a --- /dev/null +++ b/inst/shiny/11_timer/Readme.md @@ -0,0 +1,4 @@ +The function `invalidateLater()` can be used to invalidate an observer or +reactive expression in a given number of milliseconds. In this example, the +output `currentTime` is updated every second, so it shows the current time +on a second basis. diff --git a/inst/shiny/11_timer/app.R b/inst/shiny/11_timer/app.R new file mode 100644 index 0000000000..0ec5f98591 --- /dev/null +++ b/inst/shiny/11_timer/app.R @@ -0,0 +1,20 @@ +library(shiny) +library(bslib) + +# Define UI for displaying current time ---- +ui <- page_fluid( + h2(textOutput("currentTime")) +) + +# Define server logic to show current time, update every second ---- +server <- function(input, output, session) { + + output$currentTime <- renderText({ + invalidateLater(1000, session) + paste("The current time is", Sys.time()) + }) + +} + +# Create Shiny app ---- +shinyApp(ui, server)