Let’s start with a blank Shiny app
library(shiny)
ui <- fluidPage(
)
server <- function(input, output) {
}
shinyApp(ui = ui, server = server)
You learned in The Basics of Shiny Apps how to add input and output elements to the user interface of an app.
But the way we added elements was ugly.
library(shiny)
library(ggplot2)
ui <- fluidPage(
selectInput("var", "Which Variable?", choices = names(mtcars)),
plotOutput("plot")
)
server <- function(input, output) {
output$plot <- renderPlot({
ggplot(mtcars, aes(x = .data[[input$var]])) +
geom_histogram(bins = 20)
})
}
shinyApp(ui = ui, server = server)
Today, we will learn how to make your layout more sophisticated than a list of items.
fluidPage()
function.
fluidPage()
to specify the layout
of your app.navbarPage()
.dashboardPage()
: https://rstudio.github.io/shinydashboard/dashboardPage()
: https://rinterface.github.io/shinydashboardPlus/Add a title to your app using the titlePanel()
function.
library(shiny)
ui <- fluidPage(
titlePanel("My First Title")
)
server <- function(input, output) {
}
shinyApp(ui = ui, server = server)
Running the app, you should get something like this:
To create a general layout, use the fluidRow()
and
column()
functions.
fluidRow()
column()
calls as input.column()
calls as you want
columns.column()
fluidRow()
.width
).column()
calls should have width
s that
sum to 12.Hadley’s Graphic:
Let’s make a shiny app with two input columns in one row, and three plot columns in a second row.
library(shiny)
library(ggplot2)
ui <- fluidPage(
fluidRow(title = "Inputs",
column(6,
selectInput("var1", "Variable 1", choices = names(mtcars)),
selectInput("var2", "Variable 2", choices = names(mtcars))
),
column(6,
sliderInput("bins", "Number of Bins", min = 1, max = 50, value = 20)
)
),
fluidRow(title = "Outputs",
column(4,
plotOutput("plot1")
),
column(4,
plotOutput("plot2")
),
column(4,
plotOutput("plot3")
)
)
)
server <- function(input, output) {
output$plot1 <- renderPlot({
ggplot(mtcars, aes(x = .data[[input$var1]], y = .data[[input$var2]])) +
geom_point()
})
output$plot2 <- renderPlot({
ggplot(mtcars, aes(x = .data[[input$var1]])) +
geom_histogram(bins = input$bins)
})
output$plot3 <- renderPlot({
ggplot(mtcars, aes(x = .data[[input$var2]])) +
geom_histogram(bins = input$bins)
})
}
shinyApp(ui = ui, server = server)
Running the app, you should get something like this:
Note: You can nest fluidRow()
’s inside
fluidRow()
’s. It can get quite complicated.
Exercise: Create a grid layout of four squares
where the top left square takes as input the variables of the
palmerpenguins::penguins
dataset to include in a
scatterplot and the bottom right contains the resulting scatterplot,
color-coded by species. The top right square and bottom left squares
should remain empty.
Your final app should look like this:
You can have outputs subdivided by tabs with
tabsetPanel()
and tabPanel()
.
tabsetPanel()
tabPanel()
calls.mainPanel()
in
the sidebar layout, or in one of the column()
calls in the
grid layout.tabPanel()
tabsetPanel()
.Here is an example from the mtcars
dataset, where
the tabs have different plots for the variables we select.
library(shiny)
library(ggplot2)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
selectInput("var1", "Variable 1", choices = names(mtcars)),
selectInput("var2", "Variable 2", choices = names(mtcars)),
sliderInput("bins", "Number of Bins", min = 1, max = 50, value = 20)
),
mainPanel(
tabsetPanel(
tabPanel("Scatterplot",
plotOutput("plot1")
),
tabPanel("Histogram of Variable 1",
plotOutput("plot2")
),
tabPanel("Histogram of Variable 2",
plotOutput("plot3")
)
)
)
)
)
server <- function(input, output) {
output$plot1 <- renderPlot({
ggplot(mtcars, aes(x = .data[[input$var1]], y = .data[[input$var2]])) +
geom_point()
})
output$plot2 <- renderPlot({
ggplot(mtcars, aes(x = .data[[input$var1]])) +
geom_histogram(bins = input$bins)
})
output$plot3 <- renderPlot({
ggplot(mtcars, aes(x = .data[[input$var2]])) +
geom_histogram(bins = input$bins)
})
}
shinyApp(ui = ui, server = server)
Running the app, you should get something like this:
Exercise: Create a basic Shiny app that has a
tab for a density plot, a histogram, and a boxplot for a variable from
the palmerpenguins::penguins
dataset. The user should get
to choose the variable plotted, the the number of bins for the
histogram, and the bandwidth for the density plot (see the help page of
geom_smooth()
). A good default value for the bandwidth
might be 0.25 in this case.
Your app should look like this:
You can group elements together in a slightly inset border with
wellPanel()
.
library(shiny)
library(ggplot2)
ui <- fluidPage(
wellPanel(
sliderInput("bins", "How many bins?", min = 1, max = 50, value = 20),
plotOutput("hist")
)
)
server <- function(input, output, session) {
output$hist <- renderPlot({
ggplot(mtcars, aes(x = mpg)) +
geom_histogram(bins = input$bins)
})
}
shinyApp(ui, server)
There are many other visual styles for groupings.
absolutePanel()
.conditionalPanel()
.fixedPanel()
.headerPanel()
.inputPanel()
.navlistPanel()
.For extreme customizability on the look of your Shiny App, you’ll have to learn CSS.
We will not learn CSS.
But the shinythemes package allows you to access many different themes available in Bootstrap.
Inside fluidPage()
, list the theme
argument to be shinytheme("theme_name")
, where
"theme_name"
is one of the themes that comes with
shinythemes.
The full list of available themes can be found by
help("shinythemes")
Example:
library(shiny)
library(shinythemes)
ui <- fluidPage(theme = shinytheme("darkly"),
sidebarLayout(
sidebarPanel(
sliderInput("number", "select a number", 0, 100, 40)
),
mainPanel(
tabsetPanel(
tabPanel("a"),
tabPanel("b"),
tabPanel("c")
)
)
)
)
server <- function(input, output, session) {
}
shinyApp(ui, server)
The shinydashboard package lets you obtain more proffesional looking Shiny apps.
The only thing that changes in a shinydashboard is the user interface.
The structure of a shinydashboard looks like this:
library(shiny)
library(shinydashboard)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody()
)
server <- function(input, output, session) {
}
shinyApp(ui, server)
dashboardHeader()
just changes the title of the
Shiny app.
dashboardSidebar()
is where you place a
menu.
dashboardBody()
is where you place content.
Use fluidRow()
and box()
(or
column()
) to add content to
dashboardBody()
.
library(shiny)
library(shinydashboard)
library(ggplot2)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody(
fluidRow(
box(
plotOutput("hist")
),
box(
sliderInput("nobs", "Number of observations", min = 1, max = 100, value = 50),
title = "Controls"
)
)
)
)
server <- function(input, output, session) {
output$hist <- renderPlot({
x <- rnorm(input$nobs)
qplot(x, bins = 10)
})
}
shinyApp(ui, server)
Create tabs by:
using sidebarMenu()
and menuItem()
in
dashboardSidebar()
.
using tabItems()
and tabitem()
in
dashboardBody()
.
library(shiny)
library(shinydashboard)
library(ggplot2)
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(
sidebarMenu(
menuItem(text = "Histogram", tabName = "tabhist"),
menuItem(text = "Scatterplot", tabName = "tabscat")
)
),
dashboardBody(
tabItems(
tabItem(tabName = "tabhist",
fluidRow(
box(
plotOutput("hist")
),
box(
sliderInput("nobs", "Number of observations",
min = 1,
max = 100,
value = 50),
title = "Controls"
)
)
),
tabItem(tabName = "tabscat",
fluidRow(
box(
plotOutput("scatter")
),
box(
sliderInput("nobs2", "Number of observations",
min = 1,
max = 100,
value = 50),
sliderInput("corr", "Correlation",
min = 0,
max = 1,
value = 0,
step = 0.1),
title = "Controls"
)
)
)
)
)
)
server <- function(input, output, session) {
output$hist <- renderPlot({
x <- rnorm(input$nobs)
qplot(x, bins = 10)
})
output$scatter <- renderPlot({
x <- rnorm(n = input$nobs2)
y <- rnorm(n = input$nobs2,
mean = input$corr * x,
sd = sqrt(1 - input$corr^2))
qplot(x, y)
})
}
shinyApp(ui, server)
Use the skin
argument in
dashboardPage()
to change the appearence of your
dashboard.
For more information on shinydashboards, see: https://rstudio.github.io/shinydashboard/index.html