Shiny Dashboard Date Slider Input - r

I am new to R and Shiny and have a problem that I have not been able to solve for hours.
I have a dataset from which I display the daily consumption of coffee on a dashboard, which works very well. The plot is a ggplot geom_line chart.
But now I want to be able to change the time period with two sliders.
The sliders I have also managed to do, but the plot does not change when the slider is moved.
I also suspect that I have an error with the date format.
What am I doing wrong?
Thanks for the help
RawData Dataset
library(shiny)
library(dplyr)
library(data.table)
library(ggplot2)
ui <- shinyUI(fluidPage(
# Application title
titlePanel("Coffee consumption"),
# Sidebar with a slider input for the number of bins
sidebarLayout(
sidebarPanel(
sliderInput("DatesMerge",
"Dates:",
min = as.Date("2018-01-22","%Y-%m-%d"),
max = as.Date("2020-04-04","%Y-%m-%d"),
value= c(as.Date("2018-01-22","%Y-%m-%d"),as.Date("2020-04-04","%Y-%m-%d")),
timeFormat="%Y-%m-%d")
),
mainPanel(
plotOutput("plot_daycount"),
tableOutput("structure"),
tableOutput("rawdata"),
tableOutput("dayconsumption"))
)
)
)
# RawData import
coffeedata = fread("C:/temp/ProductList.csv")
setDF(coffeedata)
coffeedata$Date = as.Date(coffeedata$Date, "%d.%m.%Y")
# Products a day counter
countcoffee <- function(timeStamps) {
Dates <- as.Date(strftime(coffeedata$Date, "%Y-%m-%d"))
allDates <- seq(from = min(Dates), to = max(Dates), by = "day")
coffee.count <- sapply(allDates, FUN = function(X) sum(Dates == X))
data.frame(day = allDates, coffee.count = coffee.count)}
# Making a DF with day consumption
daylicounter = countcoffee(df$coffee.date)
server <- shinyServer(function(input, output) {
output$structure = renderPrint({
str(coffeedata)
})
# Raw Data
output$rawdata = renderTable({
head(coffeedata)
})
output$dayconsumption = renderTable({
head(daylicounter)
})
# GGPLOT2
output$plot_daycount = renderPlot({
DatesMerge = input$DatesMerge
ggplot(daylicounter[daylicounter == DatesMerge], aes(daylicounter$day, daylicounter$coffee.count)) +
geom_line(color = "orange", size = 1)
scale_x_date(breaks = "3 month",
date_labels = "%d-%m-%Y")
# Try outs
# ggplot(daylicounter[month(day) == month(DatesMerge)], mapping = aes(day = day)) +
# geom_line(color = "orange", size = 1)
# scale_x_date(breaks = "3 month",
# date_labels = "%d-%m-%Y")
})
})
shinyApp(ui, server)
I appreciate your help

As noted by #Kevin, you need to use input$DatesMerge[1] and input$DatesMerge[2] when subsetting your data. For clarity, this can be done in a separate step. Try something like this in your server:
output$plot_daycount = renderPlot({
DatesMerge <- as.Date(input$DatesMerge, format = "%Y-%m-%d")
sub_data <- subset(daylicounter, day >= DatesMerge[1] & day <= DatesMerge[2])
ggplot(sub_data, aes(x = day, y = coffee.count)) +
geom_line(color = "orange", size = 1) +
scale_x_date(breaks = "3 month", date_labels = "%d-%m-%Y")
})
Edit Additional question from OP was asked:
Why does my date format look normal with str(coffeedata) but with
head(coffeedata) the date is just a number?
renderTable uses xtable which may have trouble with dates. You can get your dates to display correctly by converting to character first (one option):
output$rawdata = renderTable({
coffeedata$Date <- as.character(coffeedata$Date)
head(coffeedata)
})
output$dayconsumption = renderTable({
daylicounter$day <- as.character(daylicounter$day)
head(daylicounter)
})
See other questions on this topic:
as.Date returns number when working with Shiny
R shiny different output between renderTable and renderDataTable

