Создайте линию на нескольких графиках в ggplot2

Я хочу создать горизонтальную линию, проходящую через два участка в сочетании с пакетом пэчворк.

library(ggplot2)
library(patchwork)

# Annotation after plot
p1 <- ggplot(mtcars, aes(x=disp,y=mpg))+
  geom_point()
p2 <- ggplot(mtcars, aes(x=hp,y=mpg))+
  geom_point()
# Want line across plots at y (mpg) of 15
p3 <- (p1+p2)+annotate("segment",x=-Inf,xend=Inf,y=15,yend=15)
p3

Этот метод только помещает линию через последний график (p2).

Пробуем поставить аннотацию к каждому сюжету.

# Annotation with each plot
p1 <- ggplot(mtcars, aes(x=disp,y=mpg))+
  geom_point()+
  annotate("segment",x=-Inf,xend=Inf,y=15,yend=15)
p2 <- ggplot(mtcars, aes(x=hp,y=mpg))+
  geom_point()+
  annotate("segment",x=-Inf,xend=Inf,y=15,yend=15)

p1+p2

Этот метод ставит черту на каждом участке, но не между ними.

Я хочу что-то вроде этого:

2 ответа

Решение

Вы можете нарисовать линию, используя grid.draw, который отображает линию поверх всего, что находится в окне построения:

library(grid)
p3
grid.draw(linesGrob(x = unit(c(0.06, 0.98), "npc"), y = unit(c(0.277, 0.277), "npc")))

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

Второе предостережение заключается в том, что линия располагается в пространстве npc, тогда как ggplot использует комбинацию фиксированных и гибких интервалов. Результатом этого является то, что линия будет перемещаться относительно графика при изменении размера графика. Опять же, это можно исправить программно. Если вы действительно хотите открыть эту банку с червями, вы можете увидеть решение чего-то подобного с пунктами в моем ответе на этот вопрос.

Мне нравится ответ @Allan, но вот альтернативный подход с использованием facet_wrap.

Сначала нам нужно развернуть данные дольше, чтобы они были в форме для использования facet_wrap. Затем начинаются хаки. Во-первых, нам нужно переместить метки полос фасетов вниз с помощьюstrip.position = 'bottom'. Затем мы можем отключить обрезку с помощьюcoord_cartesian(clip = 'off')так что линии могут быть построены за пределами области графика. Далее мы исправляемxlim поэтому область построения графика не меняется, когда вы пытаетесь построить сегмент за пределами области графика.

Наконец, большой взлом, вы строите geom_segmentс новыми данными, поэтому он отображается только в одном фасете. Вы делаете новыйdata.frame в звонке geom_segment с данными, которые заставляют его строить на последней панели, которая будет отображаться, чтобы линия была сверху.

Наконец, всего несколько изменений в theme() поэтому фон полосы пуст, а размещение находится вне отметок оси.

library(ggplot2)
library(dplyr)
library(tidyr)
ggplot(pivot_longer(mtcars, -mpg) %>% filter(name %in% c("disp", "hp")),
       aes(x=value, y=mpg, group=name)) +
  geom_point() + 
  facet_wrap(.~name, strip.position = "bottom") + 
  geom_segment(data = data.frame(mpg = 15, name = "hp"),
               x=-650, xend=525, y=15, yend=15) +
  coord_cartesian(clip = 'off', xlim = c(0,500)) +
  theme(aspect.ratio = 1,
        strip.background = element_blank(),
        strip.placement = "outside") +
  labs(x = "") 

Другие вопросы по тегам