You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为geom_hex绘制的单细胞UMAP六边形分配特定颜色?

单细胞UMAP六边形分箱按簇比例混色的问题解决

问题根源拆解

  1. 颜色对应错误:geom_hex默认会对输入数据做分箱统计(统计每个箱内的细胞数),此时直接传递原细胞级的颜色向量,会被ggplot按分箱后的统计逻辑重新映射,而非直接对应每个六边形。
  2. 六边形大小异常:如果在geom_hex中绑定原细胞的cell或簇字段作为分组/映射变量,会强制ggplot为每个细胞单独生成六边形,导致每个六边形尺寸极小,完全偏离预期的分箱效果。

正确实现步骤与代码

核心思路:先对UMAP坐标做六边形分箱,统计每个箱内各细胞簇的数量比例,计算出混合色后,再基于分箱后的汇总数据绘制统一大小的六边形。

1. 依赖包加载

library(ggplot2)
library(hexbin)
library(dplyr)
library(tidyr)

2. 数据准备(示例)

假设你的单细胞数据框sc_data包含UMAP_1、UMAP_2(UMAP坐标)和cluster(细胞簇标签),先定义各簇的对应颜色:

# 自定义簇颜色(替换为你的实际颜色映射)
cluster_colors <- c(
  "Cluster0" = "#E41A1C", "Cluster1" = "#377EB8", 
  "Cluster2" = "#4DAF4A", "Cluster3" = "#984EA3"
)

3. 分箱统计与混合色计算

# 第一步:生成六边形分箱,获取每个箱的坐标与基础计数
xbins <- 30  # 分箱数量,可根据数据密度调整
hb <- hexbin(sc_data$UMAP_1, sc_data$UMAP_2, xbins = xbins)
hex_df <- data.frame(hcell2xy(hb), hex_id = seq_len(nrow(hcell2xy(hb))), count = hb@count)

# 第二步:统计每个六边形内各簇的细胞数量
cluster_hex_counts <- sc_data %>%
  # 为每个细胞分配所属的六边形ID
  mutate(hex_id = hexbin(UMAP_1, UMAP_2, xbins = xbins, IDs = TRUE)) %>%
  group_by(hex_id, cluster) %>%
  summarise(n = n(), .groups = "drop") %>%
  # 转换为宽格式,方便后续计算
  pivot_wider(names_from = cluster, values_from = n, values_fill = 0)

# 第三步:计算每个六边形的混合颜色
hex_df <- hex_df %>%
  left_join(cluster_hex_counts, by = "hex_id") %>%
  rowwise() %>%
  mutate(
    # 提取当前箱内所有簇的细胞数
    cluster_ns = c_across(all_of(names(cluster_colors))),
    total_cells = sum(cluster_ns),
    # 计算加权混合RGB颜色
    fill_color = if (total_cells == 0) {
      "#F0F0F0"  # 无细胞的箱设为浅灰色
    } else {
      # 提取各簇颜色的RGB值
      cluster_rgb_list <- lapply(names(cluster_ns), function(c) col2rgb(cluster_colors[c]))
      # 按细胞数加权求和
      mixed_rgb <- Reduce("+", mapply(function(rgb, n) rgb * n, cluster_rgb_list, cluster_ns, SIMPLIFY = FALSE)) / total_cells
      # 转换为十六进制颜色
      rgb(mixed_rgb[1], mixed_rgb[2], mixed_rgb[3], maxColorValue = 255)
    }
  ) %>%
  ungroup()

4. 绘制正确的六边形图

使用geom_hex配合stat = "identity",直接基于分箱后的汇总数据绘制,避免触发默认的分箱统计逻辑:

ggplot() +
  geom_hex(
    data = hex_df,
    aes(x = x, y = y, fill = fill_color),
    stat = "identity",
    # 设置六边形宽度,与分箱数量匹配
    binwidth = c(diff(range(sc_data$UMAP_1))/xbins, diff(range(sc_data$UMAP_2))/xbins)
  ) +
  scale_fill_identity() +
  theme_bw() +
  labs(x = "UMAP_1", y = "UMAP_2", title = "Hex-binned UMAP with cluster proportion colors")

或者使用hexbin包的hexPolygons函数绘制更精准的六边形:

hex_polys <- hexPolygons(hb, hex_df$fill_color)
ggplot() +
  geom_polygon(data = hex_polys, aes(x = x, y = y, group = id, fill = fill)) +
  scale_fill_identity() +
  theme_bw() +
  labs(x = "UMAP_1", y = "UMAP_2")

关键注意事项

  • 绝对不要在geom_hex中引入原细胞级的字段(如cell、cluster)作为映射变量,否则会破坏分箱逻辑,导致大小异常。
  • 混合色的计算必须基于分箱后的簇数量比例,而非原细胞的颜色,才能保证每个六边形的颜色准确反映箱内细胞组成。
  • xbins参数控制分箱密度,可根据你的UMAP图的细胞密度调整,数值越大分箱越细。

内容的提问来源于stack exchange,提问作者YumTum

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 06:25:28