如何使用ggplot2和facet_wrap但不删除x轴上组内的因子?

M. *_*eil 2 r ggplot2 facet-wrap

我想使用facet_wrap 在x 轴上为不同的组绘制不同的值。但是,使用 时scale = "free_x",它会显示每个组内的唯一值。请参阅下面的示例:

library(ggplot2)
set.seed(1234)
nb = rep(LETTERS[1:3],4)
expand.grid(LETTERS[1:3], 1:3)
df = data.frame(ps = paste(rep(c("ps1","gc1"),6)),
                cr = rep(LETTERS[1:3],4),
                id = rep(x = month.abb[1:4], each = 3));df
df = df[order(df$ps),]
df[df$ps == "ps1","cr"] <- sample(LETTERS[4:6], size = 6, replace = TRUE)
df.all = rbind(df,df,df,df,df,df)
df.all$val = rnorm(n = nrow(df.all))

ggplot(df.all, 
       aes(x = cr,
           y = val)) + 
  geom_violin() +
  facet_wrap(vars(ps, id), 
             scales = "free_x",
             ncol = 4) +
  geom_point(position = position_jitter(width = 0.1, height = 0.1), 
             alpha= .3)
Run Code Online (Sandbox Code Playgroud)

在此处的图像中(这是上面代码的输出),我添加了缺少的级别。基本上,有一个组“gc1”,我希望其中的级别不要下降。但我也不希望“ps1”中的级别出现在“gc1”中。所以最后 gc1 应该只显示级别 A、B、C,而 ps1 应该只显示 D、E 和 F。有没有办法做到这一点?

在此输入图像描述

ste*_*fan 5

ggh4x您可以通过使用该软件包来实现您想要的结果,该软件包ggh4x::facetted_pos_scales允许单独设置每个方面的比例,例如,对于您的情况,您可以这样做:

library(ggplot2)
library(ggh4x)

ggplot(
  df.all,
  aes(
    x = cr,
    y = val
  )
) +
  geom_violin() +
  geom_point(
    position = position_jitter(width = 0.1, height = 0.1),
    alpha = .3
  ) +
  facet_wrap(vars(ps, id),
    scales = "free_x",
    ncol = 4
  ) +
  facetted_pos_scales(
    x = list(
      ps == "gc1" ~ scale_x_discrete(limits = c("A", "B", "C")),
      ps == "ps1" ~ scale_x_discrete(limits = c("D", "E", "F"))
    )
  )
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

编辑这是一种根据数据动态创建比例的方法,该方法循环遍历ps组并用于reformulate创建formulas facetted_pos_scales

library(ggplot2)
library(ggh4x)

scale_x <- lapply(unique(df.all$ps), \(x) {
  reformulate(
    paste0("scale_x_discrete(limits=sort(unique(df.all$cr[df.all$ps =='", x, "'])))"),
    paste0("ps == '", x, "'")
  )  
})

ggplot(
  df.all,
  aes(
    x = cr,
    y = val
  )
) +
  geom_violin() +
  geom_point(
    position = position_jitter(width = 0.1, height = 0.1),
    alpha = .3
  ) +
  facet_wrap(vars(ps, id),
    scales = "free_x",
    ncol = 4
  ) +
  facetted_pos_scales(
    x = scale_x
  )
Run Code Online (Sandbox Code Playgroud)