利用ggplot2的第二个Y轴(双坐标轴)标记折线图的末端。
原文见https://drsimonj.svbtle.com/label-line-ends-in-time-series-with-ggplot2
这是最终的效果图(注意线右面的数字!)
数据集
需要用到tidyverse 包中的 Orange
数据。这个数据集记录了5个橘子树随着时间再不同的环境中的生长数据。
library(tidyverse)
d <- Orange
head(d)
#> Grouped Data: circumference ~ age | Tree
#> Tree age circumference
#> 1 1 118 30
#> 2 1 484 58
#> 3 1 664 87
#> 4 1 1004 115
#> 5 1 1231 120
#> 6 1 1372 142
代码模板
绘制如上图的线段末端带有数字的图,代码应该长得像下满的样子😝:
# 你的数据集包括:
# - 分类列 GROUP colum
# - X列(比加时间)X colum (say time)
# - Y列 (你感兴趣的值)Y column (the values of interest)
DATA_SET
# 先提取出每个类别Y轴末端的向量的数值
DATA_SET_ENDS <- DATA_SET %>%
group_by(GROUP) %>%
top_n(1, X) %>%
pull(Y)
# 用 `sec.axis`绘图
ggplot(DATA_SET, aes(X, Y, color = GROUP)) +
geom_line() +
scale_x_continuous(expand = c(0, 0)) +
scale_y_continuous(sec.axis = sec_axis(~ ., breaks = DATA_SET_ENDS))
让我们看看吧
让我们一点点绘图。我们已经有了数据分类列是 Tree
, X值 是age
, Y 值是circumference
。
首先当然是拿到每个类别最终点的数值:
d_ends <- d %>%
group_by(Tree) %>%
top_n(1, age) %>%
pull(circumference)
d_ends
#> [1] 145 203 140 214 177
然后建立基础图,没有标记数字,再逐层添加。
ggplot(d, aes(age, circumference, color = Tree)) +
geom_line()
现在用 scale_y_*
, 用参数 sec.axis
在右边创建第二个坐标轴, 需要展示的数值显示在 breaks
,线段末端的数值决定的值:
ggplot(d, aes(age, circumference, color = Tree)) +
geom_line() +
scale_y_continuous(sec.axis = sec_axis(~ ., breaks = d_ends))
现在有点样子了。但是X轴左边还有些空隙,不美观啊。建议扩展一下X轴。用到的是 scale_x_*
和expand
参数:
ggplot(d, aes(age, circumference, color = Tree)) +
geom_line() +
scale_y_continuous(sec.axis = sec_axis(~ ., breaks = d_ends)) +
scale_x_continuous(expand = c(0, 0))
进一步抛光打蜡
喜欢吗,这是进一步修饰图的代码:
library(tidyverse)
d <- Orange %>%
as_tibble()
d_ends <- d %>%
group_by(Tree) %>%
top_n(1, age) %>%
pull(circumference)
d %>%
ggplot(aes(age, circumference, color = Tree)) +
geom_line(size = 2, alpha = .8) +
theme_minimal() +
scale_x_continuous(expand = c(0, 0)) +
scale_y_continuous(sec.axis = sec_axis(~ ., breaks = d_ends)) +
ggtitle("Orange trees getting bigger with age",
subtitle = "Based on the Orange data set in R") +
labs(x = "Days old", y = "Circumference (mm)", caption = "Plot by @drsimonj")