改变 ggplot2 中嵌套面的美学
Change aesthetics of nested facet in ggplot2
我想在 ggplot2
中使用嵌套面板,但两个面板的名称必须位于绘图的相对两侧。这是一个可重现的例子:
library(ggplot2)
library(data.table)
# data for reproducible example
dt <- data.table(
value = c("East", "West","East", "West", "NY", "LA","NY", "LA"),
year = c(2008, 2008, 2013, 2013, 2008, 2008, 2013, 2013),
index = c(12, 10, 18, 15, 10, 8, 12 , 14),
var = c("Region","Region","Region","Region", "Metro","Metro","Metro","Metro"))
# change order or plot facets
dt[, var := factor(var, levels=c( "Region", "Metro"))]
# plot
ggplot(data=dt) +
geom_point( aes(x=index, y= factor(year), color=index)) +
facet_grid(value + var ~., scales = "free_y", space="free")
请注意,在此示例中,我使用列 value
+ var
来创建构面,但两个面板的标题绘制在一起。
预期输出:我想实现的是这样的:
使用 labeller = label_bquote(rows = .(var1))
的可能解决方案,两次调用 geom_text
和一些进一步的自定义:
ggplot(dt, aes(x = index, y = factor(year), color = index)) +
geom_point() +
geom_text(aes(x = 6, y = 1.5, label = value), color = 'black', hjust = 0) +
geom_text(aes(x = 7, label = year), color = 'black') +
geom_segment(aes(x = 7.5, xend = 7.5, y = 0.7, yend = 2.3), color = 'black') +
geom_segment(aes(x = 7.45, xend = 7.5, y = 1, yend = 1), color = 'black') +
geom_segment(aes(x = 7.45, xend = 7.5, y = 2, yend = 2), color = 'black') +
scale_x_continuous(breaks = seq(8,18,2)) +
facet_grid(value + var1 ~., scales = "free_y", space="free", labeller = label_bquote(rows = .(var1))) +
theme_minimal() +
theme(axis.title = element_blank(),
axis.text.y = element_blank(),
strip.background = element_rect(color = 'darkgrey', fill = 'lightgrey'),
panel.grid.major.y = element_blank(),
panel.grid.minor = element_blank())
给出:
注:我用了var1
而不是var
因为后者也是一个函数名
另一种可能性是利用 gridExtra
包创建附加标签并将它们放在带有 grid.arrange
:
的 y 轴标签前面
# create the main plot
mainplot <- ggplot(dt, aes(x = index, y = factor(year), color = index)) +
geom_point(size = 2) +
scale_x_continuous(breaks = seq(8,18,2)) +
facet_grid(value + var1 ~., scales = "free_y", space="free", labeller = label_bquote(rows = .(var1))) +
theme_minimal() +
theme(axis.title = element_blank(),
strip.background = element_rect(color = 'darkgrey', fill = 'lightgrey'))
# create a 2nd plot with everything besides the labels set to blank or NA
lbls <- ggplot(dt, aes(x = 0, y = factor(year))) +
geom_point(color = NA) +
geom_text(aes(x = 0, y = 1.5, label = value), color = 'black') +
scale_x_continuous(limits = c(0,0), breaks = 0) +
facet_grid(value + var1 ~.) +
theme_minimal() +
theme(axis.title = element_blank(),
axis.text.x = element_text(color = NA),
axis.text.y = element_blank(),
strip.background = element_blank(),
strip.text = element_blank(),
panel.grid = element_blank(),
legend.position = 'none')
# plot with 'grid.arrange' and give the 'lbls'-plot a small width
library(gridExtra)
grid.arrange(lbls, mainplot, ncol = 2, widths = c(1,9))
给出:
添加这个主要是为了显示一些 grob/gtable 操作:
library(ggplot2)
library(data.table)
library(gtable)
library(gridExtra)
# data for reproducible example
dt <- data.table(
value = c("East", "West","East", "West", "NY", "LA","NY", "LA"),
year = c(2008, 2008, 2013, 2013, 2008, 2008, 2013, 2013),
index = c(12, 10, 18, 15, 10, 8, 12 , 14),
var = c("Region","Region","Region","Region", "Metro","Metro","Metro","Metro"))
# change order or plot facets
dt[, var := factor(var, levels=c( "Region", "Metro"))]
# plot
ggplot(data=dt) +
geom_point( aes(x=index, y= factor(year), color=index)) +
facet_grid(value + var ~., scales = "free_y", space="free") +
theme_bw() +
theme(panel.grid=element_blank()) +
theme(panel.border=element_blank()) +
theme(axis.line.x=element_line()) +
theme(axis.line.y=element_line()) -> gg
gb <- ggplot_build(gg)
gt <- ggplot_gtable(gb)
这是它的样子:
gt
## TableGrob (14 x 8) "layout": 24 grobs
## z cells name grob
## 1 0 ( 1-14, 1- 8) background rect[plot.background..rect.5201]
## 2 5 ( 4- 4, 3- 3) axis-l absoluteGrob[GRID.absoluteGrob.5074]
## 3 6 ( 6- 6, 3- 3) axis-l absoluteGrob[GRID.absoluteGrob.5082]
## 4 7 ( 8- 8, 3- 3) axis-l absoluteGrob[GRID.absoluteGrob.5090]
## 5 8 (10-10, 3- 3) axis-l absoluteGrob[GRID.absoluteGrob.5098]
## 6 1 ( 4- 4, 4- 4) panel gTree[GRID.gTree.5155]
## 7 2 ( 6- 6, 4- 4) panel gTree[GRID.gTree.5164]
## 8 3 ( 8- 8, 4- 4) panel gTree[GRID.gTree.5173]
## 9 4 (10-10, 4- 4) panel gTree[GRID.gTree.5182]
## 10 9 ( 4- 4, 5- 5) strip-right absoluteGrob[strip.absoluteGrob.5104]
## 11 10 ( 6- 6, 5- 5) strip-right absoluteGrob[strip.absoluteGrob.5110]
## 12 11 ( 8- 8, 5- 5) strip-right absoluteGrob[strip.absoluteGrob.5116]
## 13 12 (10-10, 5- 5) strip-right absoluteGrob[strip.absoluteGrob.5122]
## 14 13 ( 4- 4, 6- 6) strip-right absoluteGrob[strip.absoluteGrob.5128]
## 15 14 ( 6- 6, 6- 6) strip-right absoluteGrob[strip.absoluteGrob.5134]
## 16 15 ( 8- 8, 6- 6) strip-right absoluteGrob[strip.absoluteGrob.5140]
## 17 16 (10-10, 6- 6) strip-right absoluteGrob[strip.absoluteGrob.5146]
## 18 17 (11-11, 4- 4) axis-b absoluteGrob[GRID.absoluteGrob.5066]
## 19 18 (12-12, 4- 4) xlab titleGrob[axis.title.x..titleGrob.5185]
## 20 19 ( 4-10, 2- 2) ylab titleGrob[axis.title.y..titleGrob.5188]
## 21 20 ( 4-10, 7- 7) guide-box gtable[guide-box]
## 22 21 ( 3- 3, 4- 4) subtitle zeroGrob[plot.subtitle..zeroGrob.5198]
## 23 22 ( 2- 2, 4- 4) title zeroGrob[plot.title..zeroGrob.5197]
## 24 23 (13-13, 4- 4) caption zeroGrob[plot.caption..zeroGrob.5199]
我们可以直接操作这些组件:
# make a copy of the gtable (not rly necessary but I think it helps simplify things since
# I'll usually forget to offset the column positions at some point if the
# manipulations get too involved)
gt2 <- gt
# add a new column after the axis title
gt2 <- gtable_add_cols(gt2, unit(3.0, "lines"), 2)
# these are those pesky strips of yours
for_left <- gt[c(4,6,8,10),5]
# let's copy them over into our new column
gt2 <- gtable_add_grob(gt2, for_left$grobs[[1]], t=4, l=3, b=4, r=3)
gt2 <- gtable_add_grob(gt2, for_left$grobs[[2]], t=6, l=3, b=6, r=3)
gt2 <- gtable_add_grob(gt2, for_left$grobs[[3]], t=8, l=3, b=8, r=3)
gt2 <- gtable_add_grob(gt2, for_left$grobs[[4]], t=10, l=3, b=10, r=3)
# then get rid of the original ones
gt2 <- gt2[, -6]
# now we'll change the background color, border color and text rotation of each strip text
for (gi in 21:24) {
gt2$grobs[[gi]]$children[[1]]$gp$fill <- "white"
gt2$grobs[[gi]]$children[[1]]$gp$col <- "white"
gt2$grobs[[gi]]$children[[2]]$children[[1]]$rot <- 0
}
grid.arrange(gt2)
IMO 第一个答案中的自定义贴标机和 geom_text 方法更具可读性和可重复性。
我想在 ggplot2
中使用嵌套面板,但两个面板的名称必须位于绘图的相对两侧。这是一个可重现的例子:
library(ggplot2)
library(data.table)
# data for reproducible example
dt <- data.table(
value = c("East", "West","East", "West", "NY", "LA","NY", "LA"),
year = c(2008, 2008, 2013, 2013, 2008, 2008, 2013, 2013),
index = c(12, 10, 18, 15, 10, 8, 12 , 14),
var = c("Region","Region","Region","Region", "Metro","Metro","Metro","Metro"))
# change order or plot facets
dt[, var := factor(var, levels=c( "Region", "Metro"))]
# plot
ggplot(data=dt) +
geom_point( aes(x=index, y= factor(year), color=index)) +
facet_grid(value + var ~., scales = "free_y", space="free")
请注意,在此示例中,我使用列 value
+ var
来创建构面,但两个面板的标题绘制在一起。
预期输出:我想实现的是这样的:
使用 labeller = label_bquote(rows = .(var1))
的可能解决方案,两次调用 geom_text
和一些进一步的自定义:
ggplot(dt, aes(x = index, y = factor(year), color = index)) +
geom_point() +
geom_text(aes(x = 6, y = 1.5, label = value), color = 'black', hjust = 0) +
geom_text(aes(x = 7, label = year), color = 'black') +
geom_segment(aes(x = 7.5, xend = 7.5, y = 0.7, yend = 2.3), color = 'black') +
geom_segment(aes(x = 7.45, xend = 7.5, y = 1, yend = 1), color = 'black') +
geom_segment(aes(x = 7.45, xend = 7.5, y = 2, yend = 2), color = 'black') +
scale_x_continuous(breaks = seq(8,18,2)) +
facet_grid(value + var1 ~., scales = "free_y", space="free", labeller = label_bquote(rows = .(var1))) +
theme_minimal() +
theme(axis.title = element_blank(),
axis.text.y = element_blank(),
strip.background = element_rect(color = 'darkgrey', fill = 'lightgrey'),
panel.grid.major.y = element_blank(),
panel.grid.minor = element_blank())
给出:
注:我用了var1
而不是var
因为后者也是一个函数名
另一种可能性是利用 gridExtra
包创建附加标签并将它们放在带有 grid.arrange
:
# create the main plot
mainplot <- ggplot(dt, aes(x = index, y = factor(year), color = index)) +
geom_point(size = 2) +
scale_x_continuous(breaks = seq(8,18,2)) +
facet_grid(value + var1 ~., scales = "free_y", space="free", labeller = label_bquote(rows = .(var1))) +
theme_minimal() +
theme(axis.title = element_blank(),
strip.background = element_rect(color = 'darkgrey', fill = 'lightgrey'))
# create a 2nd plot with everything besides the labels set to blank or NA
lbls <- ggplot(dt, aes(x = 0, y = factor(year))) +
geom_point(color = NA) +
geom_text(aes(x = 0, y = 1.5, label = value), color = 'black') +
scale_x_continuous(limits = c(0,0), breaks = 0) +
facet_grid(value + var1 ~.) +
theme_minimal() +
theme(axis.title = element_blank(),
axis.text.x = element_text(color = NA),
axis.text.y = element_blank(),
strip.background = element_blank(),
strip.text = element_blank(),
panel.grid = element_blank(),
legend.position = 'none')
# plot with 'grid.arrange' and give the 'lbls'-plot a small width
library(gridExtra)
grid.arrange(lbls, mainplot, ncol = 2, widths = c(1,9))
给出:
添加这个主要是为了显示一些 grob/gtable 操作:
library(ggplot2)
library(data.table)
library(gtable)
library(gridExtra)
# data for reproducible example
dt <- data.table(
value = c("East", "West","East", "West", "NY", "LA","NY", "LA"),
year = c(2008, 2008, 2013, 2013, 2008, 2008, 2013, 2013),
index = c(12, 10, 18, 15, 10, 8, 12 , 14),
var = c("Region","Region","Region","Region", "Metro","Metro","Metro","Metro"))
# change order or plot facets
dt[, var := factor(var, levels=c( "Region", "Metro"))]
# plot
ggplot(data=dt) +
geom_point( aes(x=index, y= factor(year), color=index)) +
facet_grid(value + var ~., scales = "free_y", space="free") +
theme_bw() +
theme(panel.grid=element_blank()) +
theme(panel.border=element_blank()) +
theme(axis.line.x=element_line()) +
theme(axis.line.y=element_line()) -> gg
gb <- ggplot_build(gg)
gt <- ggplot_gtable(gb)
这是它的样子:
gt
## TableGrob (14 x 8) "layout": 24 grobs
## z cells name grob
## 1 0 ( 1-14, 1- 8) background rect[plot.background..rect.5201]
## 2 5 ( 4- 4, 3- 3) axis-l absoluteGrob[GRID.absoluteGrob.5074]
## 3 6 ( 6- 6, 3- 3) axis-l absoluteGrob[GRID.absoluteGrob.5082]
## 4 7 ( 8- 8, 3- 3) axis-l absoluteGrob[GRID.absoluteGrob.5090]
## 5 8 (10-10, 3- 3) axis-l absoluteGrob[GRID.absoluteGrob.5098]
## 6 1 ( 4- 4, 4- 4) panel gTree[GRID.gTree.5155]
## 7 2 ( 6- 6, 4- 4) panel gTree[GRID.gTree.5164]
## 8 3 ( 8- 8, 4- 4) panel gTree[GRID.gTree.5173]
## 9 4 (10-10, 4- 4) panel gTree[GRID.gTree.5182]
## 10 9 ( 4- 4, 5- 5) strip-right absoluteGrob[strip.absoluteGrob.5104]
## 11 10 ( 6- 6, 5- 5) strip-right absoluteGrob[strip.absoluteGrob.5110]
## 12 11 ( 8- 8, 5- 5) strip-right absoluteGrob[strip.absoluteGrob.5116]
## 13 12 (10-10, 5- 5) strip-right absoluteGrob[strip.absoluteGrob.5122]
## 14 13 ( 4- 4, 6- 6) strip-right absoluteGrob[strip.absoluteGrob.5128]
## 15 14 ( 6- 6, 6- 6) strip-right absoluteGrob[strip.absoluteGrob.5134]
## 16 15 ( 8- 8, 6- 6) strip-right absoluteGrob[strip.absoluteGrob.5140]
## 17 16 (10-10, 6- 6) strip-right absoluteGrob[strip.absoluteGrob.5146]
## 18 17 (11-11, 4- 4) axis-b absoluteGrob[GRID.absoluteGrob.5066]
## 19 18 (12-12, 4- 4) xlab titleGrob[axis.title.x..titleGrob.5185]
## 20 19 ( 4-10, 2- 2) ylab titleGrob[axis.title.y..titleGrob.5188]
## 21 20 ( 4-10, 7- 7) guide-box gtable[guide-box]
## 22 21 ( 3- 3, 4- 4) subtitle zeroGrob[plot.subtitle..zeroGrob.5198]
## 23 22 ( 2- 2, 4- 4) title zeroGrob[plot.title..zeroGrob.5197]
## 24 23 (13-13, 4- 4) caption zeroGrob[plot.caption..zeroGrob.5199]
我们可以直接操作这些组件:
# make a copy of the gtable (not rly necessary but I think it helps simplify things since
# I'll usually forget to offset the column positions at some point if the
# manipulations get too involved)
gt2 <- gt
# add a new column after the axis title
gt2 <- gtable_add_cols(gt2, unit(3.0, "lines"), 2)
# these are those pesky strips of yours
for_left <- gt[c(4,6,8,10),5]
# let's copy them over into our new column
gt2 <- gtable_add_grob(gt2, for_left$grobs[[1]], t=4, l=3, b=4, r=3)
gt2 <- gtable_add_grob(gt2, for_left$grobs[[2]], t=6, l=3, b=6, r=3)
gt2 <- gtable_add_grob(gt2, for_left$grobs[[3]], t=8, l=3, b=8, r=3)
gt2 <- gtable_add_grob(gt2, for_left$grobs[[4]], t=10, l=3, b=10, r=3)
# then get rid of the original ones
gt2 <- gt2[, -6]
# now we'll change the background color, border color and text rotation of each strip text
for (gi in 21:24) {
gt2$grobs[[gi]]$children[[1]]$gp$fill <- "white"
gt2$grobs[[gi]]$children[[1]]$gp$col <- "white"
gt2$grobs[[gi]]$children[[2]]$children[[1]]$rot <- 0
}
grid.arrange(gt2)
IMO 第一个答案中的自定义贴标机和 geom_text 方法更具可读性和可重复性。