Today, we’ll discover how you can use the power of R (and RStudio) to create, for instance, an interactive visualization with the ShinyApp framework.
Shiny is a framework that allows you to create web applications - ShinyApps π You can use them for multiple purposes - a common example is visualizing data (for instance the Scottish Household Survey), building interactive appendices, search engines, and so much more β¨
Alternative text
Scottish Household Survey showing a visualization of data in a line chart
Alternative text
Appendix of an academic paper showing a correlation matrix
Alternative text
Search engine showing a coordinate system where papers are located and a sidebar on the left-hand side that allows the users to select papers relevant to them
A ShinyApp consists of two central components. The UI and the server – or, as I like to think about them, the body π€ and the brain π§
The user interface (or short UI) is like the body of your app π€ It allows you to define how it looks and where the components (such as text, visualizations, or tables) are placed. It defines the outer appearance of your app. The code works as follows:
An image showing a pseudo UI
Alternative text
ui <- fluidPage(
titltePanel("Your Title"),
sidebarLayout(sidebarPanel(... Some content...),
mainPanel(...place-your-plot...))
The server is the brain - here’s where all the computing happens π§ You can dump (more or less) all your typical functions (such as plotting something with π¦{ggplot2}) in here π€ It can look like this:
An image showing a pseudo server
Alternative text
server <- function(input, output{output$first_plot <- renderPlot({...create-your-plot....})}
But how do we set it up? Easy!
Code snapshot showing how to create a simple ShinyApp
Alternative text
###Build your first ShinyApp β¨
library(shiny) # Shiny
library(ggplot2) # For plotting
library(dplyr) # For data wrangling
library(overviewR) # To get the data
data(toydata)
#---------------------------------------------------------#
##UI π€
ui <- fluidPage(titlePanel ("Visualization"),
###Define sidebar
sidebarLayout(sidebarPanel(
checkboxGroupInput(
"countries",
h4("Select the countries"),
choices = unique(toydata$ccode),
selected = c("RWA", "AGO")
)
),
###Show the visualization
mainPanel(plotOutput("first_plot"))))
ππΌββοΈ
#---------------------------------------------------------#
##Server π§
server <- function (input, output) {
output$first_plot <-
renderPlot({
###Generate a normal ggplot2 with some data wrangling
toydata %>%
dplyr::filter(ccode %in% input$countries) %>%
dplyr::mutate(year = as.integer(year)) %>%
ggplot2::ggplot(aes(x = year, y = population)) +
ggplot2::geom_col() +
ggplot2::facet_wrap( ~ ccode) +
ggplot2::theme_minimal()
})
}
#---------------------------------------------------------#
##Let it run ποΈ
shinyApp (ui = ui, server = server)
What you now see in code is how you can fill the UI and server with content. I picked checkboxes for the selection in the sidebar of the UI (but there are multiple other possibilities for more control widgets) and added a ggplot2 inside the renderPlot
function in the server to generate the visualization π©πΌβπ¨
And here’s how it “runs” (just highlight the code and let it run - a new window with your first ShinyApp will open π)
Alternative text
GIF showing how to run code and how a simple ShinyApp showing bar graphs opens
What I learned from building ShinyApps:
To better understand how a ShinyApp works, it’s good to understand reactivity. To describe it, I love the image of a carrier pigeon π¦ (I picked up this idea when reading a post by Garett Grolemund - so all credits go to him β¨):
What reactivity does is “a magic trick [that] creates the illusion that one thing is happening, when in fact something else is going on”. Your ShinyApp only re-runs those parts where it is necessary. But what does this have to do with a carrier pigeon? Have a look at the GIF:
Alternative text
GIF showing a pigeon carrier flying to the server to update a visualization when it is relevant
It shows your ShinyApp (bottom right) and the server (top right). The user (bottom left) asks for something. In the first round, the user asks for “Rwanda” and - after checking, the ShinyApp does not re-run because it already shows Rwanda. In the next round, the user asks for “Rwanda” and “Angola” - the ShinyApp evaluates and initiates a re-run to update the requested selection. Here comes the carrier pigeon π¦ It starts sending the signal to update to the server. Once it has delivered the message, it comes back to where it started and waits until it gets a new message to deliver (just like a carrier pigeon π).
This was a simple wrap-up of Garrett Grolemundβs post - if you want to know more about reactive values and observers, have a look here π©πΌβπ»
More helpful resources:
π And if you also keep thinking about brains and bodies, here is more of it to summarize the key points π€ (also as πPDF for you to download here):
A visual summary of ShinyApps left side:
User interface (body) that defines the outer appearance of the app
An image showing a pseudo UI right side:
Alternative text
ui <- fluidPage(
titltePanel("Your Title"),
sidebarLayout(sidebarPanel(... Some content...),
mainPanel(...place-your-plot...))
server (brain) where all the calculation happens
An image showing a pseudo server
server <- function(input, output{output$first_plot <- renderPlot({...create-your-plot....})}