【问题标题】:How to change facet labels?如何更改构面标签?
【发布时间】:2011-03-29 05:30:06
【问题描述】:

我使用了以下ggplot 命令:

ggplot(survey, aes(x = age)) + stat_bin(aes(n = nrow(h3), y = ..count.. / n), binwidth = 10)
  + scale_y_continuous(formatter = "percent", breaks = c(0, 0.1, 0.2))
  + facet_grid(hospital ~ .)
  + theme(panel.background = theme_blank())

生产

我想将 facet 标签更改为更短的标签(例如 Hosp 1、Hosp 2...),因为它们现在太长而且看起来很拥挤(增加图形的高度不是一个选项,它会在文档中占用太多空间)。我查看了facet_grid 帮助页面,但不知道怎么做。

【问题讨论】:

标签: r ggplot2 symbols facet plotmath


【解决方案1】:

使用以下内容更改基础因子级别名称:

# Using the Iris data
> i <- iris
> levels(i$Species)
[1] "setosa"     "versicolor" "virginica" 
> levels(i$Species) <- c("S", "Ve", "Vi")
> ggplot(i, aes(Petal.Length)) + stat_bin() + facet_grid(Species ~ .)

【讨论】:

  • @wishihadabettername:为避免更改基础数据,您可以使用:ggplot(transform(iris, Species = c("S", "Ve", "Vi")[as.numeric(Species)]), aes(Petal.Length)) + stat_bin() + facet_grid(Species ~ .)
  • 相关...如果您希望面板标签为 bquote() 表达式(例如,levels(x$measurements) &lt;- c(bquote(Area ~~ (cm^2)), bquote(Length ~~ (cm)))),它将不会出现在数学表达式中。如何将表达式显示为方面标签?
  • 与在构面标签中包含表达式有关,使用labeller选项到facet_grid:stackoverflow.com/questions/37089052/…
【解决方案2】:

这是避免编辑数据的解决方案:

假设您的情节由数据框的 group 部分组成,该部分具有级别 control, test1, test2,然后创建一个由这些值命名的列表:

hospital_names <- list(
  'Hospital#1'="Some Hospital",
  'Hospital#2'="Another Hospital",
  'Hospital#3'="Hospital Number 3",
  'Hospital#4'="The Other Hospital"
)

然后创建一个 'labeller' 函数,并将其推送到您的 facet_grid 调用中:

hospital_labeller <- function(variable,value){
  return(hospital_names[value])
}

ggplot(survey,aes(x=age)) + stat_bin(aes(n=nrow(h3),y=..count../n), binwidth=10)
 + facet_grid(hospital ~ ., labeller=hospital_labeller)
 ...

这使用数据框的级别来索引医院名称列表,返回列表值(正确的名称)。


请注意,这仅在您只有一个刻面变量时才有效。如果您有两个方面,那么您的标注器函数需要为每个方面返回不同的名称向量。你可以这样做:

plot_labeller <- function(variable,value){
  if (variable=='facet1') {
    return(facet1_names[value])
  } else {
    return(facet2_names[value])
  }
}

其中facet1_names 和facet2_names 是由分面索引名称('Hostpital#1' 等)索引的名称的预定义列表。


编辑:如果您传递了一个贴标机不知道的变量/值组合,上述方法将失败。您可以为未知变量添加故障保护,如下所示:

plot_labeller <- function(variable,value){
  if (variable=='facet1') {
    return(facet1_names[value])
  } else if (variable=='facet2') {
    return(facet2_names[value])
  } else {
    return(as.character(value))
  }
}

答案改编自how to change strip.text labels in ggplot with facet and margin=TRUE


编辑:警告:如果您使用此方法按 character 列进行分面,您可能会得到不正确的标签。请参阅this bug report。 在 ggplot2 的最新版本中已修复。

