Home > OS >  Draw arrow on ggplot with dates as variable, by specifying co-ordinates rather than using the units
Draw arrow on ggplot with dates as variable, by specifying co-ordinates rather than using the units

Time:01-18

I am attempting to plot the blood test results for a patient in a time series. I have managed to do this and included a reference range between two shaded y-intercepts. My problem is that the annotate() or geom_segment() calls want me to specify, in the units of my independent variable, which is, unhelpfully, a date (YYYY-MM-DD).

Is it possible to get R to ignore the units of the x- and y-axis and specify the arrow co-ordinates as if they were on a grid?

result <- runif(25, min = 2.0, max = 3.5)
start_date <- ymd("2021-08-16")
end_date <- ymd("2022-10-29")
date <- sample(seq(start_date, end_date, by = "days"), 25, replace = TRUE)
q <- data.table(numbers, date)
ggplot(q, aes(x = date, y = result))   
  geom_line()   
  geom_point(aes(x = date, y = result), shape = 21, size = 3)  
  scale_x_date(limits = c(min(q$date), max(q$date)), 
               breaks = date_breaks("1 month"),
               labels = date_format("%b %Y"))  
  ylab("Corrected calcium (mmol/L") 
  xlab("Date of blood test")   
  ylim(1,4) 
  geom_ribbon(aes(ymin=2.1, ymax=2.6), fill="grey", alpha=0.2, colour="grey") 
  geom_vline(xintercept=as.numeric(q$date[c(3, 2)]),
             linetype=4, colour="black")  
  theme(axis.text.x = element_text(angle = 45))   theme_prism(base_size = 10)  
  annotate("segment", x = 1, y = 2, xend = 3, yend = 4, arrow = arrow(length = unit(0.15, "cm")))

The error produced is Error: Invalid input: date_trans works with objects of class Date only.

I can confirm that:
> class(q$date)
[1] "Date"

I've just gone with test co-ordinates (1,2,3,4) for the annotate("segment"...), ideally I want to be able to get the arrow to point to a specific data point on the plot to indicate when the patient went on treatment.

Many thanks,
Sandro

CodePudding user response:

You don't need to convert to points or coordinates. Just use the actual values from your data frame. I am just subsetting within annotate using a hard coded index (you can also automate this of course), but you will need to "remind" R that you are dealing with dates - thus the added lubridate::as_date call.

library(ggplot2)
library(lubridate)

result <- runif(25, min = 2.0, max = 3.5)
start_date <- ymd("2021-08-16")
end_date <- ymd("2022-10-29")
date <- sample(seq(start_date, end_date, by = "days"), 25, replace = TRUE)
q <- data.frame(result, date)

## I am arranging the data frame by date
q <- dplyr::arrange(q, date)

ggplot(q, aes(x = date, y = result))   
  geom_line()   
## for start use a random x and y so it starts whereever you want it to start
## for end, use the same row from your data frame, in this case row 20
  annotate(geom = "segment", 
           x = as_date(q$date[2]), xend = as_date(q$date[20]), 
           y = min(q$result), yend = q$result[20], 
           arrow = arrow(),
           size = 2, color = "red")

enter image description here

  • Related