Every Shiny app is maintained by a computer running R.
User interface (UI), server instructions are two required components.
The minimal code for a Shiny app.
library(shiny)
ui <- fluidPage("My Shiny App")
server <- function(input, output) {}
shinyApp(ui = ui, server = server)
Three types of functions: input, output and server.
library(shiny)
ui <- fluidPage("My Shiny App"
# *Input() functions
# *Output() functions
)
server <- function(input, output) {
# server functions
}
shinyApp(ui = ui, server = server)
Add elements to your app as arguments to fluidPage().
library(shiny)
ui <- fluidPage("My Shiny App"
# *Input() functions
sliderInput(inputId = "num",
label = "Choose a number",
value = 25, min = 1, max = 100)
# *Output() functions
)
server <- function(input, output) {}
shinyApp(ui = ui, server = server)
To display reactive results, add to fluidPage() with an *Output() function.
library(shiny)
ui <- fluidPage("My Shiny App"
# *Input() functions
sliderInput(inputId = "num",
label = "Choose a number",
value = 25, min = 1, max = 100) # Add commas
# between
# arguments
# *Output() functions
plotOutput("hist") # Adds a space
# in ui for R object.
# Build object
# in server func.
)
server <- function(input, output) {}
shinyApp(ui = ui, server = server)
Rules to writing server functions:
- Save objects to display to output$
- output$foo is referenced in plotOutput("foo")
- Build objects to display with render*()
- Access input values with input$
library(shiny)
ui <- fluidPage(
titlePanel("My Shiny App"),
sidebarLayout( # Add side panel for inputs
sidebarPanel(
# *Input() functions
sliderInput(inputId = "num",
label = "Choose a number",
value = 25, min = 1, max = 100)
),
mainPanel(
# *Output() functions
plotOutput(outputId = "hist") # Adds an output space
# in ui for R object.
# Build object
# in server func.
)
)
)
server <- function(input, output) {
output$hist <- renderPlot({ # Can add R scripts and code between render {}
title <- "100 Random Normal Values"
hist(rnorm(input$num), main = title) # Code that builds obj.
# input$num from sliderInput in UI, num-num, :)
# num-num causes automatic reativity!
}) # Save object to output$
# Referenced in plotOutput("")
}
shinyApp(ui = ui, server = server)
One directory with every file the app needs:
- app.R (your script which ends with a call to shinyApp())
- datasets, images, css, helper scripts, etc. Note- you must use exact name, app.R.
http://shiny.rstudio.com/articles/shinyapps.html
# Install rsconnect package
if (!require("devtools"))
install.packages("devtools")
devtools::install_github("rstudio/rsconnect")
# Set up your shinyapps.io account to recognize your computer
rsconnect::setAccountInfo(name='jefflong',
token='57EB65311F1075B42840A7E9AF80368B',
secret='<secret>')
# When ready to deploy app, point rsconnect to the app dir
library(rsconnect)
rsconnect::deployApp('/Users/jeffreylong/R/shiny/tutorialApp/shinyTutorial')
https://jefflong.shinyapps.io/shinytutorial/
Build reactive output to display in UI with render*(). E.g.
renderPlot( { hist(rnorm(input$numNum)) })
When notified that it is invalid, the object created by a render*() function will rerun the entire block of code associated with it.
library(shiny)
ui <- fluidPage(
#titlePanel(title=div(img(src="https://upload.wikimedia.org/wikipedia/commons/f/f5/Hoffmann-La_Roche_logo.svg", align="right"), "Jeff Long's Reactive Shiny App")),
#titlePanel(title=div(img(src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/17/Roche_Logo.svg/64px-Roche_Logo.svg.png", align="right"), "Jeff Long's Reactive Shiny App")),
titlePanel(title=div(img(src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/17/Roche_Logo.svg/128px-Roche_Logo.svg.png", align="right"), "Jeff Long's Reactive Shiny App")),
#titlePanel(title=div(img(src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/17/Roche_Logo.svg/256px-Roche_Logo.svg.png", align="right"), "Jeff Long's Reactive Shiny App")),
sidebarLayout( # Add side panel for inputs
sidebarPanel(
# *Input() functions
sliderInput(inputId = "numNum", # Input value of Slider
label = "Choose a number",
value = 25, min = 1, max = 100),
br(),
textInput(inputId = "note",
label = "Note",
value = "Histogram with statistics"),
actionButton(inputId = "addButton",
label = "Add Note")
),
mainPanel( # *Output() functions
verbatimTextOutput(outputId = "stats"),
verbatimTextOutput(outputId = "note"),
plotOutput(outputId = "hist") # Adds an output space
# in ui for R object.
# Build object
# in server func.
)
)
)
server <- function(input, output) {
data <- reactive({ # To sync data across multiple
rnorm(input$numNum) # outputs. data is a function and
}) # must be referred to as data()
output$stats <- renderPrint({
summary(data())
})
output$note <- renderText({
input$addButton
paste0("Note: ", isolate({input$note}))
})
output$hist <- renderPlot({ # Reactive function handles reactive
# value from *Input() function.
title <- paste(input$numNum, # Can add R scripts and
" Random Normal Values") # code between render {}
hist(data(), main = title) # Code that builds obj.
# input$num from sliderInput
# in UI, num-num, :)
# num-num causes automatic reativity!
}) # Save object to output$
} # Referenced in plotOutput("")
shinyApp(ui = ui, server = server)
An image of the Shiny app.
Use tags() to add static content to your Shiny app.
library(shiny)
names(tags)
Make a "www" directory, deposit images, no need to reference dir in call.
library(shiny)
ui <- fluidPage(
wellPanel(
tags$a(href = "https://github.com/jeffreyCarlLong/platinum-dragon/blob/master/README.md", "R Shiny Tutorial Notebook"),
tags$h3("HTML in R"),
tags$code("ls -la ~/*"), br(), br(),
"Text in fluidPage will also print in the Shiny App", br(), br(),
tags$hr(),
tags$p("Will split content..."),
tags$p("into separate paragraphs, with ",
tags$strong("nested"),
" tags.")
)
)
server <- function(input, output) {}
shinyApp(ui = ui, server = server)
Output from above code looks like this:
Combine tabPanel() with tabsetPanel(), navlistPanel(), or navbarPage().
Add horizonal block of space with fluidRow() and blocks within with column().
The first argument to column() is the width in 12 unit increments.
Offsets from the right can also be used.
library(shiny)
fluidPage(
tabsetPanel(
tabPanel("Shiny App Tab 1",
tags$img(height = 100, width = 100, src = "https://upload.wikimedia.org/wikipedia/commons/f/f5/Hoffmann-La_Roche_logo.svg"),
fluidRow( # <div class="row"> In the row</div>
column(3),
column(2), # or column(2, plotOutput("hist")),
column(5) # or column(5, sliderInput(...))
),
HTML("<h4>My Roche Shiny App</h4>")
),
fluidRow(
column(4, offset=8)
)
)
)
Output from above code looks like this:
R wrapper functions exist for: a(), br(), code(), em(), h1(), h2(), ..., h(6), hr(), img(), p(), and strong().
library(shiny)
ui <- fluidPage(
navbarPage(
navbarMenu()
)
)
server <- function(input, output) {}
shinyApp(ui = ui, server = server)
http://rstudio.github.io/shinydashboard/
https://bootswatch.com/cerulean/
<head>
<link type="text/css" rel="stylesheet" href="bootswatch-cerulean.css"/>
<style>
li {
color:purple;
}
.blue-item {
color:blue;
}
#dark {
color:navy;
}
</style>
</head>
<div>
<div class="container-fluid">
<h1>CSS examples</h1>
<p>This webpage uses...
</p>
<ol>
<li> Purple line item</li>
<li class="blue-item"> Blue item, class style over-rides global li style. </li>
<li id="dark" class="blue-item"> Navy item, id over-rides class style. </li>
<li id="dark" class="blue-item" style="color:green"> Green item, specify style to rule them all. </li>
</ol>
</div>
Output from above code looks like this:
Place .css files in the www folder of your app dir. To get the CSS to be used by Shiny, try one of the following.
library(shiny)
ui <- fluidPage(
theme = "bootswatch-cerulean.css",
sidebarLayout(
sidebarPanel("This is the ", strong("sidebarPanel"), " for theme bootswatch-cerulean"),
mainPanel("This is the ", strong("mainPanel"), " for theme bootswatch-cerulean")
)
)
server <- function(input, output) {}
shinyApp(ui = ui, server = server)
Output from above code looks like this:
library(shiny)
ui <- fluidPage(
tag$head(
tags$link(
rel = "stylesheet",
type = "text/css",
href = "bootswatchLitera.css"
)
)
)
server <- function(input, output) {}
shinyApp(ui = ui, server = server)
Add global style to header for paragraph tags (p).
library(shiny)
ui <- fluidPage(
tags$head(
tags$style(HTML("
p {
color:red;
}
"))
),
tags$p("This is some red style in Shiny.")
)
server <- function(input, output) {}
shinyApp(ui = ui, server = server)
Output from above code looks like this:
library(shiny)
ui <- fluidPage(
includeCSS("file.css") # Can be in app dir, not necessarily www
)
# where file.css is
HTML( # HTML() is not in the file.css
<style>
p {
color:red;
}
</style>
)
# OR
ui <- fluidPage(
tags$h1("Title", style = "color:red;")
)
HTML class at Code Academy, http://www.codeacademy.com/tracks/web
Shiny CSS article, http://shiny.rstudio.com/articles/css.html.
jQuery addition in the header, http://shiny.rstudio.com/articles/google-analytics.html.