Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I add annotations below the x axis in ggplot2?

Tags:

r

ggplot2

I have the following graph:

library(ggplot2)
library(scales)
library(magrittr)
df1 <-
  structure(
    list(
      x = structure(
        1:5, .Label = c("5", "4", "3", "2",
                        "1"), class = "factor"
      ), y = c(
        0.166666666666667, 0.361111111111111,
        0.0833333333333333, 0.222222222222222, 0.291666666666667
      )
    ), .Names = c("x",
                  "y"), row.names = c(NA,-5L), class = c("tbl_df", "tbl", "data.frame"), drop = TRUE
  )

df1 %>% ggplot(aes(x , y )) + geom_bar(stat = "identity") +
  scale_y_continuous(labels = percent) 

I would like to add a two lines note with bold text below 5 and 1. For example, 'Highest \nvalue' bellow 5 and 'Lowest \nvalue' below 1.

I tried geom_text but I cannot place the text where I want.

like image 412
Ignacio Avatar asked Jun 26 '15 17:06

Ignacio


2 Answers

This can be done using annotation_custom(). I am drawing from this answer.

The difficulty is that ggplot clips annotations that are placed outside the plot area, which is what you want to do. But clipping can be turned off.

annotation_custom() uses grobs, so you first need to create the them:

library(grid)
text_high <- textGrob("Highest\nvalue", gp=gpar(fontsize=13, fontface="bold"))
text_low <- textGrob("Lowest\nvalue", gp=gpar(fontsize=13, fontface="bold"))

Next, you set up the plot and store it:

p <-
df1 %>% ggplot(aes(x , y )) + geom_bar(stat = "identity") +
   scale_y_continuous(labels = percent) +
   theme(plot.margin = unit(c(1,1,2,1), "lines")) +
   annotation_custom(text_high,xmin=1,xmax=1,ymin=-0.07,ymax=-0.07) + 
   annotation_custom(text_low,xmin=5,xmax=5,ymin=-0.07,ymax=-0.07)

The third line makes sure that there is enough room beneath the plot for your labels and the last two add the annotations. The position is given as min and max values for both coordinates. The grob will be centered in the region that is defined by these coordinates. In the present situation, it seems easiest to simply define a point by setting min and max values identical.

The last step is to turn off clipping such that objects outside the plot area (i.e., the annotations) are also drawn. For ggplot2 3.0.0 and newer this can be done using coord_cartesian() (see the answer by tfad334):

p + coord_cartesian(clip = "off")

With older versions of ggplot2 the procedure is slightly more complicated:

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

The last line draws the plot.

enter image description here

like image 73
Stibu Avatar answered Oct 13 '22 15:10

Stibu


With ggplot2 version 3.0.0, you won't need gtable to turn clipping off in Stibu's answer. Use coord_cartesian() to achieve the same thing:

library(gridExtra)
df1 %>% ggplot(aes(x , y )) + geom_bar(stat = "identity")+
scale_y_continuous(labels = percent)+
theme(plot.margin = unit(c(1,1,2,1), "lines")) +
annotation_custom(text_high,xmin=1,xmax=1,ymin=-0.07,ymax=-0.07) + 
annotation_custom(text_low,xmin=5,xmax=5,ymin=-0.07,ymax=-0.07)+
coord_cartesian(ylim=c(0,0.35), clip="off")
like image 38
tfad334 Avatar answered Oct 13 '22 15:10

tfad334