【问题标题】:Place a legend for each facet_wrap grid in ggplot2在 ggplot2 中为每个 facet_wrap 网格放置一个图例
【发布时间】:2013-01-28 05:32:52
【问题描述】:

我有这个数据框:

        Date Server FileSystem PercentUsed
1  12/1/2011      A          /          60
2   1/2/2012      A       /var          50
3   2/1/2012      A        tmp          90
4  2/10/2012      A        /db          86
5  2/13/2012      A       /app          90
6  12/1/2011      B         C:          67
7   1/2/2012      B         D:          67
8   2/1/2012      B         F:          34
9  2/10/2012      B   /restore          89
10 2/13/2012      B         G:          56
11 12/1/2011      C          /          90
12  1/2/2012      C       /tmp          78
13  2/1/2012      C      /data          67
14 2/10/2012      C   /Storage          34
15 2/13/2012      C  /database          12

dput(x)
structure(list(Date = structure(c(2L, 1L, 3L, 4L, 5L, 2L, 1L, 
3L, 4L, 5L, 2L, 1L, 3L, 4L, 5L), .Label = c("1/2/2012", "12/1/2011", 
"2/1/2012", "2/10/2012", "2/13/2012"), class = "factor"), Server = structure(c(1L, 
1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 3L, 3L, 3L, 3L, 3L), .Label = c("A", 
"B", "C"), class = "factor"), FileSystem = structure(c(1L, 9L, 
14L, 5L, 2L, 10L, 11L, 12L, 6L, 13L, 1L, 8L, 3L, 7L, 4L), .Label = c("/", 
"/app", "/data", "/database", "/db", "/restore", "/Storage", 
"/tmp", "/var", "C:", "D:", "F:", "G:", "tmp"), class = "factor"), 
    PercentUsed = c(60L, 50L, 90L, 86L, 90L, 67L, 67L, 34L, 89L, 
    56L, 90L, 78L, 67L, 34L, 12L)), .Names = c("Date", "Server", 
"FileSystem", "PercentUsed"), class = "data.frame", row.names = c(NA, 
-15L))

我想在每个facet_wrap 网格旁边放一个图例,它自己的FileSystem:

当我这样做时,它会将图例放在所有FileSystem 的情节一侧。是否可以将FileSystem 属于每个网格旁边的每个服务器?

ggplot(x, aes(Date, PercentUsed, group=1, colour=FileSystem)) + 
     geom_jitter(size=0.5) + geom_smooth(method="loess", se=T) + 
     facet_wrap(~Server, ncol=1)

