Измените strip.background в соответствии с strip.text в ggplot facet_wrap
Я пытаюсь сделать много "маленьких кратных" заговоров.
(Вне / Задний план) У меня слишком много граней для отображения на одном графике, поэтому мне нужно вручную разбить их на отдельные графики. Я надеялся, что смогу просто передать желаемое ncol
а также nrow
в facet_wrap
и это сделало бы столько, сколько мне нужно. Это не относится к делу.
Поскольку у меня так много граней, пространство стоит на первом месте. Итак, я хотел уменьшить размер надписей фасетов. Достаточно легко уменьшить strip.text
размер шрифта, но, к сожалению, strip.background
прямоугольник не соответствует размеру шрифта и не обеспечивает параметры размера (кроме размера границы). Установка его в element_blank()
фактически не удаляет пространство, выделенное для него, а просто делает то же пространство прозрачным.
MWE:
set.seed(1)
xcat = rep(1:10, 1000)
yvalue1 = rep(runif(10,5,7),1000)
yvalue2 = rep(runif(10,4,6),1000)
id = rep(1:1000,each=10)
df = data.frame(id,xcat,yvalue1,yvalue2)
for(i in seq(1, length(unique(df$id)), by=100)){
print(
ggplot(subset(df, id %in% unique(df$id)[i:(i+99)]), aes(x=xcat)) +
annotate("line", y=yvalue1, x=xcat, colour="cornflowerblue") +
annotate("line", y=yvalue2, x=xcat, colour="grey20") +
theme(axis.text.x = element_text(size=5),
axis.text.y = element_text(size=5),
strip.text = element_text(size=5)) +
facet_wrap(~id, ncol=10, nrow=10) +
expand_limits(y=0))
}
Любые идеи о том, как я могу уменьшить высоту этого strip.background, чтобы он не занимал так много места? В идеале размер должен быть точно равен высоте текста идентификатора.
В качестве бонуса, как уменьшить расстояние между гранями? (Есть ли параметр в facet_wrap, который мне не хватает?)
Это также занимает ДЕЙСТВИТЕЛЬНО много времени для рендеринга в RStudio с facet_wrap
(без facet_wrap это намного быстрее.
1 ответ
Результат, который вы хотите, - это достижимое изменение grobs
создано ggplot
, Процесс несколько запутанный и требует ручной настройки:
Оставив в стороне петлю, которая не имеет значения для проблемы, мы можем начать с уменьшения расстояния между фасетами. Это легко сделать, добавив panel.spacing
аргумент theme
,
library(ggplot2)
d <- ggplot(subset(df, id %in% unique(df$id)[1:(100)]), aes(x=xcat)) +
annotate("line", y=yvalue1, x=xcat, colour="cornflowerblue") +
annotate("line", y=yvalue2, x=xcat, colour="grey20") +
theme(axis.text.x = element_text(size=5),
axis.text.y = element_text(size=5),
strip.text = element_text(size=5),
panel.spacing = unit(.5, 'pt')) +
facet_wrap(~id, ncol=10, nrow=10) +
expand_limits(y=0)
Затем мы должны сгенерировать заговор ggplot2. Это создаст список отдельных элементов, составляющих сюжет.
g <- ggplotGrob(d)
head(g, 5)
# TableGrob (5 x 43) "layout": 13 grobs
# z cells name grob
# 1 3 ( 5- 5, 4- 4) axis-t-1-1 zeroGrob[NULL]
# 2 3 ( 5- 5, 8- 8) axis-t-2-1 zeroGrob[NULL]
# 3 3 ( 5- 5,12-12) axis-t-3-1 zeroGrob[NULL]
# 4 3 ( 5- 5,16-16) axis-t-4-1 zeroGrob[NULL]
# 5 3 ( 5- 5,20-20) axis-t-5-1 zeroGrob[NULL]
# 6 3 ( 5- 5,24-24) axis-t-6-1 zeroGrob[NULL]
# 7 3 ( 5- 5,28-28) axis-t-7-1 zeroGrob[NULL]
# 8 3 ( 5- 5,32-32) axis-t-8-1 zeroGrob[NULL]
# 9 3 ( 5- 5,36-36) axis-t-9-1 zeroGrob[NULL]
# 10 3 ( 5- 5,40-40) axis-t-10-1 zeroGrob[NULL]
# 11 4 ( 4- 4, 4-40) xlab-t zeroGrob[NULL]
# 12 8 ( 3- 3, 4-40) subtitle zeroGrob[plot.subtitle..zeroGrob.77669]
# 13 9 ( 2- 2, 4-40) title zeroGrob[plot.title..zeroGrob.77668]
Наша цель - найти и зафиксировать высоту относительно полос.
for(i in 1:length(g$grobs)) {
if(g$grobs[[i]]$name == 'strip') g$grobs[[i]]$heights <- unit(5, 'points')
}
К сожалению strip
grobs
также зависят от различных heights
основной сюжет делится на, поэтому мы должны уменьшить и те. Я не нашел способа программно определить, какая высота относится к полосе, но проверяя g$heights
довольно быстро, чтобы выяснить, что нам нужно.
g$heights
# [1] 5.5pt 0cm 0cm 0cm 0cm
# [6] 0.518897450532725cm 1null 0cm 0.5pt 0cm
# [11] 0.518897450532725cm 1null 0cm 0.5pt 0cm
# [16] 0.518897450532725cm 1null 0cm 0.5pt 0cm
# [21] 0.518897450532725cm 1null 0cm 0.5pt 0cm
# [26] 0.518897450532725cm 1null 0cm 0.5pt 0cm
# [31] 0.518897450532725cm 1null 0cm 0.5pt 0cm
# [36] 0.518897450532725cm 1null 0cm 0.5pt 0cm
# [41] 0.518897450532725cm 1null 0cm 0.5pt 0cm
# [46] 0.518897450532725cm 1null 0cm 0.5pt 0cm
# [51] 0.518897450532725cm 1null 0.306264269406393cm 1grobheight 0cm
# [56] 5.5pt
strip_grob_position <- seq(6, length(g$heights) - 5, 5)
for(i in strip_grob_position) {
g$heights[[i]] = unit(.05, 'cm')
}
Мы можем наконец нарисовать результат:
library(grid)
grid.newpage()
grid.draw(g)
Я вообще не эксперт в данной области, поэтому я мог сказать или объяснить что-то неправильно или неточно. Более того, могут быть лучшие (и более простые и более ggplot-ish) способы получения результата.
По словам Хэдли, теперь есть более простое решение. Я привел пример с более простым кодом для всех, кто наткнется на этот ответ. Ключевым моментом является установка margin = margin() всякий раз, когда вы устанавливаете размер текста.
set.seed(2112)
# dataframe with two groups
df <- data.frame(group1 = sample(LETTERS[1:5], size = 300, replace = TRUE),
group2 = sample(1:5, size = 300, replace = TRUE),
x = rnorm(300), y = rnorm(300))
ggplot(df, aes(x = x, y = y)) +
geom_point() +
facet_grid(group1 ~ group2) +
theme(strip.text.x = element_text(size = 4, margin = margin()),
strip.text.y = element_text(size = 20, margin = margin()))