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

如何让ggplot2中树状图与散点图使用一致的调色板?

解决树状图与NMDS散点图同组颜色匹配问题

问题描述

使用同一数据通过ggplot2绘制树状图与散点图:

  • 将hclust()对象经as.dendrogram()转换后,用dendextend包的set()函数设置分支和标签颜色;
  • 用vegan包的metaMDS()和scores()获取NMDS结果,以dendextend::cutree()生成的分组为散点图点上色;
  • 两组图使用同一调色板,但同组颜色不匹配(例如巴塞罗那在树状图中为调色板第四色,在散点图中因属于cutree分组2而使用第二色)。

需要确保两组图的同组颜色完全一致。

可复现代码(MWE)

library(RColorBrewer)
library(dendextend)
library(dplyr)
library(ggplot2)
library(vegan)

kay <- 5
mycolors <- brewer.pal(kay, "Dark2")

euro.hc <- hclust(eurodist)
euro.cut <- dendextend::cutree(euro.hc, k = kay)

euro.nmds <- metaMDS(eurodist, k = kay)

euro.df <- scores(euro.nmds, display = "sites", tidy = TRUE) %>%
  mutate(grp = as.factor(euro.cut))

dend <- as.dendrogram(euro.hc) %>%
  set("branches_k_color",
    value = mycolors,
    k = kay
  ) %>%
  set("labels_colors",
    value = mycolors,
    k = kay
  ) %>%
  set("branches_lwd", 1.0) %>%
  set("labels_cex", 1)


dend %>% ggplot(horiz = TRUE) +
  scale_x_continuous(expand = c(-1, -1)) +
  scale_y_reverse(expand = c(1, 1)) +
  theme(
    axis.title = element_blank(),
    axis.text = element_blank(),
    axis.ticks = element_blank()
  )

euro.df %>%
  ggplot() +
  geom_point(aes(x = NMDS1, y = NMDS2, color = grp)) +
  geom_text(aes(x = NMDS1, y = NMDS2, label = label, color = grp),
    vjust = -1,
    hjust = .50
  ) +
  scale_colour_manual(values = mycolors, guide = NULL) +
  coord_equal() +
  theme_minimal() +
  theme(
    line = element_blank(),
    axis.text = element_blank()
  )

问题根源

dendextend的branches_k_color和labels_colors是按树状图的分支聚类顺序分配调色板颜色,而cutree()返回的分组编号是按观测值的原始顺序生成的,两者的分组编号与颜色的映射逻辑完全不同,导致同组颜色不匹配。

解决方案

直接从树状图中提取每个观测对应的颜色,建立标签与颜色的映射关系,再将该映射应用到散点图中,确保两组图的颜色逻辑完全一致。

修正后的完整代码

library(RColorBrewer)
library(dendextend)
library(dplyr)
library(ggplot2)
library(vegan)

kay <- 5
mycolors <- brewer.pal(kay, "Dark2")

euro.hc <- hclust(eurodist)
euro.cut <- dendextend::cutree(euro.hc, k = kay)

euro.nmds <- metaMDS(eurodist, k = kay)

# 生成树状图并设置颜色
dend <- as.dendrogram(euro.hc) %>%
  set("branches_k_color",
    value = mycolors,
    k = kay
  ) %>%
  set("labels_colors",
    value = mycolors,
    k = kay
  ) %>%
  set("branches_lwd", 1.0) %>%
  set("labels_cex", 1)

# 关键步骤:提取每个叶节点(观测)对应的颜色,建立标签-颜色映射
label_color_map <- tibble(
  label = labels(dend),
  group_color = get_leaves_branches_col(dend)
)

# 处理NMDS数据,匹配对应颜色
euro.df <- scores(euro.nmds, display = "sites", tidy = TRUE) %>%
  left_join(label_color_map, by = "label")

# 绘制树状图(无需修改)
dend %>% ggplot(horiz = TRUE) +
  scale_x_continuous(expand = c(-1, -1)) +
  scale_y_reverse(expand = c(1, 1)) +
  theme(
    axis.title = element_blank(),
    axis.text = element_blank(),
    axis.ticks = element_blank()
  )

# 绘制散点图:直接使用树状图中对应的颜色
euro.df %>%
  ggplot() +
  geom_point(aes(x = NMDS1, y = NMDS2, color = group_color), size = 3) +
  geom_text(aes(x = NMDS1, y = NMDS2, label = label, color = group_color),
    vjust = -1,
    hjust = .50
  ) +
  scale_colour_identity(guide = NULL) + # 直接使用提取的颜色值
  coord_equal() +
  theme_minimal() +
  theme(
    line = element_blank(),
    axis.text = element_blank(),
    axis.title = element_blank()
  )

代码说明

  1. get_leaves_branches_col(dend):从树状图中直接提取每个叶节点(即每个观测)对应的颜色,这一步保证了颜色与树状图的分支颜色完全一致。
  2. left_join(label_color_map, by = "label"):将NMDS结果中的观测标签与颜色映射表匹配,确保每个观测都能获取到树状图中对应的颜色。
  3. scale_colour_identity():散点图中直接使用映射到的颜色值,跳过默认的因子-颜色映射逻辑,彻底避免分组编号带来的颜色错位。

内容的提问来源于stack exchange,提问作者Michael S Taylor

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 21:44:57