【讨论】:

  • 不错,但不适用于 facet_wrap,而@Vince 解决方案也适用于 facet_wrap。
  • @ArnaudAmzallag:正确,不过如果有人想捐赠一些时间,it could in the future。
  • 为未知的刻面变量添加了故障保护。
  • 注意:这在 ggplot2 v.2 中不起作用 - labeller 功能已更改。 @mbirons 回答有效stackoverflow.com/a/34811062/162832
  • 有趣,但这并不总是有效,而编辑因子总是有效。
【解决方案3】:

请注意,如果 ggplot 显示的因子少于您的变量实际包含的因子(例如,如果您进行了子集化,则可能发生这种情况),此解决方案将无法正常工作:

 library(ggplot2)
 labeli <- function(variable, value){
  names_li <- list("versicolor"="versi", "virginica"="virg")
  return(names_li[value])
 }

 dat <- subset(iris,Species!="setosa")
 ggplot(dat, aes(Petal.Length)) + stat_bin() + facet_grid(Species ~ ., labeller=labeli)

一个简单的解决方案(除了在 names_li 中添加所有未使用的因子,这可能很乏味)是在原始数据集或 labbeler 函数中使用 droplevels() 删除未使用的因子,请参阅:

labeli2 <- function(variable, value){
  value <- droplevels(value)
  names_li <- list("versicolor"="versi", "virginica"="virg")
  return(names_li[value])
}

dat <- subset(iris,Species!="setosa")
ggplot(dat, aes(Petal.Length)) + stat_bin() + facet_grid(Species ~ ., labeller=labeli2)