Welcome to R and Shiny, you are off to a great start. Few things:
I don't recommend you using = in shiny, majority of the cases you want to use <-
To simplify code, no reason to add a variable like DatesMerge. It adds no value (at least in the code above)
For a dual slider, you need to tell shiny which end to pick. input$DatesMerge doesn't mean anything but input$DatesMerge[1] does.
When asking for help, it is always better to add a subset of data within the code itself. You tend to get more help and it is easier to run for the person trying to help (like me I was too lazy to download the file and place it in a folder so I didn't run it)
You need to account for a range of dates in your slider when subsetting the data; you also for the , when subsetting the data.
ggplot(daylicounter[daylicounter %in% input$DatesMerge[1]:input$DatesMerge[2],], aes(daylicounter$day, daylicounter$coffee.count)) +
geom_line(color = "orange", size = 1) +
scale_x_date(breaks = "3 month",
date_labels = "%d-%m-%Y")

Related

Subset a data frame in R/Shiny to generate a ggplot2 sf object

A complete ggplot2/Shiny beginner here. I have been searching on Stack and Google for days and could not come up with a decent solution.
Task: to create an interactive leaflet map showing a user-selected column in a long data format (Covid vaccine doses - first, second, and third dose; need shiny to feed this into ggplot2's "data"), which are pre-filtered based on additional user choices (month of the year, age group, type of vaccine administered; these cannot be fed into ggplot2 directly so I need to filter out the data). I am therefore interested in subsetting selected columns (time, age_group, vaccine) based on the values the users select in the input.
I am importing a data frame in .csv which needs to be merged with a sf object later on to match the data with the sf coordinates (supplied by RCzechia).
# Load packages
library(shiny)
library(here)
library(tidyverse)
library(ggplot2)
library(RCzechia)
library(sf)
# Load data
df <- read.csv("data", encoding = "UTF-8")
# load geo-spatial sf data for ggplot
czrep <- republika()
regions <- kraje(resolution = "low")
# Defining UI for the ggplot application
ui <- fluidPage(
titlePanel(),
# Sidebar
sidebarLayout(
sidebarPanel(width = 3,
selectInput("box_time", label = "Month & Year",
choices = sort(unique(df$time)), selected = "",
width = "100%", selectize=FALSE),
selectInput("box_age", label = "Age group",
choices = sort(unique(df$age_group)), selected = "",
width = "100%", selectize=FALSE),
selectInput("box_vax", label = "Type of vaccine",
choices = sort(unique(df$vaccine)), selected = "",
width = "100%", selectize=FALSE),
radioButtons("button_dose", label = "Vaccine dose",
choices = c("First dose" = "first_dose",
"Second dose" = "second_dose",
"Booster" = "booster"))
),
# Displaying the user-defined ggplot
mainPanel(
plotOutput("map")
)))
# Server
server <- function(input, output) {
# select column for ggplot
r_button_dose <- reactive({input$button_dose})
### Subset based on user choices - this is where I tried to create a new data frame (new_df) as a result of subsetting by - see below. ###
# merge the df with the sf object
new_df <- merge(regions, new_df, by.x = "region_id", by.y="region_id")
# transform data set into an sf object (readable by ggplot)
new_df <- st_as_sf(new_df)
})
# Generating the plot based on user choices
output$map <- renderPlot({
ggplot(data = new_df) +
geom_sf(aes_string(fill = r_button_dose(), colour = NA, lwd = 2)) +
geom_sf(data = czrep, color = "grey27", fill = NA) +
scale_fill_viridis_c(trans = "log", labels = scales::comma) +
labs(fill = "log scale") +
theme_bw() +
theme(legend.text.align = 1,
legend.title.align = 0.5)
})
}
# Starting the Shiny application
shinyApp(ui = ui, server = server)
I cannot figure out how to subset the data - I have tried many different things that I found here and on the RStudio community forms.
Here are a couple of things I have already tried:
# used both filter() and subset(); also tried both '==' and '%in%'
new_df %>%
filter(time %in% box_time() &
age_group %in% input$box_age() &
vaccine %in% input$box_vax())
})
#OR#
new_df <- reactive({
df <- df %>%
filter(time %in% box_time() &
age_group %in% input$box_age() &
vaccine %in% input$box_vax())
})
#OR#
new_df <- df
new_df$time <- df[df$time==box_time(),]
new_df$age_group <- df[df$age_group==input$box_age(),]
new_df$vaccine <- df[df$vaccine ==input$box_vax(),]
# I also tried passing them the same way as this example:
r_button_dose <- reactive({input$button_dose})
#OR EVEN#
new_df <- reactive({
new_df <- df
new_df$time <- df[df$X.U.FEFF.year_mo==box_time(),]
new_df$age_group <- df[df$age_group==input$box_age(),]
new_df$vaccine <- df[df$vaccine ==input$box_vax(),]
})
With the latest option, I get the following error - even though they are similar:
Listening on http://127.0.0.1:4092
Warning: Error in $: object of type 'closure' is not subsettable
1: runApp
Warning: Error in $: object of type 'closure' is not subsettable
1: runApp
Warning: Error in as.data.frame.default: cannot coerce class ‘c("reactiveExpr", "reactive", "function")’ to a data.frame
176: stop
175: as.data.frame.default
172: merge.data.frame
168: renderPlot [C:/Users/xyz/Documents/R/example/gg_app.R#78]
166: func
126: drawPlot
112: <reactive:plotObj>
96: drawReactive
83: renderFunc
82: output$map
1: runApp
I don't know what to do - looking for more examples online has not worked. I know that I cannot pass a reactive value directly (even though I am not sure if it is because it returns a logical value). I would be extremely grateful for any tips regarding how to resolve this - thank you!
You can define your reactive dataframe as a reactiveVal:
df_filtered <- reactiveVal(df) ## df being your initial static dataframe
The tricky bit is to treat your reactive dataframe as a function, not an static object:
## works:
df_filtered(df %>% filter(age_group == input$box_age))
renderDataTable(df_filtered()) ## note the parentheses
instead of:
## won't work:
df_filtered <- df %>% filter(age_group %in% input$box_age)
renderDataTable(df_filtered)
finally, wrap it into a reactive expression:
observe({df_filtered(df %>% filter(age_group == input$box_age))
## note: function argument, not assignment operator
output$map <- renderPlot({
df_filtered() %>% ## again: note function (parentheses)
ggplot() # etc.
})
}) %>% bindEvent(input$box_age, input$some_other_picker)
I think you are almost there, slight syntax issue. Note I return the new_df as part of reactive block (essentially a function), and, in renderPlot, I tell 'data' is in essence invocation result of function r_button_dose. You need to modify the fill attribute as I'm not sure what you want it to be filled with
# select column for ggplot
r_button_dose <- reactive({input$button_dose})
### Subset based on user choices - this is where I tried to create a new data frame (new_df) as a result of subsetting by - see below. ###
# merge the df with the sf object
new_df <- merge(regions, new_df, by.x = "region_id", by.y="region_id")
# transform data set into an sf object (readable by ggplot)
new_df <- st_as_sf(new_df)
new_df
})
# Generating the plot based on user choices
output$map <- renderPlot({
ggplot(data = r_button_dose()) +
geom_sf(aes_string(fill = r_button_dose()$region_id, colour = NA, lwd = 2)) +
geom_sf(data = czrep, color = "grey27", fill = NA) +
scale_fill_viridis_c(trans = "log", labels = scales::comma) +
labs(fill = "log scale") +
theme_bw() +
theme(legend.text.align = 1,
legend.title.align = 0.5)
})

