7 ggplot2的其他元素-解释性图表
7.1 Labels-标签
通过使用labs()函数,可以为图表添加标题、子标题、坐标轴标签和图例标题。
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point(aes(color = class)) +
labs(
x = "Engine displacement (L)", # x轴标签
y = "Highway fuel economy (mpg)", # y轴标签
color = "Car type", # 图例标题
title = "Fuel efficiency generally decreases with engine size", # 主标题
subtitle = "Two seaters (sports cars) are an exception because of their light weight", # 子标题
caption = "Data from fueleconomy.gov" # 图表说明
)
除以上常规的标签外,labs()函数还支持以数学公式的形式代替普通文本标签,只需将引号替换为quote()即可,具体语法可参看 ?plotmath。
7.2 Annotations-注释
除 小节 7.1 中的标签外,对个别重点关注的观测值(组)也很有用。实现这个注释功能的基础函数时geom_text()。
geom_text()与geom_point()类似,但增加了一个美学属性label,用于在图形中条件文本标签。注释有两种实现的方法:
7.2.1 第一种实现注释的方法-建立专门的数据框用作标注数据框
例如,我们提取每种驱动类型中发动机排量最大的车型信息:
# A tibble: 3 × 4
# Groups: drv [3]
drv displ hwy drive_type
<chr> <dbl> <int> <chr>
1 4 6.5 17 4-wheel dive
2 f 5.3 25 front-wheel drive
3 r 7 24 rear-wheel drive
# use annotate_info to annotate the data
ggplot(mpg, aes(x = displ, y = hwy, color = drv)) +
geom_point(alpha = 0.3) +
geom_smooth(se = F) +
geom_text(
data = annotate_info,
aes(x = displ, y = hwy, label = drive_type),
fontface = "bold",
size = 5,
hjust = "right", # 水平位置调整
vjust = "bottom" # 垂直位置调整
) +
theme_sub_legend(position = "none")
上图中的注释和数据点存在重叠,影响了图形的阅读,此时可以使用ggrepel包的geom_label_repel()自动调整位置:
ggplot(mpg, aes(x = displ, y = hwy, color = drv)) +
geom_point(alpha = 0.3) +
geom_smooth(method = "loess", se = FALSE) +
ggrepel::geom_label_repel(
data = annotate_info,
aes(x = displ, y = hwy, label = drive_type),
fontface = "bold",
size = 5,
nudge_y = 2 # 垂直偏移
) +
theme(legend.position = "none")-1.png)
结合geom_text_repel()和特殊标记则可以突出异常点:
potential_outliers <- mpg |>
filter(hwy > 40 | (hwy > 20 & displ > 5))
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point() +
ggrepel::geom_text_repel(data = potential_outliers, aes(label = model)) +
geom_point(
data = potential_outliers,
color = "red",
size = 3,
shape = "circle open" # 空心红圈标记
)-1.png)
7.2.2 第二种实现注释的方法-使用annotate()直接添加注释
annotate()函数允许直接在图形上添加注释,而无需创建单独的数据框。这种方法更适合添加少量、独立的标注元素,例如添加一段文本到图形的特定位置。
trend_text <- "Larger engine sizes tend to have lower fuel economy." |>
str_wrap(width = 30) # 自动换行
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point() +
annotate(
geom = "label",
x = 3.5,
y = 38,
label = trend_text,
hjust = "left",
color = "red"
) +
annotate(
geom = "segment",
x = 3,
y = 35,
xend = 5,
yend = 25,
color = "red",
arrow = arrow(type = "closed")
)
其他标注特殊点的方法还包括:
-
参考线:使用
geom_hline()/geom_vline()。一般会将参考线的linetype设为虚线,并将color设为灰色或白色以减少视觉干扰,同时将其绘制在主数据层的下方。 -
矩形标记:使用
geom_rect()或ggforce::geom_mark_hull()。矩形的边缘使用xmin,xmax,ymin,ymax参数定义。 -
箭头指示:使用
geom_segment(arrow = arrow())。使用x和y参数定义箭头的起点,使用xend和yend参数定义箭头的终点。
注释是传达可视化图表主要观点和有趣特征的强大工具,在调整注释的位置时要保持十足的耐心)!
7.3 标度
如果想要详细了解标度,还是需要阅读ggplot2官方文档。此外,ggplot2tor提供了详细的标度信息说明供查阅参考。
标度是什么?标度就是用来调整数据映射的图形属性,换句话说,标度控制了美学映射(aes())的视觉表现形式。
先来看一个例子:
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point(aes(color = class))
上图已经很美观,但其实是因为ggplot2设置了一些默认的标度缺省条件,上图代码的完整版应该如下:
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point(aes(color = class)) +
# 以下为默认标度
scale_x_continuous() +
scale_y_continuous() +
scale_color_discrete()

