= R Shiny = '''Shiny''' is a package and web framework for R. <> ---- == Installation == {{{ install.packages('shiny') }}} ---- == Usage == === Project Folders and Templates === A basic Shiny app is structured as: * * `run.R` * * `app.R` `run.R` should contain: {{{ library(shiny) runApp("") }}} This is the file that should be executed to launch the web server. A template for `app.R` is: {{{ library(shiny) library(bslib) # this is a layout for the entire UI # note: `page_sidebar` comes from the `bslib` package ui <- page_sidebar( # this is a title shown above the layout title = "Hello Shiny!", # this is the sidebar element expected by this layout sidebar = sidebar( # this is a widget we are putting into the sidebar element sliderInput( # this is an ID we can reference in code inputId = "bins", # this is a title shown above the widget label = "Number of bins:", min = 1, max = 50, # this is the default value value = 30 ) ), # this is the main element expected by this layout plotOutput( # this is an ID we can reference in code outputId = "distPlot" ) ) # this is the function that serves content server <- function(input, output) { # elements of the output are referenced by the IDs set above like `output$distPlot # values from input widgets are referenced by the IDs set above like `input$bins` # `renderPlot` is a reactive function watching `input$bins` for changes output$distPlot <- renderPlot({ # note: `faithful` is a builtin data frame x <- faithful$waiting bins <- seq(min(x), max(x), length.out = input$bins + 1) hist(x, breaks = bins, col = "#007bc2", border = "white", xlab = "Waiting time to next eruption (in mins)", main = "Histogram of waiting times") }) } # this is the main application loop shinyApp(ui = ui, server = server) }}} ---- === Alternative Layouts === A basic page is created by `fluidPage()`. A basic horizontal row is created by `fluidRow()`. Using `fluidRow`s and `columns`, a simple grid layout can be created. Note that the page is divided into 12 equal units, so at most 12 columns are possible. For example: {{{ ui <- fluidPage( fluidRow( column(width = 4, "row 1 column 1"), column(width = 4, "row 1 column 2"), column(width = 4, "row 1 column 3") ), fluidRow( column(width = 4, "row 2 column 2", offset = 4) ), fluidRow( column(width = 4, "row 3 column 1"), column(width = 4, "row 3 column 3", offset = 4) ) ) }}} Note that any of the literal strings like `"row 1 column 1"` could have been widgets instead. A sidebar layout is best acheived with `sidebarLayout`, `sidebarPanel`, and `mainPanel`. For example: {{{ ui <- fluidPage( TitlePanel("Hello Shiny!"), sidebarLayout( sidebarPanel( sliderInput("obs", "Observations:", min = 0, max = 1000, value = 500) ), mainPanel( plotOutput("distPlot") ) ) ) }}} A tabbed layout with distinct pages is best acheived with `tabsetPanel` and `tabPanel`s. For example: {{{ ui <- fluidPage( tabsetPanel( tabPanel("Step 1", "page 1"), tabPanel("Step 2", "page 2"), tabPanel("Step 3", "page 3") ) ) }}} Note that any of the literal strings like `"page 1"` could have been widgets instead. The first string values in each call are the labels shown on the navigation element. A similar layout is acheived with `navbarPage`; the difference is that members can be both `tabPanel`s and `navbarMenu`s, which contains other `tabPanel`s. For example: {{{ ui <- navbarPage( tabPanel("Step 1", "page 1"), tabPanel("Step 2", "page 2"), navbarMenu("Step 3", tabPanel("Step 3a", "page 3.1"), tabPanel("Step 3b", "page 3.2"), tabPanel("Step 3c", "page 3.3") ) ) }}} `navlistPanel` enables a similar mode of operation, but the navigation element is a vertical table of contents instead of a bar. {{{ ui <- fluidPage( navlistPanel( "Do this first", tabPanel("Step 1", "page 1"), "Do this next", tabPanel("Step 2", "page 2"), tabPanel("Step 3", "page 3") ) ) }}} ---- === Widgets === Shiny includes these '''input widget functions''': ||'''Function''' ||'''Widget''' ||'''Example''' || ||`selectInput` ||Single- and multiple-select ropdown menu ||`selectInput(inputId = "state", label = "State?", choices = c("Alabama"), multiple = TRUE)` || ||`radioButtons` ||Single-select buttons ||`radioButtons(inputId = "state", label = "State?", choices = c("Alabama"))` || ||`checkboxInput` ||One multiple-select button ||`checkboxInput(inputId = "yesno", label = "Yes?", value = TRUE)` || ||`checkboxGroupInput`||Several multiple-select buttons ||`checkboxGroupInput(inputId = "state", label = "State?", choices = c("Alabama"), selected = c("Alaska"))`|| ||`textInput` ||Text box ||`textInput(inputId = "name", label = "Name?")` || ||`textAreaInput` ||Large and resizable text box || || ||`passwordInput` ||Text box with some privacy || || ||`sliderInput` ||Numeric slider (operates as a range slider if e.g. `value = c(1, 2)`) ||`sliderInput(inputId = "age", label = "Age?", value = 18, min = 0, max = 100)` || ||`numericInput` ||Text box accepting only numbers, with incrementing/decrementing buttons||`numericInput(inputId = "age", label = "Age?", value = 18, min = 0, max = 100)` || ||`dateInput` ||Calendar picker ||`dateInput(inputId = "dob", label = "When?")` || ||`dateRangeInput` ||Paired calendar pickers || || These input widgets are meant to be reacted to, by referencing their values from the `server` function like `input$id`. Shiny includes these '''output widget functions''': ||'''Function''' ||'''Widget''' ||'''Renderer Function''' || ||`textOutput` ||Text ||`renderText("Text!")` || ||`verbatimTextOutput`||Text in a notebook cell ||`renderPrint("Text!")` || ||`tableOutput` ||Table ||`renderTable(head(faithful)` || ||`dataTableOutput` ||Table as for a complete data frame ||`renderDataTable(faithful)` || ||`plotOutput` ||Show a base R or [[R/Ggplot2|ggplot]] graphic||`renderPlot(hist(faithful, breaks = 12))`|| These output widgets are meant to be written to like `output$id`. Shiny also includes `actionButton`s. These emit events that should be hooked on using `observeEvent` or `eventReactive`. {{{ ui <- fluidPage( actionButton(inputId = "run", label = "Run!"), actionButton(inputId = "start", label = "Start!"), plotOutput(outputId = "distPlot") ) server <- function(input, output) { output$distPlot <- renderPlot({ # because `input$run` is referenced here, the reactive function will execute anytime that button activates # note that it will also activate on page initialization input$run renderPlot(hist(faithful, breaks = 12)) }) } }}} Other widgets are available from packages like [[R/ShinyWidgets|shinyWidgets]] and [[R/Dt|DT]]. ---- CategoryRicottone