R: Removed n rows containing missing values (geom_path)

I get a warning (Warning: Removed 2 rows containing missing values (geom_path).), which I don't want to have for the following code:
library(shiny)
library(ggplot2)
library(scales)
ui <- navbarPage("Test",
tabPanel("Test_2",
fluidPage(
fluidRow(
column(width = 12, plotOutput("plot", width = 1200, height = 600))
),
fluidRow(
column(width = 12, sliderInput("slider",
label = "Range [h]",
min = as.POSIXct("2019-11-01 00:00"),
max = as.POSIXct("2019-11-01 07:00"),
value = c(as.POSIXct("2019-11-01 00:00"),as.POSIXct("2019-11-01 07:00"))))
))))
server <- function(input, output, session) {
df <- data.frame("x" = c(as.POSIXct("2019-11-01 00:00"),as.POSIXct("2019-11-01 01:00"),
as.POSIXct("2019-11-01 02:00"),as.POSIXct("2019-11-01 03:00"),
as.POSIXct("2019-11-01 04:00"),as.POSIXct("2019-11-01 05:00"),
as.POSIXct("2019-11-01 06:00"),as.POSIXct("2019-11-01 07:00")),
"y" = c(0,1,2,3,4,5,6,7))
observe({
len_date_list <- length(df$x)
min_merge_datetime <- df$x[1]
max_merge_datetime <- df$x[len_date_list]
updateSliderInput(session, "slider",
min = as.POSIXct(min_merge_datetime),
max = as.POSIXct(max_merge_datetime),
timeFormat = "%Y-%m-%d %H:%M")
})
output$plot <- renderPlot({
in_slider_1 <- input$slider[1]
in_slider_2 <- input$slider[2]
ggplot(data=df, aes(x, y, group = 1)) +
theme_bw() +
geom_line(color="black", stat="identity") +
# geom_point() +
scale_x_datetime(labels = date_format("%m-%d %H:%M"),
limits = c(
as.POSIXct(in_slider_1),
as.POSIXct(in_slider_2)))
})
}
shinyApp(server = server, ui = ui)
It seems to be an general problem with the "missing values", because I have found a lot of similar questions. In this question it is explained that it must be the range of the axis. So in my case I'm sure that it is because of the limits in scale_x_datetime.
scale_x_datetime(labels = date_format("%m-%d %H:%M"),
limits = c(
as.POSIXct(in_slider_1),
as.POSIXct(in_slider_2)))
But I didn't found an answered question when scale_x_datetime, as.POSIXct and a slider is used.
BTW: If I comment out "geom_point" I get a further similar warning.
I think it is because you haven't filtered df so when the limits of scale_x_datetime come along they remove the rows in df that don't fit between the slider parameters. I added this:
df %>% filter(between(x, in_slider_1, in_slider_2))
which seems to remove the issue for me. Please test. Just to mention that I did have some time zone problems.
Full code below:
library(shiny)
library(ggplot2)
library(scales)
ui <- navbarPage("Test",
tabPanel("Test_2",
fluidPage(
fluidRow(
column(width = 12, plotOutput("plot", width = 1200, height = 600))
),
fluidRow(
column(width = 12, sliderInput("slider",
label = "Range [h]",
min = as.POSIXct("2019-11-01 00:00"),
max = as.POSIXct("2019-11-01 07:00"),
value = c(as.POSIXct("2019-11-01 00:00"),as.POSIXct("2019-11-01 07:00"))))
))))
server <- function(input, output, session) {
df <- data.frame("x" = c(as.POSIXct("2019-11-01 00:00"),as.POSIXct("2019-11-01 01:00"),
as.POSIXct("2019-11-01 02:00"),as.POSIXct("2019-11-01 03:00"),
as.POSIXct("2019-11-01 04:00"),as.POSIXct("2019-11-01 05:00"),
as.POSIXct("2019-11-01 06:00"),as.POSIXct("2019-11-01 07:00")),
"y" = c(0,1,2,3,4,5,6,7))
observe({
len_date_list <- length(df$x)
min_merge_datetime <- df$x[1]
max_merge_datetime <- df$x[len_date_list]
updateSliderInput(session, "slider",
min = as.POSIXct(min_merge_datetime),
max = as.POSIXct(max_merge_datetime),
timeFormat = "%Y-%m-%d %H:%M")
})
output$plot <- renderPlot({
in_slider_1 <- input$slider[1]
in_slider_2 <- input$slider[2]
ggplot(data=df %>% filter(between(x, in_slider_1, in_slider_2)), aes(x, y, group = 1)) +
theme_bw() +
geom_line(color="black", stat="identity") +
# geom_point() +
scale_x_datetime(labels = date_format("%m-%d %H:%M"),
limits = c(
as.POSIXct(in_slider_1),
as.POSIXct(in_slider_2)))
})
}
shinyApp(server = server, ui = ui)
It looks like you could now actually remove the scale_x_datetime completely and just have:
ggplot(data=df %>% filter(between(x, in_slider_1, in_slider_2)), aes(x, y, group = 1)) +
theme_bw() +
geom_line(color="black", stat="identity")
I know this question already has an answer, but this is another possible solution for you.
If you just want to get rid of it, that implies to me that you are OK with the output. Then you can try the following:
Add na.rm=TRUE to geom_line like : geom_line(..., na.rm=TRUE )
This explicitly tells geom_line and geom_path that is OK to remove NA values.
Reasoning with the warning:
Warning of: Removed k rows containing missing values (geom_path)
This tells you mainly 3 things:
geom_path is being called by another geom_something which is firing the warning. In your case, is geom_line.
It already removed k rows. So if the output is as desired, then you want to those rows removed.
The reason for removal is that some values ARE missing (NA).
What the warning doesn't tells you is WHY those rows have missing (NA) values.
You know that the reason comes from scale_x_datetime. Mainly from the limits argument. In a sense of (X,Y) pairs to be drawn, you set the X scale to values where is no "Y", or Y=NA. Your scale may be continuous, but your data is not. You may want to set a larger scale for a different number of reasons, but ggplot will always find that there isn't an associated Y value, and it makes a unilateral decision and fires a warning instead of an error.
Hopefully, times will come when Errors and Warnings highlights intuitive, language-independent calling trace to the emitter and a link to a correctly explained site with common mistakes, etc.

