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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 06:00:59