Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ggplot2: Draw geom_segment() outside of the plot area

Tags:

r

ggplot2

I have a two facet plots created in ggplot2. I would like to add an arrow outside of the plot area. Multiple questions tried to address this: How to draw lines outside of plot area in ggplot2? Displaying text below the plot generated by ggplot2

but I can't make my example work. Also, I hope there is an easier way to accomplish this?

I tried to increase plot.margins and to use coord_cartesian(), but neither helped.

enter image description here

Instead, I want:

enter image description here

My dummy example:

# read library to assess free data
library(reshape2)
library(ggplot2)


ggplot(tips,
       aes(x=total_bill,
           y=tip/total_bill)) + 
  geom_point(shape=1) +
  facet_grid(. ~ sex) +
  # define the segment outside the plot
  geom_segment(aes(x = 10, 
                   y = -0.25, 
                   xend = 10, 
                   yend = 0),
               col = "red",
               arrow = arrow(length = unit(0.3, "cm"))) +
  theme_bw() +
  # limit the displayed plot extent
  coord_cartesian(ylim = c(0, 0.75)) +
  # increase plot margins - does not help
  theme(plot.margin = unit(c(1,1,1,0), "lines"))
like image 769
maycca Avatar asked Sep 19 '18 18:09

maycca


2 Answers

You can draw outside the panel using the argument clip="off" in coord_cartesian. I also use the expand argument of scale_y to start the y-axis at zero. There is a bit a manual selection over the y start position.

So your example

library(reshape2)
library(ggplot2)

ggplot(tips,
       aes(x=total_bill,
           y=tip/total_bill)) + 
  geom_point(shape=1) +
  facet_grid(. ~ sex) +
  annotate("segment", x=12, y=-0.05, xend=12, yend=0,
               col="red", arrow=arrow(length=unit(0.3, "cm"))) +
  scale_y_continuous(expand=c(0,0))+
  theme_bw() +
  coord_cartesian(ylim = c(0, 0.75), clip="off") +
  theme(plot.margin = unit(c(1,1,1,0), "lines"))

(I changed geom_segment to annotate as you were not mapping aesthetics)

Which produces

enter image description here

like image 95
user20650 Avatar answered Sep 30 '22 13:09

user20650


This is a workaround which is not exactly super satisfying, because you will need to play around with the position of your plots. Principally it uses custom annotation, possible with cowplot

library(ggplot2) 
library(cowplot)
library(reshape2)

First define your plots, with the same coordinate limits.

p <- 
  ggplot(tips, aes(x = total_bill, y = tip/total_bill)) + 
  geom_point(shape = 1) +
  facet_grid(. ~ sex) +
  theme_bw() +
  coord_cartesian(ylim = c(0, 0.75), xlim = c(0, 50)) 

arrow_p <- 
  ggplot(tips) +
  geom_segment(aes(x = 1, y = -1, xend = 1, yend = 0),
               col = "red",
               arrow = arrow(length = unit(0.3, "cm"))) +
  coord_cartesian(ylim = c(0, 0.75), xlim = c(0,50)) +
  theme_void()

arrow_p is created on a void background for use as overlay. You can now position it where you want with:

 ggdraw() +
    draw_plot(p) +
    draw_plot(arrow_p, x = 0.10, y = 0.05) +
    draw_plot(arrow_p, x = 0.57, y = 0.05)

enter image description here

Unfortunately, you have to trial-and-error here. You can also change specify the width/height/scale parameters of draw_plot(). There might be a better way, but this is a fairly straight forward workaround...

like image 23
tjebo Avatar answered Sep 30 '22 14:09

tjebo