1

Say I have a plot like this:

# Load libraries
library(ggplot2)
library(grid)

# Load data
data(mtcars)

# Plot results
p <- ggplot(data = mtcars) 
p <- p + geom_bar(aes(cyl)) 
p <- p + coord_flip()
p <- p + facet_wrap(~am)

print(p)

enter image description here

Now, I want to plot lines all the way across both facets where the bars are. I add this:

p <- p + geom_vline(aes(xintercept = cyl))

enter image description here

which adds the lines, but they don't cross both facets. So, I try to turn off clipping using this solution:

# Turn off clipping
gt <- ggplot_gtable(ggplot_build(p))
gt$layout$clip[gt$layout$name == "panel"] <- "off"

# Plot results
grid.draw(gt)

but that doesn't solve the problem: the lines are still clipped. So, I wondered if this is specific to geom_vline and tried approaches with geom_abline and geom_line (the latter with values across ±Inf), but the results are the same. In other posts, the clipping solution seems to work for text and points, but presumably in this case the lines are only defined within the limits of the figure. (I even tried gt$layout$clip <- "off" to switch off all possible clipping, but that didn't solve the problem.) Is there a workaround?

Dan
  • 11,370
  • 4
  • 43
  • 68
  • 2
    Does [this answer](https://stackoverflow.com/a/31691313/496488) do what you need? – eipi10 Jul 17 '17 at 15:16
  • It certainly looks like it. Thanks! Apparently I have particularly weak Google Fu today... – Dan Jul 17 '17 at 15:19
  • Actually, that code doesn't seem to work for me (or for another person who posted a couple of hours ago). Can anyone else run it successfully? – Dan Jul 17 '17 at 15:22

1 Answers1

0
library(grid)
library(gtable)

# Starting from your plot `p`
gb <- ggplot_build(p)
g <- ggplot_gtable(gb)

# Get position of y-axis tick marks
ys <- gb$layout$panel_ranges[[1]][["y.major"]]


# Add segments at these positions
# subset `ys` if you only want to add a few
# have a look at g$layout for relevant `l` and `r` positions
g <- gtable_add_grob(g, segmentsGrob(y0=ys, y1=ys, 
                                     gp=gpar(col="red", lty="dashed")), 
                     t = 7, l = 4, r=8)

grid.newpage()
grid.draw(g)

see ggplot, drawing multiple lines across facets for how to rescale values for more general plotting. ie

data2npc <- function(x, panel = 1L, axis = "x") {
  range <- pb$layout$panel_ranges[[panel]][[paste0(axis,".range")]]
  scales::rescale(c(range, x), c(0,1))[-c(1,2)]
}

start <- sapply(c(4,6,8), data2npc, panel=1, axis="y")

g <- gtable_add_grob(g, segmentsGrob(y0=start, y1=start),
                      t=7, r=4, l=8)
user20650
  • 24,654
  • 5
  • 56
  • 91