【讨论】:

    【解决方案4】:

    只是扩展 naught101 的答案——归功于他

    plot_labeller <- function(variable,value, facetVar1='<name-of-1st-facetting-var>', var1NamesMapping=<pass-list-of-name-mappings-here>, facetVar2='', var2NamesMapping=list() )
    {
      #print (variable)
      #print (value)
      if (variable==facetVar1) 
        {
          value <- as.character(value)
          return(var1NamesMapping[value])
        } 
      else if (variable==facetVar2) 
        {
          value <- as.character(value)
          return(var2NamesMapping[value])
        } 
      else 
        {
          return(as.character(value))
        }
    }
    

    你要做的是创建一个名称到名称映射的列表

    clusteringDistance_names <- list(
      '100'="100",
      '200'="200",
      '300'="300",
      '400'="400",
      '600'="500"
    )
    

    并使用新的默认参数重新定义plot_labeller():

    plot_labeller <- function(variable,value, facetVar1='clusteringDistance', var1NamesMapping=clusteringDistance_names, facetVar2='', var1NamesMapping=list() )
    

    然后:

    ggplot() + 
      facet_grid(clusteringDistance ~ . , labeller=plot_labeller) 
    

    或者,您可以为每个想要更改的标签创建一个专用函数。

    【讨论】:

      【解决方案5】:

      这是另一个解决方案,其精神与@naught101 给出的方案相同,但更简单,并且不会对最新版本的 ggplot2 发出警告。

      基本上,您首先创建一个命名字符向量

      hospital_names <- c(
                          `Hospital#1` = "Some Hospital",
                          `Hospital#2` = "Another Hospital",
                          `Hospital#3` = "Hospital Number 3",
                          `Hospital#4` = "The Other Hospital"
                          )
      

      然后你把它用作贴标机,只需将@naught101给出的代码的最后一行修改为

      ... + facet_grid(hospital ~ ., labeller = as_labeller(hospital_names))
      

      希望这会有所帮助。

      【讨论】:

      • ggplot2 的哪个版本是as_labeller?我在CRAN GitHub repository 上找到了一些源代码,但是升级到最新版本后(在 CRAN 上!)我似乎没有该功能。
      • 这很酷。但是,当您的构面网格中有两个变量时会发生什么?像hospital ~ gender 之类的?有没有办法在两个轴上使用贴标机?我在文档中看不到任何明显的内容。
      • 请注意,如果您从 naught 的答案开始,则此答案仅适用于 c() 而不是 list()。
      • 其中一个重要的部分是它适用于分面网格的两个轴!
      • @naught101 的问题的答案将是 domi 的答案:stackoverflow.com/a/37778906/8124725 如果没有这个添加,这对我不起作用,为我没有包含的变量产生 NA。
      【解决方案6】:

      如果您有两个方面 hospital 和 room 但只想重命名一个,您可以使用:

      facet_grid( hospital ~ room, labeller = labeller(hospital = as_labeller(hospital_names)))
      

      要使用基于向量的方法重命名两个方面(如 naught101 的答案),您可以这样做:

      facet_grid( hospital ~ room, labeller = labeller(hospital = as_labeller(hospital_names),
                                                       room = as_labeller(room_names)))
      

      【讨论】:

      • 这为我提供了所有标签的 NA :(
      【解决方案7】:

      我还有另一种方法可以在不更改基础数据的情况下实现相同的目标:

      ggplot(transform(survey, survey = factor(survey,
              labels = c("Hosp 1", "Hosp 2", "Hosp 3", "Hosp 4"))), aes(x = age)) +
        stat_bin(aes(n = nrow(h3),y=..count../n), binwidth = 10) +
        scale_y_continuous(formatter = "percent", breaks = c(0, 0.1, 0.2)) +
        facet_grid(hospital ~ .) +
        opts(panel.background = theme_blank())
      

      我上面所做的是更改原始数据框中因子的标签,这是与原始代码相比的唯一区别。

      【讨论】:

        【解决方案8】:

        这是我使用 ggplot2 版本 2.2.1 处理 facet_grid(yfacet~xfacet) 的方法:

        facet_grid(
            yfacet~xfacet,
            labeller = labeller(
                yfacet = c(`0` = "an y label", `1` = "another y label"),
                xfacet = c(`10` = "an x label", `20` = "another x label")
            )
        )
        

        请注意,这不包含对 as_labeller() 的调用——我曾为此苦苦挣扎了一段时间。

        这种方法的灵感来自帮助页面Coerce to labeller function 上的最后一个示例。

        【讨论】:

        • 这行得通!!!我无法应用其他解决方案,因为一些建议的解决方案在当前 ggplot2 版本中已被弃用。
        • 你可以用setNames()stackoverflow.com/a/22428439/3362993构造这些命名向量
        【解决方案9】:

        facet_wrap 和 facet_grid 都接受来自 ifelse 的输入作为参数。所以如果用于分面的变量是合乎逻辑的,那么解决方法就很简单了:

        facet_wrap(~ifelse(variable, "Label if true", "Label if false"))
        

        如果变量的类别较多,ifelse语句需要为nested。

        作为副作用,这还允许在 ggplot 调用中分面创建组。

        【讨论】:

          【解决方案10】:

          我认为所有其他解决方案都非常有助于做到这一点,但还有另一种方法。

          我假设:

          • 您已经安装了dplyr 包,它有方便的mutate 命令,并且
          • 您的数据集名为 survey。

            调查 %>% 变异(Hosp1 = Hospital1, Hosp2 = Hospital2,........)

          此命令可帮助您重命名列,但保留所有其他列。

          然后做同样的facet_wrap,你现在很好。

          【讨论】:

          • 对不起,它不起作用,因为它还会更改列内容
          • 这是不正确的,因为:1.不同的Hosp1,Hosp2...变量不存在。原始问题使用一个名为“hospital”的单列,其中包含字符串 2。即使您有不同的列,您的命令也会查找名为 Hospital1、Hospital2 等的对象,并且会抛出错误,因为它们不存在. 3. 正如@Jens 所说,如果您改用字符串,即“Hospital1”,它将用该值填充整个列。您可能正在寻找结合case_when() 的mutate()?不知道为什么这被赞成,因为它肯定行不通。
          【解决方案11】:

          您是否尝试过更改 Hospital 向量的特定级别?

          levels(survey$hospital)[levels(survey$hospital) == "Hospital #1"] <- "Hosp 1"
          levels(survey$hospital)[levels(survey$hospital) == "Hospital #2"] <- "Hosp 2"
          levels(survey$hospital)[levels(survey$hospital) == "Hospital #3"] <- "Hosp 3"
          

          【讨论】:

            【解决方案12】:

            以variable, value 作为参数的标签函数定义对我不起作用。另外,如果你想使用表达式,你需要使用 lapply 并且不能简单地使用arr[val],因为函数的参数是一个data.frame。

            这段代码确实有效:

            libary(latex2exp)
            library(ggplot2)
            arr <- list('virginica'=TeX("x_1"), "versicolor"=TeX("x_2"), "setosa"=TeX("x_3"))
            mylabel <- function(val) { return(lapply(val, function(x) arr[x])) }
            ggplot(iris, aes(x=Sepal.Length, y=Sepal.Width)) + geom_line() + facet_wrap(~Species, labeller=mylabel)
            

            【讨论】:

              【解决方案13】:

              由于我还不允许对帖子发表评论,因此我将其单独发布为 Vince's answer 和 son520804's answer 的附录。归功于他们。

              儿子520804:

              使用虹膜数据:

              我假设:
              你已经安装了 dplyr 包,它有方便的 mutate 命令,并且 您的数据集名为调查。 survey %&gt;% mutate(Hosp1 = Hospital1, Hosp2 = Hospital2,........) 此命令可帮助您重命名列,但保留所有其他列。 然后做同样的 facet_wrap,你现在很好。

              使用 Vince 的 iris 示例和 son520804 的部分代码,我使用 mutate 函数进行了此操作,并在不触及原始数据集的情况下实现了简单的解决方案。 诀窍是创建一个替代名称向量并在管道内使用 mutate() 临时更正构面名称:

              i <- iris
              
              levels(i$Species)
              [1] "setosa"     "versicolor" "virginica"
              
              new_names <- c(
                rep("Bristle-pointed iris", 50), 
                rep("Poison flag iris",50), 
                rep("Virginia iris", 50))
              
              i %>% mutate(Species=new_names) %>% 
              ggplot(aes(Petal.Length))+
                  stat_bin()+
                  facet_grid(Species ~ .)
              

              在此示例中,您可以看到 i$Species 的级别临时更改为包含在 new_names 向量中的相应常用名称。包含

              的行
              mutate(Species=new_names) %>%
              

              可以轻松移除以显示原始命名。

              注意事项:如果没有正确设置 new_name 向量,这很容易在名称中引入错误。使用单独的函数来替换变量字符串可能会更干净。请记住,可能需要以不同的方式重复 new_name 向量以匹配原始数据集的顺序。请仔细检查这是否正确实现。

              【讨论】:

              • 使用起来可能会更好一些:new_names &lt;- c('setosa' = 'Bristle-pointed iris', 'versicolor' = 'Poison flag iris', 'virginica' = 'Virginia iris') 然后在 mutate 中你可以创建一个新列:mutate(Spec = new_names[Species])
              【解决方案14】:

              此解决方案与@domi 的解决方案非常接近,但旨在通过获取前 4 个字母和最后一个数字来缩短名称。

              library(ggplot2)
              
              # simulate some data
              xy <- data.frame(hospital = rep(paste("Hospital #", 1:3, sep = ""), each = 30),
                               value = rnorm(90))
              
              shortener <- function(string) {
                abb <- substr(string, start = 1, stop = 4) # fetch only first 4 strings
                num <- gsub("^.*(\\d{1})$", "\\1", string) # using regular expression, fetch last number
                out <- paste(abb, num) # put everything together
                out
              }
              
              ggplot(xy, aes(x = value)) +
                theme_bw() +
                geom_histogram() +
                facet_grid(hospital ~ ., labeller = labeller(hospital = shortener))
              

              【讨论】:

                【解决方案15】:

                这对我有用。

                定义一个因素:

                hospitals.factor<- factor( c("H0","H1","H2") )
                

                并使用,ggplot():

                facet_grid( hospitals.factor[hospital] ~ . )
                

                【讨论】:

                  【解决方案16】:

                  在不修改基础数据的情况下进行更改的最简单方法是:

                  1. 使用as_labeller() 创建一个对象。如果列名以数字开头或包含空格或特殊字符,请不要忘记使用反引号:
                  # Necessary to put RH% into the facet labels
                  hum_names <- as_labeller(
                       c(`50` = "RH% 50", `60` = "RH% 60",`70` = "RH% 70", 
                         `80` = "RH% 80",`90` = "RH% 90", `100` = "RH% 100"))
                  
                  1. 添加到 ggplot:
                      ggplot(dataframe, aes(x = Temperature.C, y = fit)) + 
                          geom_line() + 
                          facet_wrap(~Humidity.RH., nrow = 2, labeller = hum_names)
                  

                  【讨论】:

                  • 我认为这是最优雅的方法——它有效并且适用于 ggplot2 版本 3.0.0.9000
                  • 但是当有两个方面时它不起作用,例如,type~Humidity
                  • @DenisCousineau 在这种情况下使用 labeller = labeller(Type = c(...), Humidity = c(...)) 其中 ... 是键值对
                  • 我还要注意,如果您只是在所有内容前面加上 RH%,一个更可靠的解决方案是用 hum_names &lt;- as_labeller(function(x) paste('RH%', x)) 替换此答案中的第 1 步
                  【解决方案17】:

                  添加另一个类似于@domi 的解决方案,解析数学符号、上标、下标、括号/括号等。

                  library(tidyverse)
                  theme_set(theme_bw(base_size = 18))
                  
                  ### create separate name vectors
                  # run `demo(plotmath)` for more examples of mathematical annotation in R
                  am_names <- c(
                    `0` = "delta^{15}*N-NO[3]^-{}",
                    `1` = "sqrt(x,y)"
                  )
                  
                  # use `scriptstyle` to reduce the size of the parentheses &
                  # `bgroup` to make adding `)` possible 
                  cyl_names <- c(
                    `4` = 'scriptstyle(bgroup("", a, ")"))~T~-~5*"%"',
                    `6` = 'scriptstyle(bgroup("", b, ")"))~T~+~10~degree*C',
                    `8` = 'scriptstyle(bgroup("", c, ")"))~T~+~30*"%"'
                  )
                  
                  ggplot(mtcars, aes(wt, mpg)) + 
                    geom_jitter() +
                    facet_grid(am ~ cyl,
                               labeller = labeller(am  = as_labeller(am_names,  label_parsed),
                                                   cyl = as_labeller(cyl_names, label_parsed))
                               ) +
                    geom_text(x = 4, y = 25, size = 4, nudge_y = 1,
                              parse = TRUE, check_overlap = TRUE,
                              label = as.character(expression(paste("Log"["10"], bgroup("(", frac("x", "y"), ")")))))
                  

                  ### OR create new variables then assign labels directly
                  # reverse facet orders just for fun
                  mtcars <- mtcars %>% 
                    mutate(am2  = factor(am,  labels = am_names),
                           cyl2 = factor(cyl, labels = rev(cyl_names), levels = rev(attr(cyl_names, "names")))
                    )
                  
                  ggplot(mtcars, aes(wt, mpg)) + 
                    geom_jitter() +
                    facet_grid(am2 ~ cyl2,
                               labeller = label_parsed) +
                    annotate("text", x = 4, y = 30, size = 5,
                             parse = TRUE, 
                             label = as.character(expression(paste("speed [", m * s^{-1}, "]"))))
                  

                  由reprex package (v0.2.1.9000) 于 2019 年 3 月 30 日创建

                  【讨论】:

                  【解决方案18】:

                  我觉得我应该为此添加答案,因为我花了很长时间才完成这项工作:

                  如果满足以下条件,此答案适合您:

                  • 您确实不想要编辑您的原始数据
                  • 如果您需要标签中的表达式 (bquote) 和
                  • 如果您想要单独的标签名称向量的灵活性

                  我基本上将标签放在命名向量中,这样标签就不会混淆或切换。 labeller 表达式可能更简单,但这至少有效(非常欢迎改进)。注意 `(反引号)以保护方面因素。

                  n <- 10
                  x <- seq(0, 300, length.out = n)
                  
                  # I have my data in a "long" format
                  my_data <- data.frame(
                    Type = as.factor(c(rep('dl/l', n), rep('alpha', n))),
                    T = c(x, x),
                    Value = c(x*0.1, sqrt(x))
                  )
                  
                  # the label names as a named vector
                  type_names <- c(
                    `nonsense` = "this is just here because it looks good",
                    `dl/l` = Linear~Expansion~~Delta*L/L[Ref]~"="~"[%]", # bquote expression
                    `alpha` = Linear~Expansion~Coefficient~~alpha~"="~"[1/K]"
                    )
                  
                  
                  ggplot() + 
                    geom_point(data = my_data, mapping = aes(T, Value)) + 
                    facet_wrap(. ~ Type, scales="free_y", 
                               labeller = label_bquote(.(as.expression(
                                 eval(parse(text = paste0('type_names', '$`', Type, '`')))
                                 )))) +
                    labs(x="Temperature [K]", y="", colour = "") +
                    theme(legend.position = 'none')
                  

                  【讨论】:

                    【解决方案19】:

                    经过一段时间的努力,我发现我们可以结合使用forcats中的fct_relevel()和fct_recode()来更改构面的顺序以及修复构面标签。我不确定它是否受设计支持,但它有效!看看下面的图:

                    library(tidyverse)
                    
                    before <- mpg %>%
                      ggplot(aes(displ, hwy)) + 
                      geom_point() +
                      facet_wrap(~class)
                    before
                    

                    after <- mpg %>%
                      ggplot(aes(displ, hwy)) + 
                      geom_point() + 
                      facet_wrap(
                        vars(
                          # Change factor level name
                          fct_recode(class, "motorbike" = "2seater") %>% 
                            # Change factor level order
                            fct_relevel("compact")
                        )
                      )
                    after
                    

                    由reprex package (v0.3.0) 于 2020-02-16 创建

                    【讨论】:

                      【解决方案20】:

                      简单的解决方案(来自here):

                      p <- ggplot(mtcars, aes(disp, drat)) + geom_point()
                      # Example (old labels)
                      p + facet_wrap(~am)
                      
                      
                      to_string <- as_labeller(c(`0` = "Zero", `1` = "One"))
                      # Example (New labels)
                      p + facet_wrap(~am, labeller = to_string)
                      

                      【讨论】:

                        【解决方案21】:

                        来自mishabalyasin 的一个班轮 :

                        facet_grid(.~vs, labeller = purrr::partial(label_both, sep = " #"))

                        查看实际情况

                        library(reprex)
                        library(tidyverse)
                        
                        mtcars %>% 
                          ggplot(aes(x="", y=gear,fill=factor(gear), group=am)) +
                          geom_bar(stat="identity", width=1) +
                          coord_polar("y", start=0) +
                          facet_grid(.~vs, labeller = purrr::partial(label_both, sep = " #"))
                        

                        由reprex package (v2.0.0) 于 2021-07-09 创建

                        【讨论】:

                          猜你喜欢
                          • 2015-01-17
                          • 2021-09-29
                          • 2021-09-15
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          相关资源
                          最近更新 更多