How to connect dateRangeInput and sliderInput in R-Shiny - r

In my Shiny-app, I have to subset a dataframe by time. The most convenient Widget for me is a sliderInput, but I also want to allow for the possibility of selecting the specific dates from a calendar, just as I would do with dateRangeInput, because the dataset spans multiple years of daily data. I have tried to link the two of them, updating the slider when dateRange changes and vice versa using two separate renderUI(). Generally, this works well, but in some cases, I get stuck in an infinite loop where the slider and rangeInput invalidate each other constantly. The infinite loop only triggers after changes thorugh the slider.
My Approach so far looks like this:
output$dateRangeSliderUI <- renderUI({
date_range_input <- input$dateRangeInput
data <- isolate(dataset())
start_date <- default_start
end_date <- default_end
if (is.null(date_range_input)){
range_slider <- c(start_date, end_date)
} else {
range_slider <- date_range_input
}
sliderInput("dateRangeSlider",
label = "Date Range:",
value = range_slider,
min = min(data$Date),
max = max(data$Date),
step = 1,
timeFormat = "%F")
})
output$dateRangeInputUI <- renderUI({
date_range_slider <- input$dateRangeSlider
data <- isolate(dataset$regressions)
start_date <- default_start
end_date <- default_end
if (is.null(date_range_slider)){
range_input <- c(start_date, end_date)
} else {
range_input <- date_range_slider
}
dateRangeInput("dateRangeInput",
label = NULL,
start = range_input[1],
end = range_input[2],
min = min(data$Date),
max = max(data$Date))
})
As you can see, the two widgets are only reactive to changes in each other, and start_date and end_date account for errors during startup during which both of them are still NULL.
Can you help me, how I might avoid getting stuck in an infinite loop?

To avoid recursion you can use two reactiveVal to store last update time of sliderInput and dateRange.
Update is only done after a certain delay which ensures that this was manual :
library(shiny)
ui <- fluidPage(
sliderInput(
"slider",
"Slider",
min = Sys.Date() - 90,
max = Sys.Date(),
value = c(Sys.Date() - 30, Sys.Date())
),
dateRangeInput(
"daterange",
"Input date range",
start = Sys.Date() - 30,
end = Sys.Date()
)
)
server <- function(input, output, session) {
## Avoid chain reaction
reactdelay <- 1
change_slider <- reactiveVal(Sys.time())
change_daterange <- reactiveVal(Sys.time())
observeEvent(input$slider, {
if (difftime(Sys.time(), change_slider()) > reactdelay) {
change_daterange(Sys.time())
updateDateRangeInput(session,
"daterange",
start = input$slider[[1]],
end = input$slider[[2]])
}
})
observeEvent(input$daterange, {
if (difftime(Sys.time(), change_daterange()) > reactdelay) {
change_slider(Sys.time())
updateSliderInput(session,
"slider",
value = c(input$daterange[[1]], input$daterange[[2]]))
}
})
}
shinyApp(ui, server)

Related

No "datesdisabled" in updateDateInput in R Shiny?

