ggplot2 热图,瓦片高度和宽度为 aes()

ggplot2 heatmap with tile height and width as aes()

我正在尝试为 OD 矩阵创建热图,但我想按特定权重缩放行和列。由于这些权重在每个类别中都是恒定的,因此我希望该图能够保持行和列结构。

# Tidy OD matrix
df <- data.frame (origin  = c(rep("A", 3), rep("B", 3),rep("C", 3)),
                  destination = rep(c("A","B","C"),3),
                  value = c(0, 1, 10, 5, 0, 11, 15, 6, 0))

# Weights
wdf <- data.frame(region = c("A","B","C"),
                  w = c(1,2,3))

# Add weights to the data.
plot_df <- df %>% 
  merge(wdf %>% rename(w_origin = w), by.x = 'origin', by.y = 'region') %>% 
  merge(wdf %>% rename(w_destination = w), by.x = 'destination', by.y = 'region')
  

数据如下:

> plot_df
  destination origin value w_origin w_destination
1           A      A     0        1             1
2           A      C    15        3             1
3           A      B     5        2             1
4           B      A     1        1             2
5           B      B     0        2             2
6           B      C     6        3             2
7           C      B    11        2             3
8           C      A    10        1             3
9           C      C     0        3             3

但是,当在 aes() 中将权重作为 widthheight 传递时,我得到这个:

ggplot(plot_df, 
       aes(x = destination, 
           y = origin)) +
  geom_tile(
    aes(
      width = w_destination,
      height = w_origin,
      fill = value),
    color = 'black')

它似乎适用于列的大小(宽度),但不完全是因为比例不正确。而且行到处都是,没有对齐。

我只使用 geom_tile 因为我可以通过 heightwidth 作为美学,但我接受其他建议。

所以我想我可以为您提供部分解决方案。在玩了 geom_tile 之后,当您使用高度和宽度时,数据框的顺序似乎很重要。

这是我根据您的代码想出的一些示例代码(运行 首先是您的代码)。我将您的 data_frame 转换为 tibble(dplyr 的一部分),以便更容易按列排序。

# Converted your dataframe to a tibble dataframe
plot_df_tibble = tibble(plot_df)

# Sorted your dataframe by your w_origin column:
plot_df_tibble2 = plot_df_tibble[order(plot_df_tibble$w_origin),]

# Plotted the sorted data frame:
ggplot(plot_df_tibble2, 
       aes(x = destination, 
           y = origin)) +
  geom_tile(
    aes(
      width = w_destination,
      height = w_origin,
      fill = value),
    color = 'black')

得到这个情节: Link to image I made

我应该注意,如果你在排序之前 运行 转换后的小标题,你会得到与你发布的相同的情节。

geom_tile 这部分的高度和宽度争论似乎没有完全展开,因为我觉得 df 的顺序应该无关紧要。 干杯

问题是您的图块重叠了。原因是虽然您可以将宽度和高度作为美学传递,但 geom_tile 不会为您调整图块的 x 和 y 位置。当您在 x 和 y 上映射离散变量时,您的图块位于等距网格上。在您的情况下,图块位于 .5、1.5 和 2.5。然后在这些位置上以指定的宽度和高度绘制图块。

这可以通过为您的情节添加一些透明度来轻松看到:

library(ggplot2)
library(dplyr)

ggplot(plot_df, 
       aes(x = destination, 
           y = origin)) +
  geom_tile(
    aes(
      width = w_destination,
      height = w_origin,
      fill = value), color = "black", alpha = .2)

为了达到您想要的结果,您必须根据所需的宽度和高度手动计算 x 和 y 位置,以防止框重叠。为此,您可以切换到连续比例并通过 scale_x/y_ continuous:

设置所需的中断和标签
breaks <- wdf %>% 
  mutate(cumw = cumsum(w),
         pos = .5 * (cumw + lag(cumw, default = 0))) %>% 
  select(region, pos)

plot_df <- plot_df %>% 
  left_join(breaks, by = c("origin" = "region")) %>% 
  rename(y = pos) %>% 
  left_join(breaks, by = c("destination" = "region")) %>% 
  rename(x = pos)

ggplot(plot_df, 
       aes(x = x, 
           y = y)) +
  geom_tile(
    aes(
      width = w_destination,
      height = w_origin,
      fill = value), color = "black") +
  scale_x_continuous(breaks = breaks$pos, labels = breaks$region, expand = c(0, 0.1)) +
  scale_y_continuous(breaks = breaks$pos, labels = breaks$region, expand = c(0, 0.1))