Можно ли создать перекрывающиеся оси y с общей осью x?

#r #ggplot2 #patchwork

Вопрос:

У меня часто есть цифры, у которых одна и та же общая ось x, но разные оси y. Они не могут быть гранеными, так как некоторые оси y нуждаются в сложных именах и/или имеют перевернутые координаты по историческим/интерпретационным причинам.

Ниже я приведу пример такой фальшивой записи и покажу, как я хотел бы, чтобы этот сюжет выглядел после настройки в Inkscape. Есть ли какой-либо способ достичь этого результата изнутри R/patchwork?

 library(tidyverse)
library(patchwork)

set.seed(123)
dat <- tibble::tibble(a = 1:10,
                      b = c(0, 2, 5, 8, 5, 4, 6, 4, 3, 2),
                      c = -stats::rnorm(10, b, 3),
                      d = sample(letters[1:3], 10, TRUE))

shared_x <- c(0, 11)

pl1 <- dat %>%
  ggplot(aes(x = a, y = b))  
  geom_point(colour = "indianred")  
  coord_cartesian(xlim = shared_x)  
  scale_y_continuous("B is awesome", position = "right")

pl2 <- dat %>%
  ggplot(aes(x = a, y = c))  
  geom_point(colour = "steelblue")  
  scale_y_reverse("C is inversely related to B")  
  coord_cartesian(xlim = shared_x, ylim = c(3, -13))

theme_set(theme_classic())
(pl1 amp; theme(axis.title.x = element_blank(), axis.text.x = element_blank(), axis.ticks.x = element_blank(), axis.line.x = element_blank())) / pl2
 

 ggsave("overlapping_axes.pdf", width = 10, height = 8, units = "cm")
 

Создано 2021-07-09 с помощью пакета reprex (версия 2.0)

а вот версия, измененная вручную:

Комментарии:

1. Обратите внимание, что мне пришлось использовать theme_classic() здесь, потому что в противном случае сетки перекрывались бы, что еще больше затрудняло бы выполнение этой задачи.

2. Потребовалось несколько лет, чтобы убедить ggplot2 авторов дополнить sec_axis его сюжеты, в основном по той причине, что наличие двух осей с разными единицами может слишком легко сбить с толку. Ваша «измененная вручную версия» (по моему мнению) — это именно та путаница, о которой они говорили: в вертикальном размещении между красными и синими точками подразумевается релевантность. Можно ли это сделать? Возможно, хотя линии осей, вероятно, придется рисовать вручную, и все координаты нужно будет нормализовать с помощью переопределенных вручную меток оси.

3. Сказав это, я предполагаю, что грани и patchwork для меня гораздо яснее. Вы уже выполняете patchwork свою часть, я предлагаю добавить содержащие блоки фасеток, которые четко разделяли бы эти два аспекта. Если это то, чего вы не хотите, и вы хотите, чтобы синие/красные точки смешивались, тогда (опять же, имо) потребуется много объяснений, чтобы оправдать это таким образом. (Субъективно, я признаю.)

4. Спасибо за ответ! В моей области (палеоцеанография) у нас есть много различных типов данных, которые генерируются для одних и тех же интервалов глубины/возраста (обычно по оси x). Часто мы хотим изучить, показывают ли восстановленные температуры те же самые закономерности, что и в разных прокси, например, для CO2. Таким образом, это совершенно разные оси y с разными значениями, но мы хотим поместить их рядом друг с другом, чтобы лучше визуально сравнить узоры. См., например .

5. Или, возможно, другой пример изображения . Но у них у всех есть коробки вокруг… хммм

Ответ №1:

Я вижу, что r2evans уже дал вам предупреждения, которые следует учитывать каждый раз, когда можно подумать, что вторичная ось решит ваши проблемы. Я согласен с ними, однако, это не значит, что этого нельзя сделать.

Пока вы можете думать о преобразовании, и оно обратное, вы, вероятно, могли бы сделать это с помощью вторичных осей (не путать с «вы должны это сделать»). Усеченный вид оси можно воспроизвести с ggh4x::axis_truncated() помощью (отказ от ответственности, я являюсь автором этой функции).

В приведенном ниже примере преобразование для вторичной оси -x * 0.5 , таким образом, является обратным - x / 0.5 , но, вероятно, вы можете сделать это лучше в соответствии с вашими потребностями.

 library(ggplot2)
library(ggh4x)

set.seed(123)
dat <- tibble::tibble(a = 1:10,
                      b = c(0, 2, 5, 8, 5, 4, 6, 4, 3, 2),
                      c = -stats::rnorm(10, b, 3),
                      d = sample(letters[1:3], 10, TRUE))

ggplot(dat, aes(a))  
  geom_point(aes(y = b, colour = "b"))  
  geom_point(aes(y = -c * 0.5, colour = "c"))  
  scale_y_continuous(
    position = "right", breaks = seq(0, 8, by = 2),
    guide = guide_axis_truncated(),
    name = "B is awesome",
    sec.axis = sec_axis(
      trans = ~ -.x/0.5, breaks = c(0, -5, -10),
      guide = guide_axis_truncated(trunc_lower = -Inf),
      name = "C is inversely related to B"
    )
  )  
  scale_colour_manual(values = c("indianred", "steelblue"))  
  theme_classic()  
  theme(
    axis.title.y.left = element_text(colour = "steelblue"),
    axis.title.y.right = element_text(colour = "indianred")
  )
 

Создано 2021-07-09 пакетом reprex (v1.0.0)

Вероятно, вы можете немного изменить расположение названий осей, установив соответствующие hjust s.

Комментарии:

1. Спасибо за решение. Это действительно кажется слишком сложным для графиков с >5 панелями, где эти отношения не очень понятны. Я думаю, что либо оставлю их разделенными как есть, либо при желании вручную настрою их в inkscape.