R Shiny plot for time series data, ggplot, producing NAs only

I have problems with my ggplot in Shiny. I am new to Shiny, so there are probably some rookie mistakes in the code. But I receive the following warnings:
Listening on http://127.0.0.1:4278`
Warning: Removed 93 rows containing non-finite values (stat_smooth).
Warning: Removed 93 rows containing missing values (geom_point).
Warning: Removed 1 rows containing missing values (geom_text).
The R code:
library(shiny)
library(ggplot2)
ggplot_df <- data.frame("start_ts"=c(1555279200,1555280100,1555281000,1555281900,1555282800),
"V1"=c(6.857970e-04,7.144347e-05,1.398045e-06,2.997632e-05,2.035446e-06),
"sum"=c(20,21,22,15,23))
# Small test data set with 5 observations... 93 in original one
# Define UI for application
ui <- fluidPage(sliderInput("time", "Time:",
min = as.POSIXct("00:00",format="%H:%M", tz=""),
max = as.POSIXct("24:00",format="%H:%M", tz=""),
value = c(
as.POSIXct("00:00",format="%H:%M")
), timeFormat = "%H:%M", step=60*15, timezone = "",
animate=
animationOptions(interval=300, loop=TRUE)),
plotOutput("plot")
)
# Define server logic required
server <- function(input, output) {
output$plot<-renderPlot({
ggplot_df$start_ts <-as.POSIXct(ggplot_df$start_ts, format="%H:%M", tz="",origin="1970-01-01")
ggplot_df<-ggplot_df[ggplot_df$start_ts==input$time,]
ggplot(ggplot_df,aes(x=sum,y=V1))+geom_point() +
theme_bw() +
geom_smooth(method = "lm", se = FALSE) +
ylim(0,3) +
xlim(0,max(ggplot_df$sum)) +
annotate('text', max(ggplot_df$sum)-10,3,
label = paste("~R^{2}==",round(cor(ggplot_df$sum, ggplot_df$V1), digits=2)),parse = TRUE,size=4)
})
}
# Run the application
shinyApp(ui = ui, server = server)
Note that exactly the same thing is happening even if I define the time zone.
ggplot_df is a data frame with 93 rows. What have I done wrong? The plot I receive is empty, no points, etc, as shown below:
The problem is that the POSIXct column is a datetime, but the slider input is only a time. Is date important here is it only time of day which is of interest? The code below makes some plots, although I can't tell what the desired end result is, so it may not be quite right
ui <- fluidPage(sliderInput("time", "Time:",
min = as.POSIXct("2019-04-14 00:00",format="%Y-%m-%d %H:%M", tz=""),
max = as.POSIXct("2019-04-15 24:00",format="%Y-%m-%d %H:%M", tz=""),
value = c(
as.POSIXct("2019-04-14 00:00")
), timeFormat = "%Y-%m-%d %H:%M", step=60*15, timezone = "",
animate=
animationOptions(interval=300, loop=TRUE)),
plotOutput("plot")
)
# Define server logic required
server <- function(input, output) {
output$plot<-renderPlot({
ggplot_df$start_ts <-as.POSIXct(ggplot_df$start_ts, tz="",origin="1970-01-01")
ggplot_df<-ggplot_df[ggplot_df$start_ts==input$time,]
ggplot(ggplot_df,aes(x=sum,y=V1))+geom_point() +
theme_bw() +
geom_smooth(method = "lm", se = FALSE) +
ylim(0,3) +
xlim(0,max(ggplot_df$sum)) +
annotate('text', max(ggplot_df$sum)-10,3,
label = paste("~R^{2}==",round(cor(ggplot_df$sum, ggplot_df$V1), digits=2)),parse = TRUE,size=4)
})
}

