
数据可视化【免费下载链接】ggplot2An implementation of the Grammar of Graphics in R项目地址https://gitcode.com/gh_mirrors/gg/ggplot2点击查看免费下载stat_ydensity()是 ggplot2 中服务于geom_violin()小提琴图的统计层stat它把每个分组内的连续数据拟合成核密度估计再按面积、计数或宽度三种模式缩放出小提琴的轮廓。本文以仓库中 tests/testthat/_snaps/stat-ydensity.md 这份快照测试文档为切入点结合 R/stat-ydensity.R、R/geom-violin.R、R/stat-density.R 与 tests/testthat/test-stat-ydensity.R 中的实现与用例深入讲解带宽自动选择的规则约束、drop参数对单点分组的处理策略、quantiles分位线的计算方式以及scale三种缩放模式的底层语义让你不仅会用geom_violin()更能理解其统计管线每一步在做什么。快照文档定位两个被钉死的运行时行为tests/testthat/_snaps/stat-ydensity.md是 testthat 快照测试snapshot test生成的预期输出文件。它的作用不是直接可执行而是记录stat_ydensity()在两类边界场景下必须原样呈现的用户提示信息calc_bw()的输入校验提示xmust contain at least 2 elements to select a bandwidth automatically. —— 当分组内不足 2 个数据点时无法自动选择带宽testis not a valid bandwidth rule. —— 当传入的带宽规则字符串不在白名单内时直接报错。drop FALSE对单点分组的保留行为Groups with fewer than two datapoints have been dropped. /iSetdrop FALSEto consider such groups for position adjustment purposes. —— 默认丢弃少于两个数据点的分组时的警告Cannot compute density for groups with fewer than two datapoints. —— 设置drop FALSE后无法计算密度时的警告。这两组消息分别由 R/stat-ydensity.R 的compute_group与calc_bwR/stat-ydensity.R抛出并由 tests/testthat/test-stat-ydensity.R 中的expect_snapshot_error()/expect_snapshot_warning()断言。也就是说快照文档实质上是围绕小样本组处理与带宽校验的契约性测试基线下面逐一展开其背后的实现细节。calc_bw()带宽自动选择的规则白名单与最小样本量约束带宽bandwidth是核密度估计的平滑参数。stat_ydensity()允许两种指定方式直接给数值作为核的标准差或给字符串规则名由内置函数自动计算。字符串路径由calc_bw()统一处理calc_bw - function(x, bw) { if (is.character(bw)) { if (length(x) 2) { cli::cli_abort({.arg x} must contain at least 2 elements to select a bandwidth automatically.) } bw - switch( to_lower_ascii(bw), nrd0 stats::bw.nrd0(x), nrd stats::bw.nrd(x), ucv stats::bw.ucv(x), bcv stats::bw.bcv(x), sj , sj-ste stats::bw.SJ(x, method ste), sj-dpi stats::bw.SJ(x, method dpi), cli::cli_abort({.var {bw}} is not a valid bandwidth rule.) ) } bw }这里值得注意的细节大小写不敏感规则名先经to_lower_ascii()归一化因此NRD0与nrd0等价支持的规则全集nrd0默认Scott 经验法则的变体、nrdstats::bw.nrd、ucv无偏交叉验证、bcv有偏交叉验证、sj-ste/sj-dpiSheather Jones 的 STE 与 DPI 两种求解法全部来自 R 基础包stats边界行为传入任何不在此集合内的字符串如快照中的test都会触发cli_abort错误信息即快照文档第二行最小样本量字符串规则依赖经验公式或迭代优化样本量少于 2 时无意义因此直接报错——这正是快照文档第一行消息的来源。注意数值型bw不经过此校验直接透传权重盲区与 R/stat-density.R 文档一致自动带宽计算不考虑权重加权数据的平滑效果需自行调节adjust。对应的单元测试tests/testthat/test-stat-ydensity.R用expect_silent(calc_bw(1:5, nrd0))验证合法输入不报错用两个expect_snapshot_error()锁定上述两条错误消息的文本。drop参数少于两个数据点的分组何去何从密度估计至少需要 2 个点才能展开核平滑但真实数据中完全可能有一个分组只有 1 个观测。StatYdensity的compute_group是这样处理的R/stat-ydensity.Rif (nrow(data) 2) { if (isTRUE(drop)) { cli::cli_warn(c( Groups with fewer than two datapoints have been dropped., i Set {.code drop FALSE} to consider such groups for position adjustment purposes. )) return(data_frame0()) } ans - data_frame0(x data$x, n nrow(data)) return(ans) }drop TRUE默认该分组被整体丢弃同时发出快照文档中的警告。这里有一个容易被忽视的语义丢弃发生在统计计算阶段警告文本明确提示consider such groups for position adjustment purposes——即drop不是纯粹的过滤开关而是与后续 position默认dodge躲避的布局空间有关被丢弃的组不会占据 x 轴上的位置槽位drop FALSE保留该分组但不计算密度只输出x与n 1两列占位数据使分组继续参与位置调整、占据应有宽度。此时密度缺失警告转移到compute_panel阶段统一发出R/stat-ydensity.Rif (!drop any(data[[n]] 2)) { cli::cli_warn(Cannot compute density for groups with fewer than two datapoints.) }测试 tests/testthat/test-stat-ydensity.R 给出了这个差异的实证构造一个x为因子、含 A/B 两组、其中一组仅 1 行的数据框drop TRUE时get_layer_data()得到的unique(ld$x)长度为 3一组被删仅剩 3 个因子水平位置drop FALSE时为 4所有位置保留。compute_group()从原始分组到小提琴轮廓的完整管线当分组内至少 2 个点时compute_group执行以下步骤R/stat-ydensity.R计算数据范围与密度区间range - range(data$y, na.rm TRUE)若trim TRUE默认modifier 0密度估计范围严格限定在数据极值内若trim FALSEmodifier 3范围向两侧各外扩3 * bw让尾部平滑延伸到数据范围之外带宽求解bw - calc_bw(data$y, bw)核密度估计调用 R/stat-density.R 的共享函数compute_density()内部经stats::density()计算同时生成density原始密度、scaled归一化到最大值为 1与n等派生变量。bounds c(-Inf, Inf)时不做边界修正一旦bounds含有限值则先剔除越界点带警告再对边界做反射校正reflect_density这一机制与geom_density()共用坐标对调dens$y - dens$x——因为StatYdensity的required_aes x|y支持横向/纵向两种朝向密度沿 y 轴展开后把密度采样点写回dens$y作为小提琴的纵向轮廓坐标x 定位若该分组 x 取值唯一则用vec_rep()重复填充以保留mapped_discrete类测试 tests/testthat/test-stat-ydensity.R 专门断言scale_x_discrete(drop FALSE)下ld$x仍为mapped_discrete且unique(ld$x)为c(1, 3)跳过空水平 2若 x 有多个值连续 x 上的分组则取 x 均值并将width设为 x 跨度的 0.9 倍分位线计算见下一节。quantiles基于真实数据的分位线而非密度反推stat_ydensity()默认在 0.25/0.50/0.75 三个分位处生成quantile标记行供GeomViolin画分位线。关键设计是分位值直接来自数据的经验分位数R/stat-ydensity.Rif (!is.null(quantiles)) { if (!(all(quantiles 0) all(quantiles 1))) { cli::cli_abort({.arg quantiles} must be between 0 and 1.) } if (!is.null(data[[weight]]) || !all(data[[weight]] 1)) { check_installed(Hmisc, for weighted quantiles.) quants - Hmisc::wtd.quantile(data$y, weights data$weight, probs quantiles) } else { quants - stats::quantile(data$y, probs quantiles) } ... }分位值来源无权重时用stats::quantile()有权重时用Hmisc::wtd.quantile()需安装 Hmisc 包check_installed会自动提示安装范围校验quantiles必须落在[0, 1]否则直接报错密度插值得到分位对应的 y 值后用stats::approx()从密度曲线上插值出该分位点处的density、scaled、x、width等其余指标并将这些行并入输出同时从原密度采样中剔除重合行测试佐证quantiles are based on actual data (#4120)tests/testthat/test-stat-ydensity.R用y 0:10、q seq(0.1, 0.9, by 0.1)验证ld$y[!is.na(ld$quantile)]精确等于1:9——即分位线画在真实数据分位上而非密度曲线拟合值上加权的用例第 L55-L65 行把第 12 个点的权重设为 0结果仍为1:9证明权重为 0 的点不参与分位计算。compute_panel()与scale三种小提琴宽度缩放模式统计计算完成后compute_panel负责把密度转换为最终绘制宽度R/stat-ydensity.Rdata$violinwidth - switch( scale, area data$density / max(data$density, na.rm TRUE), count data$density / max(data$density, na.rm TRUE) * data[[n]] / max(data[[n]]), width data$scaled )area默认各组最大宽度一致、面积未修剪前相同最常用于组间比较分布形状count在归一化基础上再乘上n / max(n)面积正比于样本量大样本组更宽width直接使用scaled密度归一化到最大值 1所有小提琴最大宽度恒定。scale的取值在stat_ydensity()构造器中通过arg_match0(scale, c(area, count, width))校验R/stat-ydensity.R非法值在参数入口即被拒绝。随后GeomViolin$draw_groupR/geom-violin.R用violinwidth计算左右轮廓xminv/xmaxv按 y 排序后首尾相接闭合多边形若存在quantile行且quantile.linetype非 0则叠加分位线 grob——quantile.linetype 0L是geom_violin()的默认值这正是分位线默认隐藏、设置quantile.linetype后显示的机制来源。朝向自适应与弃用参数StatYdensity还包含两个值得注意的实现细节朝向自动翻转setup_params中has_flipped_aes(data, params, main_is_orthogonal TRUE, group_has_equal TRUE)自动识别 x 与 y 哪个是离散轴flipped_aes TRUE时数据在统计前后经flip_data()/flip_data()对调因此geom_violin()对aes(factor(cyl), mpg)与aes(mpg, factor(cyl))两种写法都能自动确定纵向/横向小提琴见 R/geom-violin.R 示例draw_quantiles弃用setup_params中若检测到旧参数draw_quantiles会经deprecate(4.0.0)提示改用quantiles并把旧值透传为params$quantilesgeom_violin()侧R/geom-violin.R同样处理并自动把quantile.linetype提升到至少 1以便旧代码仍能看到分位线。该参数保留在extra_params中仅为弃用修复服务。实战示例在真实数据上验证快照场景以下代码可直接在安装好 ggplot2 的 R 会话中运行复现并验证本文讨论的行为library(ggplot2) # 1. 默认 drop TRUE少于 2 个点的分组被丢弃并警告 df - data.frame( x factor(rep(1:2, each 4)), y rep(1:2, 4), g rep(c(A, A, B, B), 2) ) df - df[-nrow(df), ] # 删掉最后一行使 B 组只剩 1 个点 p - ggplot(df, aes(x, y, fill g)) p geom_violin(drop TRUE) # 警告: Groups with fewer than two datapoints... # 2. drop FALSE保留分组位置但无法计算密度 p geom_violin(drop FALSE) # 警告: Cannot compute density for groups... # 3. 显示默认四分位线25%/50%/75% ggplot(mtcars, aes(factor(cyl), mpg)) geom_violin(quantile.linetype solid) # 4. 自定义分位与缩放模式 ggplot(mtcars, aes(factor(cyl), mpg)) geom_violin(scale count, quantiles c(0.2, 0.4, 0.6, 0.8), quantile.linetype dashed) # 5. 纵向小提琴朝向自动翻转 ggplot(mtcars, aes(mpg, factor(cyl))) geom_violin()总结tests/testthat/_snaps/stat-ydensity.md虽然只是一份快照基线但它精准锁定了stat_ydensity()最容易被用户撞到的两类边界行为带宽字符串规则的输入校验至少 2 个点、规则名白名单与单点分组的 drop 语义。深入源码可以看到这两类行为背后分别是calc_bw()的switch白名单 最小样本量断言以及compute_group/compute_panel两级警告机制。理解了bw、drop、trim、bounds、quantiles、scale六个核心参数的底层作用路径——从stats::density()核估计、Hmisc::wtd.quantile()加权分位到violinwidth的三种缩放公式——你就能在小提琴图的每个细节上做到知其然也知其所以然。进一步的源码与测试证据可在 R/stat-ydensity.R、R/geom-violin.R、R/stat-density.R 与 tests/testthat/test-stat-ydensity.R 中查阅。赞分享数据可视化【免费下载链接】ggplot2An implementation of the Grammar of Graphics in R项目地址https://gitcode.com/gh_mirrors/gg/ggplot2点击查看免费下载相关推荐WordPress Gutenberg 模板部件core/template-part块完整指南属性、渲染机制与源码实现WordPress Gutenberg 模板部件core/template part块完整指南属性、渲染机制与源码实现 模板部件Template Par数据可视化企业级多业务线线程池隔离架构DynamicTp如何实现资源治理的精细化管控企业级多业务线线程池隔离架构DynamicTp如何实现资源治理的精细化管控 在复杂的分布式系统中多业务线共享线程池往往导致资源竞争和性能抖动。Dynamic后端任务调度可观测性RSUITE IconButton 带文本图标按钮实战从组件实现到样式原理的完整解析RSUITE IconButton 带文本图标按钮实战从组件实现到样式原理的完整解析 IconButton 是 rsuite 中图标 按钮结合的组件前端UI组件上一篇axum 路由合并merge详解MethodRouter 与 Router 的组合、状态对齐与 fallback 约束下一篇Composio Zoom 工具包 OAuth 配置与故障排查实战指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考