Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ggplot2 - annotate outside of plot

I would like to associate sample size values with points on a plot. I can use geom_text to position the numbers near the points, but this is messy. It would be much cleaner to line them up along the outside edge of the plot.

For instance, I have:

df=data.frame(y=c("cat1","cat2","cat3"),x=c(12,10,14),n=c(5,15,20))  ggplot(df,aes(x=x,y=y,label=n))+geom_point()+geom_text(size=8,hjust=-0.5) 

Which produces this plot: enter image description here

I would prefer something more like this: enter image description here

I know I can create a second plot and use grid.arrange (a la this post) but it would be tedious to determine the spacing of the textGrobs to line up with the y-axis. Is there an easier way to do this? Thanks!

like image 440
jslefche Avatar asked Sep 13 '12 15:09

jslefche


People also ask

How to add text outside of plot in ggplot2?

To write text outside plot using ggplot2, we can use annotate function and coord_cartesian function. The annotate function will define the text value and the coord_cartesian function will define the position of the text outside the plot area.

How do you annotate outside of plot?

Use scatter() method to plot x and y data points using star marker and copper color map. To place annotation outside the drawing, use xy coordinates tuple accordingly. To display the figure, use show() method.


2 Answers

This is now straightforward with ggplot2 3.0.0, since now clipping can be disabled in plots by using the clip = 'off' argument in coordinate functions such as coord_cartesian(clip = 'off') or coord_fixed(clip = 'off'). Here's an example below.

    # Generate data     df <- data.frame(y=c("cat1","cat2","cat3"),                      x=c(12,10,14),                      n=c(5,15,20))      # Create the plot     ggplot(df,aes(x=x,y=y,label=n)) +       geom_point()+       geom_text(x = 14.25, # Set the position of the text to always be at '14.25'                 hjust = 0,                 size = 8) +       coord_cartesian(xlim = c(10, 14), # This focuses the x-axis on the range of interest                       clip = 'off') +   # This keeps the labels from disappearing       theme(plot.margin = unit(c(1,3,1,1), "lines")) # This widens the right margin 

enter image description here

like image 134
bschneidr Avatar answered Oct 26 '22 05:10

bschneidr


You don't need to be drawing a second plot. You can use annotation_custom to position grobs anywhere inside or outside the plotting area. The positioning of the grobs is in terms of the data coordinates. Assuming that "5", "10", "15" align with "cat1", "cat2", "cat3", the vertical positioning of the textGrobs is taken care of - the y-coordinates of your three textGrobs are given by the y-coordinates of the three data points. By default, ggplot2 clips grobs to the plotting area but the clipping can be overridden. The relevant margin needs to be widened to make room for the grob. The following (using ggplot2 0.9.2) gives a plot similar to your second plot:

library (ggplot2) library(grid)  df=data.frame(y=c("cat1","cat2","cat3"),x=c(12,10,14),n=c(5,15,20))  p <- ggplot(df, aes(x,y)) + geom_point() +            # Base plot      theme(plot.margin = unit(c(1,3,1,1), "lines"))   # Make room for the grob  for (i in 1:length(df$n))  { p <- p + annotation_custom(       grob = textGrob(label = df$n[i], hjust = 0, gp = gpar(cex = 1.5)),       ymin = df$y[i],      # Vertical position of the textGrob       ymax = df$y[i],       xmin = 14.3,         # Note: The grobs are positioned outside the plot area       xmax = 14.3)  }      # Code to override clipping gt <- ggplot_gtable(ggplot_build(p)) gt$layout$clip[gt$layout$name == "panel"] <- "off" grid.draw(gt) 

enter image description here

like image 35
Sandy Muspratt Avatar answered Oct 26 '22 05:10

Sandy Muspratt