Home Articles

ggplot中多个填充的传说

Asked
Viewed 1827 times
7

我是 ggplot2 的初学者 . 所以,如果这个问题听起来太基本,我道歉 . 我已经花了4个小时在这上面看了这个SO线程R: Custom Legend for Multiple Layer ggplot作为指导,但结果无处可去 .

Objective: 我希望能够将图例应用于用于不同图层的不同填充颜色 . 我正在做这个例子只是为了测试我对应用概念 ggplot2 概念的理解 .

另外,我想 NOT 想要改变形状类型;改变填充颜色很好 - 通过"fill"我不是说我们可以改变"color" . 所以,如果你能纠正我工作中的错误,我将不胜感激 .

Try 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

输出如下所示:
enter image description here

现在,此图像存在一些问题:

Issue 1) 显示"high mpg areas"的青色矩形已失去其传奇 .

Issue 2) ggplot尝试组合两个 geom_point() 图层的图例,因此两个 geom_point() 的图例也是混合的 .

Issue 3) ggplot2 使用的默认颜色paleltte使我的眼睛无法区分颜色 .

所以,我采取了手动设置颜色的方法,即上面固定#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"))

这是输出:
enter image description here
不幸的是,上面强调的一些问题仍然存在 . 有关订购的新问题 .

Issue#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

所以,我有两个问题:

Question 1: 如何修复图例 - 我想要三个不同的图例 - 一个用于矩形填充(我称之为高mpg矩形),另一个用于填充 geom_point()mtcars$vs 表示,最后一个用于填充 geom_point()mtcars$cyl 表示

Question2: 我的假设是按照正确的层次排序颜色(即上面讨论的问题#4)?我很怀疑,因为如果有很多因素,我们需要记住它们,然后按照绘制的图层对它们进行排序,最后记得按照每个 geom_*() 图层的顺序手动应用调色板吗?

作为一个初学者,我花了很多时间在这上面,谷歌搜索到处都是 . 所以,我很感激你的善意指导 .

2 Answers

  • 7

    (注意,我编辑了这个以便在几次来回之后进行清理 - 请参阅修订历史以了解更多我尝试过的内容 . )

    标度实际上是为了显示一种类型的数据 . 一种方法是同时使用 colfill ,这可以让你获得至少2个传说 . 然后你可以使用 override.aes 添加 linetype 并稍微破解它 . 值得注意的是,我认为这可能(通常)会引发更多问题,而不是解决问题 . 如果你迫切需要这样做,你可以(例如下面的例子) . 但是,如果我能说服你:我恳请你尽可能不使用这种方法 . 映射到不同的东西(例如 shapelinetype )可能会减少混淆 . 我举一个下面的例子 .

    此外,在手动设置颜色或填充时,使用 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)))
    

    enter image description here

    Here is the plot I think will work better for nearly all use cases:

    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")
    

    enter image description here

    出于某种原因,你坚持使用 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 松散地将它们拼接在一起tutorial .

    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))
    

    enter image description here

    正如您所看到的,结果几乎与我演示如何执行此操作的第一种方式相同,但现在不使用任何其他美学 . 我仍然不明白为什么你认为这种区别是重要的,但至少现在有另一种方法可以给猫皮肤 . 我可以使用这种方法的一般性(例如,当多个绘图共享颜色/符号/线型美学混合并且您想要使用单个图例时)但我认为在此处使用它没有任何 Value .

  • 0

    你也可以实现这是通过使用 cowplot 中的 align_plotsggdraw 函数分层多个图 . 这是我用于将散射(离散色标)放到光栅上的解决方案(连续色标) . 请参阅以下链接中的插图 .

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

Related