【问题讨论】:

    标签: r ggplot2 legend facet facet-wrap


    【解决方案1】:

    最好的方法是使用 gridExtra 包:

    library(gridExtra)
    
    xs <- split(x,f = x$Server)
    p1 <- ggplot(xs$A,aes(x = Date,y = PercentUsed,group = 1,colour = FileSystem)) + 
            geom_jitter(size=0.5) + 
            geom_smooth(method="loess", se=T) + 
            facet_wrap(~Server, ncol=1)
    
    p2 <- p1 %+% xs$B
    p3 <- p1 %+% xs$C
    
    grid.arrange(p1,p2,p3)
    

    【讨论】:

    • 我应该注意到您在geom_jitter 中提出的观点非常小,我不知道为什么,但我保持原样。点在那里,但很难看到。
    • 我对@9​​87654324@ 运算符有点感兴趣。你能解释一下它的作用吗?
    • @Legend 这是一种使 ggplot 对象“模块化”的方法,因为您可以使用它来简单地放入新的数据框,但使用之前绘图中的所有相同几何规范。当然,只有当列名全部匹配,并且你没有在其他层使用任何 other 数据框时,它才会起作用。
    • +1 感谢您的及时回复。这是重用对象的绝佳方式!
    • @joran 如何让网格中的每个图占据相等的空间,以便它们的 x 刻度对齐?
    【解决方案2】:

    嗯,@joran 打败了我(我的 gridExtra 已经过时了,但我花了 10 分钟才意识到这一点)。这是一个类似的解决方案,但这个解决方案通常按Server 中的级别为猫剥皮。

    library(gridExtra)
    out <- by(data = x, INDICES = x$Server, FUN = function(m) {
          m <- droplevels(m)
          m <- ggplot(m, aes(Date, PercentUsed, group=1, colour = FileSystem)) + 
             geom_jitter(size=2) + geom_smooth(method="loess", se=T)
       })
    do.call(grid.arrange, out)
    
    # If you want to supply the parameters to grid.arrange
    do.call(grid.arrange, c(out, ncol=3))
    

    【讨论】:

    • 非常好。我没有意识到droplevels() 有一个data.frames 的方法。这很方便!
    • 有没有一种简洁的方法来强制对齐,即保持绘图区域宽度相同?规定图例宽度?
    • @mlt 考虑将图例移动到第一个图的顶部并将其从其余部分中删除。
    • 确实,我同时将所有图例移到了顶部。我不能使用单个图例,因为它们每个情节都是独一无二的。虽然很高兴知道是否有规定宽度的方法。
    • @mlt 考虑提出一个新问题,尽管 AFAIK,但这是不可能的(尽管可以定义边距)。
    【解决方案3】:

    我们可以不使用构面,而是为每个组创建一个绘图列表,然后使用 cowplot::plot_grid 进行绘图。每个人都有自己的传奇:

    # make list of plots
    ggList <- lapply(split(x, x$Server), function(i) {
      ggplot(i, aes(Date, PercentUsed, group = 1, colour = FileSystem)) + 
        geom_jitter(size = 2) +
        geom_smooth(method = "loess", se = TRUE)})
    
    # plot as grid in 1 columns
    cowplot::plot_grid(plotlist = ggList, ncol = 1,
                       align = 'v', labels = levels(x$Server))
    

    按照@Axeman 的建议,我们可以使用facet_grid(~Server) 添加标签,而不是labels = levels(x$Server)。

    【讨论】:

    • 太棒了。如果您希望显示灰色刻面条,您仍然可以添加+ facet_grid(~Server)。在plot_grid 中使用align = 'v' 会得到更好看的结果。
    • @Axeman 关于“v”的好点,谢谢,更新了。我想避免使用 facet,所以用 label 代替。
    【解决方案4】:

    我喜欢@joran 的回答,并以他们的代码为起点提供了几个选项。 这两个选项都解决了未对齐方面的问题。

    方面之外的图例

    如果您为图例项选择等宽字体,您可以使用str_pad 在所有图例项的右侧添加填充,强制每个项的长度保持一致。

    如果您愿意使用等宽字体,这是一种快速解决方法。

    library(ggplot2)
    library(dplyr)
    library(gridExtra)
    library(stringr)
    
    l <- max(nchar(as.character(x$FileSystem)))
    mylevels <- as.character(levels(x$FileSystem))
    mylevels <- str_pad(mylevels, width = l, side = "right", pad = " ")
    x <- mutate(x, FileSystem = factor(str_pad(FileSystem, width = l, side = "right", pad = " "),
                levels = mylevels))
    windowsFonts("Lucida Sans Typewriter" = windowsFont("Lucida Sans Typewriter"))
    xs <- split(x,f = x$Server)
    p1 <- ggplot(xs$A,aes(x = Date,y = PercentUsed,group = 1,colour = FileSystem)) + 
      geom_jitter(size=0.5) + 
      geom_smooth(method="loess", se=T) + 
      facet_wrap(~Server, ncol=1) +
      theme(legend.text = element_text(family = "Lucida Sans Typewriter"))
    
    p2 <- p1 %+% xs$B
    p3 <- p1 %+% xs$C
    
    grid.arrange(p1,p2,p3)
    

    方面内的图例

    如果您不介意每个 facet 中的图例,您可以使用 scale 调用中的“expand”参数为每个 facet 添加额外的空间:

    library(lubridate)
    x <- mutate(x, Date = as.Date(as.character(Date), format = "%m/%d/%Y"))
    xs <- split(x,f = x$Server)
    p1 <- ggplot(xs$A,aes(x = Date,y = PercentUsed,group = 1,colour = FileSystem)) + 
      geom_jitter(size=0.5) + 
      scale_x_date(expand = expansion(add = c(5, 20)),
                   date_labels = "%d-%m-%Y") +
      geom_smooth(method="loess", se=T) + 
      facet_wrap(~Server, ncol=1) +
      theme_bw() +
      theme(legend.position = c(0.9, 0.5))
    
    p2 <- p1 %+% xs$B
    p3 <- p1 %+% xs$C
    
    grid.arrange(p1,p2,p3)
    

    【讨论】:

      【解决方案5】:

      现在游戏中除了gridExtra 和cowplot 之外,还有patchwork。因此,您可以执行以下操作:

      require(ggplot2)
      require(patchwork)
      # split
      dfs = split(df, f = df$Server)
      # apply ggplot function and write to list
      gg_l = lapply(dfs, function(x) {
        ggplot(x, aes(x = Date,y = PercentUsed, group = 1, colour = FileSystem)) + 
          geom_jitter(size = 0.5) + 
          geom_smooth(method = "loess", se = TRUE) + 
          facet_wrap(~ Server, ncol = 1)
      })
      # patchwork
      wrap_plots(gg_l, ncol = 1)
      

      您也可以手动组合图,看看here。我将 OP 的数据用于df。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-10-25
        • 1970-01-01
        • 2018-03-14
        • 1970-01-01
        • 1970-01-01
        • 2015-10-24
        相关资源
        最近更新 更多