Mr K
Mr K

Reputation: 446

Annotate with shapes outside plot area in specified color

I need to annotate my plots in a certain way. Following the answer here, I could come up with this,

df = data.frame(y= rep(c(1:20, 1:10), 5), x=c(rep("A", 20), rep("B", 10), rep("C", 20), rep("D", 10), rep("E", 20),
                                          rep("F", 10), rep("G", 20), rep("H", 10), rep("I", 20), rep("J", 10)), 
            g= c(rep(sample(1:2, 1), 20), rep(sample(1:2, 1), 10),rep(sample(1:2, 1), 20), rep(sample(1:2, 1), 10),
                 rep(sample(1:2, 1), 20), rep(sample(1:2, 1), 10),rep(sample(1:2, 1), 20), rep(sample(1:2, 1), 10),
                 rep(sample(1:2, 1), 20), rep(sample(1:2, 1), 10)))

p <- ggplot(df, aes(factor(x), y)) + geom_boxplot()+            # Base plot
     theme(plot.margin = unit(c(3,1,1,1), "lines"), plot.background= element_rect(color= "transparent"))   # Make room for the grob
for (i in 1:length(df$g))  {
  p <- p + annotation_custom(
     grob = textGrob(label = df$g[i], hjust = 0, gp = gpar(cex = 1.5)),
     xmin = df$x[i],      # Vertical position of the textGrob
     xmax = df$x[i],
     ymin = 22,         # Note: The grobs are positioned outside the plot area
     ymax = 22)
}    

gt <- ggplot_gtable(ggplot_build(p))
gt$layout$clip[gt$layout$name == "panel"] <- "off"
grid.draw(gt)

This generates this plot .

I want blue triangles with size 0.6 pt instead of 2 in annotation and blue "+" signs instead of 1. Can you please help me out here?

Upvotes: 3

Views: 1874

Answers (2)

baptiste
baptiste

Reputation: 77114

Turning clipping off should really be a last resort, since it can have unwanted side-effects for other layers. Here it may be easier to add a row to the gtable and place a grob at the required position.

p <- ggplot(df, aes(factor(x), y)) + 
       geom_boxplot() + ggtitle("this plot has a title")


library(grid)
library(gtable)

gb <- ggplot_build(p)

# get the axis positions
xpos <- gb$panel$ranges[[1]][["x.major"]]

g <- ggplot_gtable(gb)
g <- gtable_add_rows(g, unit(1,"line"), 2)
gl <- pointsGrob(xpos, rep(0.5, length(xpos)), pch=seq_along(xpos),
                 default.units = "npc")
g <- gtable_add_grob(g, gl, t=3, l=4)
grid.draw(g)

enter image description here

If a more complex grob was needed, or simply to ensure a consistent mapping between annotations and plot, one could place a ggplot plot panel in the same fashion.

Upvotes: 3

A Gore
A Gore

Reputation: 1910

You would have to use pointsGrob instead of the textGrob function. The line you would need to add points instead of text labels would be following.

pointsGrob(pch = ifelse(df$g[i]==1,3,17), gp = gpar(cex = 0.6,col=ifelse(df$g[i]==1,"red","blue")))

Here I'm using 3 for + point and 17 for $\triangle$ shape. The entire code is shown below

df = data.frame(y= rep(c(1:20, 1:10), 5), x=c(rep("A", 20), rep("B", 10), rep("C", 20), rep("D", 10), rep("E", 20),
                                              rep("F", 10), rep("G", 20), rep("H", 10), rep("I", 20), rep("J", 10)), 
                g= c(rep(sample(1:2, 1), 20), rep(sample(1:2, 1), 10),rep(sample(1:2, 1), 20), rep(sample(1:2, 1), 10),
                     rep(sample(1:2, 1), 20), rep(sample(1:2, 1), 10),rep(sample(1:2, 1), 20), rep(sample(1:2, 1), 10),
                     rep(sample(1:2, 1), 20), rep(sample(1:2, 1), 10)))

p <- ggplot(df, aes(factor(x), y)) + geom_boxplot()+            # Base plot
  theme(plot.margin = unit(c(3,1,1,1), "lines"), plot.background= element_rect(color= "transparent"))   # Make room for the grob
for (i in 1:length(df$g))  {
  p <- p + annotation_custom(
    grob = pointsGrob(pch = ifelse(df$g[i]==1,3,17), gp = gpar(cex = 0.6,col=ifelse(df$g[i]==1,"red","blue"))),
    xmin = df$x[i],      # Vertical position of the textGrob
    xmax = df$x[i],
    ymin = 22,         # Note: The grobs are positioned outside the plot area
    ymax = 22)
}    

gt <- ggplot_gtable(ggplot_build(p))
gt$layout$clip[gt$layout$name == "panel"] <- "off"
grid.draw(gt)

And the plot generated is shown below

enter image description here

I hope this helps.

Upvotes: 4

Related Questions