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

如何在ggplot中标记非零起始Y轴并优化折线效果?

复刻Gapminder生育率图表的问题与解决方案

目标与当前效果对比

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 21:01:11