1

I would like to know if you can help me with the following question:

I've inserted an executable app below just to give you a sense of what I want to do. When running the APP, you will notice that it has a field called SelectDate. It's a calendar. It is from January to December 2021, as it is contemplating 01/01 and 05/12 which refers to my df database. However, I would like the calendar to show the holidays days. Leave the holiday days in a different color or highlighted on the calendar, something like that. By any chance, is there any way to do this?

library(shiny)
library(shinythemes)

function.cl<-function(df,date, d1,d2){
  df <- structure(
    list(date = c("2021-01-01","2021-03-02","2021-04-03","2021-09-04","2021-12-05"),
         d1 = c(0,1,4,5,6), d2 = c(2,4,5,6,7)),class = "data.frame", row.names = c(NA, -5L))
}    
ui <- fluidPage(
  
  ui <- shiny::navbarPage(theme = shinytheme("flatly"), collapsible = TRUE,
                          br(),
                          
                          tabPanel("",
                                   sidebarLayout(
                                     sidebarPanel(
                                       
                                       uiOutput("date"),
                                       selectInput("d1", label = h4("D1"),""),
                                       selectInput("d2", label = h4("D2"),""),
                                       br(),
                                       actionButton("reset", "Reset"),
                                     ),
                                     
                                     mainPanel(
                                     ))
                          )))


server <- function(input, output,session) {
  data <- reactive(function.cl())
  
  output$date <- renderUI({
    all_dates <- seq(as.Date('2021-01-01'), as.Date('2021-01-15'), by = "day")
    disabled <- as.Date(setdiff(all_dates, as.Date(data()$date)), origin = "1970-01-01")
    
    dateInput(input = "date", 
              label = "Select Date",
              min = min(data()$date),
              max = max(data()$date),
              value = max(data()$date),
              format = "dd-mm-yyyy",
              datesdisabled = disabled)
  })
  
  observe({
    updateSelectInput(session, "d1", label = "D1", unique(data()$d1))
    updateSelectInput(session, "d2", label = "D2", unique(data()$d2))
  })
}

shinyApp(ui = ui, server = server)
Waldi
  • 39,242
  • 6
  • 30
  • 78
