如何修改ggplot2中scales包生成的标签 保留SI单位同时去除负号

遇到的问题
制作人口金字塔类ggplot2可视化时,配置scale_y_continuous(labels = scales::label_number_si(accuracy = 0.1))生成坐标轴标签后,女性侧的负半轴标签会自带负号,需要移除所有负数值标签前的负号,同时完全保留SI单位后缀、小数精度等原有格式。
之前尝试直接写labels = abs(label_number_si())实现取绝对值的效果,直接触发报错:Error in abs: non-numeric argument to mathematical function。
补充复现说明:运行demo_continuous(c(-1e10,1e10), label = label_number_si())即可得到默认标签样式,最终需求仅为移除负号,其余格式和默认输出完全一致。

之前写法报错的原因
scales::label_number_si()是高阶函数,调用后返回的是用于生成实际标签的函数对象,而非处理好的数值或标签文本。abs()只接受数值向量作为输入,当你把函数对象传给abs()时,就会触发“非数值参数传入数学函数”的报错。
实现方案
直接对原生SI标签函数的输出做字符层面的负号移除,不改动内部的单位换算、精度计算逻辑,能最大程度保证和默认格式的一致性:
- 自定义封装适配的标签函数:
label_number_si_abs <- function(accuracy = 0.1, ...) { # 复用原生SI标签逻辑,保留所有参数配置能力 base_func <- scales::label_number_si(accuracy = accuracy, ...) # 内层函数接收实际绘图的数值向量,生成标签后移除开头负号 function(x) { raw_labels <- base_func(x) sub("^-", "", raw_labels) } }
- 在坐标轴配置中替换原生标签即可:
scale_y_continuous(labels = label_number_si_abs(accuracy = 0.1))
效果验证
运行demo_continuous(c(-1e10,1e10), label = label_number_si_abs(accuracy = 0.1))测试:
- 正半轴标签和默认输出完全一致,比如1e10对应为10.0B
- 负半轴标签去掉前置负号,原本的-10.0B会输出为10.0B,SI单位、小数位数和默认格式完全统一,没有格式偏差。
内容的提问来源于stack exchange,提问作者paxton
相关产品推荐
相关产品推荐