I built an app in R Shiny which uses time series data that excludes many dates. Within the app a user can select a new dataset, so the dates available will change. I'm using updateDateInput to update the dateInput selector. However, updateDateInput does not seem to allow the datesdisabled function?
Here is a reprex:
library(shiny)
# Sample 3 dates and disable the rest
my_dates <- sample(seq(as.Date('2021-01-01'), as.Date('2021-01-31'), by = "day"), 3)
date_choices <- seq.Date(from = min(my_dates), to = max(my_dates), by = 1)
dates_disabled <- date_choices[!(date_choices %in% my_dates)]
ui <- fluidPage(
dateInput("date", "Select Date",
min = min(date_choices),
max = max(date_choices),
value = max(date_choices),
datesdisabled = dates_disabled),
actionButton("click", "Click Me")
)
server <- function(input, output, session) {
observeEvent(input$click, {
my_dates <- sample(seq(as.Date('2021-01-01'), as.Date('2021-01-31'), by = "day"), 3)
date_choices <- seq.Date(from = min(my_dates), to = max(my_dates), by = 1)
dates_disabled <- date_choices[!(date_choices %in% my_dates)]
updateDateInput(
session,
"date",
min = min(date_choices),
max = max(date_choices),
value = max(date_choices),
datesdisabled = dates_disabled)
})
}
shinyApp(ui, server)
When the button is clicked and the updateDateInput runs, I get this error:
Warning: Error in updateDateInput: unused argument (datesdisabled =
dates_disabled)
I guess there is the option of changing the date to a character and using selectInput? But then I don't get the nice calendar!
You are right, the datesdisabled argument is not available in the update function. You can change the disabled dates by moving the UI declaration into the server and feed it to the client with renderUI().
The sample does not declare the date input in the UI but a uiOutput("date"). The server can dynamically create the dateInput using the datesdisabled argument. This way you can change the disabled dates.
The example will pick only 3 enabled dates after every button click.
# Reprex: The actual implementation of this uses data from a file:
# 1. Reads data file before ui and server are established
# 2. Does a bunch of calculations
# 3. Identifies dates that exist in data file
# 4. The data file is getting updated in the background from another application.
# 5. Allows user to click the button to update the data file. Reprex shows code
# that is used to update the date selector based on new data read. Dates are
# random in reprex, but would come from data file in actual code.
# Sample 3 dates and disable the rest - actual code reads data file here
# and parses out dates that exist in records
my_dates <- seq(as.Date('2021-01-01'), as.Date('2021-01-31'), by = "day")
date_choices <- sample(my_dates, 31-3)
ui <- fluidPage(
uiOutput("date"), textOutput("disabled"),
actionButton("click", "Click Me")
)
server <- function(input, output, session) {
dates_disabled <- reactiveVal(NULL)
# Init 'dates_disabled()' once before Shiny flushes the reactive system with callback,
# using date_choices that exist in original data set
onFlush(fun = function () {dates_disabled(date_choices)}, once = TRUE)
# dateInput widget
output$date <- renderUI({
maxDate <- as.Date(max(setdiff(my_dates, dates_disabled())),
origin = "1970-01-01")
dateInput(input = "date",
label = "Select Date",
min = min(my_dates),
max = max(my_dates),
value = maxDate,
datesdisabled = dates_disabled())
})
# This output makes it easier to test if it works by showing the enabled dates
output$disabled <- renderPrint({
req(dates_disabled()) # only run this when 'dates_disabled' is initialized properly
Enabled <- as.Date(setdiff(seq(as.Date('2021-01-01'), as.Date('2021-01-31'), by = "day"),
dates_disabled()),
origin = '1970-01-01')
paste("Enabled:", paste(Enabled[order(Enabled)], collapse = ", "))
})
# Set new datesdisabled on button click
# Actual code would read updated data file and parse new dates
observeEvent(input$click, {
SelectedDates <- sample(my_dates, 31-3)
dates_disabled( SelectedDates )
})
}
shinyApp(ui, server)

R Shiny - saving values of function in data table after action button press