Antonio
  • 1,091
  • 7
  • 24
  • Maybe you'll need to create a custom component. I think that you can't do it with dateInput. – Yves Cavalcanti Aug 17 '21 at 02:43
  • Thank you Yves. Honestly, I don't know either. I tried to find some example similar to what I want to do, unfortunately I didn't find it either. Have you ever seen something like that? Even if it's not a shiny app, any app made in R. – Antonio Aug 17 '21 at 02:49
  • Can you explain more what your ultimate goal is? What are you trying to do with your `dateInput`? E.g. "The dateInput is for users to filter the dates they want to examine in the database. Data is not collected on holidays, and so dates that are holidays are not valid" or whatever the case is for you. – Sam Rogers Aug 17 '21 at 03:05
  • Right Sam! I will try to explain my idea better: I intend to do something like a forecast model where I will have a calendar and some filters. As it will be a forecast model, I will want to predict certain values for the next 30 days, for example. So, on the calendar, I would like the days that were holidays to be highlighted in some way on the calendar, you know? – Antonio Aug 17 '21 at 03:21
  • I can think in two solutions: 1. Use some javascript libraries like [https://github.com/year-calendar/js-year-calendar][1] [1]: https://github.com/year-calendar/js-year-calendar 2. Create or extends components with some javascript and css on your own, this is a good project, i think – Yves Cavalcanti Aug 17 '21 at 13:33

2 Answers2

1

Since holidays are disabled in your dateInput, they have the custom class td.disabled.day (open the app in browser and check in the Inspector). Therefore, you can customize the CSS just for these dates.

Example: put a red background for holidays. The CSS is:

td.disabled.day {
  background-color: red !important;
}

You need to put it in tags$head(tags$style(HTML(...))) in your app, here's the example:

library(shiny)
library(shinythemes)

function.cl<-function(df,date, d1,d2){
  df <- structure(
    list(date = c("2021-01-01","2021-03-02","2021-04-03","2021-09-04","2021-12-05"),
         d1 = c(0,1,4,5,6), d2 = c(2,4,5,6,7)),class = "data.frame", row.names = c(NA, -5L))
}    

  ui <- shiny::fluidPage(
    tags$head(
      tags$style(
        HTML("td.disabled.day {
              background-color: red !important
              }")
      )
    ),
    theme = shinytheme("flatly"), collapsible = TRUE,
                          
                          br(),
                          
                          tabPanel("",
                                   sidebarLayout(
                                     sidebarPanel(
                                       
                                       uiOutput("date"),
                                       selectInput("d1", label = h4("D1"),""),
                                       selectInput("d2", label = h4("D2"),""),
                                       br(),
                                       actionButton("reset", "Reset"),
                                     ),
                                     
                                     mainPanel(
                                     ))
                          ))


server <- function(input, output,session) {
  data <- reactive(function.cl())
  
  output$date <- renderUI({
    all_dates <- seq(as.Date('2021-01-01'), as.Date('2021-01-15'), by = "day")
    disabled <- as.Date(setdiff(all_dates, as.Date(data()$date)), origin = "1970-01-01")
    
    dateInput(input = "date", 
              label = "Select Date",
              min = min(data()$date),
              max = max(data()$date),
              value = max(data()$date),
              format = "dd-mm-yyyy",
              datesdisabled = disabled)
  })
  
  observe({
    updateSelectInput(session, "d1", label = "D1", unique(data()$d1))
    updateSelectInput(session, "d2", label = "D2", unique(data()$d2))
  })
}

shinyApp(ui = ui, server = server)
bretauv
  • 7,756
  • 2
  • 20
  • 57
  • Thanks for the answer Bretauv! It's already a big step forward. From what I understand it considers holidays every day that are not part of the range 01/01 to 05/12, right? But, I understand that holidays, for example, is Christmas, New Year, that's what I was referring to holidays. Sorry if I wasn't clear on the question, but it was a big step forward. – Antonio Aug 17 '21 at 19:00
  • @Jose Ah sorry I probably misread the post. I thought that the disabled dates were the holidays but it is not the case. The holidays are the dates specified in `function.cl()`, right? Or did I miss something? – bretauv Aug 17 '21 at 19:58
  • In fact, the holidays I'm talking about are national holidays, such as Christmas (25/12), New Year (01/01), Father's Day (19/06). These dates are not specified from my df database. However, in the calendar I would like those days that are national holidays to be in red, as you did in your application. I don't know if it was clearer? – Antonio Aug 17 '21 at 20:38
  • It's clearer but I don't know if it is possible. In my answer, I was able to color some dates in red because they were disabled. Therefore, they had a different class from the enabled dates, which allowed me to customize the CSS for them quite simply. If the holidays you want to customize aren't disabled, I don't know how to distinguish them from the other dates. I hope it's clear, I will think a bit more about that. – bretauv Aug 17 '21 at 20:57
  • I understood! I think you've done half of it. We just need to figure out how to leave the holiday dates in red. I'll search too, thanks for the help! – Antonio Aug 17 '21 at 21:24
0

Highlighing specific days on the calendar using one of the pre-existing dateInput widgets is going to be quite difficult to do (if it's even possible) unfortunately. You will certainly need some custom CSS, and most likely need some custom javascript as well that would enable you to do this.

However, one alternative alternative option is that you could actually create a calendar as a plot, and then have the user select days from the plot rather than a real dateInput() field by registering clicks on the plot. This would give you much more control over the layout and styling of the calendar/plot, but the downside is it would potentially not be as smooth as the widget version.

Another option would be a completely custom dateInput UI element, but that's likely to be a difficult task as well.

Sam Rogers
  • 787
  • 1
  • 8
  • 19