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 textOutput
s 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:
And this is the result of clicking on the right-hand-side of the same bar (expected):
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)