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

R语言factoextra包绘制PCA双图时遇环境对象不可子集化错误

解决factoextra绘制PCA双图时的Error in range[1] : object of type 'environment' is not subsettable错误

问题背景

使用factoextra包绘制PCA双图时反复触发上述错误,数据框结构如下:

head(pcadata)
  log_response_ratio water_depth_m maxbottomtemp BOsalinity
1         -0.4514584            10      17.09915     35.066
2         -0.1408754            10      17.09915     35.066
3         -0.6519815            10      17.09915     35.066
4         -0.5682017            15      17.09915     35.066
5         -0.2082759            15      17.09915     35.066
6         -0.3052670            15      17.09915     35.066

复现代码

pcadata <- read.csv("pca.csv")
pcadata$water_depth_m <- as.numeric(pcadata$water_depth_m)
log_response_ratio <- complete.cases(pcadata$log_response_ratio)
pcadata <- pcadata[log_response_ratio, ]

# remove lnRR for the PCA
pcanolrr <- pcadata %>% dplyr::select(-log_response_ratio)

# create scaled df
pcadatafinal <- scale(pcanolrr, center = TRUE, scale = TRUE)

col_pca <- ncol(pcadatafinal)

pca_out <- PCA(pcadatafinal, scale.unit = FALSE, ncp = col_pca, graph = FALSE) # since already scaled, not need to do it again

# scree plot
fviz_screeplot(pca_out, addlabels = TRUE, ylim = c(0, 50))

# biplot
range(pcadata$log_response_ratio, na.rm=TRUE)
length(pcadata$log_response_ratio)

round(seq(-2, 2.25, length=1397), 4)

(var_breaks <- round(seq(-2, 2.25, length=1397), 4))

var_limits <- c(-2, 2.25)

fviz_pca_biplot(pca_out,
                geom.ind = "point",
                pointsize = 1.5,
                pointshape=21,
                col.ind = "#666666",
                stroke.ind = 1,
                fill.ind = pcadata$log_response_ratio,
                alpha.ind = 1,
                label ="var",
                labelsize = 2,
                col.var = "#666666",
                repel = TRUE,
                invisible="quali"
) +
  coord_fixed(ratio = 1) +
  labs(title="", x="Dim1", y="Dim2") +
  scale_x_continuous(breaks = scales::pretty_breaks(6), limits = xlim) +
  scale_y_continuous(breaks = scales::pretty_breaks(6), limits = ylim) +
  guides(fill = guide_colorbar(title.position = "top", title.hjust = 0.5)) +
  scale_fill_gradient2(low="#2166AC", mid="white", high="#B2182B", midpoint = median(pcadata$log_response_ratio)) +
  theme_bw() +
  theme(panel.grid.major = element_line(linewidth = 0.3, linetype = "dashed"),
        panel.grid.minor = element_blank(),
        axis.title = element_text(size = 10),
        axis.text = element_text(size = 10),
        axis.title.x = element_text(margin = margin(t=10)),
        axis.title.y = element_text(margin = margin(r=10)),
        legend.title = element_text(size=10),
        legend.text = element_text(size=10),
        legend.position = c(0.18, 0.1),
        legend.key.height = unit(2, units = "mm"),
        legend.key.width = unit(8, units = "mm"),
        legend.direction = "horizontal",
        aspect.ratio = 1
  )

错误信息

Error in range[1] : object of type 'environment' is not subsettable

回溯信息:

17.
oob(...)
16.
self$oob(x, limits)
15.
map(..., self = self)
14.
scales[[i]][[method]](data[[var]][scale_index[[i]]])
13.
FUN(X[[i]], ...)
12.
lapply(seq_along(scales), function(i) {
scales[[i]][[method]](data[[var]][scale_index[[i]]])
})
11.
FUN(X[[i]], ...)
10.
lapply(vars, function(var) {
pieces <- lapply(seq_along(scales), function(i) {
scales[[i]][[method]](data[[var]][scale_index[[i]]])
}) ...
9.
scale_apply(layer_data, x_vars, "map", SCALE_X, self$panel_scales_x)
8.
FUN(X[[i]], ...)
7.
lapply(data, function(layer_data) {
match_id <- match(layer_data$PANEL, layout$PANEL)
x_vars <- intersect(self$panel_scales_x[[1]]$aesthetics,
names(layer_data)) ...
6.
map_position(..., self = self)
5.
layout$map_position(data)
4.
ggplot_build.ggplot(x)
3.
ggplot_build(x)
2.
print.ggplot(x)
1.
(function (x, ...)
UseMethod("print"))(x)

问题原因与解决方案

核心原因

代码中scale_x_continuous和scale_y_continuous的limits参数调用了未定义的xlim和ylim,而R中xlim是ggplot2的内置函数(属于环境对象),直接尝试将其作为参数传递会触发"无法子集环境对象"的错误。

解决步骤

方法1:定义PCA维度的坐标范围

从PCA结果中提取样本点在维度1和维度2的坐标范围,可适当扩展范围提升图形美观度:

# 在绘制双图前添加以下代码
xlim <- range(pca_out$ind$coord[, 1]) * 1.1  # 扩展10%范围
ylim <- range(pca_out$ind$coord[, 2]) * 1.1

方法2:删除limits参数

如果不需要手动限制坐标范围,直接删除scale_x_continuous和scale_y_continuous中的limits = xlim、limits = ylim参数,factoextra会自动适配合适的坐标范围。

修改后的完整双图代码片段

# 先定义xlim和ylim
xlim <- range(pca_out$ind$coord[, 1]) * 1.1
ylim <- range(pca_out$ind$coord[, 2]) * 1.1

# 绘制双图
fviz_pca_biplot(pca_out,
                geom.ind = "point",
                pointsize = 1.5,
                pointshape=21,
                col.ind = "#666666",
                stroke.ind = 1,
                fill.ind = pcadata$log_response_ratio,
                alpha.ind = 1,
                label ="var",
                labelsize = 2,
                col.var = "#666666",
                repel = TRUE,
                invisible="quali"
) +
  coord_fixed(ratio = 1) +
  labs(title="", x="Dim1", y="Dim2") +
  scale_x_continuous(breaks = scales::pretty_breaks(6), limits = xlim) +
  scale_y_continuous(breaks = scales::pretty_breaks(6), limits = ylim) +
  guides(fill = guide_colorbar(title.position = "top", title.hjust = 0.5)) +
  scale_fill_gradient2(low="#2166AC", mid="white", high="#B2182B", midpoint = median(pcadata$log_response_ratio)) +
  theme_bw() +
  theme(panel.grid.major = element_line(linewidth = 0.3, linetype = "dashed"),
        panel.grid.minor = element_blank(),
        axis.title = element_text(size = 10),
        axis.text = element_text(size = 10),
        axis.title.x = element_text(margin = margin(t=10)),
        axis.title.y = element_text(margin = margin(r=10)),
        legend.title = element_text(size=10),
        legend.text = element_text(size=10),
        legend.position = c(0.18, 0.1),
        legend.key.height = unit(2, units = "mm"),
        legend.key.width = unit(8, units = "mm"),
        legend.direction = "horizontal",
        aspect.ratio = 1
  )

内容的提问来源于stack exchange,提问作者Liesl Blackman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 03:05:55