For a few days I've been working on an app with the shiny
library and now I would like to test the new adaptations with the shinydashboard
package. The problem is that my plot does not show up (render) in the tab that I would like it to appear when I set the inputs in the sidebar.
Using only the shiny package, I've set the following code, with no menu sidebar (as in shinydashboard):
library(shiny)
library(ggplot2)
library(dplyr)
rm(list=ls()); gc()
#functions to order the bar graph
reorder_within <- function(x, by, within, fun = mean, sep = "___", ...) {
new_x <- paste(x, within, sep = sep)
stats::reorder(new_x, by, FUN = fun)
}
scale_x_reordered <- function(..., sep = "___") {
reg <- paste0(sep, ".+$")
ggplot2::scale_x_discrete(labels = function(x) gsub(reg, "", x), ...)
}
#setting example data
sample_data = data.frame(Company_Name=c("Company 1","Company 2","Company 3",
"Company 1","Company 2","Company 3",
"Company 1","Company 2","Company 3"),
Profits_MM = c(20,100,80,
45,120,70,
50,110,130),
Sales_MM = c(200,800,520,
300,1000,630,
410,1150,1200),
Year=c(2016,2016,2016,
2017,2017,2017,
2018,2018,2018))
# UI
ui <- fluidPage(
sidebarLayout(
# Input(s)
sidebarPanel(
checkboxGroupInput(inputId = "sel_com",
label = "Company Selection:",
choices = c("Company 1","Company 2","Company 3"),
selected = "Company 1"),
selectInput(inputId = "y",
label = "Performance Variable",
choices = c("Profits (in Millions)" = "Profits_MM",
"Sales (in Millions)" = "Sales_MM"),
selected = "Profits_MM"),
sliderInput("year","Year Selection:",
min=2016,
max=2018,
value=c(2017,2018),
step=1)
),
# Output(s)
mainPanel(
plotOutput(outputId = "barplot")
)
)
)
# Server
server <- function(input, output, session) {
companies_sel <- reactive({
req(input$sel_com)
sample_data_gg = filter(sample_data, Company_Name %in% input$sel_com)
# print(sample_data_gg)
sample_data_gg
})
year_sample <- reactive({
req(input$year)
sample_data_gg = sample_data
if((input$year[2] - input$year[1])>1){
Years = seq(input$year[1],input$year[2])
sample_data_gg = filter(companies_sel(), Year %in% Years)
}
if((input$year[2] - input$year[1])==1){
sample_data_gg = filter(companies_sel(), Year %in% input$year)
}
# print(sample_data_gg)
sample_data_gg
})
output$barplot = renderPlot({
sample_data_gg = year_sample()
y <- input$y
ggplot(data = sample_data_gg, aes(x=reorder_within(Company_Name, get( y ), Year), y = get( y ))) +
geom_col(position="dodge", fill="darkred") +
facet_wrap(Year~., scales = "free") +
scale_x_reordered() +
theme(axis.text.x = element_text(angle = 60, hjust = 1))
})
}
shinyApp(ui = ui, server = server)
This code works within the shiny package and shows the type of plot that I would like to show up in the app.
But if I change this coding for the shinydashboard
package -- while setting the inputs inside the sidebar -- the plot does not show up and I'm trying to figure out why. Here it is the code:
library(shiny)
library(ggplot2)
library(dplyr)
library(shinydashboard)
reorder_within <- function(x, by, within, fun = mean, sep = "___", ...) {
new_x <- paste(x, within, sep = sep)
stats::reorder(new_x, by, FUN = fun)
}
scale_x_reordered <- function(..., sep = "___") {
reg <- paste0(sep, ".+$")
ggplot2::scale_x_discrete(labels = function(x) gsub(reg, "", x), ...)
}
rm(list=ls()); gc()
sample_data = data.frame(Company_Name=c("Company 1","Company 2","Company 3",
"Company 1","Company 2","Company 3",
"Company 1","Company 2","Company 3"),
Profits_MM = c(20,100,80,
45,120,70,
50,110,130),
Sales_MM = c(200,800,520,
300,1000,630,
410,1150,1200),
Year=c(2016,2016,2016,
2017,2017,2017,
2018,2018,2018))
# UI
ui <- dashboardPage(
dashboardHeader(title = "Dashboard Test"),
dashboardSidebar(
sidebarMenu(id="tab",
menuItem("Data Selection", tabName = "dc", icon = icon("dashboard"),
checkboxGroupInput(inputId = "sel_com",
label = "Company Selection:",
choices = c("Company 1","Company 2","Company 3"),
selected = "Company 1"),
selectInput(inputId = "y",
label = "Performance Variable",
choices = c("Profits (in Millions)" = "Profits_MM",
"Sales (in Millions)" = "Sales_MM"),
selected = "Profits_MM"),
sliderInput("year","Year Selection:",
min=2016,
max=2018,
value=c(2017,2018),
step=1)))),
dashboardBody(
tabItems(
# First tab content
tabItem(tabName = "dc",
fluidRow(column(width=12,box(plotOutput("plot1")))
)
)
)
)
)
# Server
server <- function(input, output, session) {
companies_sel <- reactive({
req(input$sel_com)
sample_data_gg = filter(sample_data, Company_Name %in% input$sel_com)
# print(sample_data_gg)
sample_data_gg
})
year_sample <- reactive({
req(input$year)
sample_data_gg = sample_data
if((input$year[2] - input$year[1])>1){
Years = seq(input$year[1],input$year[2])
sample_data_gg = filter(companies_sel(), Year %in% Years)
}
if((input$year[2] - input$year[1])==1){
sample_data_gg = filter(companies_sel(), Year %in% input$year)
}
# print(sample_data_gg)
sample_data_gg
})
output$barplot = renderPlot({
sample_data_gg = year_sample()
y <- input$y
ggplot(data = sample_data_gg, aes(x=reorder_within(Company_Name, get( y ), Year), y = get( y ))) +
geom_col(position="dodge", fill="darkred") +
facet_wrap(Year~., scales = "free") +
scale_x_reordered() +
theme(axis.text.x = element_text(angle = 60, hjust = 1))
})
}
shinyApp(ui = ui, server = server)
I believe I might be missing some interaction between the barplot and the input selection in the sidebar, but I cannot figure exactly what is wrong.
You actually had a few issues in your code that were collectively causing the issue:
First: The first was identified in the comments - your use of
rm(list=ls())
was deleting functions that you needed later.Second: Your
plotOutput()
was using the id"plot1"
while your renderPlot was referring to"barplot"
. I assume that was a simple translation error from when you were switching over toshinydashboard
. Make them the same and that will help.Third: This was the more serious of the three.
shinydashboard
has a known issue, described very well here, where multiple elements withinmenuItem
cause the loss of the attributes that link the content totabItem
s. You can overcome that with a custom function that sets those values manually, and then wrap yourmenuItem
calls in that function, taking care to specify the tabName in the function.Updated UI for your situation would look like this: