Я нахожу эту проблему очень интересной, и я думаю, что нет идеального решения.Лично я хочу, чтобы все выглядело аккуратно и выровнено, поэтому аргумент gridExtra::grid.arrange
top
(или bottom
для метки оси) не очень радует мой глаз.
Другое решение состоит в использовании фасетов иотредактируйте сюжет с пакетами gtable
и grid
.Это также не идеально, потому что я не нашел решения для индивидуальной настройки масштабов фасетов.Единственный вариант - освободить весы, добавив scales = "free_x"
к фасету.Если максимальный процент с обеих сторон близок, это работает очень хорошо.Если нет, может быть, не так.
Сначала я написал функцию для удаления столбца в гробе.Мы будем использовать его для перемещения меток оси в центр.
library(tidyverse)
library(grid)
library(gtable)
delete_col <- function(x, pattern) {
t <- x$layout %>%
filter(str_detect(name, pattern)) %>%
pull(l)
x <- gtable_filter(x, pattern, invert = TRUE)
x$widths[t] <- unit(0, "cm")
x
}
Затем мы создадим данные и базовый график.Два параметра темы необходимы, чтобы установить тексты осей прямо в середине фасетов.
test_data <- rnorm(500, 50, 15) %>%
crossing(sex = c("M", "F")) %>%
transmute(sex, value = cut(., c(min(.), 20, 40, 60, max(.)), include.lowest = TRUE))
test_data <- test_data %>%
count(sex, value) %>%
group_by(sex) %>%
mutate(p = n/sum(n)) %>%
ungroup() %>%
mutate(p = if_else(sex == "F", -p, p)) # negative values for the left-hand side.
p1 <- test_data %>%
ggplot(aes(value, p)) +
facet_wrap(~ sex, scales = "free_x") +
geom_col() +
coord_flip() +
theme(axis.text.y = element_text(hjust = 0.5, margin = margin(0, 0, 0, 0)),
axis.ticks.length = unit(0, "pt")) +
scale_y_continuous(labels = function(x) paste0(abs(x) * 100, "%")) +
labs(x = NULL)
Теперь это становится немного сложнее.Сначала мы создадим объект grob из объекта ggplot.
p1_g <- ggplotGrob(p1)
Затем мы расширим пространство между фасетами, взяв существующее пространство, занятое текстами оси, и добавив несколько пробелов.Я взглянул на объект grob, чтобы увидеть, какие столбцы какие, используя gtable_show_layout(p1_g)
.
p1_g$widths[7] <- p1_g$widths[4] + unit(0.5, "cm")
Далее мы отсоединим тексты осей от своего собственного объекта для дальнейшего использования.
p1g_axis <- gtable_filter(p1_g, "axis-l-1-1")
И, наконец, мы добавим все это вместе.Теперь я знаю, глядя на макет, где все положить.l
для левого экстента и t
для верхнего экстента.
p1_g %>%
gtable_add_grob(p1g_axis, l = 7, t = 8, name = "middle_axis") %>% # add the axis to the middle
delete_col("axis-l-1-1") %>% # delete the original axis
gtable_add_grob(textGrob("Label", gp = gpar(fontsize = 11)), l = 7, t = 7) %>% # add the top label
grid.draw() # draw the result
![enter image description here](https://i.stack.imgur.com/BOGOu.png)