如何在 ggplot2中向 faces 添加通用标签?

我经常使用分面的数值。 我希望提供足够的信息来解释这些分面值在一个补充标题,类似于轴标题。 标签选项重复许多不必要的文本,并且不适用于较长的可变标题。

有什么建议吗?

默认值:

test<-data.frame(x=1:20, y=21:40, facet.a=rep(c(1,2),10), facet.b=rep(c(1,2), each=20))
qplot(data=test, x=x, y=y, facets=facet.b~facet.a)

enter image description here

我想要的:

enter image description here

我在 ggplot 中能做的最好的事情是:

qplot(data=test, x=x, y=y)+facet_grid(facet.b~facet.a, labeller=label_both)

enter image description here

正如@Hendy 所指出的,类似于: 在 ggplot2图上添加一个次要的 y 轴-使它更完美

23173 次浏览

As the latest ggplot2 uses gtable internally, it is quite easy to modify a figure:

library(ggplot2)
test <- data.frame(x=1:20, y=21:40,
facet.a=rep(c(1,2),10),
facet.b=rep(c(1,2), each=20))
p <- qplot(data=test, x=x, y=y, facets=facet.b~facet.a)


# get gtable object
z <- ggplotGrob(p)


library(grid)
library(gtable)
# add label for right strip
z <- gtable_add_cols(z, unit(z$widths[[7]], 'cm'), 7)
z <- gtable_add_grob(z,
list(rectGrob(gp = gpar(col = NA, fill = gray(0.5))),
textGrob("Variable 1", rot = -90, gp = gpar(col = gray(1)))),
4, 8, 6, name = paste(runif(2)))


# add label for top strip
z <- gtable_add_rows(z, unit(z$heights[[3]], 'cm'), 2)
z <- gtable_add_grob(z,
list(rectGrob(gp = gpar(col = NA, fill = gray(0.5))),
textGrob("Variable 2", gp = gpar(col = gray(1)))),
3, 4, 3, 6, name = paste(runif(2)))


# add margins
z <- gtable_add_cols(z, unit(1/8, "line"), 7)
z <- gtable_add_rows(z, unit(1/8, "line"), 3)


# draw it
grid.newpage()
grid.draw(z)

enter image description here

Of course, you can write a function that automatically add the strip labels. A future version of ggplot2 may have this functionality; not sure though.

In addition to the method outlined by kohske, you can add a border to the boxes added by changing

col=NA

to

col=gray(0.5), linetype=1

Also, change

fill=gray(0.5)

for

fill=grey(0.8)

and

gp=gpar(col=gray(1))

to

gp=gpar(col=gray(0))

If you want the new bars to match the facet labels

ie

z <- gtable_add_grob(z,
list(rectGrob(gp = gpar(col = gray(0.5), linetype=1, fill = gray(0.8))),
textGrob("Variable 1", rot = -90, gp = gpar(col = gray(0)))),
4, 8, 6, name = paste(runif(2)))

There may be a better way to do it, but you can :

fac1 = factor(rep(c('a','b'),10))
fac2 = factor(rep(c('a','b'),10))
data = data.frame(x=1:10, y=1:10, fac1=fac1, fac2=fac2)
p = ggplot(data,aes(x,y)) + ggplot2::geom_point() +
facet_grid(fac1~fac2)
p + theme(plot.margin = unit(c(1.5,1.5,0.2,0.2), "cm"))
grid::grid.text(unit(0.98,"npc"),0.5,label = 'label ar right', rot = 270) # right
grid::grid.text(unit(0.5,"npc"),unit(.98,'npc'),label = 'label at top', rot = 0)   # top

The secondary axis is now an option: https://ggplot2.tidyverse.org/reference/sec_axis.html

# Basic faceted plot
p <- ggplot(mtcars, aes(cyl, mpg)) +
geom_point() +
facet_grid(vs ~ am)
    

# Create a simple secondary axis for the facets (use the appropriate scale_x function)
p +
scale_y_continuous(sec.axis = sec_axis(~ . , name = "SECOND Y AXIS", breaks = NULL, labels = NULL)) +
scale_x_continuous(sec.axis = sec_axis(~ . , name = "SECOND X AXIS", breaks = NULL, labels = NULL))

Plot output

Apologies for replying to this decade old question, but wanted to put it out there that you can use ggh4x::facet_nested() to put spanning strips in a plot. Downside is that you'd need an extra package, upside is that you don't need to mess about with the gtables.

# install.packages("ggh4x")
library(ggplot2)


test<-data.frame(x=1:20, y=21:40, facet.a=rep(c(1,2),10), facet.b=rep(c(1,2), each=20))


ggplot(test, aes(x, y)) +
geom_point() +
ggh4x::facet_nested("Facet B" + facet.b ~ "Facet A" + facet.a)

Created on 2022-09-08 by the reprex package (v2.0.1)

Disclaimer: I wrote ggh4x.

My preferred solution is to use gridExtra. You can put in text or you can use calls to grid.text to get some formatting options.

library(ggplot2)
# Basic faceted plot


p <- ggplot(mtcars, aes(cyl, mpg)) +
geom_point() +
facet_grid(vs ~ am)


grid.arrange(p,top='Top Label', right='Right Label')

enter image description here