Suppressing non-integer axis breaks in ggplot2 graphs (in Shiny app)

I have tried all solutions recommended in How to display only integer values on an axis using ggplot2. Unfortunately, I could not solve the issue with any of them.
I have created a Shiny app that produces line graphs of annual data on a variety of variables. This works out nicely for most parameterizations:
No non-integer breaks
However, if I choose certain time spans on the slider, it produces graphs that have non-integer breaks on the x-axis, which makes no sense for a yearly data.
With non-integer breaks
Edit: Here a minimal reproducible version of the application
library(tidyverse)
library(shiny)
options(scipen = 999)
# Data
data1<-data.frame(values = c(15500, 16300, 18200, 28300, 23500, 23700,
31500, 35800, 34700, 36900, 40000, 44700,
53300, 55800, 69800, 89500, 1.13E+5,
1.53E+5, 1.77E+5, 1.83E+5, 1.99E+5),
year = seq(1990, 2010, 1))
#Shiny app
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
sliderInput("period", "Year:", min = 1990, max = 2010, value = c(1990, 2010), sep = "")),
mainPanel(plotOutput("ggplot2"))))
server <- function(input, output) {
data1_subset <- reactive({
filter(data1, year >= input$period[1] & year <= input$period[2])
})
output$ggplot2 <- renderPlot({
ggplot(data = data1_subset(), aes(x = year, y = values)) +
geom_line(aes(color = "red")) +
scale_x_continuous(name = "Year") +
scale_color_discrete(guide=FALSE)+
theme_minimal()
})
}
shinyApp(ui = ui, server = server)
To see the problem, select e.g. time span 2000-2010
Is there any way to suppress non-integer breaks as there are clearly nonsensical with annual data?
Thanks a lot in advance for your help!
Thanks for your help! It seems that the answer was much simpler as I thought. Putting breaks = function(x) unique(floor(pretty(x))) in my scale_x_continuous() function produced integer-only breaks, even without transforming the data into Date format. Removing the unique() does not change the behavior in my case, but it might do in other cases.
You should take care to use the correct class for your date column year (something like Date or POSIXct). As the comment suggests, you need to pick a particular date, like Jan 1st. This will inform ggplot2 about what's probably your intention and it will make it easier for you to steer the display format to something meaningful.
It will work out of the box, you can tune it more with ggplot's date/time scales.
The reprex with the presented idea implemented (and one more glitch regarding the line colour fixed):
library(tidyverse)
library(shiny)
# Data
tibble(values = c(15500,16300,18200,28300,23500,23700,
31500,35800,34700,36900,40000,44700,
53300,55800,69800,89500,1.13E+5,
1.53E+5,1.77E+5,1.83E+5,1.99E+5),
year = seq(1990, 2010, 1)) %>%
mutate(year = lubridate::ymd(year, truncated = 2L)) ->
data1
# Shiny app
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
sliderInput("period", "Year:",
min = 1990, max = 2010,
value = c(1990, 2010), sep = "")),
mainPanel(plotOutput("ggplot2"))))
server <- function(input, output) {
data1_subset <- reactive({
filter(data1,
year >= lubridate::ymd(input$period[1], truncated = 2L),
year <= lubridate::ymd(input$period[2], truncated = 2L))
})
output$ggplot2 <- renderPlot({
ggplot(data = data1_subset(), aes(x = year, y = values)) +
geom_line(color = "red") +
xlab("Year") +
theme_minimal()
})
}
shinyApp(ui = ui, server = server)

