ggplot: добавить скрипку к линейному графику

Я рисую линейный график в ggplot. Каждая линия соответствует одному человеку и его развитию во времени. Упрощенный воспроизводимый пример:

dat <- data.frame(x=rep(1:10, 10), y=rnorm(100), person=rep(LETTERS[1:10], each=10))
ggplot(dat, aes(x, y, group=person)) + geom_line(aes(color=person))

Что производит:

введите описание изображения здесь

Я хочу добавить скрипку в точке x = 11, чтобы показать общее распределение значений по оси Y.

Если я добавлю + geom_violin() к вызову ggplot, скрипка будет нарисована при каждом значении x (что имеет смысл). Но я хочу добавить скрипку, которую я получил бы с ggplot(dat, aes(x, y)) + geom_violin().

Как мне объединить эти два geom_ на одном графике, чтобы получить полный обзор моих данных?


РЕДАКТИРОВАТЬ: я заставил его работать с geom_errorbar, но не могу заставить что-то похожее на работу со скрипкой:

ggplot(dat, aes(x, y, group=person)) + geom_line(aes(color=person)) + 
  geom_errorbar(aes(x=11, ymax=mean(dat$y)+sd(dat$y), ymin=mean(dat$y)-sd(dat$y))) + 
  geom_point(aes(x=11, y=mean(dat$y)), size=4)

Что дает мне это:

введите описание изображения здесь

В идеале я бы хотел, чтобы скрипка вместо планок погрешностей лучше отражала распределение.


person Florian    schedule 15.10.2016    source источник


Ответы (2)


Вам нужно использовать group = 1 внутри aes из geom_violin:

ggplot(dat, aes(x, y)) + 
  geom_line(aes(color = person)) + 
  geom_violin(aes(group = 1), fill = NA, size = 1.5) +
  theme_minimal()

это дает:

введите описание изображения здесь

Чтобы построить скрипку рядом с линейным графиком, вы можете использовать grid.arrange из пакета gridExtra:

p1 <- ggplot(dat, aes(x, y)) + 
  geom_line(aes(color = person)) + 
  theme_minimal(base_size = 14)
p2 <- ggplot(dat, aes(x, y)) + 
  geom_violin(fill = NA) + 
  theme_minimal(base_size = 14) + 
  theme(axis.title = element_text(color = NA),
        axis.text = element_text(color = NA))

library(gridExtra)
grid.arrange(p1, p2, ncol=2, widths = c(4,1))

который дает:

введите описание изображения здесь

Однако линейный и скрипичный сюжеты теперь разделены легендой. С:

library(gtable)
leg <- gtable_filter(ggplot_gtable(ggplot_build(p1)), "guide-box") 

grid.arrange(p1 + guides(color = FALSE), p2, leg, ncol=3, widths = c(4,1,1))

вы можете снова разместить легенду в крайнем правом углу графика:

введите описание изображения здесь

person Jaap    schedule 15.10.2016
comment
И есть ли способ показать эту скрипку в точке x = 11 вместо охвата всего графика? В идеале я хочу, чтобы он отображался между тем, что сейчас является строками, и легендой. - person Florian; 15.10.2016

Я понял:

ggplot(dat, aes(x, y, group=person)) + geom_line(aes(color=person)) + 
  geom_violin(aes(x=rep(11, nrow(dat)), y=y, group=1))

Обратите внимание: установка aes(x=11, y=y) в geom_violin() не работает, потому что (а) x и y должны иметь одинаковую длину и (б) вы получите десять скрипок.

(a) можно избежать, rep() задав число для создания вектора равной длины с y, и (b) можно избежать, установив group = 1 (как указано в ответе Procrastinatus Maximus).

Получившийся сюжет:

введите описание изображения здесь

Если есть лучшее решение для этого, я хотел бы увидеть его!

person Florian    schedule 15.10.2016
comment
Это не даст правильного сюжета скрипки imo. Смотрите также мой обновленный ответ - person Jaap; 15.10.2016
comment
Что значит не правильно? Скрипка может отображаться как вертикальная линия, если значения по оси X больше, но это можно настроить с помощью geom_violin(..., width=X), но скрипка будет содержать данные в y. Что тут не так? - person Florian; 15.10.2016
comment
это приводит к другой форме скрипки - person Jaap; 15.10.2016
comment
Но разве это не вопрос масштабирования плотности? Используемые данные одинаковы, верно? - person Florian; 15.10.2016
comment
Но скрипка представляет только распределение значений y. Попробуйте (в моем коде) заменить 11 на 4, затем на 5, затем на 6. Это все одна и та же скрипка. В вашем первоначальном ответе (где скрипка охватывает весь сюжет поверх строк) отличается только параметр width (я думаю). - person Florian; 15.10.2016