Легенды для множественных заливок в ggplot

Я новичок в ggplot2, Итак, я прошу прощения, если этот вопрос звучит слишком основательно. Буду признателен за любые рекомендации. Я потратил 4 часа на это и посмотрел на эту ветку SO R: Custom Legend для многослойного ggplot для руководства, но ничего не получилось.

Цель: я хочу иметь возможность применять легенду к разным цветам заливки, используемым для разных слоев. Я делаю этот пример только для проверки моего понимания применения концепций ggplot2 концепции.

Кроме того, я не хочу менять тип фигуры; Смена цвета заливки - это нормально - под "заливкой" я не имею в виду, что мы могли бы изменить "цвет". Поэтому я был бы признателен, если бы вы могли исправить мои ошибки в моей работе.

Попробуйте 1: Вот код "голые кости" без каких-либо цветов, установленных вручную.

ggplot(mtcars, aes(disp,mpg)) +
geom_point(aes(fill = factor(vs)),shape = 23, size = 8, alpha = 0.4) +
geom_point (aes(fill = factor(cyl)),shape = 21, size = 2) +
geom_rect(aes(xmin = min(disp)-5, ymax = max(mpg) + 2,fill = "cyan"), 
xmax = mean(range(mtcars$disp)),ymin = 25, alpha = 0.02) ##region for high mpg

Вывод выглядит так: введите описание изображения здесь

Теперь есть несколько проблем с этим изображением:

Проблема 1) Голубой прямоугольник, который показывает "области высокого миль на галлон", потерял свою легенду.

Проблема 2) ggplot пытается объединить легенду из двух geom_point() слои и в результате легенда для двух geom_point() также смешаны.

Проблема 3) Цветовая палитра по умолчанию используется ggplot2 делает цвета неразличимыми для моих глаз.

Итак, я попытался вручную установить цвета iestart с исправлением № 3 выше.

ggplot(mtcars, aes(disp,mpg)) + 
       geom_point(aes(fill = factor(vs)),shape = 23, size = 8, alpha = 0.4)+
       geom_point(aes(fill = factor(cyl)),shape = 21, size = 2) +
       geom_rect(aes(xmin = min(disp)-5, ymax = max(mpg) + 2,fill = "cyan"),
                 xmax = mean(range(mtcars$disp)),ymin = 25, alpha = 0.02) + 
     scale_fill_manual(values = c("green","blue", "black", "cyan", "red", "orange"), 
labels=c("4 gears","6 gears","8 gears","High mpg","0","1"))

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

Вопрос № 4: Мне кажется, что ggplot2 ожидает, что я предоставлю цвета в том порядке, в котором были установлены слои. т.е. сначала установите цвет для mtcars$vs заполнить, затем mtcars$cyl заполните и, наконец, прямоугольник с голубым цветом. Я смог это исправить, изменив код так:

ggplot(mtcars, aes(disp,mpg)) + 
       geom_point(aes(fill = factor(vs)),shape = 23, size = 8, alpha = 0.4) +
       geom_point(aes(fill = factor(cyl)),shape = 21, size = 2) +
       geom_rect(aes(xmin = min(disp)-5, ymax = max(mpg) + 2,fill = "cyan"),
                 xmax = mean(range(mtcars$disp)),ymin = 25, alpha = 0.02) + 
     scale_fill_manual(values = c("red", "orange", "green", "blue", "black", "cyan"), 
labels=c("0","1","4 gears","6 gears","8 gears","High mpg")) #changed the order

Итак, у меня есть два вопроса:

Вопрос 1: Как я могу исправить легенды - я хочу три разные легенды - одну для заполнения прямоугольника (которую я называю прямоугольником с высоким mpg), другую для заполнения для geom_point() представлена mtcars$vs и последний для заполнения для geom_point() представлена mtcars$cyl

Вопрос 2: Правильна ли моя гипотеза об упорядочении цветов по слоям (т.е. проблема № 4, рассмотренная выше)? Я сомневаюсь, потому что, если есть много факторов - мы должны запомнить их, затем упорядочить их в соответствии с нарисованными слоями и, наконец, не забудьте применить цветовую палитру вручную в каждом порядке geom_*() слои созданы?

Как новичок, я потратил много часов на это, гуглил везде. Итак, я буду признателен за ваше любезное руководство.

2 ответа

Решение

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

Шкалы действительно предназначены для отображения данных одного типа. Один подход заключается в использовании обоих col а также fill, что может привести вас как минимум к двум легендам. Вы можете добавить linetype и взломать его немного, используя override.aes, Примечательно, что я думаю, что это может (в общем) привести вас к большему количеству проблем, чем решит. Если вам отчаянно нужно это сделать, вы можете (пример ниже). Однако, если я могу убедить вас: я умоляю вас не использовать этот подход, если это вообще возможно. Отображение на разные вещи (например, shape а также linetype) может привести к меньшему замешательству. Я приведу пример этого ниже.

