rgridr-forestplot

Add text in arbitrary location in r forestplot


As per the question, I want to add text annotation in an arbitrary location in the generated forest plot:

library(forestplot)
library(tidyr)

cohort <- data.frame(Age = c(43, 39, 34, 55, 70, 59, 44, 83, 76, 44, 
                             75, 60, 62, 50, 44, 40, 41, 42, 37, 35, 55, 46), 
                     Group = structure(c(1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 1L, 
                                         1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 2L), levels = c("1","2"), class = "factor"))

age.lm <- lm(Age ~ Group, data = cohort)

age.data <- summary(age.lm)$coefficients[2,]

age.data <- rbind(c(0,0,0,1,"Group 1", "n=15"),
                  c(age.data[1], age.data[1]-age.data[2]*1.95, 
                  age.data[1]+age.data[2]*1.95, age.data[4], "Group 2", "n=7"))

colnames(age.data) <- c("mean","lower","upper","p-val","labeltext","numbers")

age.data <- data.frame(age.data)


age.data$mean <- as.numeric(age.data$mean)
age.data$lower <- as.numeric(age.data$lower)
age.data$upper <- as.numeric(age.data$upper)


age.plot <- forestplot(age.data,
           labeltext = c(labeltext,numbers),
           boxsize = 0.1,
           xlog = FALSE,
           clip=c(-20,20),
           xticks=c(-20,-10,0,10,20),
           txt_gp = fpTxtGp(ticks=gpar(cex=1)),
           align=c("l","c","l"))

print(age.plot)

This generates the following plot: Forest plot but say I wanted to add text to this that is not part of the forestplot, like: Forest plot with annotation

Is there a way of doing this by adding to the forestplot? R/forestplot uses grid graphics, but text("Text", location) doesn't work.

Of course, I could add everything in using an image editor, but this gets tedious with a lot of things to annotate, and I'd much prefer a procedural way of doing this with text that is appropriate to the forestplot (which would make it easier to line up what I need to add)

The reason I'm asking is because I have a two-group comparison forestplot, and the effect sizes/betas can't get added automatically so I need to add them in afterwards.


Solution

  • The image produced when you print your forest plot object is created with the grid graphics system, so base graphics calls like text() don't work. Instead, you would need to do something like:

    library(grid)
    
    print(age.plot)
    grid.text("Text", 0.4, 0.45, gp = gpar(col = "red", font = 3, cex = 3))
    

    enter image description here

    Note that the x, y co-ordinates are in npc space (i.e. scaled from {x = 0, y = 0} at bottom left of the plotting window to {x = 1, y = 1} at the top right.

    Personally, I think it is preferable to do the whole thing in ggplot. This way, you have the ability to very easily style, manipulate, combine, store and save the plot, as well as having access to an entire ecosystem of extensions. You can also annotate the plot in user co-ordinates. For example, we can create a near-identical plot using age.data with the text annotation stored as part of the plot itself like this:

    library(ggplot2)
    
    age.plot <- ggplot(age.data, aes(mean, paste0(labeltext, "      ", numbers))) +
      geom_vline(xintercept = 0, col = "gray") +
      geom_linerange(aes(xmin = lower, xmax = upper)) +
      geom_point(shape = 22, fill = "black", size = 9) +
      annotate("text", label = "Text", x = -15, y = 1.3, size = 10,
               colour = "red", fontface = "italic") +
      scale_x_continuous(NULL, limits = c(-26, 20)) +
      scale_y_discrete(NULL, limits = ~rev(.x)) +
      theme_classic(20) +
      theme(axis.line.y = element_blank(), 
            axis.ticks.y = element_blank(),
            axis.text.y = element_text(hjust = 0))
    

    So now we get

    age.plot
    

    enter image description here