如何让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() )
代码说明
get_leaves_branches_col(dend):从树状图中直接提取每个叶节点(即每个观测)对应的颜色,这一步保证了颜色与树状图的分支颜色完全一致。left_join(label_color_map, by = "label"):将NMDS结果中的观测标签与颜色映射表匹配,确保每个观测都能获取到树状图中对应的颜色。scale_colour_identity():散点图中直接使用映射到的颜色值,跳过默认的因子-颜色映射逻辑,彻底避免分组编号带来的颜色错位。
内容的提问来源于stack exchange,提问作者Michael S Taylor
相关产品推荐
相关产品推荐