Кроме того, при настройке цвета или заливки вручную всегда полезно использовать именованные векторы для palette это гарантирует, что цвета соответствуют тому, что вы хотите. Если нет, то совпадения происходят в порядке уровней факторов.

ggplot(mtcars, aes(x = disp
                   , y = mpg)) +
  ##region for high mpg 
  geom_rect(aes(linetype = "High MPG")
            , xmin = min(mtcars$disp)-5
            , ymax = max(mtcars$mpg) + 2
            , fill = "cyan"
            , xmax = mean(range(mtcars$disp))
            , ymin = 25
            , alpha = 0.02
            , col = "black") + 
  ## test diff region
  geom_rect(aes(linetype = "Other Region")
            , xmin = 300
            , xmax = 400
            , ymax = 30
            , ymin = 25
            , fill = "yellow"
            , alpha = 0.02
            , col = "black") + 
  geom_point(aes(fill = factor(vs)),shape = 23, size = 8, alpha = 0.4) +
  geom_point (aes(col = factor(cyl)),shape = 19, size = 2) +
  scale_color_manual(values = c("4" = "red"
                                , "6" = "orange"
                                , "8" = "green")
                     , name = "Cylinders") +
  scale_fill_manual(values = c("0" = "blue"
                               , "1" = "black"
                               , "cyan" = "cyan")
                    , name = "V/S"
                    , labels = c("0?", "1?", "High MPG")) +
  scale_linetype_manual(values = c("High MPG" = 0
                                   , "Other Region" = 0)
                        , name = "Region"
                        , guide = guide_legend(override.aes = list(fill = c("cyan", "yellow")
                                                                       , alpha = .4)))

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

ggplot(mtcars, aes(x = disp
                   , y = mpg)) +
  ##region for high mpg 
  geom_rect(aes(linetype = "High MPG")
            , xmin = min(mtcars$disp)-5
            , ymax = max(mtcars$mpg) + 2
            , fill = NA
            , xmax = mean(range(mtcars$disp))
            , ymin = 25
            , col = "black") + 
  ## test diff region
  geom_rect(aes(linetype = "Other Region")
            , xmin = 300
            , xmax = 400
            , ymax = 30
            , ymin = 25
            , fill = NA
            , col = "black") +
  geom_point(aes(col = factor(cyl)
                 , shape = factor(vs))
             , size = 3) +
  scale_color_brewer(name = "Cylinders"
                     , palette = "Set1") +
  scale_shape(name = "V/S") +
  scale_linetype_manual(values = c("High MPG" = "dotted"
                                   , "Other Region" = "dashed")
                        , name = "Region")

Почему-то вы настаиваете на использовании fill, Вот подход, который делает точно такой же сюжет, как первый в этом ответе, но использует fill в качестве эстетики для каждого из слоев. Если это не то, на чем вы настаиваете, то я все еще не знаю, что вы ищете.

ggplot(mtcars, aes(x = disp
                   , y = mpg)) +
  ##region for high mpg 
  geom_rect(aes(linetype = "High MPG")
            , xmin = min(mtcars$disp)-5
            , ymax = max(mtcars$mpg) + 2
            , fill = "cyan"
            , xmax = mean(range(mtcars$disp))
            , ymin = 25
            , alpha = 0.02
            , col = "black") + 
  ## test diff region
  geom_rect(aes(linetype = "Other Region")
            , xmin = 300
            , xmax = 400
            , ymax = 30
            , ymin = 25
            , fill = "yellow"
            , alpha = 0.02
            , col = "black") + 
  geom_point(aes(fill = factor(vs)),shape = 23, size = 8, alpha = 0.4) +
  geom_point (aes(col = "4")
              , data = mtcars[mtcars$cyl == 4, ]
              , shape = 21
              , size = 2
              , fill = "red") +
  geom_point (aes(col = "6")
              , data = mtcars[mtcars$cyl == 6, ]
              , shape = 21
              , size = 2
              , fill = "orange") +
  geom_point (aes(col = "8")
              , data = mtcars[mtcars$cyl == 8, ]
              , shape = 21
              , size = 2
              , fill = "green") +
  scale_color_manual(values = c("4" = NA
                                , "6" = NA
                                , "8" = NA)
                     , name = "Cylinders"
                     , guide = guide_legend(override.aes = list(fill = c("red","orange","green")))) +
  scale_fill_manual(values = c("0" = "blue"
                               , "1" = "black"
                               , "cyan" = "cyan")
                    , name = "V/S"
                    , labels = c("0?", "1?", "High MPG")) +
  scale_linetype_manual(values = c("High MPG" = 0
                                   , "Other Region" = 0)
                        , name = "Region"
                        , guide = guide_legend(override.aes = list(fill = c("cyan", "yellow")
                                                                   , alpha = .4)))

