ggplot按数值正负分色绘制折线导出eps时出现锯齿如何解决
问题原因
你为折线添加颜色映射后,ggplot会按颜色取值将完整曲线拆分为多段独立线段绘制。由于原始采样点没有恰好落在y=0的位置,正负区间的线段端点无法精准衔接,放大后就会出现明显锯齿。
修复方案
方案1:手动补全过零点(兼容性最好)
先计算出所有y=0的精确坐标补入数据集,让正负段的端点正好落在零点,实现无缝衔接:
library(dplyr) library(ggplot2) # 找出所有过零的相邻点对 cross_idx <- which(diff(sign(dat$y)) != 0) # 插值计算每个过零点的坐标 zero_pts <- lapply(cross_idx, function(i) { x1 <- dat$t[i]; y1 <- dat$y[i] x2 <- dat$t[i+1]; y2 <- dat$y[i+1] x0 <- x1 - y1*(x2-x1)/(y2-y1) data.frame(t = x0, y = 0, pos = factor(NA, levels = c(1,0))) }) %>% bind_rows() # 合并数据并按x轴排序 dat_full <- bind_rows(dat, zero_pts) %>% arrange(t) # 绘图 ggplot(dat_full) + geom_line(aes(x = t, y = y, color = pos, group = 1), linewidth = 1) + scale_color_manual(values = c("1" = "#E41A1C", "0" = "#377EB8"), na.value = "transparent") + theme_bw() + theme(panel.grid = element_blank()) # 导出eps ggsave("tmp/line_smooth.eps", device = cairo_ps, width = 6, height = 6, fallback_resolution = 1200) # 导出pdf ggsave("tmp/line_smooth.pdf", device = cairo_pdf, width = 6, height = 6)
方案2:用ggforce包自动插值(代码更简洁)
用ggforce的geom_link2功能自动完成线段插值,不需要手动补点就能实现平滑分色:
# 第一次使用先安装:install.packages("ggforce") library(ggforce) ggplot(dat, aes(x = t, y = y)) + geom_link2(aes(color = after_stat(y > 0)), linewidth = 1) + scale_color_manual(values = c("TRUE" = "#E41A1C", "FALSE" = "#377EB8"), labels = c("正", "负"), name = "数值符号") + theme_bw() + theme(panel.grid = element_blank())
导出注意事项
不要用默认的device = "eps"/device = "pdf",改用cairo系列矢量设备,导出的矢量图抗锯齿效果更好,在Adobe Illustrator中打开不会出现额外毛刺。
内容的提问来源于stack exchange,提问作者Miles N.
相关产品推荐
相关产品推荐

