Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ggplot, drawing multiple lines across facets

Tags:

r

ggplot2

I drew two panels in a column using ggplot2 facet, and would like to add two vertical lines across the panels at x = 4 and 8. The following is the code:

library(ggplot2)
library(gtable)
library(grid)

dat <- data.frame(x=rep(1:10,2),y=1:20+rnorm(20),z=c(rep("A",10),rep("B",10)))

P <- ggplot(dat,aes(x,y)) + geom_point() + facet_grid(z~.) + xlim(0,10)
Pb <- ggplot_build(P);Pg <- ggplot_gtable(Pb)

for (i in c(4,8)){
    Pg <- gtable_add_grob(Pg, moveToGrob(i/10,0),t=8,l=4)
    Pg <- gtable_add_grob(Pg, lineToGrob(i/10,1),t=6,l=4)
}

Pg$layout$clip <- "off"
grid.newpage()
grid.draw(Pg)

The above code is modified from:ggplot, drawing line between points across facets. And this is the output figure.

There are two problems in this figure. First, only one vertical line was shown. It seems that moveToGrob only worked once.. Second, the shown line is not exact at x = 4. I didn't find the Pb$panel$ranges variable, so is there a way that I can correct the range as well? Thanks a lot.

like image 612
Bright Avatar asked Feb 10 '17 05:02

Bright


2 Answers

Updated to ggplot2 V3.0.0

In the simple scenario where panels have common axes and the lines extend across the full y range you can draw lines over the whole gtable cells, having found the correct npc coordinates conversion (cf previous post, updated because ggplot2 keeps changing),

library(ggplot2)
library(gtable)
library(grid)

dat <- data.frame(x=rep(1:10,2),y=1:20+rnorm(20),z=c(rep("A",10),rep("B",10)))

p <- ggplot(dat,aes(x,y)) + geom_point() + facet_grid(z~.) + xlim(0,10)
pb <- ggplot_build(p)
pg <- ggplot_gtable(pb)


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


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

pg <- gtable_add_grob(pg, segmentsGrob(x0=start, x1=start, y0=0, y1=1, gp=gpar(lty=2)), t=7, b=9, l=5)

grid.newpage()
grid.draw(pg)

enter image description here

like image 56
baptiste Avatar answered Oct 22 '22 08:10

baptiste


You can just use geom_vline and avoid the grid mess altogether:

ggplot(dat, aes(x, y)) + 
    geom_point() + 
    geom_vline(xintercept = c(4, 8)) + 
    facet_grid(z ~ .) + 
    xlim(0, 10)

plot with vlines

like image 39
alistaire Avatar answered Oct 22 '22 08:10

alistaire