Error with dates and reactive inputs in R Shiny

I am putting together a small R Shiny app which will take several inputs from the user and use these inputs to subset a data frame and provide back two histograms. The users will pick a baseball season, two teams and then this information will provide a reactive list of possible games played between these two teams. The user will then pick a date/game and then a histogram will be displayed for each team which will show the distribution of runs scored per game for each team for all games within that season up to the date/game selected. I feel like I am almost there, I just need to get this date thing sorted out. Right now with the code as is, everything evaluates but I get this error twice;
Warning: Error in eval: do not know how to convert 'input$dates' to class “Date”
and this error twice;
Warning in eval(substitute(expr), envir, enclos) :
Incompatible methods ("Ops.factor", "Ops.Date") for "<"
ui.R
library(shiny)
library(dplyr)
shinyUI(fluidPage(
# Application title
titlePanel("Predicting the winner of a Major League Baseball game"),
sidebarLayout(
sidebarPanel(
selectInput("season","1. Select an MLB Season",
choices = list(2012,2013,2014,2015),
selected = 2012),
selectInput("var_1","2. Select the first team",
choices = c("ARI","ATL","BAL","BOS","CHC","CHW","CIN","CLE","COL","DET",
"HOU","KCR","LAA","LAD","MIA","MIL","MIN","NYM","NYY","OAK",
"PHI","PIT","SDP","SFG","SEA","STL","TBR","TEX","TOR","WSN"),
selected = "BAL"),
selectInput("var_2","3. Select the second team",
choices = c("ARI","ATL","BAL","BOS","CHC","CHW","CIN","CLE","COL","DET",
"HOU","KCR","LAA","LAD","MIA","MIL","MIN","NYM","NYY","OAK",
"PHI","PIT","SDP","SFG","SEA","STL","TBR","TEX","TOR","WSN"),
selected = "BOS"),
uiOutput("dates"),
sliderInput("bins",
"Binwidth:",
min = 1,
max = 5,
value = 2)
),
#main panel
mainPanel(
plotOutput("first_team_hist"),
plotOutput("second_team_hist")
)
)))
server.R
library(shiny)
library(dplyr)
library(ggplot2)
shinyServer(
function(input, output) {
mydf <- read.csv("batting_game_logs_merged.csv")
inputData_1 <- reactive({
filter(mydf,team == input$var_1 & season == input$season & date < as.Date(input$dates,format = "%Y-%m-%d"))
})
inputData_2 <- reactive({
filter(mydf,team == input$var_2 & season == input$season & date < as.Date(input$dates,format = "%Y-%m-%d"))
})
output$dates <- renderUI({
dates = mydf %>% filter(team == input$var_1 & opponent_team == input$var_2 & season == input$season) %>% select(date)
selectInput("dates","Pick a Game Date", as.character(dates[[1]]))
})
output$first_team_hist <- renderPlot({
myplot_1 <- ggplot(inputData_1(), aes(x = team_batting_gamelogs.R)) +
geom_histogram(aes(y = ..density..),
binwidth = input$bins, fill = I("blue"),col = I("red")) +
labs(title = paste("Runs Scored per game for",input$var_1),
x= "Runs Scored per Game", y = "Density")
print(myplot_1)
})
output$second_team_hist<- renderPlot({
myplot_2 <- ggplot(inputData_2(), aes(x = team_batting_gamelogs.R)) +
geom_histogram(aes(y = ..density..),
binwidth = input$bins, fill = I("blue"),col = I("red")) +
labs(title = paste("Runs Scored per game for",input$var_2),
x= "Runs Scored per Game", y = "Density")
print(myplot_2)
})
}
)
Thank you in advance for taking the time to review my problem.
-Josh
I am guessing your problem is the initial NULL value of your input$dates. Your reactive environments inputData_1/2 respond as soon as your UI is rendered (and they get their selected value). But no value has been assigned to input$dates yet, so your first run of these functions gets a NULL. Confirm that as.Date(NULL) yields exactly your error.
I advice you to make your reactive environments only listen to input$dates, i.e.
inputData_1 <- eventReactive(input$dates, {
filter(mydf,team == input$var_1 & season == input$season & date < as.Date(input$dates,format = "%Y-%m-%d"))
})
inputData_2 <- eventReactive(input$dates, {
filter(mydf,team == input$var_2 & season == input$season & date < as.Date(input$dates,format = "%Y-%m-%d"))
})
As far as I can see, you want computations to start only after inserting a date anyway.
Other possible fixes are to isolate the other variables or just add an if(!is.null(input$dates)){ ... } clause to handle NULL input.

Resources