Home > Net >  R Shiny geom_col plotOutput click event with date-type x-axis
R Shiny geom_col plotOutput click event with date-type x-axis

Time:07-25

Say we have a Shiny app with a ggplot output with a date object on the x-axis and a numeric object on the y-axis. In the plotOutput we set click = "click" so that when a user clicks on the plot, we can access the x-coordinate of that click with input$click.

Here's a minimal example showing this:

library(shiny)
library(dplyr)
library(lubridate)
library(ggplot2)

dat <- tibble(
    x = as.Date(c("2022-01-01", "2022-01-02")),
    y = 1:2
)

ui <- fluidPage(
    plotOutput("plt", click = "click"),
    textOutput("click_raw"),
    textOutput("click_chr")
)

server <- function(input, output, session) {
    output$plt <- renderPlot({
        dat %>%
            ggplot(aes(x, y))  
                geom_col()
    })
    
    output$click_raw <- renderText({
        input$click$x
    })
    
    output$click_chr <- renderText({
        as.character(as.Date(input$click$x, origin = origin))
    })
}

shinyApp(ui, server)

The two textOutputs show the raw and character-formatted values of input$click$x, respectively.

The issue is that the x-axis ticks are effectively date limits; i.e., clicking to the left of a date tick will always return the previous date, while clicking to the right of a date tick will always return the labelled date. For example, this is the result when clicking on the left bar, on the left-hand-side of the "Jan 01" axis tick:

left

And this is the result of clicking on the right-hand-side of the same bar (expected):

right

Effectively, clicking anywhere between the axis ticks of "Jan 01" and "Jan 02" will return the Jan 01 date from input$click. That is, clicking on the left-hand-side of the right bar will return the Jan 01 date, not Jan 02. The desired/expected behaviour would be that clicking anywhere on a given bar would return the date for which that bar is counted on the y-axis.

There's probably a hacky way to get past this, e.g., adding or subtracting 12 hours from input$click depending on where you click, but... am I missing something obvious? Thanks.

CodePudding user response:

I don't think that you are missing something important. The issue is that input$click returns the exact numeric position of the click. Whether you have dates or categories does not matter, it also doesn't matter whether you have a bar chart or a scatter plot. It's up you to to account for that and do any conversion manually.

In your case each value between e.g. 18993 <= date < 18994 gets converted to 2022-01-01. If you want 18992.5 <= date < 18993.5 to be converted to 2022-01-01 then as you already suggested you could add 12 hours (or .5) to the value returned by input$click$x or as a second option you could use round:

library(shiny)
library(dplyr)
library(lubridate)
library(ggplot2)

dat <- tibble(
  x = as.Date(c("2022-01-01", "2022-01-02")),
  y = 1:2
)

ui <- fluidPage(
  plotOutput("plt", click = "click"),
  textOutput("click_raw"),
  textOutput("click_chr"),
  textOutput("click_chr1")
)

server <- function(input, output, session) {
  output$plt <- renderPlot({
    dat %>%
      ggplot(aes(x, y))  
      geom_col()
  })
  
  output$click_raw <- renderText({
    input$click$x
  })
  
  output$click_chr <- renderText({
    as.character(as.Date(as.numeric(input$click$x)   .5, origin = origin))
  })
  
  output$click_chr1 <- renderText({
    as.character(as.Date(round(as.numeric(input$click$x), 0), origin = origin))
  })
}

shinyApp(ui, server)

enter image description here

  • Related