创建具有成对点和正确方向的分割小提琴图

Posted

技术标签:

【中文标题】创建具有成对点和正确方向的分割小提琴图【英文标题】:Create a split violin plot with paired points and proper orientation 【发布时间】:2022-01-20 15:07:20 【问题描述】:

使用ggplot2,我可以创建一个带有重叠点的小提琴图,并且可以使用geom_line()连接成对的点。

library(datasets)
library(ggplot2)
library(dplyr)

iris_edit <- iris %>% group_by(Species) %>%
  mutate(paired = seq(1:length(Species))) %>%
  filter(Species %in% c("setosa","versicolor"))

ggplot(data = iris_edit,
       mapping = aes(x = Species, y = Sepal.Length, fill = Species)) +
  geom_violin() +
  geom_line(mapping = aes(group = paired),
            position = position_dodge(0.1),
            alpha = 0.3) +
  geom_point(mapping = aes(fill = Species, group = paired),
             size = 1.5, shape = 21,
             position = position_dodge(0.1)) +
  theme_classic() +
  theme(legend.position = "none",
        axis.text.x = element_text(size = 15),
        axis.title.y = element_text(size = 15),
        axis.title.x = element_blank(),
        axis.text.y = element_text(size = 10))

see 包包括 geom_violindot() 函数,用于在其组成点旁边绘制一个减半的小提琴图。我发现这个功能在绘制大量点时很有帮助,这样小提琴就不会被遮挡。

library(see)

ggplot(data = iris_edit,
       mapping = aes(x = Species, y = Sepal.Length, fill = Species)) +
  geom_violindot(dots_size = 0.8,
                 position_dots = position_dodge(0.1)) +
  theme_classic() +
  theme(legend.position = "none",
        axis.text.x = element_text(size = 15),
        axis.title.y = element_text(size = 15),
        axis.title.x = element_blank(),
        axis.text.y = element_text(size = 10))

现在,我想将geom_line() 添加到geom_violindot() 以连接成对点,如第一张图片所示。理想情况下,我希望点在里面,小提琴在外面,这样线条就不会与小提琴相交。 geom_violindot() 包含 flip 参数,它采用一个数字向量来指定要翻转的几何图形。

ggplot(data = iris_edit,
       mapping = aes(x = Species, y = Sepal.Length, fill = Species)) +
  geom_violindot(dots_size = 0.8,
                 position_dots = position_dodge(0.1),
                 flip = c(1)) +
  geom_line(mapping = aes(group = paired),
            alpha = 0.3,
            position = position_dodge(0.1)) +
  theme_classic() +
  theme(legend.position = "none",
        axis.text.x = element_text(size = 15),
        axis.title.y = element_text(size = 15),
        axis.title.x = element_blank(),
        axis.text.y = element_text(size = 10))

如您所见,调用flip 会反转小提琴的一半,但不会反转对应的点。 see documentation 似乎没有解决这个问题。

问题

    如何创建带有成对点的geom_violindot() 图,从而使连接它们的点和线“夹在”小提琴两半之间?我怀疑有一个使用David Robinson's GeomFlatViolin function 的解决方案,虽然我还没有弄清楚。 在最后一个图中,请注意线条相对于它们连接的点是倾斜的。应该为position_dotsposition 参数提供什么位置调整函数以使点和线正确对齐?

【问题讨论】:

虽然这不是您想听到的答案,但这可能是值得考虑的事情。不要追求这种可视化的想法。它令人困惑,令人费解,而且故事没有得到很好的体现。您尝试将成对的观察结果和数据的估计分布结合起来。还有其他选择。在您的示例中:在散点图中显示配对数据(每个物种在其自己的连续轴上),对于估计的分布显示例如 iso 等高线(例如 stat_density_2d) @tjebo 感谢您的评论,我可以理解可能有更好的方法来表示此类数据。如果您想写一个答案来解释您的方法作为框架挑战,我可能会在没有其他答案的情况下接受它 @acvill:可视化的目标是什么? @tjebo 我有数百个特定类型的短基因组特征。我有两种治疗的这些特征的转录组学数据。我想显示治疗之间每个特征的 RPKM 的相对变化。我还想表明,这种特征类型的治疗之间的平均 RPKM 通常会发生变化。我知道这个案例的经典可视化是火山图,但我想显示 RPKM 而不是倍数变化/p 值。 【参考方案1】:

