You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

对数刻度绘图中扩展Y轴添加内边距以避免底部点被裁剪

解决ggplot2对数刻度下0值数据点被裁剪的问题

当使用scale_y_log10(limits=c(0.01, NA))时,由于log10(0)无意义,且ggplot默认的超出范围(oob)处理逻辑会删除所有y≤0.01的点,导致原始数据中的0值点被裁剪。以下是三种可行的解决办法:

方案一:修改0值为小正数+使用squish函数

将原始数据中的0替换为略低于y轴下限的小数值,再用scales::squish将超出范围的点压缩到轴边界,既能保留点的显示,又不破坏对数刻度的整体效果:

require(data.table)
require(ggplot2)
require(scales)

dt1 <- data.table(time=c(0,31,150,230,300), value=c(2,0.2,0,0,10))
dt1[, result:=ifelse(value>0,'POSITIVE','NEGATIVE')]
# 替换0为0.005(略低于下限0.01)
dt1[, value := ifelse(value == 0, 0.005, value)]

p1 <- ggplot(dt1, aes(x=time, y=value, fill=result, group=1)) + 
  geom_line() +
  geom_point(size=3, shape=21) +
  scale_fill_manual(values = c('white','black')) +
  scale_y_log10(limits=c(0.01, NA), oob=squish)
print(p1)

方案二:使用伪对数变换(pseudo_log)

伪对数变换在数值接近0时采用线性变换,远离0时切换为对数变换,天然支持0值,无需修改原始数据:

require(data.table)
require(ggplot2)

dt1 <- data.table(time=c(0,31,150,230,300), value=c(2,0.2,0,0,10))
dt1[, result:=ifelse(value>0,'POSITIVE','NEGATIVE')]

p1 <- ggplot(dt1, aes(x=time, y=value, fill=result, group=1)) + 
  geom_line() +
  geom_point(size=3, shape=21) +
  scale_fill_manual(values = c('white','black')) +
  scale_y_continuous(trans='pseudo_log', limits=c(0.01, NA))
print(p1)

方案三:自定义OOB函数

如果不想修改原始数据,可以自定义超出范围的处理函数,将低于下限的点强制设置为下限值,从而保留点的显示:

require(data.table)
require(ggplot2)

dt1 <- data.table(time=c(0,31,150,230,300), value=c(2,0.2,0,0,10))
dt1[, result:=ifelse(value>0,'POSITIVE','NEGATIVE')]

p1 <- ggplot(dt1, aes(x=time, y=value, fill=result, group=1)) + 
  geom_line() +
  geom_point(size=3, shape=21) +
  scale_fill_manual(values = c('white','black')) +
  scale_y_log10(limits=c(0.01, NA), 
                oob=function(x, limits) pmax(pmin(x, limits[2]), limits[1]))
print(p1)

内容的提问来源于stack exchange,提问作者Vasily A

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 17:40:25