如何设置mixR包mixfit输出的mixfitEM类对象绘图的x轴范围
问题
为R语言mixR包mixfit函数输出的mixfitEM类拟合结果设置x轴绘图范围时,遇到两个问题:
- 调用base版
plot()方法绘图时,传入的xlim参数被忽略不生效 - 尝试用
ggplot2绘图时,直接传入mixfitEM对象会报错,无法转换为ggplot支持的数据格式
可复现测试代码如下:
rm(list=ls()) library(mixR) library(tidyverse) set.seed(07062022) N <- 1000 lbda=.5 mu1=1 Del=3 mu2=mu1+Del components <- sample(1:2,prob=c((1-lbda), lbda),size=N,replace=TRUE) mus <- c(mu1,mu2) sds <- sqrt(c(1,.5)) Y <- rlnorm(n=N,meanlog=mus[components],sdlog=sds[components]) mod4 <- mixfit(Y, ncomp = 2, family = 'lnorm') # base绘图尝试,xlim无效 plot(mod4, title = 'Log-Normal Mixture (2 components)', xlim=c(0,200)) # ggplot绘图尝试,报错 ggplot(mod4)+ coord_cartesian(xlim = c(0, 200))
运行ggplot代码的报错信息:
Error in `fortify()`: ! `data` must be a data frame, or other object coercible by `fortify()`, not an S3 object with class mixfitEM.
解决方案
方法1:base绘图(最简方案)
plot.mixfitEM默认以原始数据的最小值、最大值作为密度曲线的计算边界,不会自动适配传入的xlim参数。函数本身提供了xmin、xmax参数用于控制密度曲线的计算范围,同时搭配xlim控制坐标轴显示范围即可生效:
plot(mod4, title = 'Log-Normal Mixture (2 components)', xmin = 0, # 密度曲线计算起点 xmax = 200, # 密度曲线计算终点 xlim = c(0, 200) # x轴显示范围 )
如果需要调整x轴刻度,可以额外搭配axis()函数自定义刻度位置。
方法2:ggplot2自定义绘图(更高自由度)
mixR包没有为mixfitEM类提供ggplot2的fortify方法,因此不能直接将模型对象传入ggplot(),需要手动从模型结果中提取原始数据、拟合密度等元素,再组装图层,即可自由调整坐标轴、主题等所有样式:
# 1. 提取原始数据直方图密度 hist_obj <- hist(mod4$x, breaks = 50, plot = FALSE) hist_df <- data.frame( x_mid = hist_obj$mids, density = hist_obj$density, width = diff(hist_obj$breaks)[1] ) # 2. 计算指定x范围内的拟合密度 x_seq <- seq(0, 200, length.out = 1000) # 整体混合密度 total_dens <- dmixlnorm(x_seq, mod4$mu, mod4$sd, mod4$pi) # 各组分单独密度 comp_dens_list <- lapply(1:mod4$ncomp, function(i) { mod4$pi[i] * dlnorm(x_seq, meanlog = mod4$mu[i], sdlog = mod4$sd[i]) }) dens_df <- data.frame( x = rep(x_seq, times = mod4$ncomp + 1), density = c(total_dens, unlist(comp_dens_list)), type = rep(c("整体拟合", paste0("组分", 1:mod4$ncomp)), each = length(x_seq)) ) # 3. 绘图,自由设置x轴范围 ggplot() + geom_col(data = hist_df, aes(x = x_mid, y = density), width = hist_df$width[1], fill = "grey85", color = "white") + geom_line(data = dens_df, aes(x = x, y = density, color = type, linewidth = type)) + scale_color_manual(values = c("整体拟合" = "black", "组分1" = "#E41A1C", "组分2" = "#377EB8")) + scale_linewidth_manual(values = c("整体拟合" = 1.2, "组分1" = 0.8, "组分2" = 0.8)) + coord_cartesian(xlim = c(0, 200)) + # 自定义x轴范围 labs(title = "Log-Normal Mixture (2 components)", x = "观测值", y = "密度", color = "", linewidth = "") + theme_bw()
内容的提问来源于stack exchange,提问作者FicusBenji
相关产品推荐
相关产品推荐

