是否有R函数可为三维聚类绘制椭球(或其他包围图形)?
给三维聚类添加半透明包围椭球(基于plot_ly与iris数据集)
要给plot_ly生成的三维聚类图添加半透明椭球,核心思路是先计算每个聚类的统计特征(均值、协方差矩阵),再基于这些特征生成椭球的网格点,最后将椭球作为曲面层叠加到散点图上。以下是完整实现代码:
步骤1:加载依赖包
library(plotly) library(dplyr)
步骤2:定义3D椭球生成函数
这个函数通过单位球变换生成对应聚类分布的椭球:
generate_ellipsoid <- function(mean_vec, cov_mat, n_points = 100, scale = 1) { # 生成单位球的球面点 theta <- seq(0, 2*pi, length.out = n_points) phi <- seq(0, pi, length.out = n_points) x <- cos(theta) * sin(phi) y <- sin(theta) * sin(phi) z <- cos(phi) sphere <- cbind(x, y, z) # 用协方差矩阵的Cholesky分解将单位球映射为目标椭球 chol_mat <- chol(cov_mat) ellipsoid <- t(chol_mat %*% t(sphere)) * scale + rep(mean_vec, each = n_points^2) # 整理为plot_ly兼容的数据框格式 as.data.frame(ellipsoid) %>% rename(x = V1, y = V2, z = V3) }
步骤3:计算聚类统计量并生成椭球数据
按Species分组计算每个聚类的均值和协方差,再生成对应椭球的坐标点:
# 分组计算每个物种的均值与协方差矩阵 cluster_stats <- iris %>% group_by(Species) %>% summarise( mean_sw = mean(Sepal.Width), mean_sl = mean(Sepal.Length), mean_pl = mean(Petal.Length), cov_mat = list(cbind(Sepal.Width, Sepal.Length, Petal.Length) %>% cov()), .groups = "drop" ) # 生成所有物种的椭球数据 ellipsoid_data <- lapply(1:nrow(cluster_stats), function(i) { mean_vec <- c(cluster_stats$mean_sw[i], cluster_stats$mean_sl[i], cluster_stats$mean_pl[i]) generate_ellipsoid(mean_vec, cluster_stats$cov_mat[[i]], scale = 1.5) %>% mutate(Species = cluster_stats$Species[i]) }) %>% bind_rows()
步骤4:绘制带椭球的三维聚类图
先绘制基础散点图,再逐个添加对应物种的半透明椭球:
# 绘制基础散点图 p <- plot_ly(iris, x=~Sepal.Width, y=~Sepal.Length, z=~Petal.Length, color = ~Species, type = "scatter3d", mode = "markers", marker = list(size = 4)) # 为每个物种添加半透明椭球 for (sp in unique(ellipsoid_data$Species)) { sp_ellipsoid <- filter(ellipsoid_data, Species == sp) # 匹配对应物种的颜色,设置半透明 sp_color <- unique(iris$Species)[which(unique(iris$Species) == sp)] p <- add_surface(p, x=~x, y=~y, z=~z, data = sp_ellipsoid, opacity = 0.2, showlegend = FALSE, colorscale = list(c(0, 1), c(sp_color, sp_color))) } # 展示图形 p
关键参数说明
scale:控制椭球的大小,设置为1.5时基本能覆盖聚类中大部分数据点,可根据需求调整opacity:设置椭球的透明度,0.2既能突出聚类范围,又不会遮挡散点showlegend = FALSE:避免椭球在图例中重复显示,保持图例简洁
如果需要其他包围方式(比如凸包),可以用convhulln函数(来自geometry包)生成凸包点,再用add_mesh添加到图中,但椭球更能直观体现聚类的正态分布特征。
内容的提问来源于stack exchange,提问作者panuffel
相关产品推荐
相关产品推荐

