переместить контур ggplot2 с других граней на основной

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

MWE:

library(ggplot2)
library(dplyr)

data(volcano)
nx <- 87; ny <- 61
vdat <- data_frame(w=0L, x=rep(seq_len(nx), ny), y=rep(seq_len(ny), each=nx), z=c(volcano))
vdat <- bind_rows(vdat,
                  mutate(vdat, w=1L, x=x+4, y=y+4, z=z-20),
                  mutate(vdat, w=2L, x=x+8, y=y+8, z=z-40))

ggplot(vdat, aes(x, y, fill=z)) +
  geom_tile() +
  facet_wrap(~ w, nrow=1) +
  geom_contour(aes(z=z), color='white', breaks=c(-Inf,110,Inf))

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

В каждом аспекте у меня есть:

  • грань 0: X,Y,Z для w==0L, контур для w==0L
  • фасет 1: X,Y,Z для w==1L, контур для w==1L
  • грань 2: X,Y,Z для w==2L, контур для w==2L

То, что я хотел бы иметь, - это одна панель, эффективно:

  • X,Y,Z для w==0L, контур для всех значений категории w

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

(Простите мои поспешные навыки работы с GIMP. В реальных данных контуры, скорее всего, не будут перекрываться, но я не думаю, что это будет проблемой.)

Реальные данные имеют разные значения (и градиенты) z для одной и той же системы X, Y, поэтому в остальном контур совместим с первой гранью. Однако он все еще «другой», поэтому я не могу смоделировать контуры с одними данными w==0L.

Я предполагаю, что может быть несколько способов сделать это:

  • формировать данные "правильно" с первого раза, сообщая ggplot, как тянуть контуры, но укладывать их на один график (например, используя разные data= для определенных слоев);
  • сформируйте граненый график, извлеките контуры из других граней, примените их к первой и отбросьте другие грани (возможно, используя grid и/или gtable); или, возможно,
  • (сам математически вычисляю контуры и добавляю их как независимые линии; я надеялся повторно использовать усилия ggplot2, чтобы избежать этого...).

person r2evans    schedule 03.05.2018    source источник


Ответы (1)


Это не совсем соответствует грамматике графики, но вы можете просто добавить вызов geom_contour для каждого подмножества данных. Быстрый способ — добавить список таких вызовов в граф, который вы можете быстро сгенерировать, lapply просматривая разделенные данные:

ggplot(vdat[vdat$w == 0, ], aes(x, y, z = z, fill = z)) +
    geom_tile() +
    lapply(split(vdat, vdat$w), function(dat){
        geom_contour(data = dat, color = 'white', breaks = c(-Inf, 110, Inf))
    })

Можно даже сделать легенду, если нужно:

ggplot(vdat[vdat$w == 0, ], aes(x, y, z = z, fill = z, color = factor(w))) +
    geom_raster() +
    lapply(split(vdat, vdat$w), function(dat){
        geom_contour(data = dat, breaks = c(-Inf, 110, Inf))
    })

person alistaire    schedule 03.05.2018
comment
Это выглядит невероятно, гораздо более прямолинейно, чем я ожидал. Я попробую это утром, но я уверен, что это сделает то, что мне нужно, отлично. Спасибо, @alistaire! - person r2evans; 03.05.2018
comment
Я не уверен, что понимаю, как он знает, что нужно делать +.list (поскольку lapply — это список гроба, а не список гроба), но пока я могу нажать «Я верю». Спасибо еще раз! - person r2evans; 03.05.2018
comment
Если вы посмотрите на ?ggplot2::`+.gg`, после другого списка вещей, которые вы можете добавить, он говорит, что вы также можете предоставить список, и в этом случае каждый элемент списка будет добавлен по очереди, поэтому его легче рассматривать как список ( этакие оцененные) звонки. Это работает только в том случае, если вы добавляете его к существующему объекту ggplot, т. е. объекту, начатому с вызова ggplot, так как он определяет, какой метод + вызывается. - person alistaire; 03.05.2018
comment
Аааа, да, это имеет смысл... +.gg смотрит на первый аргумент, который является grob на левой стороне, а не на list на правой. Ду, понял. - person r2evans; 03.05.2018
comment
Кстати: мне пришлось переместить color= в тиски geom_contour внутри ggplot(aes(...)), не знаю, почему это сработало для вас, а не для меня. Np, он работает и делает то, что я хочу/нужно/надеюсь/ожидаю. (ggplot2-2.2.1, R-3.3.3, если это что-то меняет) - person r2evans; 03.05.2018
comment
Точно. Эта идиома часто используется с stat_function. - person alistaire; 03.05.2018
comment
О, я переключил второй на geom_raster, который никогда не окрашивает сетку (и работает быстрее). Вы можете использовать geom_tile с color = NA, но это не очень понятно. - person alistaire; 03.05.2018