In this practical you’ll practice creating interactive graphics with shiny
.
If you don’t have it already, you can access the shiny
cheatsheet here http://shiny.rstudio.com/images/shiny-cheatsheet.pdf
app.R
should now be open. Click the “Run App” button to open the app.By the end of this practical, you’ll try to create the following app:
Start by following the example above so you have your own app.R
Explore the code in the app to see how it works. Where in the app is the user interface defined? Where is the server code? Where does the server code get access to the vector of geyser data? In what object is the geyser data stored?
Change the main title of the app from “Old Faithful Geyser Data” to “___’s first Shiny App!" using your first name.
In the server code, change the color of the bins of the histogram to "red"
. Reload your app to see your changes!
selectInput
to change bin colorsselectInput
like in the code below.# Add a new selectInput to your app below the sliderInput():
sliderInput("bins",
"Number of bins:",
min = 1,
max = 50,
value = 30), # <- Dont forget to put a comma here
# HERE!!! Add Bin Color Select Input
selectInput(inputId = "bincolor",
label = "Color",
choices = c("red", "blue", "green", "black"),
selected = "black")
hist()
) to use the new color input! In the server portion of the app, tell the histogram to use the new color input as follows:# Make this change to the hist() function in your app
# This will tell Shiny that the colors of the histogram
# bins should change based on the user's input
hist(x,
breaks = bins,
col = input$bincolor, # HERE!!! Change color based on input$bincolor
border = 'white')
choices = c("red", "blue", "green", and "black")
. But R has so many more colors, what if we wanted the select input to show all of the named colors in R like "gold"
, "skyblue"
, and more obscure colors like "peachpuff4"
, "olivedrab"
and "lavender"
? It would be quite a pain to have to type all possible color names. Thankfully, we can easily pass a vector of color names to the choices
input. The function colors()
will return a vector of all 657 color names. In your console, try running colors()
to see all of the colors.# Print a vector of all color names
colors()
choices = colors()
as follows:# This code will tell Shiny to include ALL 657 colors
# in R as possible choices for the user in the bincolor input
selectInput(inputId = "bincolor",
label = "Color",
choices = colors(), # <- HERE!!! change the choices to colors()
selected = "black")
checkboxInput
to add mean line"addmean"
# Add a new checkboxInput to your app
checkboxInput(inputId = "addmean",
label = "Add mean line?",
value = FALSE)
hist()
code that creates the histogram, include the following:# Add this code just below the histogram code to add
# a line at the mean IF the addmean checkbox is checked.
if(input$addmean) { # If the addmean box is checked...
# Add a vertical line at the mean of x
abline(v = mean(x),
lwd = 2, # Thickness
lty = 2) # Dashed line
} # close if statement
textInput
textInput()
function in the user interface.# Add 2 text inputs to the sidepanel with textinput()
textInput(inputId = "main",
label = "Plot Title"),
textInput(inputId = "xlab",
label = "X-axis label")
hist()
function in the server code:hist(x,
breaks = bins,
col = input$bincolor,
border = 'white',
main = input$main, # HERE!!! Change main title based on input$main
xlab = input$xlab) # HERE!!! Change x label based on input$xlab
tabsetPanel
tabsetPanel()
within the mainPanel()
function like this:# Create different tabs within your app by using tabsetPanel()
# Here, we'll create three tabs, where the first tab
mainPanel(
tabsetPanel(type = "tabs",
tabPanel("Histogram", plotOutput("distPlot")), # The original Histogram
tabPanel("Summary"), # Empty for now
tabPanel("Description") # Empty for now
)
)
renderPrint()
, and then assign the result to output$summary
. To do this, add the following code within your server function (you can actually put it anywhere in the server function!)# Add this code to the server function to return summary statistics
output$summary <- renderPrint({
x <- faithful[, 2] # Define x again
summary(x)
})
"Summary"
tab panel to display this information. To do this, add the function verbatimTextOutput("summary")
to the "Summary"
tab panel as follows:# Add verbatimTextOutput("summary") to the Summary tab panel
tabsetPanel(type = "tabs",
tabPanel("Histogram", plotOutput("distPlot")),
tabPanel("Summary", verbatimTextOutput("summary")), # <- HERE!!!
tabPanel("Description")
)
h3(), p(), a()
functions. If you’re familiar with HTML, these functions simply return HTML. Using the following code template, update the contents of the "Description"
tab panel to display some text and a link.# Add HTML functions to the Description tab
tabsetPanel(type = "tabs",
tabPanel("Histogram", plotOutput("distPlot")),
tabPanel("Summary", verbatimTextOutput("summary")),
tabPanel("Description",
h3("Shiny is Awesome!"),
p("You can really do anything with Shiny!"),
a("Click me to go to the Shiny page",
href = "https://shiny.rstudio.com/gallery/")
)
)
reactive()
# Add a new select input called mydata
selectInput(inputId = "mydata",
label = "Dataset",
choices = c("geyser", "diamonds", "economics"),
selected = "geyser")
x
as a reactive value that depends on the user’s input to input$mydata
. To do this, we’ll remove the existing code that defines the object x
and replace it with x_reactive()
using the reactive()
function. The reactive()
function tells Shiny that x_reactive
is isn’t a stable value, but will change depending on user input.x
(right now you’ll find it in both the hist()
function and when we defined output$summary
x_reactive
as a reactive value that can change depending on the input$mydata
. If you haven’t seen it before, the switch()
function is a very helpful function that works like a series of if-then statements.# x is a reactive value that depends on input$mydata
# This code should replace the previous code that defined x
# Put this code just after the server() function and BEFORE output$distPlot
x_reactive <- reactive({
switch(input$mydata, # Look at the value of input$mydata...
"geyser" = faithful[,2], # If the value is 'geyser', return data from faithful
"economics" = economics$unemploy, # if the value is 'economics' return unemployment data
"diamonds" = diamonds$price) # If the value is 'diamonds' return price data
})
x
we need to replace x
with x_reactive()
(Don’t forget the parentheses!!). Make this replacement for hist()
, summary()
, and abline()
. Here is how you can do it:# Change the value x to x_reactive() in seq(), hist(), abline() and summary()
bins <- seq(min(x_reactive()), # HERE!!! Change to x_reactive()
max(x_reactive()), # HERE!!! Change to x_reactive()
length.out = input$bins + 1)
# [Skip some code...]
hist(x_reactive(), # HERE!!! Change to x_reactive()
breaks = 10,
col = input$bincolor,
border = 'white',
main = input$main,
xlab = input$xlab)
# [Skip some code...]
abline(v = mean(x_reactive()), # HERE!!! Change to x_reactive()
lwd = 2,
lty = 2)
# [Skip some code...]
output$summary <- renderPrint({
summary(x_reactive()) # HERE!!! Change to x_reactive()
})
C1. Now that you have multiple datasets, try removing the Plot title and X-axis label inputs (input$main
, input$xlab
), and instead have the plot automatically adjust the plot title and axis label based on the dataset the users selects. Just like we did with x_reactive()
, you’ll need to assign the main title and x label as reactive values.
C2. Add a new panel called “Table” where the user can view their selected dataset. To do this, in the server code, you’ll need to create a new output called output$tbl
which is is a rendered version of the data. Then in the UI, you’ll need to include
#### SERVER
# Send a rendered data table to output
# DATASET should the the data as a dataframe
output$tbl <- renderUI({
output$mytbl <- DT::renderDataTable(expr = DATASET,
options = list(lengthChange = FALSE))
DT::dataTableOutput('mytbl')
})
#### UI
# Add the new Table tabpanel
tabsetPanel(type = "tabs",
tabPanel("Histogram", plotOutput("distPlot")),
tabPanel("Summary", verbatimTextOutput("summary")),
tabPanel("Description"),
tabPanel("Table", uiOutput('tbl'))) # <- HERE!!!
C3. Try adding a new panel called Test
where people can conduct a one-sample t-test on their data and view the results. To do this, you’ll need to create a new output in the server called output$printttest
which is a call to renderPrint()
. Inside of renderPrint()
you’ll create the code for your test, and print the result. Next, in the UI, you’ll need to add a new tab panel, and show the results by running verbatimTextOutput('printttest')
. Look at the template below for help. If you’d like, you could also add a new user input that allows the user to customise the main arguments for the t.test, like mu
and alternative
.
#### SERVER
# Send results of t-test to output
# DATASET should the the data as a dataframe
# Print Test output
output$printttest <- renderPrint({
mytest <- t.test(x = DATA, mu = 0, alternative = "two.sided")
print(mytest)
})
#### UI
# Add the new Table tabpanel
tabsetPanel(type = "tabs",
tabPanel("Histogram", plotOutput("distPlot")),
tabPanel("Summary", verbatimTextOutput("summary")),
tabPanel("Description"),
tabPanel("Test", verbatimTextOutput('printttest'))) # <- HERE!!!
C4. So far we’ve used base plotting functions (e.g.; hist()
, abline()
). Try replacing these functions with ggplot code. For example, you could use ggplot(data, aes(x)) + geom_hist()
to create a histogram. Note that because of the way you build on plots in ggplot, some parts of the code, such as the addmean
functionality will be a bit tricky, so you may wish to remove it.
C5. In the RStudio Shiny Gallery at https://shiny.rstudio.com/gallery/, you’ll see a really cool Shiny App called Google Charts Demo. Click on the app, and then look at the underlying code. Try replicating this app yourself by creating a new app, and copying and pasting the Google Charts demo code into your app. Make sure the app runs. Then, try customising it! For example, you could change the default colors, or include the option for an additional filter in addition to the main “year” filter. Alternatively, you could try applying the chart to a dataset we’ve used in the bootcamp (like mpg
or diamonds
)