使用facet_grid在ggplot2中进行成对值(热图)可视化

5

我有包含10个样本的数值对数据:

data = dget(url("https://git.io/vCTpG"))

数据看起来像这样:
sampleB  sampleA  ol   labelA  labelB  facetA  facetB
2409     2409     100  2409|B  2409|B  B       B
2409     2413     0    2413|A  2409|B  A       B
2409     2414     0    2414|A  2409|B  A       B
2409     2417     0    2417|C  2409|B  C       B
2409     2411     0    2411|A  2409|B  A       B
2409     2418     0    2418|B  2409|B  B       B
2409     2416     0    2416|C  2409|B  C       B
2409     2412     4    2412|B  2409|B  B       B
2409     2415     0    2415|C  2409|B  C       B
2409     2410     19   2410|A  2409|B  A       B
...      ...      ...  ...     ...     ...     ...

我想将ol的值可视化为热力图:
library(ggplot2)
ggplot(data = data, mapping = aes(x=labelA, y=labelB)) + 
  geom_tile(mapping = aes(fill=ol)) +
  scale_fill_gradient(low = "white", high = "black") + 
  theme(legend.position = "none") +
  theme(axis.text.x = element_text(angle = 90, hjust = 1))

不分面的图形

现在,我想将这个10x10的热力图按照每个样本所关联的类别(在此示例中为A,BC)进行结构化。但是,如果我使用facet_grid...

last_plot() + facet_grid(facetA~facetB)

plot with facet

...这将导致一个30x30的热图,而不是一个被分成3个类别的10x10的热图(仍然只显示100个值)。我记得使用以下方法进行了修复:

last_plot() + facet_grid(facetA~facetB, scales = "free", space = "free")

然而,过去我无法再次重现这个结果。希望得到的解决方案应该像这样(这是通过图像编辑器制作的,不是 ggplot 生成的):

enter image description here

即一个重新排序、分组为10x10矩阵的图像。


1
你能详细说明你期望看到什么吗?现在看起来相当正确:你的完整图片是所有切面图片之和。例如,在A面与C面的 2409|B 上,你期望看到什么?自然地,它是空白的。 - tonytonov
@tonytonov 我添加了一张手动创建的图片,以更好地解释所需的结果。 - barbaz
1
有趣的是,改变分面顺序可以让你接近 last_plot() + facet_grid(facetB~facetA, scales = "free") - user20650
@user20650 哇,这正是我想要的...但是...为什么? - barbaz
1
我怀疑这是ggplot中的一个小错误(或不一致性),可能是最近引入的。 - tonytonov
显示剩余4条评论
1个回答

2
你需要使用 facet_wrap() 代替 facet_grid(),或按照评论中的建议改变 facet_grid() 中的分面顺序。
原因在于,根据定义,facet_grid 不允许在同一行的面板中 y 轴限制不同。换句话说,在顶部行中的所有三个面板必须具有相同的 y 轴限制,在第二行中的所有三个面板必须具有相同的 y 轴限制,以此类推。添加 scales = "free_y" 表示第一行可以具有与第二行不同的 y 轴限制(但在给定行内,所有面板始终必须具有相同的 y 轴限制)。在你的例子中,当你使用
facet_grid(facetA ~ facetB, scales = "free")

你正在强制ggplot在所有行中使用所有y值;例如,顶部行的左侧面板必须包含值2418 | B,因为该值存在于顶部行的中间面板中。在使用scales = "free_x"时,对分面顺序进行反转恰好完成了此任务,因为你的数据结构如此。
如果你想要每个面板都有不同的独立x和y比例尺,而不管相邻的面板,你需要使用facet_wrap
编辑:如何获得所需的图形的更详细说明。回到你的具体示例,反转您的分面将给出
p <- ggplot(data = data, mapping = aes(x=labelA, y=labelB)) + 
    geom_tile(mapping = aes(fill=ol)) +
    scale_fill_gradient(low = "white", high = "black") + 
    theme(legend.position = "none") +
    theme(axis.text.x = element_text(angle = 90, hjust = 1)) + 
    facet_grid(facetB ~ facetA, scales = "free")
p

这里包含了您需要的所有面板。要按照您所要求的顺序排列,只需重新排列行即可。可以通过设置facetB级别的顺序(编辑:或者如评论中@user20650所建议的那样,在facet_grid()中设置as.table=FALSE)来实现:

输入图像描述

data1 <- data    
data1$facetB <- factor(data1$facetB, levels = c("C", "B", "A"))
p %+% data1

enter image description here


这不是我想要的,我想要的是在我的问题末尾所示的图形。正如用户20650已经指出的那样,只需在公式中交换两个facet变量即可解决问题。我已经提交了一个错误报告。 - barbaz
@barbaz 我试图解释这不是一个错误,而是按照预期工作的原因,以及为什么在使用这种顺序的分面时你得到了不同的x和y轴(这就是你在评论中讨论的内容,对这种行为的解释)。一旦你反转分面的顺序,获得你展示的图形就是重新排列行的问题 - 我更新了答案并提供了更多细节。 - konvas
1
嗨Konvas,我认为你可以使用as.table参数来获取面板的顺序... facet_grid(facetB ~ facetA, scales = "free", as.table=FALSE) - user20650

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接