R Shiny DateRangeInput Select Only Specific Days - r

I'm working on creating a shiny dashboard using R Shiny. I'm using selectInput to choose a view(Daily, Weekly, Monthly, Yearly) and a dateRangeInput which will allow the user to choose the dates the plots should display. The plots are made using Plotly.
Custom date range input to allow min/max views for dates(credit here):
CustomDateRangeInput <- function(inputId, label, minview = "days", maxview = "decades", ...) {
d <- shiny::dateRangeInput(inputId, label, ...)
d$children[[2L]]$children[[1]]$attribs[["data-date-min-view-mode"]] <- minview
d$children[[2L]]$children[[3]]$attribs[["data-date-min-view-mode"]] <- minview
d$children[[2L]]$children[[1]]$attribs[["data-date-max-view-mode"]] <- maxview
d$children[[2L]]$children[[3]]$attribs[["data-date-max-view-mode"]] <- maxview
d
}
Code for creating the dateRangeInput based on the selected view:
output$asymp_dates <- renderUI({
switch (
input$id_view,
"Daily" = {
data <- GetDateRangeData(asymp, "day")
dateRangeInput("id_asymp_dates", "Date Range", min(data$Date), max(data$Date), min(data$Date), max(data$Date), "mm/dd/yyyy", "month")
},
"Weekly" = {
data <- GetDateRangeData(asymp, "week")
dateRangeInput("id_asymp_dates", "Date Range", min(data$Date), max(data$Date), min(data$Date), max(data$Date), "mm/dd/yyyy", "month")
},
"Monthly" = {
data <- GetDateRangeData(asymp, "month")
min_date <- min(floor_date(data$Date, "month"))
max_date <- max(ceiling_date(data$Date, "month")) - 1
CustomDateRangeInput("id_asymp_dates", "Date Range", "year", "decades", min_date, max_date, min_date, max_date, "MM, yyyy", "year")
},
"Yearly" = {
data <- GetDateRangeData(asymp, "year")
min_date <- min(floor_date(data$Date, "year"))
max_date <- max(ceiling_date(data$Date, "year")) - 1
CustomDateRangeInput("id_asymp_dates", "Date Range", "decades", "decades", min_date, max_date, min_date, max_date, "yyyy", "decades")
# The calculation is needed in order to reset the date range,
# but we don't want the date range editable.
shinyjs::disable("id_asymp_dates")
}
)
})
Everything works fine, but I would like for the weekly view to only be able to select the first/last day of each week so that my date ranges go from the start date being a beginning of a week and the end date being the end of a week.
ie:
dateRangeInput Calendar
March 8 - March 14, March 15 - March 21, and March 22 - March 28 are weeks. I want to be able to only select March 8, March 15, or March 22 as the first date and then March 14, March 21, or March 28 as my end date.

Related

Yahoo Finance ticker scraping using Library yfR

Wondering if there is a way to use yf_get() to grab a previousClose value from Yahoo Finance if there is no value for the date given. For example:
curr <- yf_get(tickers, first_date = Sys.Date() - 1, last_date = Sys.Date())
prev_q <- yf_get(tickers = tickers,
first_date = quarters[1]-.5,
last_date = quarters[1])
prev_q_closes <- round(prev_q$price_close,2)
prev_q2 <- yf_get(tickers = tickers,
first_date = quarters[2]-.5,
last_date = quarters[2], thresh_bad_data = 0.45)
prev_q2_closes <- round(prev_q2$price_close,2)
prev_q3 <- yf_get(tickers = tickers,
first_date = quarters[3]-.5,
last_date = quarters[3])
prev_q3_closes <- round(prev_q3$price_close,2)
close_prices <- cbind(prev_q3_closes, prev_q2_closes, prev_q_closes, current_close)
tick_close <- data.frame(Tickers = tickers,
ClosingPrices = close_prices,
PercentChanges = percent_changes)
dates <- rev(quarters)
dates_change <- as.character(format(dates, "%m-%d"))
#colnames(tick_close) <- c("Tickers", "Prev Q3 Closing Prices", "Prev Q2 Closing Prices", "Prev Q1 Closing Prices", "Current Closing Prices")
colnames(tick_close) <- c("Tickers", as.character(dates[1]), as.character(dates[2]), as.character(dates[3]), as.character(CurrentDate),
paste(dates_change[1],dates_change[2], sep=" to "), paste(dates_change[1], dates_change[3], sep=" to "),
paste(dates_change[1],as.character(format(CurrentDate, "%m-%d")), sep=" to "),
paste(dates_change[3],as.character(format(CurrentDate, "%m-%d")), sep=" to "))
etc and I then grab the previous quarterly date values, for some Chinese companies on Yahoo Finance they do not have a value for December 31st, and my algorithm falls apart because it cannot grab a different value. I want it to grab the December 30th value IF there is no December 31st value on Yahoo Finance!

Shiny Dashboard Date Slider Input

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")

Dynamic Time Series Function R

