rtimeline

Creating a timeline in R Tidyverse


If I have a dataset (see below) consisting of ID (1 to 20), age, gender, and disease/control group, how do I then create a timeline based on “Age” from 0 to 99 where I would have all samples from the “disease” group above the timeline and all “control” individuals below the timeline? Additionally, if there e.g. are two diseased patients at the same age I would like to stack them on top of each other? And preferably have the timeline (x-axis) in between the two so that it would be an actual timeline and not just the dotted line where I am at the moment? See below for data and the code where I got to:

   Age = c(10, 10, 11, 15, 50, 20, 25, 24, 24, 10, 12, 25, 99, 80, 99, 20, 58, 76, 19, 19), 
   disease = c("disease", "disease", "control", "control", "disease", "control", "disease", "control", "disease", "control", "control", "disease", "control", "control", "disease", "disease", "control", "disease", "control", "control"),
   gender = sample(c("M", "F"), 20, replace = TRUE))

Plot:

      ggplot(aes(x = Age, y = disease, color = gender)) + 
      geom_text(aes(label = gender), check_overlap = FALSE) +
      geom_hline(yintercept = 1.5, linetype = "dashed", color = "black") +
      scale_y_discrete(limits = c("disease", "control")) + 
      labs(x = "Age", y = "Disease") +
      theme_LasseVoss1()

  Which returns the following (see attached): enter image description here

Issues being:

1)I’d like the timeline/x-axis in the middle between control and disease group instead of the dotted line.

  1. In cases where there are two individuals at the same age (or very close to each other in age) from the same group, they should be stacked on top of each other.

I hope you can help. Very much appreciated!


Solution

  • You cannot have an axis running through the middle of the plot in ggplot, so you'll have to roll one yourself. You can either do this by adding text and line layers or by stitching plots together with patchwork. I think the first version is easier.

    To conditionally dodge labels that would otherwise clash, use geom_text_repel from the ggrepel package. Set direction = "y" to ensure the dodging only occurs vertically.

    ggplot(data, aes(x = Age, y = disease)) + 
      ggrepel::geom_text_repel(aes(label = gender, color = gender),
                               direction = 'y', segment.color = 'transparent') +
      geom_hline(yintercept = 1.5, color = "black") +
      geom_text(aes(label = after_stat(x)), vjust = 1,
                data = data.frame(Age = 1:4 * 25, disease = 1.45)) +
      geom_linerange(aes(ymin = 1.48, ymax = 1.5),
                     data = data.frame(Age = 1:4 * 25, disease = 1.45)) +
      annotate('text', x = 57.5, y = 1.3, label = 'Age', size = 14/.pt,
               fontface = 'bold') + 
      scale_y_discrete(limits = c("disease", "control")) + 
      labs(x = "Age", y = "Disease") +
      theme_classic(base_size = 16) +
      theme(text = element_text(face = 2),
            axis.text.x = element_blank(),
            axis.title.x = element_blank(),
            panel.border = element_rect(fill = NA, color = 'black', 
                                        linewidth = 0.8),
            axis.ticks = element_blank(),
            legend.position = 'bottom')
    

    enter image description here