Chapter 9 Building Apps
9.1 Summary
This chapter will introduce the development of data visualisation applications using the R-based Shiny web framework. Shiny allows you to rapidly design, build and deploy highly customised and advanced interactive data visualisations using R and RStudio.
9.1.1 Learning Objectives
The learning objectives associated with this chapter are:
- Understand how data visualisation applications are designed, built and deployed through Shiny and RStudio.
- Develop your own data visualisation apps using a Shiny framework. This includes the following tasks:
- Create a Shiny web application project in RStudio
- Create a
ui.R
andserver.R
file - Edit and customise the layout and appearance of
ui.R
- Add inputs and plot outputs to
ui.R
- Load packages and perform the statistical computations in
server.R
required by the application. - Map inputs from
ui.R
to changing parameters inserver.R
- Bundle output in
server.R
to display as output inui.R
- Run and debug your app in RStudio
- Deploy your app publicly on the shinyapps.io Shiny cloud server
9.2 Apps
Chapter 8 covered the basics of adding functional interactive features to data visualisations using Plotly. However, we learnt that Plotly does not manipulate data and interactivity can be somewhat limited. This chapter will explore the use of Shiny, which allows almost unlimited scope for interactivity when coupled with Plotly.
Data visualisation apps can be incredibly powerful. You only have to look at the amazing Gapminder app to have a sense of what can be achieved. Here is a list of some of the common interactive features that you can deploy using applications:
- Add slider bars to change parameters used in the data visualisation.
- Add a play button to transition the data visualisation based on a time variable.
- Add drop-down menus for the viewer to change the variables used in the visualisations.
- Add buttons to turn features on or off.
- Add input boxes for people to add their own code or data.
- Add multiple tabs that can be selected to change the type of data visualisation displayed.
- Add selection boxes to choose colour palettes or map additional variables to aesthetics.
Being able to program applications will take your data visualisation skills to the next level. There are many ways to develop applications. However, without strong web-programming skills, many approaches present significant barriers. Fortunately, RStudio has developed Shiny, which allows R coders to jump over this barrier.
9.3 Shiny
Shiny is an open source, web-based framework for rapidly developing powerful R-based applications. Think of it like a mini-version of R sitting on a server in order to drive a user interface. Shiny integrates with RStudio and opens the computational power of R to help you develop cutting-edge interactive data visualisations without the need to understand HTML, CSS and JavaScript. Shiny can run locally through RStudio or be deployed on a Shiny server in order to share with others. As Shiny is web-based, your apps will run on any device with a modern web-browser.
Shiny works by loading a streamlined version of R, with all the required packages to run your app, on a server. You build a user interface that interacts with the server to run statistical computations, manipulate data and create data visualisations. The server then feeds output back into the user interface for the viewer to see.
The best way to learn Shiny is by example. Shiny is very powerful and there is lots to learn. You won’t learn everything all at once. This chapter has been designed for you to learn using examples. However, afterwards, I encourage you to continue learning because it’s really useful and lots of fun. The Shiny website has many great resources.
- A gallery of helpful examples
- Tutorials to work through in your own time
- Other useful references discussing various topics
Have a go at the following examples first and then get stuck into your own apps. You always learn more working on your own projects.
9.4 shinyapps.io
Shinyapp.io provides cloud-based Shiny servers to host your apps. A free account is limited to 5 apps and 25 active hours. You can sign-up for a free account here. You will need this service to host your apps in the cloud. Alternatively, you can deply your own Shiny Server.
9.5 Building Your First App
The following slideshow will take you through the steps of developing your first app and hosting it in the cloud. Later sections contain all the code you need to follow along and replicate the example. You can view a downloadable version of the presentation here.
9.6 Histograms App
Here is the Histograms app covered in the slideshow.
The ui.R
and server.R
code for the Histogram app is shown below:
9.6.1 ui.R
# Histograms Shiny App
library(shiny)
shinyUI(fluidPage(
# App title
titlePanel("Histograms - Exploring the Effect of Sample Size and Bin Number"),
# Sidebar with a sample button and slider input for number of bins
sidebarLayout(
sidebarPanel(
p("Select a sample size to randomly sample.
Click sample to draw. If you draw multiple samples
of the same sampl size, you can see how histograms
can vary from sample to sample."),
sliderInput("n",
"Sample size:",
min = 10,
max = 10000,
value = 5),
actionButton("SampleButton", "Sample"),
p("Adjust the number of bins to see how
it impacts the histogram's appearance."),
sliderInput("bins",
"Number of bins:",
min = 1,
max = 100,
value = 30)
),
# Show a plot of the generated distribution
mainPanel(
p("The red line is the target population
distribution and the blue line is
the sample density estimate."),
plotOutput("distPlot"),
p("Histograms perform best for large samples that can support many bins.")
)
) ))
9.6.2 server.R
# Histograms Shiny App
library(shiny)
library(ggplot2)
shinyServer(function(input, output) {
# Monitor 'Sample' button. When pressed, generate a random sample of normal data
# based on selected sample size from slider input.
<- eventReactive(input$SampleButton, {
df data.frame(x=rnorm(input$n,0,1))
})
# Using random data, and slider input for number of histogram bins, generate
# histogram. Overlay theoretical and density estimate of distribution
$distPlot <- renderPlot({
output<- ggplot(df(), aes(x=x))
m + geom_histogram(bins=input$bins,aes(y = ..density..),colour = "white") +
m geom_density(colour="blue") +
stat_function(fun = dnorm, colour = "red") +
scale_x_continuous(limits=c(-3,3)) + scale_y_continuous(limits=c(0,1))
})
})
9.7 Population Pyramid App
The following app will replicate the basic functionality of the Australian Bureau of Statistics (ABS) Population Pyramid app. The app shows how the age and gender distribution of the Australian population has grown and changed over time.
9.7.1 Data
The aus_age_gender_hist
dataset was extracted from the ABS catalogue number 3101.0 - Australian Demographic Statistics, Sep 2015 data cubes. The dataset contains the frequency distribution of Australia by age category and gender from 1921 to 2011.
Here is a preview of the dataset.
Here is the Population Pyramid app:
Here are the ui.R
and server.R
code.
9.7.2 ui.R
# Australian Population Pyramid
# Load required packages
library(shiny)
shinyUI(fluidPage(
# Application title
titlePanel("Population Pyramid - Australia 1921 - 2011"),
# Sidebar with a slider input for year
sidebarPanel(
sliderInput("year", label = "Year", min = 1921, sep="",
max = 2011, value = 1921,
animate = animationOptions(interval = 500, loop = TRUE))
),
# Population Pyramid
mainPanel(
plotOutput("pyramid")
) ))
9.7.3 server.R
# Australian Population Pyramid
# Load required packages
library(shiny)
library(ggplot2)
library(dplyr)
library(tidyr)
library(stringr)
# Thanks to https://rpubs.com/walkerke/pyramids_ggplot2!
# Import data
<- read.csv("data/aus_age_gender_hist.csv",stringsAsFactors = TRUE)
ABS
# Label Age_cat factor
$Age_Cat<- factor(ABS$Age_Cat,
ABSlabels = c("0 to 4","5 to 9","10 to 14",
"15 to 19","20 to 24","25 to 29",
"30 to 34","35 to 39","40 to 44",
"45 to 49","50 to 54","55 to 59",
"60 to 64","65 to 69","70 to 74",
"75 to 79","80 to 84","85 and over"))
# Convert ABS to long format
<- gather(ABS,"Year","Population",X1901:X2011)
ABS_long
#Strip x from "x1901" in year variable
$Year <- as.numeric(str_replace(ABS_long$Year,"\\w",""))
ABS_long
# Now we define the shinyServer function
shinyServer(function(input, output) {
$pyramid <- renderPlot({
output<- ggplot(ABS_long, aes(x = Age_Cat, y = Population, fill = Gender))
p1 + geom_bar(data = filter(ABS_long,Gender == "Females" & Year == input$year),
p1 stat = "identity") +
geom_bar(data = filter(ABS_long,Gender == "Males" & Year == input$year),
aes(y=Population*(-1)), stat = "identity") +
scale_y_continuous(breaks = seq(-1000000, 1000000, 250000),
limits = c(-1000000, 1000000),
labels = paste0(as.character(abs(seq(-1, 1,.25))), "M")) +
labs(x = "Age Category", y = "Population (Million)")+
coord_flip()
}) })
9.8 Shiny Apps II
In the following sections, we will look at improving coding efficiency, improving appearance and adding advanced features to Shiny apps. Specifically, we will consider the following:
- Single file apps
- Building a
ui
quickly - Tabsets and navbars
- Plotly and Shiny
- Reactivity
- Upload data and preview data tables
- Shiny themes
You will need to install the relevant packages and run the apps in RStudio. Study each example closely and ensure you understand the gist of the code.
9.8.1 Single File Apps
Shiny apps can be created as a single file named app.R
. For small apps, this can make it easier to code and share. However, with larger apps, the separation of the ui.R
and server.R
files may be more efficient. Here is an example of a single file app:
## Single file Shiny app.R
# Load packages and prepare data
library(ggplot2)
library(shiny)
library(dplyr)
library(lubridate)
<- ggplot2::txhousing
texas
<- txhousing %>% group_by(year,month) %>%
texas_sum summarise(sales = sum(sales,na.rm = TRUE),
volume = sum(volume,na.rm = TRUE),
median = sum(median,na.rm = TRUE),
listings = sum(listings,na.rm = TRUE),
inventory = sum(inventory,na.rm = TRUE))
<- texas_sum %>% ungroup()
texas_sum
$date <- ymd(paste0(texas_sum$year,"-",texas_sum$month,"-1"))
texas_sum
# Assign server function
<- function(input, output) {
server $distPlot <- renderPlot({
outputggplot(data = texas_sum, aes(x = date, y = get(input$var))) +
geom_line() + labs(y = input$var)
})
}
# Create ui
<- fluidPage(
ui titlePanel("Texas Housing Data"),
sidebarLayout(
sidebarPanel(
selectInput("var", "Variable",
colnames(texas_sum[3:7]), selected = colnames(texas_sum[3]))
),mainPanel(plotOutput("distPlot"))
)
)
# Deploy app
shinyApp(ui = ui, server = server)
9.8.2 Building a ui
Quickly
Building a ui
can be tedious. However, there are shortcuts. We can use a data.frame
’s colnames
or a factor’s levels
to create lists that can be fed into to the ui
. For example, if we wanted a list of factors included in the MGP
dataset, we could write:
<- ggplot2::mpg
MPG names(MPG)[ sapply(MPG, is.character) | sapply(MPG, is.factor) ]
## [1] "manufacturer" "model" "trans" "drv" "fl"
## [6] "class"
Using this list, we can automatically label widgets in the ui
.
# Load packages and prepare data
library(ggplot2)
library(shiny)
<- ggplot2::mpg
MPG
$year <- MPG$year %>% as.factor()
MPG$cyl <- MPG$cyl %>% as.factor()
MPG
# Generate variables lists for ui
<- names(MPG)[ sapply(MPG, is.character) | sapply(MPG, is.factor) ]
factors <- names(MPG)[ sapply(MPG, is.numeric)]
quantitative
# Assign server function
<- function(input, output) {
server2 $distPlot <- renderPlot({
outputggplot(data = MPG, aes(x = factor(get(input$var1)), y = get(input$var2))) +
geom_boxplot() + labs(x = input$var1, y = input$var2)
})
}
# Create ui
<- fluidPage(
ui2 titlePanel("Side-by-side Comparisons"),
sidebarLayout(
sidebarPanel(
selectInput("var1", "Grouping Variable",
choices = factors, selected = factors[1]),
selectInput("var2", "Response Variable",
choices = quantitative, selected = quantitative[1])
),mainPanel(plotOutput("distPlot"))
)
)
# Deploy app
shinyApp(ui = ui2, server = server2)
9.8.4 Plotly and Shiny
Plotly and Shiny work seamlessly and provide designers with the best of both worlds - the raw power of R and the interactivity of Plotly.
# Load packages and prepare data
library(ggplot2)
library(shiny)
library(plotly)
library(gapminder)
library(RColorBrewer)
<- gapminder::gapminder %>% filter(country != "Kuwait") # remove outlier!
gapminder_filt
# Assign server function
<- function(input, output) {
server5 $gapminder <- renderPlotly({
output
$highlight <- ifelse(gapminder_filt$country == input$highlight,
gapminder_filt$highlight,"Other")
input
$highlight <- gapminder_filt$highlight %>%
gapminder_filtfactor(levels = c(input$highlight,"Other"))
<- ifelse(input$highlight == "continent", "continent",
col "highlight")
plot_ly(gapminder_filt, x = ~gdpPercap, y = ~lifeExp, color = ~get(col), colors = "Set1",
frame = ~year, alpha = 1, type = "scatter", mode = "markers") %>%
layout( title = "GDP Per Capita vs. Life Expectancy by Year",
yaxis = list(zeroline = FALSE, title = "Life Expectancy"),
xaxis = list(zeroline = FALSE, title = "GDP Per Capita"))
})
}
# Create ui
<- fluidPage(
ui5 titlePanel("Plotly & Shiny"),
sidebarLayout(
sidebarPanel(
selectInput("highlight", "Track Country",
choices = c("continent",levels(gapminder$country)),
selected = "continent")
),mainPanel(plotlyOutput("gapminder"))
)
)
# Deploy app
shinyApp(ui = ui5, server = server5)
9.8.5 Reactive Events
Reactive output is a great way to speed up apps. Reactive output will only execute changes on the Shiny server when the user changes an input. This is useful when you have resource-hungry applications. By default, Shiny will update with any change to an input. However, using advanced reactive observers, such as the eventReactive
, you can delay these updates by linking to an actionButton
input. The following example shows the use of an actionButton
.
library(shiny)
library(ecodist)
<- fluidPage(
ui6 titlePanel("Guess the Correlation"),
sidebarLayout(
sidebarPanel(
actionButton("go", "Generate random correlation"),
actionButton("answer", "Show answer"),
verbatimTextOutput("answer")),
mainPanel(plotOutput("plot"))
)
)
<- function(input, output) {
server6
<- eventReactive(input$go, {
rcor data.frame(corgen(50, r=runif(1,-1,1), population = FALSE, epsilon = 0))
})
<- eventReactive(input$answer, {
r cor(rcor()$x, rcor()$y)
})
$plot <- renderPlot({
outputqplot(data = rcor(), x = x, y = y, geom = "point") +
scale_y_continuous(limits = c(-3,3)) +
scale_x_continuous(limits = c(-3,3))
})
$answer <- renderText({
outputpaste0("Answer: r = ", round(r(),2))
})
}
shinyApp(ui = ui6, server = server6)
The following RShiny re-make of the classic “Guess that Correlation” game was developed by Arion Barzoucas-Evans, a very talented former student of the course. I have to thank Arion for giving me permission to show his code here. I’ve had the opportunity to build upon Arion’s work. Specifically, I have simplified the generation of the correlated data, fixed the plot size and constrained the axis limits.
library(shiny)
library(ecodist)
library(shinyjs)
<- fluidPage(
ui7
useShinyjs(),
# Application title
titlePanel("Guess the correlation game"),
sidebarLayout(
sidebarPanel(
HTML(
paste("<b><i>INSTRUCTIONS:<br>1. Click on the 'Generate Scatter Plot'
button to generate", "a new scatter plot.<br>2. Guess the
correlation present in the scatter plot (a value between -1 and 1)
and enter the value", "in the 'Guess the correlation box'.
<br>3. Click the 'Submit' button to submit your guess.",
"<br><br>RULES:<ul><br><li>Guess within 0.05 of the true correlation:
+1 life and +5 points.</li>","<br><li>Guess within 0.10 of the true
correlation: +1 point.</li>","<br><li>Guess within >0.10 of the true
correlation: -1 life.</li>","<br><li>You will also receive bonus
points if you make good guesses in a row!</li>")),
HTML("<br><br><br>"),
$head(
tags$style(
tagsHTML("#scatterButton{background-color:green}"),
HTML("#scatterButton{color:white}"),
HTML("#guessButton{background-color:green}"),
HTML("#guessButton{color:white}"),
HTML("#resetButton{background-color:blue}"),
HTML("#resetButton{color:white}"),
HTML("#highscore{color:blue}")
)
),
actionButton("scatterButton",HTML("<b>Generate Scatter Plot")),
HTML("<br><br><br>"),
numericInput("guess","Guess the correlation:",
value = 0, min = -1, max = 1, step = 0.01),
actionButton("guessButton",HTML("<b>Submit")),
conditionalPanel("output.lives < 0",
actionButton("resetButton",HTML("<b>Reset")))
),
mainPanel(
fluidRow(
column(12,verbatimTextOutput("highscore")),
column(12,plotOutput("distPlot")),
column(12,verbatimTextOutput("progress")),
column(12,conditionalPanel("output.corr_diff <= 0.1", tags$head(
$style(
tagsHTML("#wintext{color:green}"))),
verbatimTextOutput("wintext"))),
column(12,conditionalPanel("output.corr_diff > 0.1", tags$head(
$style(
tagsHTML("#losetext{color:red}"))),
verbatimTextOutput("losetext")))
)
)
)
)
<- function(input, output) {
server7
# reactive variables
<- reactiveValues(streaks = 0, counter = 0, guess_sum = 0,
vars corr_diff = 0, score = 0, lives = 3, highscore = 0)
# random scatter plot generation
<- eventReactive(input$scatterButton, {
df data.frame(corgen(runif(1, 10, 500), r=runif(1,-1,1), population = FALSE,
epsilon = 0))
})
# game progress text output
<- eventReactive(input$guessButton, {
progress $counter <- vars$counter + 1
vars$corr_diff <- abs(input$guess - cor(df()$x,df()$y))
vars$guess_sum <- vars$guess_sum + vars$corr_diff
varsif(vars$corr_diff <=0.05 && vars$streaks >= 2){
$streaks <- vars$streaks + 1
vars$score <- vars$score + 8
vars$lives <- vars$lives + 1
varselse if(vars$corr_diff <=0.05){
}$streaks <- vars$streaks + 1
vars$score <- vars$score + 5
vars$lives <- vars$lives + 1
varselse if(vars$corr_diff <=0.1 && vars$streaks >= 2){
}$streaks <- vars$streaks + 1
vars$score <- vars$score + 4
varselse if(vars$corr_diff <=0.1){
}$streaks <- vars$streaks + 1
vars$score <- vars$score + 1
varselse{
}$streaks <- 0
vars$lives <- vars$lives - 1
vars
}<- paste("Streak:",vars$streaks,
text "\nMean Error:", round(vars$guess_sum/vars$counter,2),
"\nScore:",vars$score,"\nLives Left:",vars$lives)
})
# win text display
<- eventReactive(input$guessButton, {
wintext
<- paste("True Correlation:",
text round(cor(df()$x,df()$y),2),"\nGuessed Correlation:",input$guess,
"\nDifference:", round(vars$corr_diff,2))
})
# lose text display
<- eventReactive(input$guessButton, {
losetext
<- paste("True Correlation:",round(cor(df()$x,df()$y),2),
text "\nGuessed Correlation:",input$guess,
"\nDifference:", round(vars$corr_diff,2))
})
# highscore display
<- eventReactive(input$guessButton, {
highscore
if(vars$score > vars$highscore){
$highscore <- vars$score
vars
}
<- paste("High Score:", vars$highscore)
text
})
# assigning outputs
# reactive outputs to use in UI
$lives <- reactive({vars$lives})
output$corr_diff <- reactive({vars$corr_diff})
output
# text output
$progress <- renderText(progress())
output$wintext <- renderText(wintext())
output$losetext <- renderText(losetext())
output$highscore <- renderText(highscore())
output
# make reactive variables available in UI
outputOptions(output, "lives", suspendWhenHidden = FALSE)
outputOptions(output, "corr_diff", suspendWhenHidden = FALSE)
# hide game attempt
observeEvent(input$scatterButton, {
hide("losetext")
hide("wintext")
show("progress")
})
# show game attempt
observeEvent(input$guessButton, {
show("progress")
show("losetext")
show("wintext")})
# reset game
observeEvent(input$resetButton, {
$lives <- 3
vars$streaks <- 0
vars$counter <- 0
vars$guess_sum <- 0
vars$corr_diff <- 0
vars$score <- 0
varshide("progress")
hide("wintext")
hide("losetext")})
# plot output
$distPlot <- renderPlot({
output
if(vars$lives >= 0){
ggplot(data = df(), aes(x = x, y = y)) + geom_point(size = 3) +
theme_classic() + scale_y_continuous(limits = c(-3, 3)) +
scale_x_continuous(limits = c(-3,3))
else{
}ggplot() + geom_text(aes(x= "", y = "",
label = "GAME OVER :'(\nPLEASE RESET THE GAME"),
size = 14, colour = "RED") +
theme_classic() + scale_y_continuous(limits = c(-3, 3)) +
scale_x_continuous(limits = c(-3,3))
}height = 500, width = 600)
},
}
shinyApp(ui = ui7, server = server7)
9.9 Uploading and Viewing Data
Shiny can also be used to upload user data and preview it. Allowing a user to view (and even download) the data is good practice (provided you have permission…). Here is an example of an app where the user can upload and preview a .csv
dataset.
library(shiny)
library(DT)
<- fluidPage(
ui8 titlePanel("Uploading and Viewing Data"),
sidebarLayout(
sidebarPanel(
fileInput("file", "Choose CSV Dataset",
multiple = TRUE,
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv"))
),
mainPanel(
dataTableOutput("contents")
)
)
)
# Define server logic to read selected file ----
<- function(input, output) {
server8
$contents <- renderDataTable({
output
req(input$file)
<- read.csv(input$file$datapath)
df
})
}
# Deploy app
shinyApp(ui = ui8, server = server8)
9.10 Shiny Themes
You can change Shiny themes for a different look. First install and load shinythemes
. Themes, based on the Bootstrap Themes, include the following: cerulean, cosmo, cyborg, darkly, flatly, journal, lumen, paper, readable, sandstone, simplex, slate, spacelab, superhero, united and yeti. Here is an example of the dark cyborg
theme. Notice how we can change the theme by adding a theme =
option to the ui
.
library(shiny)
library(DT)
library(shinythemes)
<- fluidPage(theme = shinytheme("cyborg"),
ui9 titlePanel("Uploading, Viewing and Downloading Data"),
sidebarLayout(
sidebarPanel(
fileInput("file", "Choose CSV Dataset",
multiple = TRUE,
accept = c("text/csv",
"text/comma-separated-values,text/plain",
".csv"))
),
mainPanel(
dataTableOutput("contents")
)
)
)
# Define server logic to read selected file ----
<- function(input, output) {
server9
$contents <- renderDataTable({
output
req(input$file)
<- read.csv(input$file$datapath)
df
})
}
shinyApp(ui = ui9, server = server9)
9.11 Avoiding Common Errors in Shiny
Building Shiny apps can be a time consuming process due to the difficulty of debugging. Shiny’s error messages are often vague and unhelpful. However, with a bit of experience and know-how, you will become more efficient at identifying and addressing bugs. The following tips will help you to avoid the most common issues:
9.11.1 Load your Packages and Data
Ensure all your packages and data are loaded in the app. When the app runs on a server, it needs to load the packages and data required for the app to run. If these are not specified in the app, the app won’t be able to locate the data or functions required for the app to load.
9.11.2 Remove the Unnecessary
Only include packages, data and code that are required for the app to run. Loading unnecessary packages will often create function conflicts and increase the risk of issues installing packages on the Shiny server. Loading unnecessary data and including unnecessary code will decrease app performance and increase the chances of errors.
9.11.3 Use Current Versions
Use current versions of packages from CRAN. This minimises the risk of issues created by outdated functions and package bugs. You can use packages from GitHub by loading Devtools v. > 1.4.
9.11.4 Use Relative Paths
Place your dataset in your app directory and load using a relative path. When the app is hosted on a Shiny server, it must access files from the server. The app will no longer have access to local paths on your computer. For example, you might load data.csv
from your local computer by directing to your C: drive.
<- read.csv("C:/folder/subfolder/data.csv") data
This will work when you run the app locally because the Shiny server has access to your local folders. However, when hosted online, the app won’t have access. Instead, place the dataset in the same directory as your app file and load using a relative path. For example…
# Right
<- read.csv("data.csv") data
This tells the app that data.csv
is located in the same folder as app.R
.
9.11.5 Build One Feature at a Time
Build your app one feature at a time. Don’t try to incorporate all your interactive features in one go. It will make debugging very slow. List the interactive features you want to include. Pick the most important. Build it. Test it. Refine it. Then move onto the next feature. This will make it much easier to identify the point in your code that is breaking the app.
9.11.6 Check Logs
Shiny includes detailed logs which can provide helpful information about bugs. Check for error clues using rsconnect::showLogs()
after you have closed the app following an error.
9.11.7 Avoid Shiny-cide Functions
There are many functions that will kill a Shiny app. Here are some common examples:
install.packages()
: This function installs a package. Shiny does not use this function to install packages on the Shiny Server. When an app is loaded on a Shiny server, there are functions that extract a list of the packages loaded usinglibrary()
orrequire()
and then uses this list to install the required packages with the help of thersconnect
package.View()
: This function opens a spreadsheet-like view of a dataset on a local machine. It was not intended for a Shiny server.setwd()
: This function specifies a local directory to efficiently load and save data and other objects in R. It will not work on a Shiny server because the server won’t have access to your local directories. Use relative paths instead (see above)
9.12 Conclusion
This chapter started by introducing the basics of Shiny applications. Part II considered efficient ways to code user-interfaces, how to incorporate useful functionality, change themes and integrate Plotly. In the next chapter, we will take another look at Shiny and how it can be used to design engaging and informative dashboards.