I currently have a time series of football data for weekly stats for variables such as shots and goals. I want to create a "form" function with input for number of games (specify date) and the variable of choice (shots, goals, etc) so that I can check the form of players for certain stats over the last 4 games, 6 games or whatever period I specify. The data frame is of the form:
week = as.vector(c(rep(25, 5), rep(26, 5), rep(27, 5)))
date = as.vector(c(rep("2019-08-09 15:00:00", 5), rep("2019-08-16 15:00:00", 5), rep("2019-08-23 15:00:00", 5)))
players = c("Player 1", "Player 2", "Player 3", "Player 4", "Player 5")
name = as.vector(c(rep(players, 3)))
goals = as.vector(sample(c(0:2), 15, replace = T))
shots = as.vector(sample(c(0:8), 15, replace = T))
data = data.frame(week, date, name, goals, shots)
Would it make sense to create a function using dplyr and input variables for time period and variable type? Or is there some package that will do this for me?
This answer could give you some idea how to filter the data frame for date or games played as specified in the comments:
library(tidyverse)
library(lubridate)
data = tibble(
week = rep(31:40, each = 2),
date = seq.Date(ymd("2019-01-01"), length.out = 20, by = "months"),
name = paste0("player", rep(1:4, each = 5)),
goals = sample(c(0:2), 20, replace = T),
shots = sample(c(0:8), 20, replace = T)
)
# last 3 months or after
data %>%
filter(date > (today() %m-% months(3) ))
# last 5 games
data %>%
filter(week > (max(week) - 4) )

Shiny - Using Date range from sliderInput in a reactive dplyr expression used for a ggplot

I am creating a Shiny App showing the trend of various financial metrics for various stocks. The financial metrics for the various stocks are provided at the end of every quarter.
I want to provide my end-users the ability to use a Slider Input to select the date range for their analysis. Previous questions on SO involves using a single value for their slider instead of a range (e.g. this post). Hence, I am unable to replicate the solution.
The following is the packages and the simulated data file I am using. There are 3 columns: (a) Date, (b) Stock, (c) Value for a particular metric.
library(shiny)
library(readxl)
library(dplyr)
library(ggplot2)
library(lubridate)
df <- data.frame(Date = c("30/09/2018", "30/06/2018", "31/03/2018", "31/12/2017", "30/09/2017", "30/06/2017",
"31/03/2017", "30/09/2018", "30/06/2018", "31/03/2018", "31/12/2017", "30/09/2017", "30/06/2017",
"31/03/2017"),
Stock = c(rep("AAA", 7), rep("BBB", 7)),
Value = c(5.1, 5.2, 5.6, 5.5, 5.6, 5.7, 5.6, 6.4, 6.9, 6.7, 7.2, 7.2, 7.2, 7.7))
df$Date <- as.Date(df$Date, format = "%d/%m/%Y")
df$Stock <- as.character(df$Stock)
The following is the user interface:
# Define UI for application
ui <- fluidPage(
# Application title
titlePanel("Stock Financials Trend"),
# Sidebar with slider input to select date range
sidebarLayout(
sidebarPanel(
selectInput("Stock_selector",
"Stock:",
c("AAA", "BBB")),
# Add a Slider Input to select date range
sliderInput("Date_range_selector", "Select Date Range",
min = 2017,
max = 2018,
value = c(2017, 2018))
),
# Show a plot of the trend
mainPanel(
plotOutput("plot")
)
)
)
The server is as follow:
server <- function(input, output) {
filtered_df <- reactive({
df %>%
filter(Stock == input$Stock_selector & year(Date) == between(year(Date), input$Date_range_selector[1], input$Date_range_selector[2]))
})
output$plot <- renderPlot({
ggplot(filtered_df(), aes_string(x = "Date", y = "Value")) + geom_line() + geom_point() +
labs(title = paste(input$Stock_selector, "Trend", sep = " "), y = "Value")
})
}
# Run the application
shinyApp(ui = ui, server = server)
My script shows that filtering is done using a dplyr expression which is then assigned to a reactive expression to be used subsequently for plotting with ggplot.
The above script shows a blank output.
I have also tried replacing the numeric values of 2017 and 2018 in the sliderInput function with year(as.Date("2017", format = "%d/%m/%Y")) but the output still fails as well.
The desired output looks something like the following (assuming Stock AAA is selected and the range is set from 2018 to 2018):
Thanks!
You need to remove year(Date) == in your filter statement, i.e change it to:
filtered_df <- reactive({
df %>%
filter(Stock == input$Stock_selector & between(year(Date), input$Date_range_selector[1], input$Date_range_selector[2]))
})

Converting weeks of year to dates

I have a data set with number of weeks from the beginning of the year (%W), which I would like to convert to dates in order to plot it using date on x-axis
dat <- structure(data.frame(week = c(22, 34, 15), year = c(2009, 2009, 2010), x = c(3.4, 5.2, 1.3)))
I try to convert the weeks based on earlier questions here, but end up getting "YYYY-10-01" for each date.
as.Date(paste("01", dat$week, dat$year, sep = "-"), format = "%d-%W-%Y")
Why is this and how can do it right?
Try this instead:
as.Date(paste("1", dat$week, dat$year, sep = "-"), format = "%w-%W-%Y")
A week and a year don't specify a date, so you do need a "day", but you need the "day of the week", or %w, rather than "day of the month", or %d. In this case, I used Monday (i.e. 1). Also, apparently %w doesn't like leading zeros.

Resources