如何使用lattice绘制带误差棒和散点的柱状图?
Lattice实现带误差棒和抖动散点的分组柱状图
完全可以实现你想要的效果,你的原始代码存在三个核心问题:
- 直接用原始数据绘制柱状图,导致每个原始值都生成了柱子,而非分组均值
panel.xyplot的参数传递错误,无法获取原始数据的坐标- 误差棒基于原始数据计算,而非统计量的标准误
实现步骤
- 预处理数据:先计算每个
dose+supp组合的均值和标准误(误差棒用),同时把dose转为因子方便x轴定位 - 设置分组偏移:让同一剂量下的两个分组柱子错开,避免重叠
- 自定义Panel函数:依次绘制柱状图、误差棒、抖动散点
完整代码
library(lattice) library(dplyr) # 转换dose为因子,方便分组定位 ToothGrowth$dose_f <- factor(ToothGrowth$dose, levels = c(0.5, 1, 2)) # 计算分组统计量:均值+标准误 summary_df <- ToothGrowth %>% group_by(dose_f, supp) %>% summarise( mean_len = mean(len), se_len = sd(len)/sqrt(n()), .groups = "drop" ) # 定义分组柱子的偏移宽度 dodge_width <- 0.3 # 绘制图形 barchart(mean_len ~ dose_f, data = summary_df, groups = supp, ylab = "牙齿长度", xlab = "剂量 (mg)", main = "不同剂量和补充剂下的牙齿生长情况", col = c("#00AFBB", "#E7B800"), panel = function(x, y, groups, subscripts, ...) { # 计算每个分组柱子的x偏移位置 x_pos <- as.numeric(x) + ifelse(groups[subscripts] == "OJ", -dodge_width/2, dodge_width/2) # 绘制分组柱状图 panel.barchart(x_pos, y, ...) # 绘制误差棒(均值±标准误) se_vals <- summary_df$se_len[subscripts] # 误差棒竖线 panel.segments(x0 = x_pos, y0 = y - se_vals, x1 = x_pos, y1 = y + se_vals, col = "black") # 误差棒两端的短横线 panel.segments(x0 = x_pos - dodge_width/4, y0 = y - se_vals, x1 = x_pos + dodge_width/4, y1 = y - se_vals, col = "black") panel.segments(x0 = x_pos - dodge_width/4, y0 = y + se_vals, x1 = x_pos + dodge_width/4, y1 = y + se_vals, col = "black") # 绘制原始数据的抖动散点 # 计算原始数据的x位置(加上分组偏移) raw_x <- as.numeric(ToothGrowth$dose_f) + ifelse(ToothGrowth$supp == "OJ", -dodge_width/2, dodge_width/2) # 抖动x轴(幅度不超过分组偏移) raw_x_jitter <- jitter(raw_x, amount = dodge_width/3) panel.xyplot(raw_x_jitter, ToothGrowth$len, col = ifelse(ToothGrowth$supp == "OJ", "#00AFBB", "#E7B800"), pch = 16, cex = 0.8, alpha = 0.6) }, # 添加图例 key = list(space = "right", text = list(c("橙汁", "维生素C")), rectangles = list(col = c("#00AFBB", "#E7B800"), fill = c("#00AFBB", "#E7B800"))) )
替代方案(不用dplyr)
如果不想用dplyr,可以用base R计算统计量:
# 用base R计算分组统计量 summary_df <- aggregate(len ~ dose + supp, data = ToothGrowth, function(x) c(mean = mean(x), se = sd(x)/sqrt(length(x)))) summary_df <- do.call(data.frame, summary_df) colnames(summary_df) <- c("dose", "supp", "mean_len", "se_len") summary_df$dose_f <- factor(summary_df$dose, levels = c(0.5, 1, 2))
内容的提问来源于stack exchange,提问作者user257122
相关产品推荐
相关产品推荐

