所有小提琴的相同区域独立于ggplot2中的方面

Posted

技术标签:

【中文标题】所有小提琴的相同区域独立于ggplot2中的方面【英文标题】:same area for all violins independent of facets in ggplot2 【发布时间】:2021-08-01 22:17:02 【问题描述】:

我想为所有小提琴具有相同面积的三个不同因素创建一个图。但是使用facet_grid(. ~ C) 似乎会迫使每个方面内的小提琴(即仅在因素 C 水平内的那些)具有相同的面积。我该如何克服这个问题?

library(ggplot2)

d <- data.frame(value = c(906, 1013, 1109, 876, 747, 759, 876, 1358, 739, 
                          1086, 807, 954, 1586, 762, 1353, 1221, 976, 1002, 
                          1129, 943, 1270, 1126, 853, 950, 677, 696, 681, 
                          615, 736, 595, 590, 618, 524, 1014, 515, 645, 860, 
                          874, 934, 728, 1078, 659, 1024, 786, 821, 541,
                          681, 744),
                A = gl(2, 12, 48),
                B = gl(2, 6, 48),
                C = gl(2, 24))

ggplot(d, aes(x = A, y = value, fill = B)) +
  geom_violin(trim = FALSE, scale = "area") +
  facet_grid(. ~ C)

【问题讨论】:

最简单的解决方案是使用x = C:A 并附加格式为scales_x_discrete 【参考方案1】:

首先,我们将创建一个具有预先计算的密度的新data.frame

library('tidyverse')

d2 <- d %>%
  group_by(A, B, C) %>%
  do(
    dens <- density(.$value)
    tibble(x = c(head(dens$x, 1), dens$x, tail(dens$x, 1)), #Add 0s at end to close lines
           y = c(0, dens$y, 0))
  ) %>% 
  ungroup() %>% 
  mutate(ymin = as.numeric(A:B) - .4*y/max(y), # Add offset for factor levels
         ymax = as.numeric(A:B) + .4*y/max(y))

现在我们将密度绘制为条带:

ggplot(d2)+
  aes(x = x,
      ymin = ymin,
      ymax = ymax,
      group = A:B,
      fill = B)+
  geom_ribbon()+

  # Enclosing lines
  geom_line(aes(y = ymin))+
  geom_line(aes(y = ymax))+

  facet_grid(. ~ C)+

  scale_y_continuous(breaks = c(1.5, 2.5),
                     minor_breaks = c(1.5, 3.5),
                     labels = levels(d2$A))+

  labs(x = 'value', y = 'A')+
  coord_flip()

【讨论】:

感谢这个聪明的解决方案。你能解释一下为什么左边的小提琴(对于 C == 2)保持不变,而只有右边的小提琴(对于 C == 1)与我的原始图相比改变了它们的面积? 是否可以用你的方法做类似trim = FALSE 的事情(即将小提琴的尾部修剪到数据的范围内)? @statmerkur,基本上是因为这个.4*y/max(y)。在 ggplot 中,每个方面都选择了 max(也应该是 .5 以进行精确匹配)。在我们的例子中,我们使用一般的max 进行缩放,这发生在第二个方面,所以只有第一个看起来不同。对于trim = TRUE,您应该将密度计算为density(.$value, from = min(.$value), to = max(.$value))do() 内。 您的建议可以解决问题并涵盖我问题的所有方面。但是,如果使用geom_violin()facet_grid(),就没有办法控制构面内的缩放吗?【参考方案2】:
Both of the below give the same plot as the faceted one:

ggplot(d, aes(x = paste(C,A), y = value, fill = B)) +
geom_violin(trim = FALSE, scale = "area") 

ggplot(d, aes(x =  C:A, y = value, fill = B)) +
geom_violin(trim = FALSE, scale = "area")

如果你能描述你的情节的目的,那就太好了。由于其他方法可能更好地满足您的目的,例如背靠背密度或 ggridges::geom_density_ridges2:

ggplot(d,
aes(x = value, y = paste(A,B), fill = B, height = ..density..))+
ggridges::geom_density_ridges2(scale = 1.2,alpha=0.2,stat = "density")+
facet_grid(. ~ C)+
ggridges::theme_ridges()+
coord_flip()

【讨论】:

有没有办法使用刻面同时得到相同面积的小提琴? (我必须使用小提琴情节) 根据上面的例子和 geom_violin scale 参数的文档:如果“area”(默认),所有小提琴都有相同的面积(在修剪尾巴之前)。如果“计数”,则区域将与观察次数成比例。如果“宽度”,所有小提琴的最大宽度都相同。当我们刻面或不刻面时,我看不出你的情节有什么区别。我建议您编辑标题,因为它与分面无关。 如果像我一样使用geom_violin(trim = FALSE, scale = "area")facet_grid(. ~ C) 会有所不同。只有每个方面/因素级别内的小提琴具有相同的面积,但我希望所有小提琴都具有相同的面积。 好的,据我所知,感谢您的澄清,并且根据文档缩放是在修剪之前完成的!你可能会考虑破解 geom_density 来做你想做的事。 ggplot(d, aes(x=value, fill=B)) + geom_density(aes(y=-..scaled..),trim=TRUE,alpha=0.5)+ geom_density(aes(y=+..scaled. .),trim=TRUE,alpha=0.5)+ facet_grid(.~C+A+B)+ 主题(axis.line=element_blank(),axis.text.x=element_blank(),,axis.ticks=element_blank( ),axis.title.x=element_blank(),axis.title.y=element_blank())+ coord_flip() 此方法将绘图分为 8 个方面。我想做一个像我的帖子中所示的情节(即 2 个方面),但所有小提琴都一样。

以上是关于所有小提琴的相同区域独立于ggplot2中的方面的主要内容,如果未能解决你的问题,请参考以下文章

【R】ggplot2绘图技巧

R语言ggplot2可视化:ggplot2可视化半小提琴图(Half Violin Plots)

R语言ggplot2可视化:ggplot2可视化水平半小提琴图(Horizontal Half Violin Plots)

R语言ggplot2可视化小提琴图分组小提琴图分离的小提琴图实战

ggplot2::coord_cartesian 在方面

用ggplot2分割小提琴图