不确定是否将 geom_violindot 与 see 包一起使用。但是您可以将 geom_half_violon 和 geom_half_dotplot 与 gghalves 包结合使用,并对数据进行子集化以指定方向:

library(gghalves)

 ggplot(data = iris_edit[iris_edit$Species == "setosa",],
           mapping = aes(x = Species, y = Sepal.Length, fill = Species)) +
   geom_half_violin(side = "l") +
    geom_half_dotplot(stackdir = "up") +
    geom_half_violin(data = iris_edit[iris_edit$Species == "versicolor",],
                     aes(x = Species, y = Sepal.Length, fill = Species), side = "r")+
    geom_half_dotplot(data = iris_edit[iris_edit$Species == "versicolor",],
                      aes(x = Species, y = Sepal.Length, fill = Species),stackdir = "down") +
    geom_line(data = iris_edit, mapping = aes(group = paired),
              alpha = 0.3)

请注意,配对中的线不会正确对齐,因为点图将每个观察值合并然后延长点线 - 配对线仅对应于 aes 中定义的 x 值,而不是点所在的位置在行中。

【讨论】:

这解决了我的主要问题,谢谢。我希望“延长点线”的过程也可以应用于连接线,但似乎并不那么容易。【参考方案2】:

根据评论 - 这不是您问题的直接答案,但我相信您在使用“斜率图”光学元件时可能无法获得最令人信服的可视化效果。这会很快变得令人费解(很多点/线重叠)并且消息会丢失。

要显示成对观察之间的变化(治疗 1 与治疗 2),您还可以(我认为:更好)使用散点图。您可以显示每个观察结果,并且更改会立即变得清晰。为了更直观,您可以添加一条等号线。

我认为您不需要显示估计的分布(左图),但如果您想显示这一点,您可以使用 geom_density2d(右图)的二维密度估计

library(tidyverse)
## patchwork only for demo purpose
library(patchwork)

iris_edit <- iris %>% group_by(Species) %>%
  ## use seq_along instead
  mutate(paired = seq_along(Species)) %>%
  filter(Species %in% c("setosa","versicolor")) %>%
## some more modificiations
  select(paired, Species, Sepal.Length) %>%
  pivot_wider(names_from = Species, values_from = Sepal.Length)

lims <- c(0, 10)

p1 <- 
  ggplot(data = iris_edit, aes(setosa, versicolor)) +
  geom_abline(intercept = 0, slope = 1, lty = 2) +
  geom_point(alpha = .7, stroke = 0, size = 2) +
  cowplot::theme_minimal_grid() +
  coord_equal(xlim = lims, ylim = lims) +
  labs(x = "Treatment 1", y = "Treatment 2")

p2 <- 
  ggplot(data = iris_edit, aes(setosa, versicolor)) +
  geom_abline(intercept = 0, slope = 1, lty = 2) +
  geom_density2d(color = "Grey") +
  geom_point(alpha = .7, stroke = 0, size = 2) +
  cowplot::theme_minimal_grid() +
  coord_equal(xlim = lims, ylim = lims) +
  labs(x = "Treatment 1", y = "Treatment 2")

p1+ p2

由reprex package (v2.0.1) 于 2021 年 12 月 18 日创建

【讨论】:

感谢您的选择——在二维中映射单个点肯定比在一个维度中映射两个链接点更干净。感谢seq_along() 的提示!

以上是关于创建具有成对点和正确方向的分割小提琴图的主要内容,如果未能解决你的问题,请参考以下文章

用ggplot2分割小提琴图

在启动应用程序时无法检测设备的方向以创建具有正确大小的 UIWebView

2021-04-25

2021-04-25

关于最小割建模正确性证明

优先级队列未正确比较 C++