ggplot geom_tile(或热图)中的分割填充:第三个值的两种颜色

2024-02-27

我有分类数据,我想映射使用热图(geom_tile)的频率,就像下面的示例一样:

data("mtcars")
freq <- data.frame(xtabs(~cyl + gear, mtcars)) #count number of 4,6,8 cyl cars by gear
ggplot(freq, aes(cyl, gear)) +
  geom_tile(aes(fill = Freq)) + 
  scale_fill_gradient(low = "white",high = "steelblue")

但我想根据显着或不显着结果(0-1 值)的比例分割每个图块。在此示例中,我将生成相同的频率计数,但区分自动传输和手动传输(am)

freq_am <- data.frame(xtabs(~cyl + gear + am, mtcars))
print(freq_am)
   #cyl gear am Freq
      4    3  0    1
      6    3  0    2
      8    3  0   12
      4    4  0    2
      6    4  0    2
      8    4  0    0
      4    5  0    0
      6    5  0    0
      8    5  0    0
      4    3  1    0
      6    3  1    0
      8    3  1    0
      4    4  1    6
      6    4  1    2
      8    4  1    0
      4    5  1    2
      6    5  1    1
      8    5  1    2

生成的热图将具有(例如)blue对于值am==0 and red for am==1。每个图块将根据该类型自动汽车的比例(沿对角线?)进行划分(am==0)或手动(am==1)。蓝色和红色的色调将与计数成比例,就像渐变已经反映一样。

例如:

  • 左上方的图块 (4,5) 将完全呈浅红色,因为所有 4 缸、5 档汽车(数量 = 2)都是手动的

  • 中间左侧的图块 (4,4) 将是 1/4 蓝色和 3/4 红色,因为 25% 的 4 档 4 缸汽车是自动的(计数 = 2),75% 是手动的(计数 = 6)

  • 左下方的图块 (4,3) 将完全是最浅的蓝色,因为所有 4 缸、3 档汽车(计数 = 1)都是自动的


这是通过操纵频率计数使频率计数变为负数来回答该问题的第二次且希望是完整的尝试am==1。区别在于第一次尝试 https://stackoverflow.com/a/41794581/3817004就是它geom_col(position = "fill")被用来代替geom_tile()用于绘图。

注:我没有编辑过第一个答案 https://stackoverflow.com/a/41794581/3817004因为OP已经对此发表了评论,我最终可能会删除第一个不完整的答案。

准备数据

freq_am <-data.frame(xtabs(~cyl + gear + am, mtcars))
freq_am$Freq_am <- freq_am$Freq * (-1)^as.integer(as.character(freq_am$am))

这会创建一个新列Freq_am where Freq计数乘以-1 if am == 1(手动的)。使用逻辑值求幂是一个需要避免的技巧ifelse.

Plotting

有两种可能性可以实现所需的热图式外观。

变体1

p <- ggplot(freq_am, (aes(x = cyl, y = Freq, fill = Freq_am))) + 
  geom_col(position = "fill", width = 1) + 
  scale_fill_gradient2() +
  facet_grid(gear ~ ., as.table = FALSE, switch = "y") + 
  scale_y_continuous(expand = c(0, 0)) + 
  scale_x_discrete(expand = c(0, 0))
p

这将创建一个堆积条形图Freq vs cyl using geom_col()其中条形垂直拉伸(position = "fill")和水平(width = 1) 来填充绘图区域。除此之外expand = c(0, 0)参数到scale函数告诉ggplot to not像往常一样展开轴。请注意,x 轴是离散的xtabs()已经胁迫cyl因素。

facet_grid()用于模拟 y 轴grid按递增顺序排列的值(as.table = FALSE). switch = "y"将面板条移至左侧。

scale_fill_gradient2()默认情况下使用方便的发散配色方案,自动变速箱的汽车数量显示为蓝色,手动变速箱的汽车数量显示为红色。

现在,我们需要删除热图不需要的所有装饰和空间。最后,y轴标签被重命名:

p + theme(panel.grid = element_blank()
          , axis.ticks = element_blank()
          , axis.text.y = element_blank()
          , strip.background = element_blank()
          , panel.spacing.y = unit(0, "pt")
) + 
  ylab("gear")

这种方法的缺点是图块之间缺乏边界。因此,如果相邻的图块具有与例如 6 缸、3 齿轮和 4 齿轮图块相同的颜色,则很难区分计数的份额。

变体2

此变体在图块之间添加了边框。边框的宽度可以灵活调整:

p <- ggplot(freq_am, (aes(x = 1, y = Freq, fill = Freq_am))) + 
  geom_col(position = "fill") + 
  scale_fill_gradient2() +
  facet_grid(gear ~ cyl, as.table = FALSE, switch = "both") +
  scale_y_continuous(expand = c(0, 0)) + 
  scale_x_continuous(expand = c(0, 0))
p

在这里,我们使用facet_grid()对于两个方向。对于每个面板,Freq绘制与虚拟变量的关系图1 using geom_col()如上。作为虚拟变量1是数字,我们不需要width参数为geom_col()。现在两个轴都是连续的。

同样,我们需要删除一些装饰并重命名 x 轴和 y 轴上的标签:

p + theme(panel.grid = element_blank()
        , axis.ticks = element_blank()
        , axis.text = element_blank()
        , strip.background = element_blank()
        # , panel.spacing = unit(0, "pt")
  ) + 
  xlab("cyl") + ylab("gear")

现在,我们确实有了一个带有图块之间边框的热图。为了删除边框或调整宽度,您可以使用以下命令取消注释该行panel.spacing并更改值。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ggplot geom_tile(或热图)中的分割填充:第三个值的两种颜色 的相关文章

随机推荐