7.3.1 丰富的标度体系

标度函数均由_分割的三部分构成:scale_美学对象_标度名,每个标度函数内都有丰富的参数系统。
- 美学对象名:例如,
x,y,color,fill,shape,size,alpha,linetype等。 - 标度名:例如,
continuous(连续),discrete(离散),manual,gradient,gradient2,gradientn,datetime等。
参数
name:设定坐标/图例的名字,不要名字可以name = NULL-
参数
limits:设定坐标/图例的范围区间,- 连续型
c(m, n) - 离散型
c("a", "b", "b")
- 连续型
参数
labels: 控制显示在坐标/图例上的值(元素)-
参数
breaks:设置坐标和图例的间隔标签:- 一般的,内置函数会自动完成这一操作
- 也可人工制定一个字符型向量,与
breaks提供的字符向量一一对应 - 也可是函数,将
breaks提供的字符型向量当作函数的输入 - NULL,即去掉标签。
-
参数
values:设置颜色、形状等的视觉属性值- 要么与数值的顺序一致
- 要么与
breaks提供的字符型向量长度一致 - 要么,用命名向量`c(“数据标签” = “视觉属性”)提供
参数
expand, 控制参数溢出量。参数
range, 设置尺寸大小范围,比如针对点的相对大小。
7.3.2 坐标轴刻度和图例键
坐标轴和图例统称为引导元素。坐标轴用于 x 轴和 y 轴的美学映射;图例则用于其他所有情况。
影响坐标轴刻度和图例键外观的两个主要参数是: breaks 和 labels 。breaks 控制刻度线的位置或与图例相关联的的数值,labels 则控制每个刻度线或图例对应的文本标签。
breaks最常见的用途是覆盖默认。breaks的另一个用途是在数据点相对较少时,用于精确标注观测值的位置。labels参数与scales包中的标签函数结合使用时,也可用于将数字格式化为货币、百分比等。利用
breaks和labels来控制图例的显示样式。对于分类变量的离散scale,labels可以是一个命名列表,其中包含现有层级名称及其对应的期望标签。
我们具体看几个例子:
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point() +
scale_y_continuous(breaks = seq(15, 40, by = 5))
ggplot(mpg, aes(x = displ, y = hwy, color = drv)) +
geom_point() +
scale_color_discrete(labels = c("4" = "4-wheel", "f" = "front", "r" = "rear"))
# 格式化坐标轴标签为货币形式
ggplot(diamonds, aes(x = price, y = cut)) +
geom_boxplot() +
scale_x_continuous(
labels = scales::label_dollar(scale = 1 / 1000, suffix = "K")
)
# 格式化图例标签为百分比形式
ggplot(diamonds, aes(x = cut, fill = clarity)) +
geom_bar(position = "fill") +
scale_y_continuous(
labels = scales::label_percent(),
name = "Percentage"
)
presidential |>
mutate(id = 33 + row_number()) |>
ggplot(aes(x = start, y = id)) +
geom_point() +
geom_segment(aes(xend = end, yend = id)) +
scale_x_date(name = NULL, breaks = presidential$start, date_labels = "'%y")
7.3.3 图例部局
布局建议:
- 宽幅图形建议图例置于顶部或底部。
- 窄幅图形建议图例置于左侧或右。
- 使用
legend.position = "none"可完全隐藏图例。
通过guide()函数配合guide_legend()或guide_colorbar()可控制单个图例显示,有两个关键的参数:
-
nrow和ncol:控制图例的行数和列数。 -
override.aes:用于覆盖图例中显示的美学属性(例如增大图例点大小)。
# guide_legend() 控制离散图例布局
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point(aes(color = class), alpha = 0.5) + # 半透明显示密集点
geom_smooth(se = F) +
theme(legend.position = "bottom") +
guides(
color = guide_legend(
nrow = 2,
override.aes = list(size = 5) # 图例点尺寸设为5倍
)
)
# guide_colorbar() 控制连续图例布局
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point(aes(color = hwy), size = 3, alpha = 0.5) + # 半透明显示密集点
geom_smooth(se = F) +
theme(legend.position = "bottom") +
guides(
color = guide_colorbar(
direction = "horizontal",
barwidth = unit(5, "in"),
barheight = unit(0.3, "in")
)
)
7.3.4 修改scale
除了修改个别细节,还可以直接把整个标度都替换掉。
最可能需要更换的scale主要有两种:连续位置scale和颜色scale。幸运的是,同样的原则适用于所有其他美学属性,因此一旦掌握了位置和颜色的调整,你就能迅速掌握其他scale的替换方法。
7.3.4.1 连续位置标度
默认情况下,ggplot2使用线性标度来映射连续变量的位置。但是,有时使用对数标度可以更好地展示数据的分布,尤其是当数据跨越多个数量级时。
ggplot(diamonds, aes(x = carat, y = price)) +
geom_bin2d() +
scale_x_log10() +
scale_y_log10()
7.3.4.2 颜色标度
离散颜色标度: 使用
ColorBrewer调色板。-
连续颜色标度: 使用内置的
scale_color_gradient()和scale_fill_gradient()函数,或使用viridis包中的调色板。- 连续型(后缀 _c),
scale_fill_viridis_c()。 - 离散型(后缀 _d),
scale_fill_viridis_d()。 - 分箱型(后缀 _b),
scale_fill_viridis_b()。
- 连续型(后缀 _c),
当需要自定义数值与颜色的映射关系时,应使用
scale_color_manual(),输入的颜色value要与数据的分组数量一致。
# 离散颜色标度示例-scale_color_brewer()
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point(aes(color = drv)) +
scale_color_brewer(palette = "Set1")
# 离散颜色标度示例-scale_color_manual()
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point(aes(color = drv)) +
scale_color_manual(values = c("4" = "blue", "f" = "green", "r" = "red"))
# 连续颜色标度示例-scale_fill_gradient()
df <- tibble(
x = rnorm(10000),
y = rnorm(10000)
)
ggplot(df, aes(x = x, y = y)) +
geom_hex() +
coord_fixed() + # 保持x轴和y轴比例一致 +
scale_fill_gradient(low = "blue", high = "red")
# 连续颜色标度示例-scale_fill_viridis_c()
ggplot(df, aes(x = x, y = y)) +
geom_hex() +
coord_fixed() + # 保持x轴和y轴比例一致 +
scale_fill_viridis_c()
# 分箱颜色标度示例-scale_fill_viridis_b()
ggplot(df, aes(x = x, y = y)) +
geom_hex() +
coord_fixed() + # 保持x轴和y轴比例一致 +
scale_fill_viridis_b()
值得注意的是,所有颜色标度均提供两种变体: scale_color_*() 和 scale_fill_*() 分别对应 color 和 fill 美学属性。。
7.3.5 缩放
缩放是指调整图形的显示范围,以便更好地观察数据的某个子集。ggplot2提供了多种方法来实现缩放效果:
- 调整绘图数据范围。
- 通过
scale_x_continuous函数设置标度范围限制,实际的效果是对数据集进行子集筛选。 - 在
coord_cartesian()中设置xlim和ylim。实际的效果是对图表的特定地区进行放大。
# 通过调整数据范围实现缩放
mpg |>
filter(displ >= 5 & displ <= 6 & hwy >= 10 & hwy <= 25) |>
ggplot(aes(x = displ, y = hwy)) +
geom_point(aes(color = drv)) +
geom_smooth()
# 通过设置标度范围限制实现缩放
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point(aes(color = drv)) +
geom_smooth() +
scale_x_continuous(limits = c(5, 6)) +
scale_y_continuous(limits = c(10, 25))
# 通过 coord_cartesian() 实现缩放
ggplot(mpg, aes(x = displ, y = hwy)) +
geom_point(aes(color = drv)) +
geom_smooth() +
coord_cartesian(xlim = c(5, 6), ylim = c(10, 25))
当我们需要在不同绘图中保证尺度一致,方便进行数据的对比时,针对单个scale分别设置limits参数是一个不错的选择。
比如当分别绘制SUV和小轿车的油耗数据时,两张图的坐标轴范围和图例显示不一致,SUV的x轴范围是4.0-6.5,轿车则是1.8-4.0;且图例也不同,SUV只有四驱和后驱,轿车只有前驱和四驱。两张图不能直接比较,需进行标度统一。
suv <- mpg |> filter(class == "suv")
compact <- mpg |> filter(class == "compact")
# 创建一致的标度范围
x_scale <- scale_x_continuous(limits = range(mpg$displ))
y_scale <- scale_y_continuous(limits = range(mpg$hwy))
color_scale <- scale_color_discrete(limits = unique(mpg$drv))
# 应用一致的标度范围
p1 <- ggplot(suv, aes(x = displ, y = hwy, color = drv)) +
geom_point() +
x_scale +
y_scale +
color_scale
p2 <- ggplot(compact, aes(x = displ, y = hwy, color = drv)) +
geom_point() +
x_scale +
y_scale +
color_scale
p1 / p2
7.4 主题
每一个元素函数都有一些列控制外观的参数。值得注意的是,元素函数使用下划线_连接,而其中的参数则使用.连接。具体的主题设置可参看 附录 C。
设置主题的函数的基本形式如下:
theme(element_name = element_function()),其中,元素函数element_function()有以下四个:
-
element_text():文本,一般用于设定坐标轴、标签和标题的字体风格。 -
element_line():线条,一般用于控制线条或线段的颜色、类型、位置等。 -
element_rect():矩形区域,一般用于控背景矩形的颜色、大小、边界线条类型等。 -
element_blank():空白,不分配相应的绘图空间,即删除相应的绘图元素。
7.5 多图布局
在数据可视化过程中,常常需要将多个图表组合在一起以便进行比较和分析。patchwork包提供了一种简便的方法来实现多图布局。
patchwork的基础语法是使用加+或\或|将多个ggplot2图形对象连接起来。此外,使用
patchwork::plot_layout()函数可以进一步控制布局的细节,例如合并图例、调整间距等。guide_area()函数用于创建一个专门的图例区域:plot_layout()函数的heights和width参数可以按找比例分配组合后的图标和图例的空间。-
pathwork中运算符区别:-
+添加图层或组合子图。 -
&批量修改主题(适用于 patchwork 全局)。
-
library(patchwork)
library(ggplot2)
# 创建3个图表对象
p1 <- ggplot(mpg, aes(x = displ, y = hwy, color = drv)) +
geom_point(show.legend = F) +
labs(title = "散点图:发动机排量 vs. 油耗")
p2 <- ggplot(mpg, aes(x = drv, y = hwy, fill = drv)) +
geom_boxplot() +
labs(title = "箱线图:驱动类型 vs. 油耗")
p3 <- ggplot(mpg, aes(x = cty, y = hwy, color = drv)) +
geom_point(show.legend = F) +
labs(title = "散点图:城市油耗 vs. 高速油耗")
# 使用 patchwork 组合图表并组合图例
(guide_area()) /
(p1 + p2 + p3) +
plot_layout(
heights = c(1, 9), # 图例与图表高度比例
guides = "collect" # 合并图例
) &
theme(legend.position = "top") # 统一调整图例位置
-1.png)