I am trying to create a way to track opening and closing of the breathing organ (i.e. a mouth) of several animals at the same time over the course of 45 minutes. The goal is to be able to calculate the total open time and frequency of opening for each animal. Basically, the idea is to have several stopwatches operating in parallel, while tracking two lists of values per animal: open time and close time.
The experiment would ideally go like this: I start the experiment and therefore the stopwatch. Every time animal 1 opens its breathing organ, I press open, and once it closes its breathing organ, I press close. The time of each, relative to the stopwatch started at the beginning of the experiment, are recorded in a dataframe for animal 1. This process repeats 10-15 times throughout 45 minutes. At the same time, another animal is opening and closing its breathing organ, and a separate dataframe for animal 2 is created using a different set of buttons. I would like to have this be possible for up to 10 animals simultaneously.
I have been able to make the stopwatches (example code below) using a watch function, as well as include action buttons that output text corresponding to the difference in system time between start time of the experiment and time of pressing the open or close buttons. However, I am unsure of how to store these values in a dataframe for each animal.
I have looked around stackoverflow and found nothing that works, including this thread: r Shiny action button and data table output
and this one:
Add values to a reactive table in shiny
Let me know if you need any more info! Thanks in advance.
library(lubridate)
library(shiny)
library(DT)
# stopwatch function ----
stop_watch = function() {
start_time = stop_time = open_time = close_time = NULL
start = function() start_time <<- Sys.time()
stop = function() {
stop_time <<- Sys.time()
as.numeric(difftime(stop_time, start_time))
}
open = function() {
open_time <<- Sys.time()
as.numeric(difftime(open_time, start_time))
}
close = function() {
close_time <<- Sys.time()
as.numeric(difftime(close_time, start_time))
}
list(start=start, open=open, close=close, stop=stop)
}
watch = stop_watch()
# ui ----
ui <- fluidPage(
titlePanel("Lymnaea stopwatch"),
sidebarLayout(
sidebarPanel(
selectInput(
"select",
label = "Number of animals",
choices = c(1,2,3,4,5,6,7,8,9,10),
selected = c("1")
)
# action button conditionals ----
),
mainPanel(
h4("Start/Stop Experiment:"),
actionButton('start1',"Start"),
actionButton('stop1', "Stop"),
textOutput('initial1'),
textOutput('start1'),
textOutput('stop1'),
textOutput('stoptime1'),
conditionalPanel(
h4("Animal 1"),
condition = "input.select == '1'||input.select == '2'||input.select == '3'||input.select == '4'||input.select == '5'||input.select == '6'||input.select == '7'||input.select == '8'||input.select == '9'||input.select == '10'",
actionButton('open1', "Open"),
actionButton('close1', "Close"),
textOutput('open1'),
textOutput('opentime1'),
textOutput('close1'),
textOutput('closetime1'),
)
)
)
)
# server ----
server <- function(input, output, session) {
values <- reactiveValues()
values$df <- data.frame(colnames(c("Open", "Close")))
newEntry <- observe({
if(input$open1 > 0) {
newLine <- isolate(c(({watch$start()})))
isolate(values$df <- rbind(values$df, newLine))
}
})
output$table <- renderTable({values$df})
# n = 1 animal ----
observeEvent(input$start1, {
watch$start()
output$initial1 <- renderText(
"Timer started."
)
})
observeEvent(input$open1, {
watch$open()
output$open1 <- renderText(
"Time of opening:"
)
output$opentime1 <- renderText({
watch$open()
})
})
observeEvent(input$close1, {
watch$close()
output$close1 <- renderText({
"Time of closing:"
})
output$closetime1 <- renderText({
watch$close()
})
})
}
shinyApp(ui, server)
I think there may be a number of ways you could set this up differently.
One recommendation I have is to avoid putting output inside of your observers.
Another is calling your stopwatch functions only once - for data integrity, to make sure your display and data collected are the same.
In addition, it might be helpful to have a single data table store all of your open and close events, with an additional column for animal number. It would be relatively easy to work with a table like this for future analyses.
Here is a quick example you can try out, just to get a sense of the behavior. Please also add tableOutput('table') to your ui after your conditionalPanel to view the data frame.
# ui ----
ui <- fluidPage(
titlePanel("Lymnaea stopwatch"),
sidebarLayout(
sidebarPanel(
selectInput(
"select",
label = "Number of animals",
choices = c(1,2,3,4,5,6,7,8,9,10),
selected = c("1")
)
# action button conditionals ----
),
mainPanel(
h4("Start/Stop Experiment:"),
actionButton('start1',"Start"),
actionButton('stop1', "Stop"),
textOutput('initial1'),
textOutput('start1'),
textOutput('stop1'),
textOutput('stoptime1'),
conditionalPanel(
h4("Animal 1"),
condition = "input.select == '1'||input.select == '2'||input.select == '3'||input.select == '4'||input.select == '5'||input.select == '6'||input.select == '7'||input.select == '8'||input.select == '9'||input.select == '10'",
actionButton('open1', "Open"),
actionButton('close1', "Close"),
textOutput('open1'),
textOutput('opentime1'),
textOutput('close1'),
textOutput('closetime1'),
),
tableOutput('table')
)
)
)
# server ----
server <- function(input, output, session) {
values <- reactiveValues(df = data.frame(Animal = integer(),
Event = character(),
Time = as.POSIXct(character()),
stringsAsFactors = FALSE),
timer = "Timer Off")
output$initial1 <- renderText({
values$timer
})
output$opentime1 <- renderText({
paste("Opened at:", tail(values$df[values$df[["Animal"]] == 1 & values$df[["Event"]] == "Open", "Time"], 1))
})
output$closetime1 <- renderText({
paste("Closed at:", tail(values$df[values$df[["Animal"]] == 1 & values$df[["Event"]] == "Close", "Time"], 1))
})
output$table <- renderTable({
values$df
})
observeEvent(input$start1, {
watch$start()
values$timer <- "Timer Started"
})
observeEvent(input$open1, {
values$df <- rbind(values$df, data.frame(Animal = 1, Event = "Open", Time = watch$open()))
})
observeEvent(input$close1, {
values$df <- rbind(values$df, data.frame(Animal = 1, Event = "Close", Time = watch$close()))
})
}
This could be scaled up for 10 animals, and there are alternative ways to provide feedback to user on data.
Let me know what you think, and if this is in the direction you had in mind.

