geom_mark_hull绘制NMDS图出现无数据空白区域的问题求助
NMDS双图包络线包含空白区域的问题分析与解决建议
问题背景
我正在绘制鱼类群落数据的NMDS双图,使用ggforce::geom_mark_hull为两类采样点绘制包络线,并按年份和季节(雨季、旱季)分面展示。但发现部分分面中,包络线会包含无数据的空白区域(例如2018年雨季、2020年旱季的上游组),调整expand参数后问题仍未解决。
使用的原始数据为物种数据fish.spp和环境/分组数据fish.env,代码如下:
library(vegan) library(ggplot2) library(ggforce) library(concaveman) fish.nmds.k3 <- metaMDS(fish.spp, distance = "bray", k = 3) fish.nmds.k3.sites <- as.data.frame(fish.nmds.k3$points) fish.nmds.k3.sp <- as.data.frame(fish.nmds.k3$species) (ggplot(fish.nmds.k3.sites, aes(MDS1, MDS2))+ ylim(-3, 3) + xlim (-3, 3) + geom_mark_hull(aes(fill = fish.env$Site), expand = unit(3, "mm")) + geom_point() + labs(title = "NMDS Plot of Freshwater Fish Community") + theme_bw() + theme(plot.title = element_text(hjust = 0.5, face = "bold", size = 10), panel.grid = element_blank()) + facet_grid(rows = vars(fish.env$Year), cols = vars(fish.env$Season)) )
问题原因
- 跨分面计算包络线:
geom_mark_hull默认基于全局同组(Site)数据生成包络线,而非当前分面内的该组数据。比如2018年雨季上游组的包络线,实际包含了其他年份/雨季上游组的点,导致在当前分面出现空白区域。 - 数据关联错误:代码中直接引用外部数据框的列(如
fish.env$Site),未将NMDS位点数据与分组数据合并,ggplot无法正确关联每个点的分面和分组信息,加剧了跨分面计算的问题。 expand参数无效:该参数仅调整包络线的扩展幅度,无法解决数据源错误导致的范围偏差。
解决方法
1. 合并数据框
先将NMDS位点得分与分组信息合并,确保每个点的分组、分面变量一一对应:
# 合并NMDS位点数据和环境分组数据 nmds_data <- cbind(fish.nmds.k3.sites, fish.env)
2. 强制按分面+分组计算包络线
修改geom_mark_hull的group参数,指定按年份、季节、采样点的组合分组,确保每个分面内的包络线仅用当前分面的该组数据:
ggplot(nmds_data, aes(MDS1, MDS2)) + ylim(-3, 3) + xlim(-3, 3) + # 指定group为分面+分组的组合,避免跨分面计算 geom_mark_hull(aes(fill = Site, group = interaction(Year, Season, Site)), expand = unit(3, "mm"), alpha = 0.3) + geom_point() + labs(title = "淡水鱼类群落NMDS图") + theme_bw() + theme(plot.title = element_text(hjust = 0.5, face = "bold", size = 10), panel.grid = element_blank()) + facet_grid(rows = vars(Year), cols = vars(Season))
3. 手动计算凹包(更稳定的方案)
如果上述方法仍有问题,可使用dplyr+concaveman手动计算每个分面+分组的凹包,再用geom_polygon绘制:
library(dplyr) # 按分面+分组计算凹包,仅保留点数≥3的组(足够生成凹包) hull_data <- nmds_data %>% group_by(Year, Season, Site) %>% filter(n() >= 3) %>% do(concaveman(select(., MDS1, MDS2))) %>% rename(MDS1 = x, MDS2 = y) %>% ungroup() # 绘制图形 ggplot(nmds_data, aes(MDS1, MDS2)) + ylim(-3, 3) + xlim(-3, 3) + geom_polygon(data = hull_data, aes(fill = Site, group = interaction(Year, Season, Site)), alpha = 0.3) + geom_point(aes(color = Site)) + labs(title = "淡水鱼类群落NMDS图") + theme_bw() + theme(plot.title = element_text(hjust = 0.5, face = "bold", size = 10), panel.grid = element_blank()) + facet_grid(rows = vars(Year), cols = vars(Season))
内容的提问来源于stack exchange,提问作者Reason
相关产品推荐
相关产品推荐

