根据因子级别重新格式化标签/保留 ggplot2::facet_wrap() 中多因子方面的顺序

Reformat label / preserve order of Multi-factor facets in ggplot2::facet_wrap() based on factor level

我希望基于两个因素对图形进行分面,使用两个分面因素值的组合重命名分面,但保留基于原始因素中水平的分面顺序。

数据看起来像这样:

library(tidyverse)

set.seed(100)

tmp.d <- data.frame(
  sector = factor(rep(c("B","A"),c(6,3)), levels = c("B","A")),
  subsector = factor(rep(c("a","b","c"), each = 3), levels = c("c","b","a")),
  year = factor(rep(2020:2022,3)),
  value = sample(8:15,9, replace = TRUE)
)

#> tmp.d
#  sector subsector year value
#1      B         a 2020     9
#2      B         a 2021    14
#3      B         a 2022    13
#4      B         b 2020    15
#5      B         b 2021    10
#6      B         b 2022     8
#7      A         c 2020     9
#8      A         c 2021    13
#9      A         c 2022    11

按部门和子部门绘制和分面...

ggplot(tmp.d, aes(x = year, y = value, group = 1)) +
  geom_path()+
  facet_wrap(facets = list("sector","subsector"))

...看起来像这样:

请注意,构面保持由“部门”和“子部门”的因素级别设置的顺序。这是可取的。

但是,我希望分面标签显示为“[sector]: [subsector]”,而不是在单独的行中列出扇区和子扇区,如“B: b”。

尝试 1:

向 tmp.d 添加辅助列,其中包含构面标签。

tmp.d <- tmp.d %>% mutate(label = factor(paste0(sector, ": ", subsector)))

ggplot(tmp.d, aes(x = year, y = value, group = 1)) +
  geom_path()+
  facet_wrap(facets = list("label"))

产生:

此处,方面标签是正确的,但我丢失了 sector/subsector 因子级别的顺序。

尝试 2:

我认为答案可能在于自定义 as_labeller 函数,或者甚至可能更改现有标签器的设置,例如 label_value,它有一个 multi_line = [bool] 属性来控制分面值是否出现在单行或多行上。 label_ 系列的其他版本有另一个属性 sep = ,我相信它控制着值在同一行中的分隔方式。据推测,...multi_line = FALSE, sep = ": "... 的组合可能会格式化标签并保留所需的顺序。

在对 facet_wrap() 的调用中应用了标签器。

ggplot(tmp.d, aes(x = year, y = value, group = 1)) +
  geom_path()+
  facet_wrap(facets = list("sector","subsector"), labeller = [the labeller function])

在不更改默认设置(见下文)的情况下将贴标器设置为现有贴标器功能会产生与我上面最初尝试相同的输出。

...
facet_wrap(facets = list("sector","subsector"), labeller = label_value)
...

正在尝试像这样更改 label_value 的属性值...

...
facet_wrap(facets = list("sector","subsector"), labeller = label_value(multi_line = FALSE))
...

... 不起作用,因为 label_value 函数需要一个我不知道如何提供的 label 值。将构面因子作为名称或字符串(作为列表或向量)传递似乎不起作用。我在文档或其他地方找到的示例使用 facet_grid 而不是 facet_wrap,并且 labels 是作为像 ~sector+subsector 这样的公式提供的,我认为它被视为 grid/matrix 其中扇区是列,子扇区是行。在我的例子中,sector/subsector 的大多数(但不一定是全部)组合将是唯一的(即,部门 A 和 B 不共享子部门)。

问题总结

有没有一种简单的方法可以实现我的目标(为方便起见重述):

谢谢,

更新:同时yake84已经答完了: 要自动化只需在使用 arrange:

后添加 fct_inorder..
tmp.d %>% 
  arrange(sector, subsector) %>% 
  mutate(my_label = paste(sector,subsector, sep=":") %>% 
           fct_inorder(ordered = TRUE)) %>% 
  ggplot(aes(x = year, y = value, group = 1)) +
  geom_path()+
  facet_wrap( ~ my_label)

第一个回答: 只需将尝试 1 中的标签转换为因子并定义级别:

library(tidyverse)

tmp.d %>% 
  mutate(my_label = paste(sector,subsector, sep=":")) %>% 
  mutate(my_label = factor(my_label, levels = c("B:b", "B:a", "A:c"))) %>% 
  ggplot(aes(x = year, y = value, group = 1)) +
  geom_path()+
  facet_wrap( ~ my_label)

哇,这比我预期的要复杂得多...一种解决方案是将它们组合到不同的字段中:

tmp.d |> 
  arrange(sector, subsector) |>          # arrange by factor levels
  mutate(
    facet = 
      paste0(sector, ": ", subsector) |>    
      fct_inorder(ordered = TRUE)        # use that order for the new field
  ) |> 
  ggplot(aes(x = year, y = value, group = 1)) +
  geom_path()+
  facet_wrap(facets = ~facet)            # here

如果可以接受“,”,这也有效:

ggplot(tmp.d, aes(x = year, y = value, group = 1)) +
  geom_path()+
  facet_wrap(
    facets = sector~subsector, 
    labeller = 
      labeller(                  # here
        sector = label_value,    #
        subsector = label_value, #
        .multi_line = FALSE      #
      )
  )

类似的事情可以用 purrr::partial() 来代替默认值,但你又得到一个逗号。我认为值得在他们的 github 页面上创建一个问题以向 label_*() 函数

添加一个 sep 参数
... +
  facet_wrap(
    facets = sector~subsector, 
    labeller = purrr::partial(label_value, multi_line = FALSE)
  )