Поскольку я, по-видимому, не могу оставить это в покое - вот еще один подход, использующий просто заливку для эстетики, затем создание отдельных легенд для отдельных слоев и склеивание всех вместе, используя cowplot слабо следуя этому уроку.

library(cowplot)
library(dplyr)

theme_set(theme_minimal())

allScales <-
  c("4" = "red"
    , "6" = "orange"
    , "8" = "green"
    , "0" = "blue"
    , "1" = "black"
    , "High MPG" = "cyan"
    , "Other Region" = "yellow")

mainPlot <-
  ggplot(mtcars, aes(x = disp
                     , y = mpg)) +
  ##region for high mpg 
  geom_rect(aes(fill = "High MPG")
            , xmin = min(mtcars$disp)-5
            , ymax = max(mtcars$mpg) + 2
            , xmax = mean(range(mtcars$disp))
            , ymin = 25
            , alpha = 0.02) + 
  ## test diff region
  geom_rect(aes(fill = "Other Region")
            , xmin = 300
            , xmax = 400
            , ymax = 30
            , ymin = 25
            , alpha = 0.02) + 
  geom_point(aes(fill = factor(vs)),shape = 23, size = 8, alpha = 0.4) +
  geom_point (aes(fill = factor(cyl)),shape = 21, size = 2) +
  scale_fill_manual(values = allScales)

vsLeg <-
  (ggplot(mtcars, aes(x = disp
                      , y = mpg)) +
     geom_point(aes(fill = factor(vs)),shape = 23, size = 8, alpha = 0.4) +
     scale_fill_manual(values = allScales
                       , name = "VS")
  ) %>%
  ggplotGrob %>%
  {.$grobs[[which(sapply(.$grobs, function(x) {x$name}) == "guide-box")]]}



cylLeg <-
  (ggplot(mtcars, aes(x = disp
                      , y = mpg)) +
     geom_point (aes(fill = factor(cyl)),shape = 21, size = 2) +
     scale_fill_manual(values = allScales
                       , name = "Cylinders")
  ) %>%
  ggplotGrob %>%
  {.$grobs[[which(sapply(.$grobs, function(x) {x$name}) == "guide-box")]]}


regionLeg <-
  (ggplot(mtcars, aes(x = disp
                      , y = mpg)) +
     geom_rect(aes(fill = "High MPG")
               , xmin = min(mtcars$disp)-5
               , ymax = max(mtcars$mpg) + 2
               , xmax = mean(range(mtcars$disp))
               , ymin = 25
               , alpha = 0.02) + 
     ## test diff region
     geom_rect(aes(fill = "Other Region")
               , xmin = 300
               , xmax = 400
               , ymax = 30
               , ymin = 25
               , alpha = 0.02) + 
     scale_fill_manual(values = allScales
                       , name = "Region"
                       , guide = guide_legend(override.aes = list(alpha = 0.4)))
  ) %>%
  ggplotGrob %>%
  {.$grobs[[which(sapply(.$grobs, function(x) {x$name}) == "guide-box")]]}


legendColumn <-
  plot_grid(
    # To make space at the top
    vsLeg + theme(legend.position = "none")
    # Plot the legends
    , vsLeg, regionLeg, cylLeg
    # To make space at the bottom
    , vsLeg + theme(legend.position = "none")
    , ncol = 1
    , align = "v")

plot_grid(mainPlot +
            theme(legend.position = "none")
          , legendColumn
          , rel_widths = c(1,.25))

Как видите, результат почти идентичен первому способу, который я продемонстрировал, как это сделать, но теперь не использует никакой другой эстетики. Я до сих пор не понимаю, почему вы думаете, что это различие важно, но, по крайней мере, теперь есть другой способ снять кожу с кошки. Я могу использовать для общих черт этого подхода (например, когда несколько графиков разделяют сочетание эстетики цвета / символа / типа линии, и вы хотите использовать одну легенду), но я не вижу смысла в ее использовании здесь.

Теперь существует отличный пакет ggnewscale, позволяющий сделать это простым способом.

Вы также можете достичь этого, наложив несколько графиков, используя align_plots а также ggdraw функции в cowplot, Это решение, которое я использовал для размещения рассеивателя (дискретная цветовая шкала) на растре (непрерывная цветовая шкала). Смотрите виньетку по следующей ссылке.

https://www.rdocumentation.org/packages/cowplot/versions/0.9.2/topics/align_plots

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