Display line plot when condition is met in data entry - r

I am building a shiny budgeting shiny application that prompts the user to enter data such as what type of expense was spent, the amount, and a description. I would like to display a line plot in the second pannel of the application labeled "Monthly Budget" ONLY when the user has entered at least one data entry where the category is "Savings". I have tried experimenting with things such as hiding/displaying the plot whenever the condition is met, but it seems that I always get a NaN error message with this approach. Thus, I am experimenting with conditionalPanel() in hopes of accomplishing this task. I've noticed similar posts to this one, however this is the first case that I have found where conditionalPanel() deals with data that the user inputs as opposed to a given dataset. In the code below I get the following error message: "Error in: Invalid input: date_trans works with objects of class Date only".
Here is the code:
# Libraries
library(shiny)
library(ggplot2)
library(shinycssloaders)
library(colortools)
library(shinythemes)
library(DT)
library(tidyverse)
library(kableExtra)
library(formattable)
library(xts)
# Creating Contrasting Colors For Buckets
bucket_colors <- wheel("skyblue", num = 6)
# Define UI for application that draws a histogram
ui <- fluidPage(
# theme = shinytheme("spacelab"),
shinythemes::themeSelector(),
## Application Title
titlePanel("2021 Budgeting & Finances"),
tags$em("By:"),
tags$hr(),
navbarPage("", id = "Budget",
tabPanel("Data Entry",
div(class = "outer",
# Sidebar Layout
sidebarLayout(
sidebarPanel(
selectInput("Name",
label = "Name:",
choices = c("","Jack", "Jill")),
selectInput("Bucket",
label = "Item Bucket:",
choices = c("","Essential", "Non-Essential", "Savings", "Rent/Bills", "Trip", "Other")),
textInput("Item",
label = "Item Name:",
placeholder = "Ex: McDonald's"),
shinyWidgets::numericInputIcon("Amount",
"Amount:",
value = 0,
step = 0.01,
min = 0,
max = 1000000,
icon = list(icon("dollar"), NULL)),
dateInput("Date",
label = "Date",
value = Sys.Date(),
min = "2021-05-01",
max = "2022-12-31",
format = "M-d-yyyy"),
actionButton("Submit", "Submit", class = "btn btn-primary"),
downloadButton("Download", "Download")),
# Show a plot of the generated distribution
mainPanel(
tableOutput("PreviewTable")
)
)
)
),
############ THIS IS WHERE THE ERROR HAPPENS #############
tabPanel("Monthly Budget",
conditionalPanel("output.any(ReactiveDf() == 'Savings') == TRUE ",
plotOutput("SavingsPlot")
)
########### THIS IS WHERE THE ERROR HAPPENS ##############
),
tabPanel("Budget to Date",
tableOutput("YearTable")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output, session) {
## SAVE DATA
# Set Up Empty DF
df <- tibble("Name" = character(),
"Date" = character(),
"Category" = character(),
"Amount" = numeric(),
"Description" = character())
# DF is made reactive so we can add new lines
ReactiveDf <- reactiveVal(value = df)
# Add inputs as new data (lines)
observeEvent(input$Submit, {
if (input$Bucket == "" | input$Amount == 0 |
is.na(input$Amount)) {
return(NULL)
}
else {
# New lines are packaged together in a DF
new_lines <- data.frame(Name = as.character(input$Name),
Date = as.character(input$Date),
Category = input$Bucket,
Amount = as.character(input$Amount),
Description = as.character(input$Item))
# change df globally
df <<- rbind(df, new_lines)
# ensure amount is numeric
df <<- df %>%
mutate("Amount" = as.numeric(Amount))
# Update reactive values
ReactiveDf(df)
#clear out original inputs now that they are written to df
updateSelectInput(session, inputId = "Name", selected = "")
updateSelectInput(session, inputId = "Bucket", selected = "")
updateNumericInput(session, inputId = "Amount", value = 0)
updateTextInput(session, inputId = "Item", value = "")
}
})
## Preview Table
observeEvent(input$Submit, {
output$PreviewTable <-
function(){
ReactiveDf()[order(ReactiveDf()$Date, decreasing = TRUE),] %>%
kable("html") %>%
kable_material(c("striped", "hover")) %>%
kable_styling("striped", full_width = TRUE) %>%
column_spec(3, color = "black", background = ifelse(ReactiveDf()[3]=="Essential", "#87CEEB", ifelse(ReactiveDf()[3] == "Non-Essential", "#EBA487", ifelse(ReactiveDf()[3] == "Savings", "#87EBA4", ifelse(ReactiveDf()[3] == "Rent/Bills", "#A487EB", ifelse(ReactiveDf()[3] == "Trip", "#CEEB87", "#EB87CE")))))) %>%
column_spec(1, color = ifelse(ReactiveDf()[1] == "Ashley", "lightpink", "lightcyan"))
}
########## THIS IS THE LINE PLOT I AM TRYING TO RENDER ##########
output$SavingsPlot <- renderPlot({
savings <- ReactiveDf()[ReactiveDf()$Category == "Savings",]
savings <- savings[, -c(1,3,5)]
savings$Date <- as.Date(savings$Date)
savings$Amount <- as.numeric(savings$Amount)
savings <- as.xts(savings$Amount, order.by = as.Date(savings$Date))
weekly <- apply.weekly(savings,sum)
weekly_savings <- as.data.frame(weekly)
weekly_savings$names <- rownames(weekly_savings)
rownames(weekly_savings) <- NULL
colnames(weekly_savings) <- c("Amount", "Date")
Expected <- NULL
for(i in 1:dim(weekly_savings)[1]){
Expected[i] <- i * 625
}
weekly_savings$Expected <- Expected
ggplot(weekly_savings, aes(x = Date)) +
geom_line(aes(y = Expected), color = "red") +
geom_line(aes(y = Amount), color = "blue") +
ggtitle("House Downpayment Savings Over Time") +
ylab("Dollars") +
scale_x_date(date_minor_breaks = "2 day") +
scale_y_continuous(labels=scales::dollar_format())
})
})
########## THIS IS THE LINE PLOT I AM TRYING TO RENDER ##########
# Downloadable csv of selected dataset ----
output$Download <- downloadHandler(
filename = function() {
paste("A&J Budgeting ", Sys.Date(),".csv", sep = "")
},
content = function(file) {
write.csv(ReactiveDf(), file, row.names = FALSE)
}
)
# use if df new lines have errors
observeEvent(input$start_over, {
# change df globally
df <- tibble("Name" = character(),
"Date" = character(),
"Expense Category" = character(),
"Amount" = numeric(),
"Description" = character())
# Update reactive values to empty out df
ReactiveDf(df)
})
## MONTHLY TABLE
output$MonthlyTable <- renderTable({
ReactiveDf()
})
## YEAR TO DATE TABLE
output$YearTable <- renderTable({
ReactiveDf()
})
}
# Run the application
shinyApp(ui = ui, server = server)

We can use a condition like nrow(filter(ReactiveDf(), Category == 'Savings')) > 0 as if ReactiveDf is a normal df. Also, when converting the xts object to a df the Date column was coerced to character.
app:
# Libraries
library(shiny)
library(tidyverse)
library(shinycssloaders)
library(colortools)
library(shinythemes)
library(DT)
library(tidyverse)
library(kableExtra)
library(formattable)
library(xts)
library(lubridate)
# Creating Contrasting Colors For Buckets
bucket_colors <- wheel("skyblue", num = 6)
# Define UI for application that draws a histogram
ui <- fluidPage(
# theme = shinytheme("spacelab"),
shinythemes::themeSelector(),
## Application Title
titlePanel("2021 Budgeting & Finances"),
tags$em("By:"),
tags$hr(),
navbarPage("", id = "Budget",
tabPanel("Data Entry",
div(class = "outer",
# Sidebar Layout
sidebarLayout(
sidebarPanel(
selectInput("Name",
label = "Name:",
choices = c("","Jack", "Jill")),
selectInput("Bucket",
label = "Item Bucket:",
choices = c("","Essential", "Non-Essential", "Savings", "Rent/Bills", "Trip", "Other")),
textInput("Item",
label = "Item Name:",
placeholder = "Ex: McDonald's"),
shinyWidgets::numericInputIcon("Amount",
"Amount:",
value = 0,
step = 0.01,
min = 0,
max = 1000000,
icon = list(icon("dollar"), NULL)),
dateInput("Date",
label = "Date",
value = Sys.Date(),
min = "2021-05-01",
max = "2022-12-31",
format = "M-d-yyyy"),
actionButton("Submit", "Submit", class = "btn btn-primary"),
downloadButton("Download", "Download")),
# Show a plot of the generated distribution
mainPanel(
tableOutput("PreviewTable")
)
)
)
),
tabPanel("Monthly Budget",
plotOutput("SavingsPlot")
),
tabPanel("Budget to Date",
tableOutput("YearTable")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output, session) {
## SAVE DATA
# Set Up Empty DF
df <- tibble("Name" = character(),
"Date" = character(),
"Category" = character(),
"Amount" = numeric(),
"Description" = character())
# DF is made reactive so we can add new lines
ReactiveDf <- reactiveVal(value = df)
# Add inputs as new data (lines)
observeEvent(input$Submit, {
if (input$Bucket == "" | input$Amount == 0 |
is.na(input$Amount)) {
return(NULL)
}
else {
# New lines are packaged together in a DF
new_lines <- data.frame(Name = as.character(input$Name),
Date = as.character(input$Date),
Category = input$Bucket,
Amount = as.character(input$Amount),
Description = as.character(input$Item))
# change df globally
df <<- rbind(df, new_lines)
# ensure amount is numeric
df <<- df %>%
mutate("Amount" = as.numeric(Amount))
# Update reactive values
ReactiveDf(df)
#clear out original inputs now that they are written to df
updateSelectInput(session, inputId = "Name", selected = "")
updateSelectInput(session, inputId = "Bucket", selected = "")
updateNumericInput(session, inputId = "Amount", value = 0)
updateTextInput(session, inputId = "Item", value = "")
}
})
## Preview Table
observeEvent(input$Submit, {
output$PreviewTable <-
function(){
ReactiveDf()[order(ReactiveDf()$Date, decreasing = TRUE),] %>%
kable("html") %>%
kable_material(c("striped", "hover")) %>%
kable_styling("striped", full_width = TRUE) %>%
column_spec(3, color = "black", background = ifelse(ReactiveDf()[3]=="Essential", "#87CEEB", ifelse(ReactiveDf()[3] == "Non-Essential", "#EBA487", ifelse(ReactiveDf()[3] == "Savings", "#87EBA4", ifelse(ReactiveDf()[3] == "Rent/Bills", "#A487EB", ifelse(ReactiveDf()[3] == "Trip", "#CEEB87", "#EB87CE")))))) %>%
column_spec(1, color = ifelse(ReactiveDf()[1] == "Ashley", "lightpink", "lightcyan"))
}
########## THIS IS THE LINE PLOT I AM TRYING TO RENDER ##########
if (nrow(filter(ReactiveDf(), Category == 'Savings')) > 0) {
output$SavingsPlot <- renderPlot({
savings <- filter(ReactiveDf(), Category == 'Savings')
savings$Date <- as.Date(savings$Date, format = "%Y-%m-%d")
savings$Amount <- as.numeric(savings$Amount)
savings <- as.xts(savings$Amount, order.by = savings$Date)
weekly <- apply.weekly(savings, sum)
weekly_savings <- as.data.frame(weekly)
weekly_savings$names <- rownames(weekly_savings)
rownames(weekly_savings) <- NULL
colnames(weekly_savings) <- c("Amount", "Date")
Expected <- NULL
for(i in 1:dim(weekly_savings)[1]){
Expected[i] <- i * 625
}
weekly_savings$Expected <- Expected
ggplot(weekly_savings, aes(x = ymd(Date))) +
geom_line(aes(y = Expected), color = "red") +
geom_line(aes(y = Amount), color = "blue") +
ggtitle("House Downpayment Savings Over Time") +
ylab("Dollars") +
scale_x_date(date_minor_breaks = "2 day") +
scale_y_continuous(labels=scales::dollar_format())
}) }
})
########## THIS IS THE LINE PLOT I AM TRYING TO RENDER ##########
# Downloadable csv of selected dataset ----
output$Download <- downloadHandler(
filename = function() {
paste("A&J Budgeting ", Sys.Date(),".csv", sep = "")
},
content = function(file) {
write.csv(ReactiveDf(), file, row.names = FALSE)
}
)
# use if df new lines have errors
observeEvent(input$start_over, {
# change df globally
df <- tibble("Name" = character(),
"Date" = character(),
"Expense Category" = character(),
"Amount" = numeric(),
"Description" = character())
# Update reactive values to empty out df
ReactiveDf(df)
})
## MONTHLY TABLE
output$MonthlyTable <- renderTable({
ReactiveDf()
})
## YEAR TO DATE TABLE
output$YearTable <- renderTable({
ReactiveDf()
})
}
# Run the application
shinyApp(ui = ui, server = server)

Related

Converting Reactive Data Table to Kable in Shiny

I am currently building a budgeting shiny application that prompts users to enter information of their past transactions such as: Amount, Type, and Description. I would like to have this information displayed in a Kable styled table in a seperate tab whenever a user hits submit, however, when I do this I get the following message and the table does not display:
"Warning: Error in as.data.frame.default: cannot coerce class ‘c("kableExtra", "knitr_kable")’ to a data.frame"
Here is what I have coded so far:
# Libraries
library(shiny)
library(ggplot2)
library(shinythemes)
library(DT)
library(kableExtra)
ui <- fluidPage(
theme = shinytheme("spacelab"),
## Application Title
titlePanel("2021 Budgeting & Finances"),
tags$em("By:"),
tags$hr(),
navbarPage("", id = "Budget",
tabPanel("Data Entry",
div(class = "outer",
# Sidebar Layout
sidebarLayout(
sidebarPanel(
selectInput("Name",
label = "Name:",
choices = c("","Jack", "Jill")),
selectInput("Bucket",
label = "Item Bucket:",
choices = c("","Essential", "Non-Essential", "Savings", "Rent/Bills", "Trip", "Other")),
textInput("Item",
label = "Item Name:",
placeholder = "Ex: McDonald's"),
shinyWidgets::numericInputIcon("Amount",
"Amount:",
value = 0,
step = 0.01,
min = 0,
max = 1000000,
icon = list(icon("dollar"), NULL)),
dateInput("Date",
label = "Date",
value = Sys.Date(),
min = "2021-05-01",
max = "2022-12-31",
format = "M-d-yyyy"),
actionButton("Submit", "Submit", class = "btn btn-primary"),
downloadButton("Download", "Download")),
# Show a plot of the generated distribution
mainPanel(
dataTableOutput("PreviewTable")
)
)
)
),
tabPanel("Monthly Budget",
tableOutput("MonthlyTable")
),
tabPanel("Budget to Date",
tableOutput("YearTable")
)
)
)
server <- function(input, output, session) {
## SAVE DATA
# Set Up Empty DF
df <- tibble("Name" = character(),
"Date" = character(),
"Category" = character(),
"Amount" = numeric(),
"Description" = character())
# DF is made reactive so we can add new lines
ReactiveDf <- reactiveVal(value = df)
# Add inputs as new data (lines)
observeEvent(input$Submit, {
if (input$Bucket == "" | input$Amount == 0 |
is.na(input$Amount)) {
return(NULL)
}
else {
# New lines are packaged together in a DF
new_lines <- data.frame(Name = as.character(input$Name),
Date = as.character(input$Date),
Category = input$Bucket,
Amount = as.character(input$Amount),
Description = as.character(input$Item))
# change df globally
df <<- rbind(df, new_lines)
# ensure amount is numeric
df <<- df %>%
mutate("Amount" = as.numeric(Amount))
# Update reactive values
ReactiveDf(df)
#clear out original inputs now that they are written to df
updateSelectInput(session, inputId = "Name", selected = "")
updateSelectInput(session, inputId = "Bucket", selected = "")
updateNumericInput(session, inputId = "Amount", value = 0)
updateTextInput(session, inputId = "Item", value = "")
}
})
## Preview Table
output$PreviewTable <- renderTable({
ReactiveDf()
})
## MONTHLY TABLE
output$MonthlyTable <- renderTable({
ReactiveDf() %>%
kbl()
})
## YEAR TO DATE TABLE
output$YearTable <- renderTable({
ReactiveDf()
})
}
# Run the application
shinyApp(ui = ui, server = server)
Ideally what I would like to have is a table preview on the main page where the user enters their information that updates once the user submits their data. Then, I would like the month tab to populate with only the data relating to the current month and the year tab to have all information for the current year. However the biggest issue currently is that the kable table is not displaying. Any help is greatly appreciated!
Kable is plain Html so it doesn't require special render functions. This should work.
## MONTHLY TABLE
output$MonthlyTable <- function(){
ReactiveDf() %>%
kable("html") %>%
kable_styling("striped", full_width = TRUE)
}

Using R Shiny User Input with RSQLite

I want to create a shiny app that takes the first date range as inputs for the SQL command to query from the RSQLite db I created. However, when I run this without having a df object prior to running the app, it does not work. If I try to update the long lat slider ranges that are currently commented out, this crashes the app. I also keep getting this error: Warning in if (!loaded) { :
the condition has length > 1 and only the first element will be used
c("Loading required package: [", "Loading required package: input$timestamp", "Loading required package: 1")
Failed with error: ‘'package' must be of length 1’
Can anyone help? I just want the user to give me the first date and last date ranges to query the database and then have dplyr do the rest of the filtering.
library(dplyr)
library(htmltools)
library(leaflet)
library(leafem)
library(shiny)
library(shinyjs)
library(shinyWidgets)
library(shinythemes)
library(shinyBS)
#Create a formatted timestamp for filename
humanTime <- function() format(Sys.time(), "%Y-%m-%d_%H-%M-%OS")
#Create a Dummy Dataset
get_data <- function(size){
df <- data.frame(OBJECT_ID = seq(from =1, to = size, by = 1))
df$LONGITUDE <- sample(seq(from=-20, to =160, by = 0.01), size, rep= TRUE)
df$LATITUDE <- sample(seq(from = -10, to= 83, by = 0.01), size, rep= TRUE)
df$LOCATION <- sample(c("A", "B", "C"), size, replace = T, prob = c(0.4, 0.4, 0.2))
df$EQUIPMENT <- sample(c("E1", "E2", "E3", "E4"), size, replace = TRUE)
startTime <- as.POSIXct("2016-01-01")
endTime <- as.POSIXct("2019-01-31")
df$DATE <- as.character(as.Date(sample(seq(startTime, endTime, 1), size))) #use as.Date to remove times
df$WEEKDAY <- weekdays(as.Date(df$DATE))
return(df)
}
#Is this necessary to get the ranges for the slider values?
df <- get_data(200)
df$DATE <- as.Date(df$DATE)
df <- df %>% mutate_if(is.character, as.factor)
ui <- navbarPage(
id = "navBar",
title = "Data Exploration",
theme = shinytheme("cerulean"),
shinyjs::useShinyjs(),
selected = "Data",
tabPanel("Data",
fluidPage(
sidebarPanel(
div(id = "form",
dateRangeInput('timestamp', label = 'Date range input:', start = '', end = ''),
pickerInput('days_of_week', 'Choose Weekdays:', choices = c("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"), options = list(`actions-box` = TRUE), multiple = T),
sliderInput('long', "Longitude Range:", min = min(df$LONGITUDE),max = max(df$LONGITUDE), value = c(min(df$LONGITUDE), max(df$LONGITUDE)), step = 0.1),
sliderInput('lat', "Latitude Range:", min = min(df$LATITUDE),max = max(df$LATITUDE), value = c(min(df$LATITUDE), max(df$LATITUDE)), step = 0.1),
pickerInput('location', "Select Location:", choices = unique(df$LOCATION), options = list(`actions-box` = TRUE), multiple = T),
pickerInput('equipment_type', "Choose Equipment:", choices = unique(df$EQUIPMENT), options = list(`actions-box` = TRUE), multiple = T),
actionButton("resetAll", "Reset Filters"),
selectInput("download_type", "Choose download formatt:", choices = c("CSV" = ".csv", "KML" = ".KML")))
),
mainPanel(
leafletOutput("datamap", width = "100%", height = 400),
DT::DTOutput('datatable')))
)
)#end the ui
server <- function(session, input, output){
filter_by_dates <- reactive({
require(input$timestamp[1])
require(input$timestamp[2])
my_conn <- dbConnect(RSQLite::SQLite(), "sample.db")
df <- DBI::dbGetQuery(my_conn, paste0("SELECT * FROM Table_1 WHERE DATE >= '", input$timestamp[1], "' AND DATE <= '", input$timestamp[2], "'"))
df$DATE <- as.Date(df$DATE)
df <- df %>% mutate_if(is.character, as.factor)
DBI::dbDisconnect(my_conn)
return(df)
})
filter_by_all <- reactive({
fd <- filter_by_dates()
if (!is.null(input$days_of_week)) {
fd <- filter(fd, WEEKDAY %in% input$days_of_week)
}
if (!is.null(input$long[1] & input$long[2])){
fd <- filter(fd, LONGITUDE >= input$long[1] & LONGITUDE <= input$long[2])
}
if (!is.null(input$lat[1] & input$lat[2])){
fd <- filter(fd, LATITUDE >= input$lat[1] & LATITUDE <= input$lat[2])
}
if (!is.null(input$location)) {
fd <- filter(fd, LOCATION %in% input$location)
}
if (!is.null(input$equipment_type)) {
fd <- filter(fd, EQUIPMENT %in% input$equipment_type)
}
return(fd)
})
observe({
require(input$timestamp[1])
require(input$timestamp[2])
updatePickerInput(session, 'days_of_week', 'Choose Weekdays:', choices = sort(unique(filter_by_all()$WEEKDAY), decreasing = T), selected = sort(input$days_of_week, decreasing = T))
#updateSliderInput(session, 'long', "Longitude Range:", min=min(filter_by_all()$LONGITUDE), max = max(filter_by_all()$LONGITUDE), value = c(input$long[1], input$long[2]))
#updateSliderInput(session, 'lat', "Latitude Range:", min=min(filter_by_all()$LATITUDE), max = max(filter_by_all()$LATITUDE), value = c(input$lat[1], input$lat[2]))
updatePickerInput(session, 'location', "Select Location:", choices = unique(filter_by_all()$LOCATION), selected = input$location)
updatePickerInput(session, 'equipment_type', "Choose Equipment:", choices = unique(filter_by_all()$EQUIPMENT), selected = input$equipment_type)
})
#Map is updated by User inputs
output$datamap <- renderLeaflet({
leaflet(data = filter_by_all() ) %>%
addCircleMarkers(
lng = ~LONGITUDE,
lat = ~LATITUDE,
radius = 3) %>%
addTiles(group = "ESRI") %>%
addTiles(group = "OSM") %>%
addProviderTiles("Esri.WorldImagery", group = "ESRI") %>%
addProviderTiles("Stamen.Toner", group = "Stamen") %>%
addLayersControl(baseGroup = c("ESRI", "OSM", "Stamen"))
})
output$datatable <- DT::renderDT({
filter_by_all()
}, server = FALSE) #this was used with SharedData doesn't work with downloading data so scrap
#Allow the user to reset all their inputs
observeEvent(input$resetAll, {
reset("form")
})
}#end server
shinyApp(ui, server)

Problems with reactive dataframe and update input in shin R

I am still a beginner with the use of shiny (and the following code will clearly demonstrate this fact). I have to generate two barplot in this example of the work I am doing. Both plots are derived from a set of data frames, each one associated with a different year. In each data frame there are some rows (8 in the example), each one associated with a value (e.g., "Value 1", "Value 2", etc.). The user select the year range (start_year and end_year) and the server calculate the difference for each value between the two years (e.g., "Value 1" for year 2018 minus "Value 1" for the year 2015). However, only a limited number of values are showed in the first barplot, in this case 4. Up to this point I have not encountered any problems. However, I have to show another barplot, linked to the input val_select in the example. I have to add as choice for this input only the first four values showed in the first barplot. Moreover, the user may choose among this short-list of values and in the second barplot it will be showed the trend of the selected value for each year within the selected year period. For example, if within the period 2005-2018 the four values showed are, say, "Value 2", "Value 4", "Value 6", "Value 7", it will be possible in the third input to select among these four values and the selected one will be showed in the second barplot with its values between 2005 and 2018.
I have two main problems in the script:
the attempt to update the list of choices in the third input val_select with updateSelectInput crushes the app;
the second barplot does not generate and returns the following error:
Problem with `mutate()` input `x`.
[31mx[39m Input `x` can't be recycled to size 2.
[34mi[39m Input `x` is `plot_data$years`.
[34mi[39m Input `x` must be size 2 or 1, not 4.
Here below the example I wrote while ad the end of the thread there is an attempt of desired output.
library(shiny)
library(shinydashboard)
library(highcharter)
library(dplyr)
# Generate data
years = c(2009:2019)
list_db = vector("list")
var = c("Value 1", "Value 2", "Value 3", "Value 4", "Value 5", "Value 6", "Value 7", "Value 8")
for (i in 1:length(years)){
x = runif(8, min = 0, max = 100)
df = data.frame(var, x)
list_db[[i]] = df
}
names(list_db) = years
# UI
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(
sidebarMenu(
menuItem("Page 1", tabName = 'tab_page_1'),
selectInput(inputId = "start_year",
label = "Select starting year:",
choices = min(years):max(years)),
selectInput(inputId = "end_year",
label = "Select ending year:",
choices = min(years):max(years)),
selectInput(inputId = "val_select",
label = "Select Value (within the selected range) to show:",
choices = var)
)
),
dashboardBody(
tabItem(tabName = 'tab_page_1'),
fluidPage(
titlePanel("Example Page 1")
),
fluidPage(
fluidRow(
box(title = "Barplot n.1",
solidHeader = TRUE,
status = 'primary',
highchartOutput("tab_1", height = 500)
),
box(title = "Barplot n.2 (Value focus)",
solidHeader = TRUE,
status = 'primary',
highchartOutput("tab_2", height = 500)
),
)
)
)
)
# Server
server <- function(input, output, session) {
# Update 'end_year' based on 'start_year' input
observeEvent(input$start_year, {
updateSelectInput(session, 'end_year',
choices = (as.integer(input$start_year)+1):max(years)
)
})
# Reactive data frame
react_data = reactive({
# Generate starting and ending data frame
assign("data_start", list_db[[as.character(input$start_year)]])
assign("data_end", list_db[[as.character(input$end_year)]])
# Add the selected year to variables' names
data_start = data_start %>% rename_at(vars(-var), ~ paste0(., "_", input$start_year))
data_end = data_end %>% rename_at(vars(-var), ~ paste0(., "_", input$end_year))
# Join starting and ending data frame
dt = full_join(data_start, data_end, by = "var")
# Calculate vars' differences between the selected years
dt$x_diff = dt[,paste0("x_",input$end_year)] - dt[,paste0("x_",input$start_year)]
# Select only first 4 Values
dt = head(dt[order(dt$x_diff),],4)
})
# Update 'val_select' b <--- Problematic
observeEvent({
val_select_data = react_data()
mylist = val_select_data$var
updateSelectInput(session, 'val_select',
choices = mylist
)
})
# Output 'tab_1' <--- This works
output$tab_1 = renderHighchart({
# Select data frame
mydata1 = react_data()
# Plot
highchart() %>%
hc_chart(type = "bar") %>%
hc_xAxis(categories = mydata1$var) %>%
hc_series(list(name = "Variables",
pointWidth = 50,
data = mydata1$x_diff,
color = "rgba(162, 52, 52, 0.5)")) %>%
hc_xAxis(labels = list(style = list(fontSize = "12"))) %>%
hc_chart(plotBackgroundColor = "#EEEEEE") %>%
hc_legend(enabled = FALSE)
})
# Output 'tab_2' <--- Problematic
output$tab_2 = renderHighchart({
# Select data frame
mydata2 = react_data()
# List of first 4 Value in the selected year range
first_values = mydata2$var
# List of years in the selected year range
years = sort(c(min(input$start_year):max(input$end_year)))
# Create a list to contain data frame for each year (inside the selected range)
data_year = vector("list", length(years))
for (i in as.character(years)){
assign("df", list_db[[i]])
# Consider only Value in 'first_values'
df = df[df$var %in% first_values,]
# Insert into the list
data_year[[i]] = df
}
# Remove empty elements from the list
data_year = data_year[!sapply(data_year,is.null)]
# Generate a yearly data frame for each Value
data_values = vector("list", length(first_values))
years_lead = years[-1]
for (row in 1:length(data_values)){
df = data_year[[as.character(years[1])]][row, c(1:length(data_year[[as.character(years[1])]]))]
for (i in years_lead){
df = rbind(df, data_year[[as.character(i)]][row, c(1:length(data_year[[as.character(i)]]))])
}
df = cbind(years, df)
data_values[[row]] = df
}
# Assign names to the list
names(data_values) = paste(first_values)
# Select the dataframe based on the selected profession
assign("plot_data", data_values[[as.character(input$val_select)]])
# Plot
highchart() %>%
hc_title(text = input$val_select) %>%
hc_subtitle(text = "Trend in the considerd period") %>%
hc_chart(type = "column") %>%
hc_add_series(name = "Amount",
data = plot_data,
type = "column",
hcaes(x = plot_data$years, y = plot_data$x),
color = "rgba(0, 102, 102, 0.6)",
yAxis = 0) %>%
hc_xAxis(labels = list(style = list(fontSize = "12")),
opposite = FALSE) %>%
hc_chart(plotBackgroundColor = "#EEEEEE") %>%
hc_legend(enabled = FALSE)
})
}
# UI
shinyApp(ui = ui, server = server)
Thank you in advance to anyone who can give me some suggestions and I apologize in advance for my probably 'clumsy' code.
The second observeEvent was not working as you did not account for null values. Also, initially the start and end years are same, and that should be accounted in the reactive data. Once you fix this part, the graph on the left is fine and the data for the second graph is also fine. However, I am not sure if that is the data you want to plot on the right. Once you are sure, you need to adjust the syntax of the second highchart in output$tab_2. Try this code:
library(DT)
# Generate data
years = c(2009:2019)
list_db = vector("list")
var = c("Value 1", "Value 2", "Value 3", "Value 4", "Value 5", "Value 6", "Value 7", "Value 8")
for (i in 1:length(years)){
x = runif(8, min = 0, max = 100)
df = data.frame(var, x)
list_db[[i]] = df
}
names(list_db) = years
# UI
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(
sidebarMenu(
menuItem("Page 1", tabName = 'tab_page_1'),
selectInput(inputId = "start_year",
label = "Select starting year:",
choices = min(years):max(years)),
selectInput(inputId = "end_year",
label = "Select ending year:",
choices = min(years):max(years)),
selectInput(inputId = "val_select",
label = "Select Value (within the selected range) to show:",
choices = var)
)
),
dashboardBody(
tabItem(tabName = 'tab_page_1'),
fluidPage(
titlePanel("Example Page 1")
),
fluidPage(
useShinyjs(),
fluidRow(
box(title = "Barplot n.1",
solidHeader = TRUE,
status = 'primary',
highchartOutput("tab_1", height = 500)
),
box(title = "Barplot n.2 (Value focus)",
solidHeader = TRUE,
status = 'primary', DTOutput("tb2")
#highchartOutput("tab_2", height = 500)
),
)
)
)
)
# Server
server <- function(input, output, session) {
plotme <- reactiveValues(data=NULL)
# Update 'end_year' based on 'start_year' input
observeEvent(input$start_year, {
updateSelectInput(session, 'end_year',
choices = (as.integer(input$start_year)+1):max(years)
)
})
# Reactive data frame
react_data <- reactive({
req(input$start_year,input$end_year)
if (input$start_year == input$end_year){
dt <- NULL
}else {
# Generate starting and ending data frame
assign("data_start", list_db[[as.character(input$start_year)]])
assign("data_end", list_db[[as.character(input$end_year)]])
# Add the selected year to variables' names
data_start = data_start %>% rename_at(vars(-var), ~ paste0(., "_", input$start_year))
data_end = data_end %>% rename_at(vars(-var), ~ paste0(., "_", input$end_year))
# Join starting and ending data frame
dt = full_join(data_start, data_end, by = "var")
# Calculate vars' differences between the selected years
dt$x_diff = dt[,paste0("x_",input$end_year)] - dt[,paste0("x_",input$start_year)]
# Select only first 4 Values
dt = head(dt[order(dt$x_diff),],4)
}
dt
})
output$tb1 <- renderDT(react_data())
# Update 'val_select' b <--- Problem fixed when you account for react_data() not being NULL
observeEvent(list(input$start_year,input$end_year), {
if (!is.null(react_data())) {
mylist <- as.character(react_data()[,1])
updateSelectInput(session, 'val_select', choices = mylist )
}
})
# Output 'tab_1' <--- This works
output$tab_1 = renderHighchart({
if (is.null(react_data())) return(NULL)
# Select data frame
mydata1 = react_data()
# Plot
highchart() %>%
hc_chart(type = "bar") %>%
hc_xAxis(categories = mydata1$var) %>%
hc_series(list(name = "Variables",
pointWidth = 50,
data = mydata1$x_diff,
color = "rgba(162, 52, 52, 0.5)")) %>%
hc_xAxis(labels = list(style = list(fontSize = "12"))) %>%
hc_chart(plotBackgroundColor = "#EEEEEE") %>%
hc_legend(enabled = FALSE)
})
observe({
req(input$start_year,input$end_year,input$val_select)
if (is.null(react_data())) return(NULL)
# Select data frame
mydata2 = react_data()
# List of first 4 Value in the selected year range
first_values = mydata2$var
# List of years in the selected year range
years = sort(c(min(as.numeric(input$start_year)):max(as.numeric(input$end_year))))
# Create a list to contain data frame for each year (inside the selected range)
data_year = vector("list", length(years))
for (i in as.character(years)){
assign("df", list_db[[i]])
# Consider only Value in 'first_values'
df = df[df$var %in% first_values,]
# Insert into the list
data_year[[i]] = df
}
# Remove empty elements from the list
data_year = data_year[!sapply(data_year,is.null)]
# Generate a yearly data frame for each Value
data_values = vector("list", length(first_values))
years_lead = years[-1]
for (row in 1:length(data_values)){
df = data_year[[as.character(years[1])]][row, c(1:length(data_year[[as.character(years[1])]]))]
for (i in years_lead){
df = rbind(df, data_year[[as.character(i)]][row, c(1:length(data_year[[as.character(i)]]))])
}
df = cbind(years, df)
data_values[[row]] = df
}
# Assign names to the list
names(data_values) = paste(first_values)
# Select the dataframe based on the selected profession
assign("plot_data", data_values[[as.character(input$val_select)]])
plotme$data <- plot_data
output$tb2 <- renderDT(plotme$data)
# Output 'tab_2' <--- Problematic - needs some work to fix the highchart
output$tab_2 = renderHighchart({
plot_data <- plotme$data
if (is.null(plot_data)) return(NULL)
# Plot
plot_data %>%
highchart() %>%
hc_title(text = unique(plot_data$var)) %>%
hc_subtitle(text = "Trend in the considerd period") %>%
hc_chart(type = "column") %>%
hc_add_series(name = "Amount",
#data = plot_data,
type = "column",
hcaes(x = plot_data$years, y = plot_data$x),
color = "rgba(0, 102, 102, 0.6)",
yAxis = 0) %>%
hc_xAxis(labels = list(style = list(fontSize = "12")),
opposite = FALSE) %>%
hc_chart(plotBackgroundColor = "#EEEEEE") %>%
hc_legend(enabled = FALSE)
})
})
}
# UI
shinyApp(ui = ui, server = server)
Thank you so much #YBS for your kind answer. With some adjustments it worked.
I had to sort both mylist and first_values to have the correspondence between the selected choice in the input 'Select Value (within the selected range) to show:' and the displayed table/barplot. Moreover, the problem with the second barplot was associated with the name I gave to the vertical axis... 'x', shame on me for such choice. In fact, I tired with ggplot2 and it worked. Then, by renaming the variable the script works just fine. Thank you again. Below the edited script I modified following your suggestions.
library(shiny)
library(shinydashboard)
library(highcharter)
library(dplyr)
library(DT)
# Generate data
years = c(2009:2019)
list_db = vector("list")
var = c("Value 1", "Value 2", "Value 3", "Value 4", "Value 5", "Value 6", "Value 7", "Value 8")
for (i in 1:length(years)){
x = runif(8, min = 0, max = 100)
df = data.frame(var, x)
list_db[[i]] = df
}
names(list_db) = years
# UI
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(
sidebarMenu(
menuItem("Page 1", tabName = 'tab_page_1'),
selectInput(inputId = "start_year",
label = "Select starting year:",
choices = min(years):max(years)),
selectInput(inputId = "end_year",
label = "Select ending year:",
choices = min(years):max(years)),
selectInput(inputId = "val_select",
label = "Select Value (within the selected range) to show:",
choices = var)
)
),
dashboardBody(
tabItem(tabName = 'tab_page_1'),
fluidPage(
titlePanel("Example Page 1")
),
fluidPage(
fluidRow(
box(title = "Barplot n.1",
solidHeader = TRUE,
status = 'primary',
highchartOutput("tab_1", height = 500)
),
box(title = "Table n.1 (Value focus)",
solidHeader = TRUE,
status = 'primary',
DTOutput("tab_2")
),
box(title = "Barplot n.2 (Value focus)",
solidHeader = TRUE,
status = 'primary',
highchartOutput("tab_3", height = 500)
)
)
)
)
)
# Server
server <- function(input, output, session) {
plotme = reactiveValues(data = NULL)
# Update 'end_year' based on 'start_year' input
observeEvent(input$start_year, {
updateSelectInput(session, 'end_year',
choices = (as.integer(input$start_year)+1):max(years)
)
})
# Reactive data frame
react_data = reactive({
req(input$start_year, input$end_year)
if (input$start_year == input$end_year){
dt = NULL
} else {
# Generate starting and ending data frame
assign("data_start", list_db[[as.character(input$start_year)]])
assign("data_end", list_db[[as.character(input$end_year)]])
# Add the selected year to variables' names
data_start = data_start %>% rename_at(vars(-var), ~ paste0(., "_", input$start_year))
data_end = data_end %>% rename_at(vars(-var), ~ paste0(., "_", input$end_year))
# Join starting and ending data frame
dt = full_join(data_start, data_end, by = "var")
# Calculate vars' differences between the selected years
dt$x_diff = dt[,paste0("x_",input$end_year)] - dt[,paste0("x_",input$start_year)]
# Select only first 4 Values
dt = head(dt[order(dt$x_diff),],4)
}
dt
})
# Update 'val_select'
observeEvent(list(input$start_year,input$end_year), {
if (!is.null(react_data())) {
mylist = as.character(react_data()[,1])
updateSelectInput(session, 'val_select', choices = sort(mylist))
}
})
# Output 'tab_1'
output$tab_1 = renderHighchart({
# Select data frame
mydata1 = react_data()
# Plot
highchart() %>%
hc_chart(type = "bar") %>%
hc_xAxis(categories = mydata1$var) %>%
hc_series(list(name = "Variables",
pointWidth = 50,
data = mydata1$x_diff,
color = "rgba(162, 52, 52, 0.5)")) %>%
hc_xAxis(labels = list(style = list(fontSize = "12"))) %>%
hc_chart(plotBackgroundColor = "#EEEEEE") %>%
hc_legend(enabled = FALSE)
})
# Output 'tab_2' and 'tab_3'
observe({
req(input$start_year,input$end_year,input$val_select)
if (is.null(react_data())) return(NULL)
# Select data frame
mydata2 = react_data()
# List of first 4 Value in the selected year range
first_values = mydata2$var
first_values = sort(first_values)
# List of years in the selected year range
years = sort(c(min(as.numeric(input$start_year)):max(as.numeric(input$end_year))))
# Create a list to contain data frame for each year (inside the selected range)
data_year = vector("list", length(years))
for (i in as.character(years)){
assign("df", list_db[[i]])
# Consider only Value in 'first_values'
df = df[df$var %in% first_values,]
# Insert into the list
data_year[[i]] = df
}
# Remove empty elements from the list
data_year = data_year[!sapply(data_year,is.null)]
# Generate a yearly data frame for each Value
data_values = vector("list", length(first_values))
years_lead = years[-1]
for (row in 1:length(data_values)){
df = data_year[[as.character(years[1])]][row, c(1:length(data_year[[as.character(years[1])]]))]
for (i in years_lead){
df = rbind(df, data_year[[as.character(i)]][row, c(1:length(data_year[[as.character(i)]]))])
}
df = cbind(years, df)
data_values[[row]] = df
}
# Assign names to the list
names(data_values) = paste(first_values)
# Select the dataframe based on the selected value
assign("plot_data", data_values[[as.character(input$val_select)]])
plotme$data = plot_data
# Plot table 'tab_2'
output$tab_2 = renderDT(plotme$data)
# Plot table 'tab_3'
output$tab_3 = renderHighchart({
#plot_data = plotme$data
if (is.null(plot_data)) return(NULL)
names(plot_data)[names(plot_data) == 'x'] = 'variable'
highchart() %>%
hc_title(text = unique(plot_data$var)) %>%
hc_subtitle(text = "Trend in the considerd period") %>%
hc_chart(type = "column") %>%
hc_add_series(name = "Amount",
data = plot_data,
type = "column",
hcaes(x = years, y = variable),
color = "rgba(0, 102, 102, 0.6)",
yAxis = 0) %>%
hc_xAxis(labels = list(style = list(fontSize = "12")),
opposite = FALSE) %>%
hc_chart(plotBackgroundColor = "#EEEEEE") %>%
hc_legend(enabled = FALSE)
})
})
}
# UI
shinyApp(ui = ui, server = server)

Pass reactive value from server to two conditional panels(not nested) in ui in shiny?

I'm making a shiny app, which takes "dateRangeInput" as input and plots plot for data within that "date range". Also, I'm using conditionalPanel to not show the plot when the dates from input are not available in data and show text to the user to select dates only available in data.
The problem is, the conditional panel is not working and not showing anyting at all irrespective of date inputs. (setting the limits to max and min dates available in data to max & min of dateRangeInput is not an option.).
link to data: https://drive.google.com/open?id=17ipXwRimovR_QBYT2O1kxSGTzem_bN-1
Here's what I've done and tried:
# loading the data and making the interpretation of first column proper
wait_data <- transform(read.csv("dummy wait times data of 12 departments.csv", header = TRUE),
Date = as.Date(Date, "%d-%m-%y"))
# sorting the data according to dates
wait_data <- data.frame(with(wait_data, wait_data[order(Date),]),
row.names = NULL)
library(shiny)
library(plotly)
ui_function <- fluidPage(
sidebarLayout(
sidebarPanel(width = 3,
dateRangeInput(inputId = 'date_range',
label = paste('Choose range from January 1, 2017 to December 31, 2018:'),
start = as.Date("2017-01-01"), end = as.Date("2017-05-31"),
min = as.Date("2017-01-01"), max = Sys.Date(),
separator = " to ", format = "MM-dd, yyyy",
startview = 'year', weekstart = 1),
selectInput(inputId = "department_input",
label = "Choose a Department to see wait times:",
choices = c("General Checkup"="General Checkup",
"Emergency"="Emergency",
"Cardiology"="Cardiology",
"Gynaecology"="Gynaecology",
"Maternity"="Maternity",
"Neurology"="Neurology",
"Oncology"="Oncology",
"Orthopedics"="Orthopedics",
"Otalaryntology"="Otalaryntology",
"Psychiatry"="Psychiatry",
"Radiology"="Radiology",
"Urology"="Urology"),
multiple = TRUE,
selected = c("Cardiology","Gynaecology"))
),
mainPanel(width = 9,
uiOutput("plots_or_text")
# uiOutput("resource_or_moretext")
# conditionalPanel(
# condition = "output.dates_matches",
# plotlyOutput("wait_times_plot"),
# dataTableOutput("resource_counts")
# ),
# conditionalPanel(
# condition = "output.dates_matches",
# htmlOutput("select_available_dates")
# )
)
)
)
server_function <- function(input, output) {
min_date_in_data <- reactive({min(wait_data[,"Date"])})
max_date_in_data <- reactive({max(wait_data[,"Date"])})
# output$dates_matches <- reactive ({
# if (input$date_range[2] > max_date_in_data() | input$date_range[1] < min_date_in_data()){return(FALSE)}
# else if (input$date_range[2] <= max_date_in_data() | input$date_range[1] >= min_date_in_data()){return(TRUE)}
# })
#
#
# # output$select_good_dates <- renderText({dates_matches()})
# output$select_available_dates <- renderText({paste("select dates available in data")})
# now filter based on date range inputs
date_range_data <- reactive({
wait_data[(wait_data[,"Date"] > input$date_range[1] & wait_data[,"Date"] < input$date_range[2]), ]
})
# now take the data returned from above aggregation and filter it for department selection.
filtered_department_data <- reactive({date_range_data()[date_range_data()[,"Department"] %in% input$department_input, ]})
# # plot it now
# output$wait_times_plot <- renderPlotly({
# plot_ly(data = filtered_department_data(),
# x = ~Date, y=~average_wait_time_min,
# split = ~Department,
# type = "scatter", mode="lines+markers")
# })
output$plots_or_text <- renderUI({
if (input$date_range[2] <= max_date_in_data() | input$date_range[1] >= min_date_in_data()){
renderPlotly({plot_ly(data = filtered_department_data(),
x = ~Date, y=~average_wait_time_min, split = ~Department,
type = "scatter", mode="lines+markers")
})
}
else if (input$date_range[2] > max_date_in_data() | input$date_range[1] < min_date_in_data()){
renderText({paste("select dates available in data")})
}
})
}
shinyApp(ui_function, server_function)
That code returns
object of type 'closure' is not subsettable in my mainPanel.
EDIT 1:
changes in server:
make_plot <- reactive({
# I've copied the below condition from my if
validate(
need(input$date_range[2] <= max_date_in_data() | input$date_range[1] >= min_date_in_data(),
message = "Seems like you've selected dates out of range. Please change your filters."))
plot_ly(data = filtered_department_data(),
x = ~Date, y=~average_wait_time_min, split = ~Department,
type = "scatter", mode="lines+markers")
# ggplot(data = filtered_department_data(),
# aes(x = Date, y=average_wait_time_min, split = Department)) + geom_line() + geom_point()
})
output$plot_or_error <- renderPlotly(make_plot())
# output$plot_or_error <- renderPlot(make_plot())
I just can't solve this. both libraries' plots show up irrespective of inputs in dateRangeInput. if the data for the selected date range is not available, there's simply a blank plot, no error messages shows up in that case.
As long as all you want to do is print an informative message when the plot can't be made for some reason, validate + need are your friends. For example:
library(shiny)
library(dplyr)
library(ggplot2)
ui <- basicPage(
selectInput(
inputId = "sp",
label = "Select species",
choices = unique(iris$Species),
#selected = unique(iris$Species),
multiple = TRUE
),
tags$br(),
plotOutput("plot_or_error")
)
server <- function(input, output) {
make_plot <- reactive({
df <- filter(iris, Species %in% input$sp)
validate(need(nrow(df) > 0,
message = "Seems like after filtering there are 0 rows. Please change your filters."))
ggplot(df, aes(x=Species, y=Sepal.Length)) + geom_boxplot()
})
output$plot_or_error <- renderPlot({
make_plot()
})
}
shinyApp(ui, server)
EDIT: r user's code and data.
# loading the data and making the interpretation of first column proper
wait_data <-
transform(
read.csv("dummy wait times data of 12 departments.csv", header = TRUE),
Date = as.Date(Date, "%d-%m-%y")
)
# sorting the data according to dates
wait_data <- data.frame(with(wait_data, wait_data[order(Date), ]),row.names = NULL)
library(shiny)
library(dplyr) # not necessary, code included with dplyr or base R
library(plotly)
ui_function <- fluidPage(
sidebarLayout(
sidebarPanel(width = 3,
dateRangeInput(inputId = 'date_range',
label = paste('Choose range from January 1, 2017 to December 31, 2018:'),
start = as.Date("2017-01-01"), end = as.Date("2017-05-31"),
min = as.Date("2017-01-01"), max = Sys.Date(),
separator = " to ", format = "MM-dd, yyyy",
startview = 'year', weekstart = 1),
selectInput(inputId = "department_input",
label = "Choose a Department to see wait times:",
choices = c("General Checkup"="General Checkup",
"Emergency"="Emergency",
"Cardiology"="Cardiology",
"Gynaecology"="Gynaecology",
"Maternity"="Maternity",
"Neurology"="Neurology",
"Oncology"="Oncology",
"Orthopedics"="Orthopedics",
"Otalaryntology"="Otalaryntology",
"Psychiatry"="Psychiatry",
"Radiology"="Radiology",
"Urology"="Urology"),
multiple = TRUE,
selected = c("Cardiology","Gynaecology"))
),
mainPanel(width = 9,
plotlyOutput("plot_or_error")
)
)
)
server_function <- function(input, output) {
make_df <- reactive({
wait_data %>%
filter(Department %in% input$department_input) %>%
filter(Date >= input$date_range[1], Date <= input$date_range[2])
})
# no dplyr
make_df_base <- reactive({
fd <- wait_data[wait_data$Department %in% input$department_input, ]
fd <- fd[fd$Date > input$date_range[1] & fd$Date < input$date_range[2], ]
fd
})
make_plot <- reactive({
validate(
need(nrow(make_df_base()) > 0, # can be make_df()
message = "Seems like you've selected dates out of range. Please change your filters."))
plot_ly(data = make_df_base(), # can be make_df()
x = ~Date, y=~average_wait_time_min, split = ~Department,
type = "scatter", mode="lines+markers")
})
output$plot_or_error <- renderPlotly({make_plot()})
}
shinyApp(ui_function, server_function)
EDIT 2: check with the dates instead of data frame
# loading the data and making the interpretation of first column proper
wait_data <-
transform(
read.csv("dummy wait times data of 12 departments.csv", header = TRUE),
Date = as.Date(Date, "%d-%m-%y")
)
# sorting the data according to dates
wait_data <- data.frame(with(wait_data, wait_data[order(Date), ]),row.names = NULL)
library(shiny)
library(dplyr)
library(plotly)
ui_function <- fluidPage(
sidebarLayout(
sidebarPanel(width = 3,
dateRangeInput(inputId = 'date_range',
label = paste('Choose range from January 1, 2017 to December 31, 2018:'),
start = as.Date("2017-01-01"), end = as.Date("2017-05-31"),
min = as.Date("2017-01-01"), max = Sys.Date(),
separator = " to ", format = "MM-dd, yyyy",
startview = 'year', weekstart = 1),
selectInput(inputId = "department_input",
label = "Choose a Department to see wait times:",
choices = c("General Checkup"="General Checkup",
"Emergency"="Emergency",
"Cardiology"="Cardiology",
"Gynaecology"="Gynaecology",
"Maternity"="Maternity",
"Neurology"="Neurology",
"Oncology"="Oncology",
"Orthopedics"="Orthopedics",
"Otalaryntology"="Otalaryntology",
"Psychiatry"="Psychiatry",
"Radiology"="Radiology",
"Urology"="Urology"),
multiple = TRUE,
selected = c("Cardiology","Gynaecology"))
),
mainPanel(width = 9,
plotlyOutput("plot_or_error")
)
)
)
server_function <- function(input, output) {
# these don't need to be reactive unless you have the user load or switch datasets
min_date_in_data <- reactive({ min(wait_data[,"Date"], na.rm = TRUE) })
max_date_in_data <- reactive({ max(wait_data[,"Date"], na.rm = TRUE) })
make_df <- reactive({
se <- input$date_range
validate(need(se[1] >= min_date_in_data(), message = "The first date is outside the range of the data."))
validate(need(se[2] <= max_date_in_data(), message = "The second date is outside the range of the data."))
validate(need(se[1] < se[2], message = "The second date needs to be after the first date."))
validate(need(input$department_input != "", message = "Please select a department."))
wait_data %>%
filter(Department %in% input$department_input) %>%
filter(Date >= input$date_range[1], Date <= input$date_range[2])
})
# no dplyr
make_df_base <- reactive({
fd <- wait_data[wait_data$Department %in% input$department_input, ]
fd <- fd[fd$Date > input$date_range[1] & fd$Date < input$date_range[2], ]
fd
})
make_plot <- reactive({
plot_ly(data = make_df(),
x = ~Date, y=~average_wait_time_min, split = ~Department,
type = "scatter", mode="lines+markers")
})
output$plot_or_error <- renderPlotly({make_plot()})
}
shinyApp(ui_function, server_function)

R Shiny: Computing new Variables selected by "selectInput"

I'm working on a dashbord with Shiny and want to compute new variables based on the selected Variabels by selectInput.
Comparable to this in normal R-Code:
library(dplyr)
new_df <- old_df %>% mutate(new_1 = old_var1 + old_var2)
I'm able to compute new values with the sliderInput, but this are only single values. I want to compute a hole new variable with all the oppertunities of displaying the new variable in Tables and graphics.
Please try the followring syntax (the data is online avalible).
As you mentioned, all Inputs are working as they should.
library(shiny)
library(readr)
library(ggplot2)
library(stringr)
library(dplyr)
library(DT)
library(tools)
load(url("http://s3.amazonaws.com/assets.datacamp.com/production/course_4850/datasets/movies.Rdata"))
ui <- fluidPage(
sidebarLayout(
# Inputs
sidebarPanel(
h3("Plotting"), # Third level header: Plotting
# Select variable for y-axis
selectInput(inputId = "y",
label = "Y-axis:",
choices = c("IMDB rating" = "imdb_rating",
"IMDB number of votes" = "imdb_num_votes",
"Critics Score" = "critics_score",
"Audience Score" = "audience_score",
"Runtime" = "runtime"),
selected = "audience_score"),
# Select variable for x-axis
selectInput(inputId = "x",
label = "X-axis:",
choices = c("IMDB rating" = "imdb_rating",
"IMDB number of votes" = "imdb_num_votes",
"Critics Score" = "critics_score",
"Audience Score" = "audience_score",
"Runtime" = "runtime"),
selected = "critics_score"),
# Select variable for color
selectInput(inputId = "z",
label = "Color by:",
choices = c("Title Type" = "title_type",
"Genre" = "genre",
"MPAA Rating" = "mpaa_rating",
"Critics Rating" = "critics_rating",
"Audience Rating" = "audience_rating"),
selected = "mpaa_rating"),
hr(),
# Set alpha level
sliderInput(inputId = "alpha",
label = "Alpha:",
min = 0, max = 1,
value = 0.5),
# Set point size
sliderInput(inputId = "beta",
label = "Beta:",
min = 0, max = 5,
value = 2)
),
# Output:
mainPanel(plotOutput(outputId = "scatterplot"),
textOutput(outputId = "description"),
DT::dataTableOutput("moviestable"))
)
)
server <- function(input, output, session) {
output$scatterplot <- renderPlot({
ggplot(data = movies, aes_string(x = input$x, y = input$y,
color = input$z)) +
geom_point(alpha = input$alpha, size = input$beta) +
labs(x = toTitleCase(str_replace_all(input$x, "_", " ")),
y = toTitleCase(str_replace_all(input$y, "_", " ")),
color = toTitleCase(str_replace_all(input$z, "_", " ")))
})
vals <- reactiveValues()
observe({
vals$x <- input$alpha
vals$y <- input$beta
vals$sum <- vals$x + vals$y
})
output$description <- renderText({
paste0("Alpha: ",input$alpha, " Beta:", input$beta," and the sum of alpha and beta:",vals$sum, ".")
})
output$moviestable <- DT::renderDataTable({
DT::datatable(data = movies,
options = list(pageLength = 10),
rownames = FALSE)
})
}
shinyApp(ui = ui, server = server)
I tried different ways to solve this problem:
1st try:
vals2 <- reactiveValues()
observe({
vals2$x <- input$y
vals2$y <- input$x
vals2$sum <- vals2$x + vals2$y
})
output$description2 <- renderText({
paste0("Input y: ",input$y, " Input x:", input$x," and the sum of both variables is:",vals2$sum, ".")
})
Warning: Error in +: non-numeric argument to binary operator
Stack trace (innermost first):
56: observerFunc [C:/Users/XXXXXX/Desktop/app.R#110]
1: runApp
ERROR: [on_request_read] connection reset by peer
2nd try:
output$try2 <- renderUI({
movies_2 <- movies %>% mutate(new_1 = input$y + input$x)
})
output$moviestable2 <- DT::renderDataTable({
DT::datatable(data = movies_2,
options = list(pageLength = 10),
rownames = FALSE)
})
Warning: Error in inherits: object 'movies_2' not found
I've no idea where I what I can try next...
I'm very happy for every kind of help!
You should make movies_2 in a reactive. Your output$try2 won't work because its expecting UI objects.
To match the call you make on the UI side I've renamed back to moviestable and have changed input$x + input$y to paste0(input$y, input$x) since they are both character.
movies_2 <- reactive({
movies %>% mutate(new_1 := movies[[input$x]] + movies[[input$y]])
})
output$moviestable <- DT::renderDataTable({
DT::datatable(data = movies_2(),
options = list(pageLength = 10),
rownames = FALSE)
})

Resources