使用ggplot2绘制对数转换值散点图并保留真实轴标签(解决报错)
解决ggplot2自定义轴转换报错的问题
问题背景
我有一个包含iso3(国家代码)、region(地区)、crude rate(粗率)、age-standardized rate(年龄标化率)的数据集,速率值可正、可负或为0。由于粗率和年龄标化率的数据存在偏斜,需要对其进行转换。想用ggplot2绘制转换后值的散点图,点按region变量着色,同时x、y轴保留原始数值的刻度标签。尝试的代码如下:
pdf("Graphs/Scatter_Crude_ASDR.pdf") scatter <- ggplot(df_scatter, aes(x = crude, y = agestd, color = region, label=iso3)) + geom_point(size = 2) + scale_x_continuous(trans=sign(crude) * log(abs(crude) + 1)) + scale_y_continuous(trans=sign(agestd) * log(abs(agestd) + 1)) + geom_text(hjust=-0.2, vjust=0, size=3) + geom_abline() + geom_hline(yintercept = 0) + labs( x="Crude rate",y="Age-standardized rate") + theme( plot.title = element_text(color = "#0099f9", size = 20, face = "bold", hjust = 0.5), plot.subtitle = element_text(size = 13, face = "bold", hjust = 0.5), plot.caption = element_text(face = "italic", hjust = 0) ) + guides(colour = guide_legend(title = "region")) print(scatter) dev.off()
运行后报错:
Error in is.trans(x) : object 'crude' not found
数据集样例:
# A tibble: 10 × 4 iso3 region crude agestd <chr> <chr> <dbl> <dbl> 1 AFG EMRO 67.5 198. 2 AGO AFRO 18.3 72.9 3 ALB EURO 255. 134. 4 AND EURO 93.9 55.1 5 ARE EMRO 21.4 55.7 6 ARG AMRO 139. 101. 7 ARM EURO 354. 251. 8 ATG AMRO -38.8 -32.9 9 AUS WPRO 12.2 1.22 10 AUT EURO 98.9 36.6
问题原因
scale_x_continuous()的trans参数要求传入转换函数对象(比如内置的"log10",或是用scales::trans_new()自定义的转换规则),而直接在参数里写sign(crude) * log(abs(crude) + 1)时,R会把crude当成全局环境中的独立对象,而非数据框内的列,因此触发“找不到crude”的报错。
解决方案
使用scales包的trans_new()自定义带符号的对数转换,既能处理正负值和0,又能让ggplot自动将转换后的坐标映射回原始数值,保留轴的可读性。
完整代码
# 加载依赖包 library(ggplot2) library(scales) # 自定义带符号的对数转换:sign(x)*log(abs(x)+1) signed_log_trans <- trans_new( name = "signed_log", # 正向转换:原始值→转换后的值 transform = function(x) sign(x) * log(abs(x) + 1), # 反向转换:转换后的值→原始值(用于生成轴刻度) inverse = function(x) sign(x) * (exp(abs(x)) - 1), # 自定义刻度生成规则,适配正负值分布 breaks = function(x) { c(seq(min(x[x<0]), 0, length.out = 5), seq(0, max(x[x>0]), length.out = 5)) } ) # 绘制散点图 pdf("Graphs/Scatter_Crude_ASDR.pdf") scatter <- ggplot(df_scatter, aes(x = crude, y = agestd, color = region, label = iso3)) + geom_point(size = 2) + # 应用自定义转换 scale_x_continuous(trans = signed_log_trans, name = "Crude rate") + scale_y_continuous(trans = signed_log_trans, name = "Age-standardized rate") + geom_text(hjust = -0.2, vjust = 0, size = 3) + geom_abline() + geom_hline(yintercept = 0) + theme( plot.title = element_text(color = "#0099f9", size = 20, face = "bold", hjust = 0.5), plot.subtitle = element_text(size = 13, face = "bold", hjust = 0.5), plot.caption = element_text(face = "italic", hjust = 0) ) + guides(colour = guide_legend(title = "region")) print(scatter) dev.off()
关键说明
- 自定义转换包含正向和反向函数,ggplot会通过反向转换将转换后的坐标映射回原始速率值,因此轴标签显示的是真实数据,点的位置则是经过对数转换后的结果,解决偏斜问题的同时保证可读性。
- 对于值为0的情况,
log(0+1)=0,所以0在图中的位置保持不变,符合预期。 - 自定义的
breaks函数可以根据数据分布调整刻度数量和范围,你可以按需修改。
内容的提问来源于stack exchange,提问作者WellWellWell
相关产品推荐
相关产品推荐

