#
# This is a Shiny web application. You can run the application by clicking
# the "Run App" button above.
#
# Find out more about building applications with Shiny here:
#
# http://shiny.rstudio.com/
#
#load libraries
library(shiny)
library(tidyverse)
library(urbnthemes)
#set urban theme branding
set_urbn_defaults()
# set shiny options
options(shiny.sanitize.errors = TRUE)
options(scipen = 999)
# create user interface
<- fluidPage(
ui
# make sure shiny.css is in www/
# if not, delete the following line
theme = "shiny.css",
#add input to select quantitative variable
selectInput("quantitative",
label = h3("Select Quantitative Variable"),
choices = c("Height" = "height", "Mass" = "mass"),
selected = "height"),
#add input to select categorical variable
selectInput("categorical",
label = h3("Select Categorical Variable"),
choices = c("Name" = "name",
"Skin Color" = "skin_color",
"Hair Color" = "hair_color",
"Homeworld" = "homeworld")),
#create plot
plotOutput("my_plot")
)
# create server session
<- function(input, output) {
server
#create output plot
$my_plot <- renderPlot({
output%>%
starwars slice(1:10) %>%
select(cat = contains(input$categorical),
quant = contains(input$quantitative)) %>%
ggplot() +
geom_col(mapping = aes(x = cat, y = quant))
})
}
# build shiny application
shinyApp(ui = ui, server = server)
R Shiny Apps
What is R Shiny?
R Shiny is an R package that enables the creation of interactive, web-based applications. These apps can be extended with CSS, Javascript and htmlwidgets to add extra pizazz.
What is a typical use case at Urban?
Shiny apps are most often used internally (or sometimes given to partners for private use) to examine data or results with many variables or models. They are great when visual aids would be easier to digest than long tables. For example, if you have a regression model that spits out hundreds of coefficients, or frequency tables for multiple different subsets of data, rather than have dozens of static images to scroll through, shiny lets you visualize them interactively and therefore engage with the results much more easily and intuitively. Below is an example of a shiny app that was developed and shared with a partner that let them select the outcome, regression type, and subgroup and display it all on one plot. Wow!
When to NOT Use a Shiny App
- A public-facing tool is needed
- You have no reason to examine multiple results
- The project is short and/or does not have enough budget
- The results are easily digestible in another format (such as R Quarto)
Getting Started
One quick way to get started using shiny is to use a helpful package made by colleagues at Urban: the urbntemplates
package. This package allows you to automatically generate specific files that you commonly use.
To do this for shiny apps, you can use the urbntemplates::construct_shiny()
function. This will create:
- app.R (do not change the name of this document)
- shiny_instructions.md
- .gitignore
- www/shiny.css (styles for web)
Inside app.R
To create shiny apps, we generally include code in an app.R
file. Each app.R
file should contain:
- A user interface
ui
object that describes how the web page will look - A
server
object, which handles the inputs put in by the user and renders output - A
shinyApp()
function to run the app using the above two objects
User Interface
The user interface portion of the app lays out what the user sees when visiting the webpage. If familiar with HTML, it is similar in that it creates the structure for the webpage.
ui
objects often start with a fluidPage()
function, which generates a page that automatically adjusts to the dimensions of the browser window. You place elements in the this function to add content to the page.
Input and Output functions
In the user interface portion of the app, we can utilize two types of functions: input functions and output functions.
Input Functions
These functions take in information from the user.
For a list of shiny input widgets, you can look at the Shiny Widget Gallery.
Output Functions
Output functions use what has been inputted and renders those inputs into helpful outputs.
Server
The server
function manages what you can think of as the backend of the website. It will point to a list of objects that will be returned every time a user inputs a new value into one of the input objects (and on load). Those objects are then used in the user interface to display the result for the user.
The server
function takes in an input
and output
parameter. You can reference the results of what the user has inputted by the syntax input$variable
, where variable
is the ID of the input object that you’ve created in the user interface. Generally, those ID’s are the first parameter in widget functions.
Inside of the server
function, we create multiple output
objects with the syntax output$first_plot
, where first_plot
refers to an ID inside an output function in the user interface. Again, the ID’s are generally the first parameters of these functions.
Render functions
Each output object in the server function should have a render*
function. These functions capture the reactive input from the user and create the relevant object.
Each render function takes in one argument surrounded by braces, from which you can include whatever code you need to output the type of object you want to output.
Examples
#
# This is a Shiny web application. You can run the application by clicking
# the "Run App" button above.
#
# Find out more about building applications with Shiny here:
#
# http://shiny.rstudio.com/
#
#load libraries
library(shiny)
library(tidyverse)
library(urbnthemes)
set_urbn_defaults()
# set shiny options
options(shiny.sanitize.errors = TRUE)
options(scipen = 999)
#read in dataset with coefficients and standard errors
<- read_csv("data/models.csv")
my_models
#pull unique model names to use later as choices user has to select from
<- my_models %>%
unique_regs pull(var) %>%
unique()
#user interface of app (what is shown on screen)
<- navbarPage("Example Regression App",
ui # make sure shiny.css is in www/
# if not, delete the following line
theme = "shiny.css",
#Create multiple tabs
tabPanel("Regression Plots",
#create sidebar/mainbar layout
sidebarLayout(
#create side panel
sidebarPanel(
#set width of panel (12 max)
width = 3,
#set style for sidebar panel
style = "background-color: #ffffff;",
#add row
fluidRow(
#add column
column(width = 5,
#add urban logo
$img(width = "250%",
tagsheight = "125%",
src = "images/urban-institute-logo.png"))),
#add empty lines
br(),
br(),
br(),
#create row
fluidRow(
#create dropdown radio buttons for regression
checkboxGroupInput(inputId = "var",
label = "Choose Dependent Variable",
choices = unique_regs,
selected = unique_regs),
selectInput(inputId = "log",
label = "Choose Whether to Log Outcome",
choices = c("Unlogged" = FALSE, "Logged" = TRUE),
selected = "Unlogged"),
)
),#create main area to plot
mainPanel(
#add empty rows
br(),
br(),
br(),
#add row
fluidRow(
width = 3,
#add plot
plotOutput(outputId = "main_plot")),
br(),
br(),
br(),
br()
))),#Add about page
tabPanel("About",
fluidRow(
column(width = 6,
offset = 3,
style = "padding-left: 3%",
h4("This is an About page."))))
)
# create server session
<- function(input, output) {
server
#Render plot
$main_plot <- renderPlot({
output
#filter dataset based on input from users
<- my_models %>%
my_dat filter(var %in% input$var,
== input$log) %>%
log #create lower and higher bounds for error bar and create a factor variable for significane
mutate(se_low = est - ((1.96) * se ),
se_high = est + ((1.96 * se)),
is_sig_t = p_val <.05,
is_sig = if_else(is_sig_t, "Significant", "Not Significant") %>% factor)
#create a dataset that's long in order to easily graph error bar
<- pivot_longer(my_dat, cols = c(se_low, se_high), values_to = "my_value")
dat_long
#create graph
<- my_dat %>%
my_plot ggplot() +
geom_point(mapping = aes(x = var, y = est, color = is_sig)) +
geom_line(data= dat_long, mapping = aes(x = var, y =my_value, color = is_sig), alpha = .5) +
scale_color_manual(values = c("Significant" = palette_urbn_cyan[4], "Not Significant" = palette_urbn_magenta[5]), drop = FALSE) +
geom_hline( yintercept = 0, linetype = "dashed", color = palette_urbn_yellow[5]) +
scale_y_continuous(labels = scales::comma) +
coord_flip() +
labs(y = input$var,
x = NULL) +
theme(legend.text = element_text(size = 15, family = "Lato"),
axis.text = element_text(size = 12, family = "Lato"),
axis.title = element_text(size = 15, family = "Lato"))
#return graph
return(my_plot)
height = 550, width = 850)
},
}
# build shiny application
shinyApp(ui = ui, server = server)