玩转数据可视化之R语言ggplot2:(七)对图形添加注释和标签(包含标题、坐标轴、参考线和高亮等注释方法)
玩转数据可视化之R语言ggplot2
- 🌸个人主页:JoJo的数据分析历险记
- 📝个人介绍:小编大四统计在读,目前保研到统计学top3高校继续攻读统计研究生
- 💌如果文章对你有帮助,欢迎关注、点赞、收藏、订阅专栏
本系列主要介绍R语言ggplot2的使用
参考资料:
ggplot2: Elegant Graphics for Data Analysis
文章目录
🎄7.ggplot2对图形加注释标签
在我们数据可视化时,一个好的注释能使图形更好的传递信息,ggplot2本身和一些扩展包都提供了一些给图形加注释的技巧
🌲7.1 图形、坐标轴和图例等标题
在我们画图时,需要给图形、坐标轴和图例加标题。在ggplot2中,我们可以使用labs()函数完成这一系列的设置
我们还是以ggplot2中的mpg数据集为例
library(ggplot2)
head(mpg)
manufacturer | model | displ | year | cyl | trans | drv | cty | hwy | fl | class |
---|---|---|---|---|---|---|---|---|---|---|
<chr> | <chr> | <dbl> | <int> | <int> | <chr> | <chr> | <int> | <int> | <chr> | <chr> |
audi | a4 | 1.8 | 1999 | 4 | auto(l5) | f | 18 | 29 | p | compact |
audi | a4 | 1.8 | 1999 | 4 | manual(m5) | f | 21 | 29 | p | compact |
audi | a4 | 2.0 | 2008 | 4 | manual(m6) | f | 20 | 31 | p | compact |
audi | a4 | 2.0 | 2008 | 4 | auto(av) | f | 21 | 30 | p | compact |
audi | a4 | 2.8 | 1999 | 6 | auto(l5) | f | 16 | 26 | p | compact |
audi | a4 | 2.8 | 1999 | 6 | manual(m5) | f | 18 | 26 | p | compact |
🌿7.1.1 文本注释
下面我们要绘制发动机排量(displ)和每加仑里程(hwy)散点图,并定义颜色为cyl
ggplot(mpg, aes(displ, hwy)) +
geom_point(aes(col=factor(cyl)))+#因为cyl是数值新数据,在这里我们将其转换为分类型数据
labs(
x='发动机排放量(displ)/L',
y='每加仑行驶里程',
colour = "Number of cylinders",
title = "Mileage by engine size and cylinders",
subtitle = '数据来源:http://fueleconomy.gov'
)
☘️7.1.2 数学表达式注释
labs()一般是增加文本数据,但也可以使用quote()
函数定义数学表达式,下面这个例子可以说明
values <- seq(from = -2, to = 2, by = .01)
df <- data.frame(x = values, y = exp(values ))
ggplot(df, aes(x, y)) +
geom_line() +
labs(y = quote(f(x) == e^x))
🍀7.1.3 markdown语法注释
同时,labs还支持markdown语法,例如有时我们需要加粗或者倾斜某些文字,我们需要指定相关theme为ggtext:element_markdown
library(ggtext)
df <- data.frame(x = 1:3, y = 1:3)
p <- ggplot(df, aes(x, y)) +
geom_point() +
labs(x = "x轴**加粗**")
p
p + theme(axis.title.x = ggtext::element_markdown())
🌳7.2 添加文本标签
向绘图中添加文本是最常见的注释形式之一。在标记异常值和其他重要点非常有用。使用geom_text()来添加指定文本,在指定的x和y位置添加标签文本。
family
美学设置字体的款式,例如sans(默认),serif,momo等,来看下面这个例子
df <- data.frame(x=1, y = 3:1, family = c('sans','serif','mono'))
ggplot(df,aes(x,y))+
geom_text(aes(label = family,family=family))
- fontface设置字体,包括三个值:‘plain’,‘bold’,‘italic’
df <- data.frame(x=1, y = 3:1, face = c('plain','bold','italic'))
ggplot(df,aes(x,y))+
geom_text(aes(label = face,fontface=face))
- 我们还可以使用hjust和vjust来调整文本对齐方式,
hjust
可以选择(‘left’,‘right’,‘center’,‘inward’,‘outward’)
vjust
选择(‘bottom’,‘middle’,‘top’,‘inward’,‘outward’),默认是居中对齐,但有时候我们需要调整。最常用的是inward。它将文本对齐到图形内部,从而确保标签保持在绘图限制内:
df <- data.frame(
x = c(1, 1, 2, 2, 1.5),
y = c(1, 2, 1, 2, 1.5),
text = c(
"bottom-left", "bottom-right",
"top-left", "top-right", "center"
)
)
ggplot(df, aes(x, y)) +
geom_text(aes(label = text))
ggplot(df, aes(x, y)) +
geom_text(aes(label = text), vjust = "inward", hjust = "inward")
从上图可以看出使用inword可以叫四个角落的文本全部保证在图形内部显示
-
size
来控制文本的大小,但是ggplot2默认的单位是mm,和大多数默认的pt不同,1pt = 72.27/25.4mm -
angle
指定文本的旋转角度(以度为单位)。 -
通常我们希望标记图形中的点,为了避免文本与点重叠,我们可以使用nudeg_x和nudeg_y来设置文本偏移
df <- data.frame(trt = c("a", "b", "c"), resp = c(1.2, 3.4, 2.5))
ggplot(df, aes(resp, trt)) +
geom_point() +
geom_text(aes(label = paste('(',resp,')')) ,nudge_y = -0.15) +
xlim(1, 3.6)
- 还有一个参数是check_overlap,从英语意思来看,是检查重叠图形,当check_overlap=TRUE,
重叠标签将自动从绘图中删除。算法很简单:标签按照它们在数据框中出现的顺序绘制;如果标签将与现有点重叠,则忽略该标签。
ggplot(mpg, aes(displ, hwy)) +
geom_text(aes(label = model)) +
xlim(1, 8)
ggplot(mpg, aes(displ, hwy)) +
geom_text(aes(label = model), check_overlap = TRUE) +
xlim(1, 8)
虽然看起来这个功能似乎没有什么用,但是当我们是按优先级顺序对数据进行排序,结果是一个带标签的图形,那么显示的就是重要的树数据点
- geom_label()是geom_text()的一个替代,它绘制一个文本框文本,当在一些有复制背景图的时候建议使用geom_label()
label <- data.frame(
waiting = c(55, 80),
eruptions = c(2, 4.3),
label = c("peak one", "peak two")
)
ggplot(faithfuld, aes(waiting, eruptions)) +
geom_raster(aes(fill = density)) +
geom_label(data = label, aes(label = label))
给数据加标签需要注意一下问题:
- 1.虽然文本标签不会影响绘图,但它仍然需要占一定的位置,此时我们需要调整xlim()和ylim()使得我们的图形美观=
- 2.如果我们要标记很多数据,我们很难避免数据点重叠,此时使用check_overlap = TRUE有用,但是我们不能控制哪些数据被去除。因此另一个较好的方法在我的R语言数据分析从入门到高级中也介绍过,使用
ggrepel
包中的geom_text_repel(),会自动避免重叠。 - 3.有时很难确保文本标签适合您想要的空间。ggfittext包可以实现这一点,其中包括一些函数可以在条形图的列中放置文本标签。
ggplot(mpg, aes(displ, hwy)) + geom_point(colour = "red") +
ggrepel::geom_text_repel(data = mpg, aes(label = class))
Warning message:
"ggrepel: 164 unlabeled data points (too many overlaps). Consider increasing max.overlaps"
🌴7.3 绘制自定义注释
上述我们用文本标记单个点是一种重要的注释,ggplot2软件包还提供了其他方法,可以使用与显示数据相同的几何图形对绘图进行注释。具体如下:
- geom_text()和geom_label()和上述讲的一样,添加文本
- geom_rect(),矩形图,其中有xmin,xmax,ymin,ymax参数
- geom_line(),geom_path()和geom_segment(),所有这些几何图形都有一个arrow参数,可以添加箭头,
- geom_vline(),geom_hline(),geom_abline(),添加横跨整个绘图范围的参照线
下面我们距离说明一下这些方法的用法,本案例使用economics数据,我们先来看一下economics数据包括哪些变量
head(economics)
date | pce | pop | psavert | uempmed | unemploy |
---|---|---|---|---|---|
<date> | <dbl> | <dbl> | <dbl> | <dbl> | <dbl> |
1967-07-01 | 506.7 | 198712 | 12.6 | 4.5 | 2944 |
1967-08-01 | 509.8 | 198911 | 12.6 | 4.7 | 2945 |
1967-09-01 | 515.6 | 199113 | 11.9 | 4.6 | 2958 |
1967-10-01 | 512.2 | 199311 | 12.9 | 4.9 | 3143 |
1967-11-01 | 517.4 | 199498 | 12.8 | 4.7 | 3066 |
1967-12-01 | 525.1 | 199657 | 11.8 | 4.8 | 3018 |
下面我们绘制一下失业率的时间序列曲线
ggplot(economics, aes(date, unemploy)) +
geom_line()
假设我们现在想要展示各个总统在任的时候失业率的情况,我们可以先使用geom_rect()引入背景颜色,然后使用geom_vline()引入分隔符,再使用geom_text()添加标签,presidential数据集如下
head(presidential)
name | start | end | party |
---|---|---|---|
<chr> | <date> | <date> | <chr> |
Eisenhower | 1953-01-20 | 1961-01-20 | Republican |
Kennedy | 1961-01-20 | 1963-11-22 | Democratic |
Johnson | 1963-11-22 | 1969-01-20 | Democratic |
Nixon | 1969-01-20 | 1974-08-09 | Republican |
Ford | 1974-08-09 | 1977-01-20 | Republican |
Carter | 1977-01-20 | 1981-01-20 | Democratic |
# 选取presidential子集
presidential <- subset(presidential, start > economics$date[1])
ggplot(economics) +
#使用geom_rect()增加矩形背景
geom_rect(
aes(xmin = start, xmax = end, fill = party),
ymin = -Inf, ymax = Inf, alpha = 0.2,
data = presidential
)+
#使用geom_vline()增加垂直分割线
geom_vline(
aes(xintercept = as.numeric(start)),
data=presidential,
col = 'grey',alpha=0.5
)+
#使用geom_text()添加文本标签
geom_text(
aes(x=start,y=2500,label=name),
data=presidential,
size = 3,nudge_x=50
)+
# 使用geom_line()绘制时间序列曲线
geom_line(aes(date, unemploy)) +
scale_fill_manual(values = c("blue", "red")) +#颜色设置
xlab("date") +
ylab("unemployment")
这里没有什么新内容:在大多数情况下,在ggplot2中注释绘图是对现有几何图形的直接操作。注意在geom_rect()使用-Inf和Inf作为位置。这些是指绘图的左侧和右侧的限制
- annotate(),有时候在绘制图形时,我们需要在一个新的数据库上进行绘制,我们可以选择每次绘图先定义这个数据库,但是太繁琐了,我们使用annotate()可以直接实现这一点,annotate()有一个参数是
geom
,指定我们要添加注释的对象是文本还是点等其他的
yrng <- range(economics$unemploy)
xrng <- range(economics$date)
caption <- paste(strwrap("Unemployment rates in the US have
varied a lot over the years", 40), collapse = "\n")
ggplot(economics, aes(date, unemploy)) +
geom_line() +
annotate(
geom = "text", x = xrng[1], y = yrng[2],
label = caption, hjust = 0, vjust = 1, size = 4
)
annotate()函数的便利性在其他情况下也很有用。例如,注释的一种常见形式是通过在主数据集下方绘制不同颜色的较大点来突出显示点的子集。要突出显示subaru制造的车辆,我们可以使用以下内容创建基本绘图:
library(dplyr)
p <- ggplot(mpg, aes(displ, hwy)) +
# 绘制突出点
geom_point(
data = filter(mpg, manufacturer == "subaru"),
colour = "orange",
size = 3
) +
geom_point()
下面我们希望在图形右上侧展示该突出点,使用annotate变得很方便
p +
annotate(geom = "point", x = 5.5, y = 40, colour = "orange", size = 3) +
annotate(geom = "point", x = 5.5, y = 40) +
annotate(geom = "text", x = 5.6, y = 40, label = "subaru", hjust = "left")
这种方法的优点是在绘图区域内创建标签,但缺点是标签与它选择的点距离较远,另一种方法是使用不同的几何图形来完成这项工作。我们之前说过,geom_curve()和geom_segment()可用于绘制带箭头的曲线和直线,并可与annotate()结合使用,如下所示:
# 添加直线箭头
p +
annotate(
geom = "segment", x = 4, y = 35, xend = 2.65, yend = 27,
arrow = arrow(length = unit(5, "mm"))
) +
annotate(geom = "text", x = 4.1, y = 35, label = "subaru", hjust = "left")
注意:annotate(geom=‘segment’) 等价于 geom_segment(),annotate(geom=‘text’)等价于geom_text(),但是使用annotate会相对更灵活,下面我们来验证一下
p +
geom_segment( x = 4, y = 35, xend = 2.65, yend = 27,
arrow = arrow(length = unit(5, "mm"))
) +
geom_text(, x = 4.1, y = 35, label = "subaru", hjust = "left")
得到的图形一样
🌵7.4 直接在图形内标记分组标签
上面图提供了“直接标记”的示例,其中打印区域本身包含不同组的标签,而不是使用图例。
这通常使绘图更容易阅读,因为它使标签更接近数据。directlabels软件包提供了许多函数是的其更容易实现:
ggplot(mpg, aes(displ, hwy, colour = class)) +
geom_point()
ggplot(mpg, aes(displ, hwy, colour = class)) +
geom_point(show.legend = FALSE) +
directlabels::geom_dl(aes(label = class), method = "smart.grid")
directlabels提供了一系列直接标签的定位方法,我们一般使用smart.grid即可。还有一个ggplot2的拓展包很有意思,ggforce,例如使用geom_mark_ellipse,就可以通过椭圆来选择不同类型的点
ggplot(mpg, aes(displ, hwy)) +
geom_point() +
ggforce::geom_mark_ellipse(aes(label = cyl, group = cyl))
- 还有一个加标签的方法是gghighlight包,用于突出显示绘图中的点或线(或各种不同的几何图形),一般在纵向数据使用的较多
data(Oxboys, package = "nlme")
ggplot(Oxboys, aes(age, height, group = Subject)) +
geom_line() +
geom_point() +
gghighlight::gghighlight(Subject %in% 1:3)
Warning message:
"Tried to calculate with group_by(), but the calculation failed.
Falling back to ungrouped filter operation..."
Warning message:
"Tried to calculate with group_by(), but the calculation failed.
Falling back to ungrouped filter operation..."
label_key: Subject
🌾7.5 对分面图增加注释
一张好的图胜过1000个字,那么一个好的注释胜过任何技巧。
如果使用得当,注释可以成为帮助读者理解数据的强大工具。
例如,当我们想比较不同方面的数据时。
例如,在下面的图中,很容易看到每个方面之间的关系,但各个方面之间的细微差异不会显现出来:
ggplot(diamonds, aes(log10(carat), log10(price))) +
geom_bin2d() +
facet_wrap(vars(cut), nrow = 1)
下面我们可以考虑增加一条参考线,来比较各个方面的细微区别,由于上述每个方面的2维散点图都显示出明显的线性关系,我们考虑用所有数据的回归曲线作为参考线
# 计算回归系数
coef <- coef(lm(log10(price)~log10(carat), data = diamonds))
ggplot(diamonds, aes(log10(carat), log10(price))) +
geom_bin2d() +
geom_abline(intercept = coef[1], slope=coef[2],col='white',size=3)+
facet_wrap(~cut, nrow = 1)
在这个图中,每个分面图都以相同的回归线显示一个类别的数据。这样可以更容易地相互比较面,因为有共享的参考线比较。
- 我们有时候希望绘图的每个方面都显示来自单个组的数据,但是在每个分面图中以不显眼的方式绘制完整的数据集,以便于我们进行比较,此时需要对背景进行修改。我们之前的策略是先对所有数据进行绘制,但是调整颜色和透明度,使得其不显眼,再对我们分面组的数据进行绘制这种方法较繁琐gghighlight软件包在这种情况下特别有用:
ggplot(mpg, aes(displ, hwy, colour = factor(cyl))) +
geom_point() +
gghighlight::gghighlight() +
facet_wrap(~cyl)
可以看出不同的cyl的displ和hwy关系不同
💟文章推荐
如果想了解更多ggplot2数据可视化技巧,欢迎访问下列文章
🌝玩转数据可视化之R语言ggplot2:(三)ggplot2实现将多张图放在一起,包括并排和插图绘制(快速入门)
🌜玩转数据可视化之R语言ggplot2::(四)单一基础几何图形绘制
🌟玩转数据可视化之R语言ggplot2:(五)分组画图
☀️玩转数据可视化之R语言ggplot2:(六)统计变换绘图:包括加权绘图、数据分布图、曲面图、图形重叠处理等
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探