如何在ggplot中标记非零起始Y轴并优化折线效果?
复刻Gapminder生育率图表的问题与解决方案
目标与当前效果对比
Gapminder原版生育率图表

当前复刻生成的图表

复刻代码
fertility <- read.csv("https://raw.githubusercontent.com/MarcoKuehne/marcokuehne.github.io/main/data/Gapminder/tfr-by-gapminder-v12-20171212.csv", sep = ";") # 数据处理 library(tidyverse) fertility <- fertility %>% select(!c(geo.name, geo, indicator)) %>% rownames_to_column %>% gather(var, value, -rowname) %>% spread(rowname, value) %>% rename(year = var, fert = `1`) %>% slice_head(n = 301) fertility[,1:2] <- sapply(fertility[,1:2], FUN=as.numeric) fertility1 <- fertility[1:217,] fertility2 <- fertility[218:301,] # 可视化 ggplot(data = fertility, aes(x=year, y=fert)) + geom_point(aes(x=year[1], y=fert[1]), size = 4) + geom_text(aes(x=year[1], y=fert[1], label = year[1]), vjust = 2.5) + geom_point(aes(x=year[165], y=fert[165]), size = 4) + geom_text(aes(x=year[165], y=fert[165], label = year[165]), vjust = -3, hjust = -0.5) + geom_text(aes(x=year[165], y=fert[165], label = "5 births"), vjust = -1.5, hjust = -0.2) + geom_text(aes(x=year[217], y=fert[217], label = year[217]), vjust = -3) + geom_text(aes(x=year[217], y=fert[217], label = "2.5 births"), vjust = -1.5) + geom_line(data = fertility1, size=1.3, arrow=arrow(length=unit(0.30,"cm"), ends="last", type = "closed")) + geom_line(data = fertility2, size=1.3, linetype="dashed") + labs(title = "Average Number Of Babies Per Woman From 1800 to Today", caption = "Source: Gapminder based on UN-Pop", y="", x="") + theme_minimal() + theme(panel.grid.major.x = element_blank(), panel.grid.minor.x = element_blank())
遇到的问题
geom_line线宽设置的视觉效果不符合预期- 需要找到
geom_line与geom_smooth的折中方案,让折线略微平滑 - 核心需求:Y轴不从0开始时,实现类似Gapminder的非零起始断开标记
解决方案
1. Y轴非零起始标记(核心需求)
Gapminder的Y轴用断开刻度线提示轴未从0开始,有两种实现方式:
方法一:使用ggh4x包快速实现
# 先安装包 install.packages("ggh4x") library(ggh4x) # 在ggplot代码中添加轴设置 ggplot(data = fertility, aes(x=year, y=fert)) + # 其他图层... scale_y_continuous(limits = c(2, 6), expand = c(0, 0)) + # 锁定Y轴范围 axis_break(axis = "y", breaks = 2, style = "slash") # 添加断开标记
方法二:手动绘制断开标记(无需额外包)
ggplot(data = fertility, aes(x=year, y=fert)) + # 其他图层... scale_y_continuous(limits = c(2, 6), expand = c(0, 0)) + # 绘制底部轴线 geom_segment(x = -Inf, xend = Inf, y = 2, yend = 2, color = "black") + # 绘制左右断开线段 geom_segment(x = -Inf, xend = -Inf + 10, y = 2, yend = 1.8, color = "black") + geom_segment(x = Inf, xend = Inf - 10, y = 2, yend = 1.8, color = "black")
2. 折线平滑的折中方案
方法一:用stat_smooth调整平滑度
通过span参数控制折线贴近原始数据的程度,值越小越贴近,越大越平滑:
ggplot(...) + # 替换原geom_line(fertility1)为以下代码 stat_smooth(data = fertility1, aes(x=year, y=fert), method = "loess", span = 0.1, size=1.3, se=FALSE, arrow=arrow(length=unit(0.30,"cm"), ends="last", type = "closed")) + geom_line(data = fertility2, size=1.3, linetype="dashed") + # 其他图层...
方法二:插值生成平滑折线
通过插值增加数据点,让折线更流畅:
# 对fertility1进行插值 fertility1_smooth <- approx(fertility1$year, fertility1$fert, n = 1000) %>% as.data.frame() %>% rename(year = x, fert = y) # 绘制插值后的折线 ggplot(...) + geom_line(data = fertility1_smooth, size=1.3, arrow=arrow(length=unit(0.30,"cm"), ends="last", type = "closed")) + geom_line(data = fertility2, size=1.3, linetype="dashed") + # 其他图层...
3. geom_line线宽优化
size是相对单位,可直接调整数值(比如从1.3改为1.2或1.4),同时保证平滑折线与虚线的size一致,维持视觉统一。若线宽显示异常,检查是否有其他图层(比如stat_smooth)的size参数冲突。
内容的提问来源于stack exchange,提问作者Marco
相关产品推荐
相关产品推荐

