如何从带阴影区域的ggplot对象提取Loess曲线边界坐标及了解其内部结构?
问题描述
给定如下ggplot2绘图代码:
library(ggplot2) library(gcookbook) # heightweight data set is from gcookbook # Two loess lines, one for males and for females; factor is in aes(): ggplot(data = heightweight, aes(x = ageYear, y = heightIn, color = sex)) + theme_bw() + # females with Venus symbol in red, males with Mars symbol in blue: geom_point( shape = if_else(heightweight$sex=="f", "♀", "♂"), size = 3, color = if_else(heightweight$sex=="f", "red", "blue")) + geom_smooth() -> p
需求是从绘图对象p中提取6组(x,y)坐标:
- 女性Loess拟合曲线的坐标
- 女性拟合曲线的上置信边界坐标
- 女性拟合曲线的下置信边界坐标
- 男性Loess拟合曲线的坐标
- 男性拟合曲线的上置信边界坐标
- 男性拟合曲线的下置信边界坐标
直接用str(p)查看对象结构时内容过于复杂,无法明确提取路径,比如不知道如何写出类似p.Loess.F.upper <- p$<..>的正确代码。同时想了解:是否有关于ggplot对象内部元素的详细说明?或其他类似非ggplot绘图对象的相关说明?
解决方案
一、提取Loess曲线及置信边界的坐标
ggplot对象的绘图数据可以通过官方提供的ggplot_build()函数提取,它会把绘图所需的所有计算后的数据整理成结构化列表:
- 先将ggplot对象转为构建后的对象:
p_build <- ggplot_build(p)
- 查看
p_build的核心结构,其中data元素包含所有图层的计算数据:
str(p_build$data)
p_build$data是一个列表,每个元素对应一个图层:
- 索引1对应
geom_point的散点数据 - 索引2对应
geom_smooth的Loess拟合及置信区间数据
- 提取
geom_smooth的计算数据:
smooth_data <- p_build$data[[2]]
这个数据框包含关键列:
x:年龄(ageYear)y:拟合身高(Loess曲线值)ymin:下置信边界ymax:上置信边界colour:分组颜色(红色对应女性,蓝色对应男性)
- 拆分出男女对应的6组数据:
# 女性相关数据 female_fit <- subset(smooth_data, colour == "red", select = c(x, y)) female_upper <- subset(smooth_data, colour == "red", select = c(x, ymax)) female_lower <- subset(smooth_data, colour == "red", select = c(x, ymin)) # 男性相关数据 male_fit <- subset(smooth_data, colour == "blue", select = c(x, y)) male_upper <- subset(smooth_data, colour == "blue", select = c(x, ymax)) male_lower <- subset(smooth_data, colour == "blue", select = c(x, ymin))
二、关于绘图对象内部结构的说明
ggplot对象的内部结构:ggplot2官方并未详细公开对象的底层私有结构,因为这些属于实现细节,可能随版本更新发生变化,不建议直接通过
p$xxx的方式访问。推荐使用ggplot_build()、ggplot_gtable()这类官方工具函数来提取数据或修改绘图元素。非ggplot绘图对象的参考:对于基础绘图(base plot)生成的对象,其内部结构同样属于底层实现,没有统一的公开详细文档。通常可以用
str()查看结构,或用recordPlot()捕获绘图状态后分析,但这类操作依赖具体版本,稳定性较差。更可控的替代思路:如果只是需要Loess拟合结果,完全可以不依赖ggplot对象,直接用
loess()函数手动拟合并计算置信区间,这种方式更灵活:
# 手动拟合女性Loess曲线 loess_female <- loess(heightIn ~ ageYear, data = subset(heightweight, sex == "f")) # 生成预测序列 x_seq <- seq(min(heightweight$ageYear), max(heightweight$ageYear), length.out = 100) female_pred <- predict(loess_female, newdata = data.frame(ageYear = x_seq), se = TRUE) # 提取拟合值和置信边界 female_fit_manual <- data.frame(x = x_seq, y = female_pred$fit) female_upper_manual <- data.frame(x = x_seq, y = female_pred$fit + 1.96*female_pred$se.fit) female_lower_manual <- data.frame(x = x_seq, y = female_pred$fit - 1.96*female_pred$se.fit)
内容的提问来源于stack exchange,提问作者user2575105
相关产品推荐
相关产品推荐

