End of post has working Shiny code
My code takes user inputs and produces two charts.
Each chart has their own renderPlot
section in Server
which saves the same variables twice, i.e.
what_races <- input$race
what_ages<- c(input$age[1],input$age[2])
and uses the same if statement to call a different function in helpers.R, i.e.
if ((length(what_races) > 0 ) & !is.null(what_ages))
And the two functions in helpers.R use the same code repeatedly.
How do I simplify the coding. I have searched Shiny samples, but lot of data is from pre-packaged libraries, so one cannot see under the hood.
Any guidance is greatly appreciated.
app.R
# Load packages ----
library(shiny)
library(ggplot2)
library(dplyr)
library(scales)
library(treemapify)
library(RColorBrewer)
library(forcats)
# Source helpers ----
source("helpers.R")
# Load data ----
data(Marriage, package="mosaicData")
# User interface ----
ui <- fluidPage(
fluidRow(
titlePanel(
h4("Marriage records from the Mobile County, Alabama, probate court.",
style='color:black;padding-left: 15px'))
),
br(),
fluidRow(
column(2,
checkboxGroupInput("race","Races to show",
c("White", "Black","American Indian", "Hispanic")),
sliderInput("age", "Age Range",min = as.integer(min(Marriage$age)), max = as.integer(max(Marriage$age)),value = c(min,max))
),
column(5,
plotOutput("tree"), style='height:100px'),
column(5,
plotOutput("chart"), style='height:100px')
)
)
server <- function(input, output) {
output$tree <- renderPlot({
what_races <- input$race
what_ages<- c(input$age[1],input$age[2])
if ((length(what_races) > 0 ) & !is.null(what_ages)) {
plot_tree(what_races,what_ages)
}
}
)
output$chart <- renderPlot({
what_races <- input$race
what_ages<- c(input$age[1],input$age[2])
if ((length(what_races) > 0 ) & !is.null(what_ages)) {
plot_bar(what_races,what_ages)
}
}
)
}
# Run the app
shinyApp(ui, server)
helpers.R
plot_tree <- function(what_races,what_ages) {
plotdata <- dplyr::filter(Marriage, race %in% what_races, age >= what_ages[1], age <= what_ages[2]) %>%
count(officialTitle)
plotdata <- na.omit(plotdata)
if (nrow(plotdata) > 0) {
ggplot(plotdata,
aes(fill = officialTitle,
area = n,
label = officialTitle)) +
geom_treemap() +
geom_treemap_text(colour = "white",
place = "centre") +
labs(title = "Marriages by officiate") +
theme(plot.title = element_text(color="black", size=14, face="bold"),legend.position = "none")
} else { }
}
plot_bar <- function(what_races,what_ages) {
plotdata <- dplyr::filter(Marriage, race %in% what_races, age >= what_ages[1], age <= what_ages[2])
plotdata$prevconc <- as.character(plotdata$prevconc)
plotdata$prevconc[is.na(plotdata$prevconc)] <- "Never Married"
plotdata <- na.omit(plotdata)
if (nrow(plotdata) > 0) {
ggplot(plotdata,
aes(x = sign,
fill = prevconc)) +
geom_bar(position = "stack") +
labs("Race per Astrological Sign") +
theme(legend.position = "top") +
coord_flip()
} else {}
}
A function is the way to go. They are useful for avoiding repeated code; making your code shorter and easier to maintain. You've got them in action already in creating your plots.
func_check_inputs <- function() {
what_races <<- input$race
what_ages <<- c(input$age[1], input$age[2])
if (length(what_races) > 0 & !is.null(what_ages)) {return(TRUE)} else {return(FALSE)}
}
As you use what_races
and what_ages
later, outside of the function, we'll make them global variables by using the <<-
operator.
Here is that function in your full app:
# Load packages ----
library(shiny)
library(ggplot2)
library(dplyr)
library(scales)
library(treemapify)
library(RColorBrewer)
library(forcats)
library(mosaicData)
# Source helpers ----
source("helpers.R")
# Load data ----
data(Marriage, package="mosaicData")
# User interface ----
ui <- fluidPage(
fluidRow(
titlePanel(
h4("Marriage records from the Mobile County, Alabama, probate court.", style='color:black;padding-left: 15px')
)
),
br(),
fluidRow(
column(2,
checkboxGroupInput("race", "Races to show", c("White", "Black", "American Indian", "Hispanic")),
sliderInput("age", "Age Range", min = as.integer(min(Marriage$age)), max = as.integer(max(Marriage$age)),value = c(min, max))
),
column(5,
plotOutput("tree"), style='height:100px'
),
column(5,
plotOutput("chart"), style='height:100px'
)
)
)
server <- function(input, output) {
#Function to check if inputs are valid
func_check_inputs <- function() {
#Make what_races and what_ages global variables
what_races <<- input$race
what_ages <<- c(input$age[1], input$age[2])
if (length(what_races) > 0 & !is.null(what_ages)) {return(TRUE)} else {return(FALSE)}
}
output$tree <- renderPlot({
if (func_check_inputs() == TRUE) {plot_tree(what_races, what_ages)}
})
output$chart <- renderPlot({
if (func_check_inputs() == TRUE) {plot_tree(what_races, what_ages)}
})
}
# Run the app
shinyApp(ui, server)