How to ask R Shiny to create several "select boxes" - based on previous input

In my tiny Shiny app I am asking the user: how many time periods do you want to cut your time series into? For example, the user selects 3.
I want to use this input to take a fixed vector of dates and make it possible for the user the select from it the desired last date of Time Period 1 (in select box 1), and Time Period 2 (in select box 2). (The last date for time period 3 will be the very last date, so I don't need to ask).
I am not sure how to do it. I understand that because I don't know the desired number of time periods in advance, I have to create a list. But how do I then collect the input from those select boxes?
Thanks a lot!
library(shiny)
### UI #######################################################################
ui = shinyUI(fluidPage(
titlePanel("Defining time periods"),
# Sidebar:
sidebarLayout(
sidebarPanel(
# Slider input for the number of time periods:
numericInput("num_periodsnr", label = "Desired number of time periods?",
min = 1, max = 10, value = 2),
uiOutput("period_cutpoints")
),
# Show just the number of periods so far.
mainPanel(
textOutput("nr_of_periods")
)
)
))
### SERVER ##################################################################
server = shinyServer(function(input, output, session) {
library(lubridate)
output$nr_of_periods <- renderPrint(input$num_periodsnr)
# Define our dates vector:
dates <- seq(ymd('2016-01-02'), ymd('2017-12-31'), by = '1 week')
# STUCK HERE:
# output$period_cutpoints<-renderUI({
# list.out <- list()
# for (i in 1:input$num_periodsnr) {
# list.out[[i]] <- renderPrint(paste0("Sometext", i), ,
# )
# }
# return(list.out)
# })
})
# Run the application
shinyApp(ui = ui, server = server)
This is similar to a question I asked and subsequently worked out an answer to here. The big changes are (predictably) in the server.
Nothing needs to change in the UI, but as you'll see below I've included another textOutput so that you can see the dates you end up selecting, and I've also added an actionButton, which I'll explain later.
The server function has a couple additions, which I'll describe first and then put together at the end. You're right that you need to create a list of input objects inside the renderUI, which you can do through lapply. At this step, you're creating as many selectInputs as you'll have cutpoints, minus one because you say you don't need the last:
output$period_cutpoints<-renderUI({
req(input$num_periodsnr)
lapply(1:(input$num_periodsnr-1), function(i) {
selectInput(inputId=paste0("cutpoint",i),
label=paste0("Select cutpoint for Time Period ", i, ":"),
choices=dates)
})
})
Next, you'll need to access the values selected in each, which you can do in the same way, using a reactiveValues object you create first, and assign the new values to it. In my version of this problem, I couldn't figure out how to get the list to update without using an actionButton to trigger it. Simple reactive() or observe() doesn't do the trick, but I don't really know why.
seldates <- reactiveValues(x=NULL)
observeEvent(input$submit, {
seldates$x <- list()
lapply(1:(input$num_periodsnr-1), function(i) {
seldates$x[[i]] <- input[[paste0("cutpoint", i)]]
})
})
Full working app code then looks like this:
library(shiny)
ui = shinyUI(fluidPage(
titlePanel("Defining time periods"),
sidebarLayout(
sidebarPanel(
numericInput("num_periodsnr", label = "Desired number of time periods?",
min = 1, max = 10, value = 2),
uiOutput("period_cutpoints"),
actionButton("submit", "Submit")
),
mainPanel(
textOutput("nr_of_periods"),
textOutput("cutpoints")
)
)
))
server = shinyServer(function(input, output, session) {
library(lubridate)
output$nr_of_periods <- renderPrint(input$num_periodsnr)
dates <- seq(ymd('2016-01-02'), ymd('2017-12-31'), by = '1 week')
output$period_cutpoints<-renderUI({
req(input$num_periodsnr)
lapply(1:(input$num_periodsnr-1), function(i) {
selectInput(inputId=paste0("cutpoint",i),
label=paste0("Select cutpoint for Time Period ", i, ":"),
choices=dates)
})
})
seldates <- reactiveValues(x=NULL)
observeEvent(input$submit, {
seldates$x <- list()
lapply(1:(input$num_periodsnr-1), function(i) {
seldates$x[[i]] <- input[[paste0("cutpoint", i)]]
})
})
output$cutpoints <- renderText({as.character(seldates$x)})
})
shinyApp(ui = ui, server = server)
you can make the boxes dynamically inside an lapply and send them as 1 output object to the ui
require("shiny")
require('shinyWidgets')
ui = shinyUI(fluidPage(
titlePanel("Defining time periods"),
# Sidebar:
sidebarLayout(
sidebarPanel(
# Slider input for the number of time periods:
numericInput("num_periodsnr", label = "Desired number of time periods?",
min = 1, max = 10, value = 2),
uiOutput("period_cutpoints")
),
# Show just the number of periods so far.
mainPanel(
textOutput("nr_of_periods")
)
)
))
# Define server logic ----
server <- function(session, input, output) {
output$period_cutpoints<- renderUI({
req(input$num_periodsnr > 0)
lapply(1:input$num_periodsnr, function(el) {
airDatepickerInput(inputId = paste('PeriodEnd', el, sep = ''), label = paste('Period End', el, sep = ' '), clearButton = TRUE, range = F, update_on = 'close')
})
})
}
# Run the app ----
shinyApp(ui = ui, server = server)
Since you did not provide a dataset to apply the inputs on, and I don't know what date ranges your data has, I did not add code to set min/max on the date pickers, and not sure what kind of code to provide for you to use the data. You would need to write something to put them in a list indeed
values <- reactiveValues(datesplits = list(),
previous_max = 0)
observeEvent(input$num_periodsnr, {
if(input$num_periodsnr > values$previous_max) {
lapply(values$previous_max:input$num_periodsnr, function(el) {
observeEvent(input[[paste(paste('PeriodEnd', el, sep = '')]], {
values$datesplits[el] <- input[[paste(paste('PeriodEnd', el, sep = '')]]
})
values$previous_max <- max(values$previous_max, input$num_periodsnr)
})
}
})
and then use the list of dates for whatever you need to do with them I think.
I use the trick with run lapenter code hereply from previous_max to input$num_periodsnr if(input$num_periodsnr > values$previous_max){} to avoid the problem you create when you repeatedly create observers for the same input element. Whereas ui elements are overwritten when created in a loop, observeEvents are made as copies, so every time your loop fires, you make another copy of observers 1:n. This results in all copies firing every time, until you have a million observers all firing, creating possible strange bugs, unwanted effects and loss of speed.

R Shiny: conditional update of possible user input choices in a dynamic situation

I've created a tiny Shiny app where the user is asked into how many periods s/he wants to cut a given vector of dates (between 2 and 4). Then, for each time period the user wants to have (except for the last one) s/he is asked to select the last date of that time period.
The app is working, however, I am afraid some foolish user might select end dates that are not incremental, e.g., the selected end date for Time Period 1 might be later in time than the end date selected for Time Period 2, etc.
In other words, I'd love to make choices (dates) available to user while defining cutpoint2 to contain only dates that come AFTER the cutpoint1 date, etc. So, if the user selected '2006-12-31' as the end date for Time Period 1, I'd like the dates available for user input box for Time Period 2 to start AFTER that date.
However, I am not sure it's even possible in this super-dynamic situation because first, I create those cutpoint inputs for the first time - when the user hasn't even been asked about dates at all, so I can't make them really dependent on each other. And then I ask the user to define the cut points - and then I'd like that dynamic to kick in.
Appreciate your advice!
library(shiny)
ui = shinyUI(fluidPage(
titlePanel("Defining time periods"),
sidebarLayout(
sidebarPanel(
numericInput("num_periodsnr", label = "Desired number of time periods?",
min = 2, max = 4, value = 2),
uiOutput("period_cutpoints"),
actionButton("submit", "Update time periods")
),
mainPanel( # Just shows what was selected
textOutput("nr_of_periods"),
textOutput("end_dates")
)
)
))
server = shinyServer(function(input, output, session) {
library(lubridate)
output$nr_of_periods <- renderPrint(input$num_periodsnr)
# Dates string to select dates from:
dates <- seq(ymd('2016-01-02'), ymd('2017-12-31'), by = '1 week')
output$period_cutpoints <- renderUI({
req(input$num_periodsnr)
lapply(1:(input$num_periodsnr - 1), function(i) {
selectInput(inputId = paste0("cutpoint", i),
label = paste0("Select the last date of Time Period ", i, ":"),
choices = dates)
})
})
dates_chosen <- reactiveValues(x = NULL)
observeEvent(input$submit, {
dates_chosen$x <- list()
lapply(1:(input$num_periodsnr - 1), function(i) {
dates_chosen$x[[i]] <- input[[paste0("cutpoint", i)]]
})
})
output$end_dates <- renderText({paste(as.character(dates_chosen$x), collapse = ", ")})
})
shinyApp(ui = ui, server = server)
Insert this into your server function:
observe({
if(input$num_periodsnr > 2){
for(i in 2:(input$num_periodsnr - 1)) {
updateSelectInput(session, paste0("cutpoint", i), choices = dates[dates > input[[paste0("cutpoint", i-1)]]])
}
}
})
Due to your lapply where you make new selectInput whenever you increase the number of periods, you (unintenionally) overwrite the previous results and reset the starting period, whenever a user goes from e.g. 3 to 4 cutpoint periods.

Add back/next button to date range input in shiny

I spent quite a while trying to figure out how to add back/next week button around the daterangeinput field in Shiny. I personally think it is a cool and handy feature and it seems that there is no similar question/answer on stackoverflow (correct me if I'm wrong and I will delete this post).
Here is a screenshot so you know what I am talking about:
Here is a list of features I could think of when I design the code.
1. When you hit back/next buttons, both dates will move backward/forward
2. Back/Next should use the gap between the two dates to jump around
3. When the date on the left hits the minimum dates and you hit back, that date won't decrease anymore but the date on the right side will still decrease until it hits the minimum dates as well
4. When both dates equals to each other at the minimum date, when you hit Next, the date on the right side will increase by 7 (a week) by default.
5. Vice versa for the right side.
I put my code on a public gist.
shiny::runGist("https://gist.github.com/haozhu233/9dd15e7ba973de82f124")
server.r
library(shiny)
shinyServer(function(input, output, session) {
session$onSessionEnded(function() {
stopApp()
})
date.range <- as.Date(c("2015-01-01", "2015-12-31"))
# ------- Date Range Input + previous/next week buttons---------------
output$choose.date <- renderUI({
dateRangeInput("dates",
label = h3(HTML("<i class='glyphicon glyphicon-calendar'></i> Date Range")),
start = "2015-05-24", end="2015-05-30",
min = date.range[1], max = date.range[2])
})
output$pre.week.btn <- renderUI({
actionButton("pre.week",
label = HTML("<span class='small'><i class='glyphicon glyphicon-arrow-left'></i> Back</span>"))
})
output$next.week.btn <- renderUI({
actionButton("next.week",
label = HTML("<span class='small'>Next <i class='glyphicon glyphicon-arrow-right'></i></span>"))
})
date.gap <- reactive({input$dates[2]-input$dates[1]+1})
observeEvent(input$pre.week, {
if(input$dates[1]-date.gap() < date.range[1]){
if(input$dates[2]-date.gap() < date.range[1]){
updateDateRangeInput(session, "dates", start = date.range[1], end = date.range[1])
}else{updateDateRangeInput(session, "dates", start = date.range[1], end = input$dates[2]-date.gap())}
#if those two dates inputs equal to each other, use 7 as the gap by default
}else{if(input$dates[1] == input$dates[2]){updateDateRangeInput(session, "dates", start = input$dates[1]-7, end = input$dates[2])
}else{updateDateRangeInput(session, "dates", start = input$dates[1]-date.gap(), end = input$dates[2]-date.gap())}
}})
observeEvent(input$next.week, {
if(input$dates[2]+date.gap() > date.range[2]){
if(input$dates[1]+date.gap() > date.range[2]){
updateDateRangeInput(session, "dates", start = date.range[2], end = date.range[2])
}else{updateDateRangeInput(session, "dates", start = input$dates[1]+date.gap(), end = date.range[2])}
}else{if(input$dates[1] == input$dates[2]){updateDateRangeInput(session, "dates", start = input$dates[1], end = input$dates[2]+7)
}else{updateDateRangeInput(session, "dates", start = input$dates[1]+date.gap(), end = input$dates[2]+date.gap())}
}})
output$dates.input <- renderPrint({input$dates})
})
#------- End of Date range input -----------------
ui.r
library(shiny)
shinyUI(
navbarPage("Demo",
position = "static-top",
fluid = F,
#================================ Tab 1 =====================================
tabPanel("Demo",class="active",
sidebarLayout(
sidebarPanel(uiOutput("choose.date"),
tags$div(class="row",
tags$div(class="col-xs-6 text-center", uiOutput("pre.week.btn")),
tags$div(class="col-xs-6 text-center", uiOutput("next.week.btn")))
),
mainPanel = (
textOutput("dates.input")
)
))))

Resources