R语言绘图:标注、气泡图、散点图矩阵、相关图、马赛克图与图形修改

Author

蟹蟹喵

Published

June 6, 2026

1. 本节学习目标

本节学习以下图形:

  1. 图形标注、标尺、主题与刻面
  2. 气泡图
  3. 散点图矩阵
  4. 分组散点图
  5. 相关图
  6. 马赛克图
  7. 图形修改与美化

主要用到这些包:

ggplot2
dplyr
GGally
corrplot
vcd

其中:

作用
ggplot2 基础绘图
dplyr 数据整理
GGally 散点图矩阵
corrplot 相关图
vcd 马赛克图,尤其是带残差着色的马赛克图

说明:

  • 基础马赛克图使用 R 自带的 mosaicplot()
  • vcd::mosaic() 功能更丰富,可以进行残差着色;
  • 但在某些中文标签或多维列联表场景下,vcd::mosaic() 在 Knit 时可能出现兼容性问题;
  • 因此本文保留 vcd 示例,但不自动执行 vcd::mosaic() 代码。

2. 安装和加载包

如果没有安装,可以先运行:

install.packages("ggplot2")
install.packages("dplyr")
install.packages("GGally")
install.packages("corrplot")
install.packages("vcd")

加载基础包:

library(ggplot2)
library(dplyr)

Attaching package: 'dplyr'
The following objects are masked from 'package:stats':

    filter, lag
The following objects are masked from 'package:base':

    intersect, setdiff, setequal, union

检查后面会用到的扩展包:

if (!requireNamespace("GGally", quietly = TRUE)) {
  message("未安装 GGally,散点图矩阵部分将不会绘图。")
}

if (!requireNamespace("corrplot", quietly = TRUE)) {
  message("未安装 corrplot,相关图部分将不会绘图。")
}

if (!requireNamespace("vcd", quietly = TRUE)) {
  message("未安装 vcd,vcd 示例代码仅展示,不影响本文运行。")
}

3. 创建示例数据

我们创建一个学生数据集。

set.seed(123)

student <- data.frame(
  id = 1:120,
  class = rep(c("一班", "二班", "三班"), each = 40),
  gender = sample(c("男", "女"), 120, replace = TRUE),
  group = sample(c("实验组", "对照组"), 120, replace = TRUE),
  chinese = round(rnorm(120, mean = 82, sd = 8), 1),
  math = round(rnorm(120, mean = 80, sd = 10), 1),
  english = round(rnorm(120, mean = 84, sd = 7), 1),
  height = round(rnorm(120, mean = 168, sd = 8), 1),
  weight = round(rnorm(120, mean = 62, sd = 10), 1)
)

student$total <- student$chinese + student$math + student$english
student$average <- round(student$total / 3, 1)

student$class <- factor(
  student$class,
  levels = c("一班", "二班", "三班"),
  ordered = TRUE
)

head(student,5)
  id class gender  group chinese math english height weight total average
1  1  一班     男 实验组    82.9 72.1    82.6  168.2   72.7 237.6    79.2
2  2  一班     男 对照组    74.4 75.0    88.6  170.5   61.7 238.0    79.3
3  3  一班     男 实验组    78.1 95.0    85.9  178.6   61.7 259.0    86.3
4  4  一班     女 实验组    80.0 68.6    91.2  169.0   46.8 239.8    79.9
5  5  一班     男 实验组    96.8 78.2    89.7  173.7   69.9 264.7    88.2

查看数据结构:

str(student)
'data.frame':   120 obs. of  11 variables:
 $ id     : int  1 2 3 4 5 6 7 8 9 10 ...
 $ class  : Ord.factor w/ 3 levels "一班"<"二班"<..: 1 1 1 1 1 1 1 1 1 1 ...
 $ gender : chr  "男" "男" "男" "女" ...
 $ group  : chr  "实验组" "对照组" "实验组" "实验组" ...
 $ chinese: num  82.9 74.4 78.1 80 96.8 76.8 83.9 82.6 74.3 81.4 ...
 $ math   : num  72.1 75 95 68.6 78.2 99 79 66.4 73.4 84.9 ...
 $ english: num  82.6 88.6 85.9 91.2 89.7 82.5 86.6 77.4 90 80.8 ...
 $ height : num  168 170 179 169 174 ...
 $ weight : num  72.7 61.7 61.7 46.8 69.9 59.9 55.4 47.9 59 53.5 ...
 $ total  : num  238 238 259 240 265 ...
 $ average: num  79.2 79.3 86.3 79.9 88.2 86.1 83.2 75.5 79.2 82.4 ...

4. 图形标注、标尺、主题与刻面

本节主要学习如何在 ggplot2 图形中添加标注,并对图形进行常见修改,包括:

  1. 添加文字标注;
  2. 只标注部分数据点;
  3. 给条形图添加数值标注;
  4. 添加参考线和参考线说明文字;
  5. 修改坐标轴标尺;
  6. 修改图形主题;
  7. 使用刻面展示分组图形。

4.1 什么是图形标注?

图形标注就是在图中添加文字说明,例如:

  • 给某个点添加编号;
  • 给柱子添加数值;
  • 标出高分学生;
  • 添加参考线;
  • 给参考线添加说明文字;
  • 在图中添加解释性文本。

常用函数如下:

函数 作用
geom_text() 添加普通文字
geom_label() 添加带边框的标签
annotate() 添加固定文字或图形
geom_vline() 添加竖直参考线
geom_hline() 添加水平参考线
geom_abline() 添加斜线

4.2 散点图 + 文字标注

先画一个语文成绩和数学成绩的基础散点图。

ggplot(student, aes(x = chinese, y = math)) +
  geom_point() +
  labs(
    title = "语文成绩与数学成绩散点图",
    x = "语文成绩",
    y = "数学成绩"
  ) +
  theme_minimal()

如果想给每个点标注学生编号,可以使用 geom_text()

ggplot(student, aes(x = chinese, y = math)) +
  geom_point(color = "steelblue") +
  geom_text(
    aes(label = id),
    vjust = -0.5,
    size = 3
  ) +
  labs(
    title = "语文成绩与数学成绩散点图:标注学生编号",
    x = "语文成绩",
    y = "数学成绩"
  ) +
  theme_minimal()

说明:

  • geom_point() 用来画散点;
  • geom_text() 用来添加文字;
  • aes(label = id) 表示把学生编号作为文字标签;
  • vjust = -0.5 表示文字显示在点的上方。

注意:如果点很多,不建议给每个点都添加文字标注,否则图形会比较拥挤。


4.3 只标注高分学生

实际绘图时,更常见的做法是只标注部分重点数据。

例如,只标注平均分大于 95 的学生。

high_student <- student %>%
  filter(average > 95)

high_student
   id class gender  group chinese math english height weight total average
1 111  三班     女 实验组    97.6 90.1    97.8  145.5   72.6 285.5    95.2

画图:

ggplot(student, aes(x = chinese, y = math)) +
  geom_point(color = "grey50", alpha = 0.7) +
  geom_point(
    data = high_student,
    color = "red",
    size = 3
  ) +
  geom_text(
    data = high_student,
    aes(label = id),
    vjust = -0.6,
    color = "red",
    size = 4
  ) +
  labs(
    title = "只标注平均分大于95的学生",
    x = "语文成绩",
    y = "数学成绩"
  ) +
  theme_minimal()

解释:

  • 第一层 geom_point() 画所有学生;
  • 第二层 geom_point(data = high_student) 突出高分学生;
  • 第三层 geom_text(data = high_student) 给高分学生加标签。

4.4 使用 geom_label() 添加标签

geom_label()geom_text() 类似,但它会给文字添加一个标签框。

ggplot(student, aes(x = chinese, y = math)) +
  geom_point(color = "grey50", alpha = 0.7) +
  geom_label(
    data = high_student,
    aes(label = paste0("ID=", id)),
    fill = "yellow",
    color = "red",
    size = 3
  ) +
  labs(
    title = "使用 geom_label() 标注高分学生",
    x = "语文成绩",
    y = "数学成绩"
  ) +
  theme_minimal()

说明:

  • fill = "yellow" 控制标签框的填充颜色;
  • color = "red" 控制文字颜色;
  • paste0("ID=", id) 把编号写成 ID=编号 的形式。

4.5 条形图 + 数值标注

除了散点图,条形图也经常需要添加数值标注。

下面先计算每个班级的平均分。

class_avg <- student %>%
  group_by(class) %>%
  summarise(
    avg_score = mean(average, na.rm = TRUE),  #每个班级的平均分,忽视缺失值
    .groups = "drop"   #手动关闭分组,把数据变回普通数据框。
  )

class_avg
# A tibble: 3 × 2
  class avg_score
  <ord>     <dbl>
1 一班       81.9
2 二班       82.6
3 三班       82.3

画条形图,并在柱子上方添加平均分数值。

ggplot(class_avg, aes(x = class, y = avg_score, fill = class)) +
  geom_col(width = 0.6) +
  geom_text(
    aes(label = round(avg_score, 1)),
    vjust = -0.5,
    size = 4
  ) +
  scale_y_continuous(
    limits = c(0, 100),
    breaks = seq(0, 100, 20)
  ) +
  labs(
    title = "不同班级平均成绩比较",
    x = "班级",
    y = "平均成绩"
  ) +
  theme_minimal() +
  theme(
    legend.position = "none"
  )

解释:

  • geom_col() 用于画已经汇总好的柱形图;
  • geom_text() 用于给柱子添加数值;
  • label = round(avg_score, 1) 表示平均分保留一位小数;
  • vjust = -0.5 表示文字放在柱子上方;
  • legend.position = "none" 表示去掉图例。

4.6 添加参考线

参考线可以帮助读者快速判断数据是否超过某个标准。

下面添加数学 80 分横线和语文 80 分竖线。

ggplot(student, aes(x = chinese, y = math)) +
  geom_point(color = "steelblue", alpha = 0.7) +
  geom_hline(
    yintercept = 80,
    linetype = "dashed",
    color = "red"
  ) +
  geom_vline(
    xintercept = 80,
    linetype = "dashed",
    color = "red"
  ) +
  labs(
    title = "语文和数学成绩散点图:添加80分参考线",
    x = "语文成绩",
    y = "数学成绩"
  ) +
  theme_minimal()

说明:

  • geom_hline(yintercept = 80) 添加水平参考线;
  • geom_vline(xintercept = 80) 添加竖直参考线;
  • linetype = "dashed" 表示虚线。

4.7 参考线 + 文字标注

如果只添加参考线,有时读者不一定知道参考线代表什么。
这时可以使用 annotate() 给参考线添加说明文字。

ggplot(student, aes(x = chinese, y = math)) +
  geom_point(color = "steelblue", alpha = 0.7) +
  geom_hline(
    yintercept = 80,
    linetype = "dashed",
    color = "red"
  ) +
  geom_vline(
    xintercept = 80,
    linetype = "dashed",
    color = "red"
  ) +
  annotate(
    "text",
    x = 95,
    y = 82,
    label = "数学80分参考线",
    color = "red",
    size = 4,
    hjust = 1          #hjust = 0 → 左对齐,hjust = 0.5 → 居中(默认),hjust = 1 → 右对齐
  ) +
  annotate(
    "text",
    x = 82,
    y = 60,
    label = "语文80分参考线",
    color = "red",
    size = 4,
    angle = 90,      # 文字旋转90度 → 竖起来了
    hjust = 0       #hjust = 0 → 左对齐,hjust = 0.5 → 居中(默认),hjust = 1 → 右对齐
  ) +
  labs(
    title = "语文和数学成绩散点图:参考线与文字说明",
    x = "语文成绩",
    y = "数学成绩"
  ) +
  theme_minimal()

解释:

  • annotate("text", ...) 可以在图中添加固定文字;
  • xy 控制文字位置;
  • label 控制文字内容;
  • angle = 90 可以让文字旋转 90 度;
  • hjust 控制文字的水平对齐方式。

4.8 修改坐标轴标尺

坐标轴标尺包括坐标轴范围、刻度间隔和坐标轴名称。

例如,把语文和数学成绩的坐标轴范围都设置为 50 到 110,并每隔 10 分显示一个刻度。

ggplot(student, aes(x = chinese, y = math)) +
  geom_point(aes(color = class), alpha = 0.7, size = 2) +
  scale_x_continuous(
    name = "语文成绩",
    limits = c(50, 110),
    breaks = seq(50, 110, 10)
  ) +
  scale_y_continuous(
    name = "数学成绩",
    limits = c(50, 110),
    breaks = seq(50, 110, 10)
  ) +
  labs(
    title = "修改坐标轴范围和刻度",
    color = "班级"
  ) +
  theme_minimal()

说明:

  • limits = c(50, 110) 设置坐标轴范围;
  • breaks = seq(50, 110, 10) 设置刻度;
  • name = "语文成绩" 设置坐标轴名称。

注意:使用 scale_x_continuous(limits = ...)scale_y_continuous(limits = ...) 时,超出范围的数据会被删除。

如果只是想改变显示范围,而不删除数据,可以使用 coord_cartesian()

ggplot(student, aes(x = chinese, y = math)) +
  geom_point(aes(color = class), alpha = 0.7, size = 2) +
  coord_cartesian(
    xlim = c(50, 110),
    ylim = c(50, 110)
  ) +
  labs(
    title = "使用 coord_cartesian() 修改显示范围",
    x = "语文成绩",
    y = "数学成绩",
    color = "班级"
  ) +
  theme_minimal()

两种方法的区别如下:

方法 特点
scale_x_continuous(limits = ...) 超出范围的数据会被删除
coord_cartesian(xlim = ...) 只是缩放显示区域,不删除数据

一般情况下,如果只是想放大或缩小图形显示区域,更推荐使用 coord_cartesian()


4.9 修改图形主题

ggplot2 提供了多种主题,可以快速改变图形风格。

先保存一个基础图形对象:

p_theme <- ggplot(student, aes(x = chinese, y = math, color = class)) +
  geom_point(size = 2, alpha = 0.7) +
  labs(
    title = "不同主题效果比较",
    x = "语文成绩",
    y = "数学成绩",
    color = "班级"
  )

使用简洁主题:

p_theme + theme_minimal()

使用经典主题:

p_theme + theme_classic()

使用黑白主题:

p_theme + theme_bw()

使用浅色主题:

p_theme + theme_light()

常见主题如下:

主题 特点
theme_minimal() 简洁
theme_classic() 经典坐标轴
theme_bw() 黑白主题
theme_light() 浅色网格
theme_void() 去掉坐标轴和背景

也可以在主题中进一步修改文字大小、标题样式和图例位置。

ggplot(student, aes(x = chinese, y = math, color = class)) +
  geom_point(size = 2, alpha = 0.7) +
  labs(
    title = "精细修改图形主题",
    subtitle = "颜色表示班级",
    x = "语文成绩",
    y = "数学成绩",
    color = "班级"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(size = 18, face = "bold"),
    plot.subtitle = element_text(size = 13),
    axis.title = element_text(size = 14),
    axis.text = element_text(size = 12),
    legend.position = "bottom"
  )


4.10 使用刻面展示分组图形

刻面可以把数据按照某个分类变量拆分成多个小图,方便比较不同组之间的差异。

例如,按照班级分别展示语文成绩和数学成绩的关系。

ggplot(student, aes(x = chinese, y = math)) +
  geom_point(color = "steelblue", alpha = 0.7, size = 2) +
  facet_wrap(~ class) +
  scale_x_continuous(
    limits = c(50, 110),
    breaks = seq(50, 110, 20)
  ) +
  scale_y_continuous(
    limits = c(50, 110),
    breaks = seq(50, 110, 20)
  ) +
  labs(
    title = "不同班级中语文成绩与数学成绩的关系",
    x = "语文成绩",
    y = "数学成绩"
  ) +
  theme_minimal()

说明:

facet_wrap(~ class)

表示按照 class 变量进行分面。

如果想按照实验组和对照组分面,也可以写:

ggplot(student, aes(x = chinese, y = math, color = class)) +
  geom_point(alpha = 0.7, size = 2) +
  facet_wrap(~ group) +
  labs(
    title = "按照实验组和对照组分面的散点图",
    x = "语文成绩",
    y = "数学成绩",
    color = "班级"
  ) +
  theme_minimal()

如果想同时按照两个分类变量分面,可以使用 facet_grid()

ggplot(student, aes(x = chinese, y = math)) +
  geom_point(color = "steelblue", alpha = 0.7, size = 2) +
  facet_grid(gender ~ class) +
  labs(
    title = "按照性别和班级分面的散点图",
    x = "语文成绩",
    y = "数学成绩"
  ) +
  theme_minimal()

解释:

facet_grid(gender ~ class)

表示:

  • 行方向按照 gender 分组;
  • 列方向按照 class 分组。

4.11 本节小结

本节常用代码如下:

# 添加普通文字
geom_text(aes(label = 变量名))

# 添加带边框标签
geom_label(aes(label = 变量名))

# 添加固定说明文字
annotate("text", x = 位置, y = 位置, label = "说明文字")

# 添加水平参考线
geom_hline(yintercept = 数值)

# 添加竖直参考线
geom_vline(xintercept = 数值)

# 修改坐标轴标尺
scale_x_continuous(limits = c(最小值, 最大值), breaks = seq(...))
scale_y_continuous(limits = c(最小值, 最大值), breaks = seq(...))

# 修改显示范围但不删除数据
coord_cartesian(xlim = c(最小值, 最大值), ylim = c(最小值, 最大值))

# 修改主题
theme_minimal()
theme_classic()
theme_bw()
theme_light()

# 按一个变量分面
facet_wrap(~ 分组变量)

# 按两个变量分面
facet_grid(行变量 ~ 列变量)

一句话总结:

标注让图形更容易解释,标尺和主题让图形更美观,刻面让分组比较更清楚。

5. 气泡图

5.1 什么是气泡图?

气泡图本质上是散点图。

区别是:

散点图用 x 和 y 表示两个变量;
气泡图额外用点的大小表示第三个变量。

例如:

  • 横轴:语文成绩;
  • 纵轴:数学成绩;
  • 气泡大小:英语成绩;
  • 颜色:班级。

5.2 基础气泡图

ggplot(student, aes(x = chinese, y = math, size = english)) +
  geom_point(alpha = 0.6) +
  labs(
    title = "气泡图:语文、数学和英语成绩",
    x = "语文成绩",
    y = "数学成绩",
    size = "英语成绩"
  ) +
  theme_minimal()


5.3 分组气泡图

ggplot(student, aes(x = chinese, y = math, size = english, color = class)) +
  geom_point(alpha = 0.6) +
  labs(
    title = "气泡图:颜色表示班级,大小表示英语成绩",
    x = "语文成绩",
    y = "数学成绩",
    size = "英语成绩",
    color = "班级"
  ) +
  theme_minimal()


5.4 调整气泡大小范围

ggplot(student, aes(x = chinese, y = math, size = english, color = class)) +
  geom_point(alpha = 0.6) +
  scale_size_continuous(range = c(2, 10)) +
  labs(
    title = "调整气泡大小范围",
    x = "语文成绩",
    y = "数学成绩",
    size = "英语成绩",
    color = "班级"
  ) +
  theme_minimal()

解释:

scale_size_continuous(range = c(2, 10))

表示最小气泡大小为 2,最大气泡大小为 10。


5.5 气泡图 + 趋势线

ggplot(student, aes(x = chinese, y = math)) +
  geom_point(
    aes(size = english, color = class),
    alpha = 0.5
    ) +
  geom_smooth(
    aes(group = 1),
    method = "lm",
    se = TRUE,
    color = "black",
    linewidth = 1
  ) +
  scale_size_continuous(range = c(2, 10)) +
  labs(
    title = "气泡图 + 总体线性趋势线",
    x = "语文成绩",
    y = "数学成绩",
    size = "英语成绩",
    color = "班级"
  ) +
  theme_minimal()
`geom_smooth()` using formula = 'y ~ x'

解释:

  • method = "lm" 表示添加线性回归趋势线;
  • aes(group = 1) 表示画一条总体趋势线,而不是每个班级一条。

6. 分组散点图

6.1 什么是分组散点图?

分组散点图是在散点图中用颜色、形状或分面表示不同组。

例如:

  • 用颜色表示班级;
  • 用形状表示性别;
  • 用分面分别展示实验组和对照组。

6.2 用颜色分组

ggplot(student, aes(x = chinese, y = math, color = class)) +
  geom_point(size = 2, alpha = 0.7) +
  labs(
    title = "分组散点图:颜色表示班级",
    x = "语文成绩",
    y = "数学成绩",
    color = "班级"
  ) +
  theme_minimal()


6.3 用形状分组

ggplot(student, aes(x = chinese, y = math, shape = gender)) +
  geom_point(size = 2, alpha = 0.7) +
  labs(
    title = "分组散点图:形状表示性别",
    x = "语文成绩",
    y = "数学成绩",
    shape = "性别"
  ) +
  theme_minimal()


6.4 颜色 + 形状同时分组

ggplot(student, aes(x = chinese, y = math, color = class, shape = gender)) +
  geom_point(size = 2.5, alpha = 0.8) +
  labs(
    title = "分组散点图:颜色表示班级,形状表示性别",
    x = "语文成绩",
    y = "数学成绩",
    color = "班级",
    shape = "性别"
  ) +
  theme_minimal()


6.5 分组散点图 + 趋势线

每个班级一条趋势线:

ggplot(student, aes(x = chinese, y = math, color = class)) +
  geom_point(size = 2, alpha = 0.7) +
  geom_smooth(method = "lm", se = FALSE) +
  labs(
    title = "不同班级语文与数学关系趋势线",
    x = "语文成绩",
    y = "数学成绩",
    color = "班级"
  ) +
  theme_minimal()
`geom_smooth()` using formula = 'y ~ x'

只画一条总体趋势线:

ggplot(student, aes(x = chinese, y = math, color = class)) +
  geom_point(size = 2, alpha = 0.7) +
  geom_smooth(
    aes(group = 1),
    method = "lm",
    se = FALSE,
    color = "black"
  ) +
  labs(
    title = "分组散点图 + 总体趋势线",
    x = "语文成绩",
    y = "数学成绩",
    color = "班级"
  ) +
  theme_minimal()
`geom_smooth()` using formula = 'y ~ x'


6.6 分面散点图

ggplot(student, aes(x = chinese, y = math, color = class)) +
  geom_point(size = 2, alpha = 0.7) +
  facet_wrap(~ group) +
  labs(
    title = "按照实验组/对照组分面的散点图",
    x = "语文成绩",
    y = "数学成绩",
    color = "班级"
  ) +
  theme_minimal()


7. 散点图矩阵

7.1 什么是散点图矩阵?

散点图矩阵用于同时查看多个连续变量之间的关系。

例如同时查看:

  • 语文;
  • 数学;
  • 英语;
  • 身高;
  • 体重;
  • 平均分。

散点图矩阵适合初步探索多个数值变量之间的相关关系。


7.2 使用 GGally::ggpairs()

选择数值变量:

score_vars <- student %>%
  select(chinese, math, english, height, weight, average)

head(score_vars,5)
  chinese math english height weight average
1    82.9 72.1    82.6  168.2   72.7    79.2
2    74.4 75.0    88.6  170.5   61.7    79.3
3    78.1 95.0    85.9  178.6   61.7    86.3
4    80.0 68.6    91.2  169.0   46.8    79.9
5    96.8 78.2    89.7  173.7   69.9    88.2

画散点图矩阵:

GGally::ggpairs(score_vars)


7.3 分组散点图矩阵

如果想按班级上色,可以把班级变量也放进去。

score_vars_group <- student %>%
  select(class, chinese, math, english, height, weight, average)


GGally::ggpairs(
    score_vars_group,
    aes(color = class, alpha = 0.6)
)
`stat_bin()` using `bins = 30`. Pick better value `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value `binwidth`.
`stat_bin()` using `bins = 30`. Pick better value `binwidth`.


7.4 只选择部分变量画矩阵

变量太多时图会很拥挤,建议只选 3 到 5 个变量。

  GGally::ggpairs(
    student,
    columns = c("chinese", "math", "english", "average"),
    aes(color = class, alpha = 0.6)
  )


8. 相关图

8.1 什么是相关图?

相关图用于展示多个连续变量之间的相关系数。

相关系数一般在 -11 之间:

相关系数 含义
接近 1 强正相关
接近 -1 强负相关
接近 0 几乎无线性相关

8.2 计算相关矩阵

先选择连续变量:

num_data <- student %>%
  select(chinese, math, english, height, weight, total, average)

head(num_data,5)
  chinese math english height weight total average
1    82.9 72.1    82.6  168.2   72.7 237.6    79.2
2    74.4 75.0    88.6  170.5   61.7 238.0    79.3
3    78.1 95.0    85.9  178.6   61.7 259.0    86.3
4    80.0 68.6    91.2  169.0   46.8 239.8    79.9
5    96.8 78.2    89.7  173.7   69.9 264.7    88.2

计算相关矩阵:

cor_matrix <- cor(num_data)

cor_matrix
            chinese        math     english      height      weight       total
chinese  1.00000000 -0.14768260 -0.07193383 -0.05882792 -0.07526751  0.43858303
math    -0.14768260  1.00000000 -0.06183304  0.02451594 -0.05947660  0.65813324
english -0.07193383 -0.06183304  1.00000000 -0.14474227  0.12703379  0.43501978
height  -0.05882792  0.02451594 -0.14474227  1.00000000  0.10953662 -0.09179652
weight  -0.07526751 -0.05947660  0.12703379  0.10953662  1.00000000 -0.02399884
total    0.43858303  0.65813324  0.43501978 -0.09179652 -0.02399884  1.00000000
average  0.43862909  0.65812300  0.43494255 -0.09298285 -0.02430803  0.99997867
            average
chinese  0.43862909
math     0.65812300
english  0.43494255
height  -0.09298285
weight  -0.02430803
total    0.99997867
average  1.00000000

8.3 处理缺失值时计算相关

如果数据有 NA,建议写:

cor_matrix <- cor(num_data, use = "complete.obs")

或者:

cor_matrix <- cor(num_data, use = "pairwise.complete.obs")

含义:

参数 含义
"complete.obs" 只使用完整行
"pairwise.complete.obs" 每一对变量分别使用非缺失值

8.4 使用 corrplot 画相关图

  corrplot::corrplot(cor_matrix)


8.5 美化相关图

  corrplot::corrplot(
    cor_matrix,
    method = "color",
    type = "upper",
    addCoef.col = "black",
    tl.col = "black",
    tl.srt = 45,
    number.cex = 0.8
  )

解释:

参数 含义
method = "color" 用颜色表示相关大小
type = "upper" 只显示上三角
addCoef.col = "black" 添加相关系数数字
tl.col = "black" 变量名颜色
tl.srt = 45 变量名旋转 45 度
number.cex = 0.8 数字大小

8.6 圆形相关图

  corrplot::corrplot(
    cor_matrix,
    method = "circle",
    type = "upper",
    addCoef.col = "black",
    tl.col = "black",
    tl.srt = 45
  )


9. 马赛克图

9.1 什么是马赛克图?

马赛克图用于展示两个或多个分类变量之间的关系。

例如:

班级和性别是否有关?

它适合分类变量。

比如:

  • 班级 vs 性别;
  • 地区 vs 渠道;
  • 是否购买 vs 性别;
  • 是否及格 vs 班级。

9.2 创建分类变量:是否优秀

先创建一个是否优秀变量:

student <- student %>%
  mutate(
    excellent = ifelse(average >= 85, "优秀", "非优秀")
  )

table(student$class, student$excellent)
      
       非优秀 优秀
  一班     29   11
  二班     29   11
  三班     29   11

9.3 基础马赛克图

基础 R 自带 mosaicplot()

tab_class_excellent <- table(student$class, student$excellent)

mosaicplot(
  tab_class_excellent,
  main = "班级与是否优秀的马赛克图",
  xlab = "班级",
  ylab = "是否优秀",
  color = TRUE
)

解释:

  • 每个矩形的面积表示人数比例;
  • 如果某一块面积大,说明该组合人数多;
  • 这里的颜色主要用于区分类别组合。

9.4 三个分类变量的马赛克图

例如同时查看:

  • 班级;
  • 性别;
  • 是否优秀。
tab3 <- table(student$class, student$gender, student$excellent)

mosaicplot(
  tab3,
  main = "班级、性别与是否优秀的马赛克图",
  color = TRUE
)

解释:

  • 该图展示班级、性别和是否优秀三个分类变量的联合分布;
  • 每个矩形区域对应一个类别组合;
  • 矩形面积越大,表示该组合中的学生人数越多。

9.5 使用 vcd 包画马赛克图,代码展示,不自动执行

vcd 包中的 mosaic() 函数可以绘制功能更丰富的马赛克图。

例如:

  • 可以设置 shade = TRUE 根据残差着色;
  • 可以设置 legend = TRUE 显示残差图例;
  • 可以用于分析分类变量组合是否明显偏离独立性假设。

但是在某些中文标签或多维列联表场景下,vcd::mosaic() 在 Knit 时可能出现如下报错:

missing value where TRUE/FALSE needed

为了保证本文顺利 Knit,这里只展示 vcd::mosaic() 代码,不自动执行。

library(vcd)
Loading required package: grid
tab3_vcd <- xtabs(~ class + gender + excellent, data = student)

vcd::mosaic(
  tab3_vcd,
  shade = TRUE,
  legend = TRUE,
  direction = c("v", "h", "v"),
  main = "班级、性别与是否优秀的马赛克图"
)

解释:

参数 含义
shade = TRUE 根据残差着色
legend = TRUE 显示残差图例
direction 指定切分方向
main 图形标题

注意:

  • mosaicplot(color = TRUE) 的颜色主要是区分类别区域;
  • vcd::mosaic(shade = TRUE) 的颜色表示残差方向和大小;
  • 两者统计含义不完全一样。

10. 图形修改与美化

下面集中讲一些常见修改方法。


10.1 修改标题和坐标轴名称

ggplot(student, aes(x = chinese, y = math)) +
  geom_point(color = "steelblue") +
  labs(
    title = "语文成绩与数学成绩的关系",
    subtitle = "示例数据:120名学生",
    caption = "数据来源:模拟数据",
    x = "语文成绩",
    y = "数学成绩"
  ) +
  theme_minimal()


10.2 修改颜色

ggplot(student, aes(x = chinese, y = math, color = class)) +
  geom_point(size = 2) +
  scale_color_manual(
    values = c(
      "一班" = "#E64B35",
      "二班" = "#4DBBD5",
      "三班" = "#00A087"
    )
  ) +
  labs(
    title = "手动修改颜色",
    x = "语文成绩",
    y = "数学成绩",
    color = "班级"
  ) +
  theme_minimal()


10.3 修改填充色

柱形图、盒形图、小提琴图通常用 fill

ggplot(student, aes(x = class, y = average, fill = class)) +
  geom_boxplot(alpha = 0.7) +
  scale_fill_manual(
    values = c(
      "一班" = "#F8766D",
      "二班" = "#7CAE00",
      "三班" = "#00BFC4"
    )
  ) +
  labs(
    title = "手动修改填充颜色",
    x = "班级",
    y = "平均分"
  ) +
  theme_minimal()


10.4 修改点的形状和大小

ggplot(student, aes(x = chinese, y = math, color = class, shape = gender)) +
  geom_point(size = 3, alpha = 0.8) +
  labs(
    title = "修改点的形状和大小",
    x = "语文成绩",
    y = "数学成绩",
    color = "班级",
    shape = "性别"
  ) +
  theme_minimal()


10.5 修改坐标轴范围

ggplot(student, aes(x = chinese, y = math)) +
  geom_point(color = "steelblue") +
  scale_x_continuous(limits = c(50, 110)) +
  scale_y_continuous(limits = c(50, 110)) +
  labs(
    title = "修改坐标轴范围",
    x = "语文成绩",
    y = "数学成绩"
  ) +
  theme_minimal()

也可以用:

ggplot(student, aes(x = chinese, y = math)) +
  geom_point(color = "steelblue") +
  coord_cartesian(
    xlim = c(50, 110),
    ylim = c(50, 110)
  ) +
  labs(
    title = "使用 coord_cartesian() 修改显示范围",
    x = "语文成绩",
    y = "数学成绩"
  ) +
  theme_minimal()

区别:

方法 特点
scale_x_continuous(limits = ...) 超出范围的数据会被删除
coord_cartesian(xlim = ...) 只是缩放显示区域,不删除数据

一般推荐用:

coord_cartesian()

10.6 修改主题

p <- ggplot(student, aes(x = chinese, y = math, color = class)) +
  geom_point(size = 2, alpha = 0.7) +
  labs(
    title = "不同主题效果",
    x = "语文成绩",
    y = "数学成绩",
    color = "班级"
  )

p + theme_minimal()

p + theme_classic()

p + theme_bw()

p + theme_light()

常见主题:

主题 特点
theme_minimal() 简洁
theme_classic() 经典坐标轴
theme_bw() 黑白主题
theme_light() 浅色网格
theme_void() 去掉坐标轴和背景

10.7 修改图例位置

ggplot(student, aes(x = chinese, y = math, color = class)) +
  geom_point(size = 2) +
  labs(
    title = "图例放到底部",
    x = "语文成绩",
    y = "数学成绩",
    color = "班级"
  ) +
  theme_minimal() +
  theme(
    legend.position = "bottom"
  )

去掉图例:

ggplot(student, aes(x = chinese, y = math, color = class)) +
  geom_point(size = 2) +
  labs(
    title = "去掉图例",
    x = "语文成绩",
    y = "数学成绩"
  ) +
  theme_minimal() +
  theme(
    legend.position = "none"
  )


10.8 修改文字大小

ggplot(student, aes(x = chinese, y = math, color = class)) +
  geom_point(size = 2) +
  labs(
    title = "修改文字大小",
    x = "语文成绩",
    y = "数学成绩",
    color = "班级"
  ) +
  theme_minimal(base_size = 16)

更精细地修改:

ggplot(student, aes(x = chinese, y = math, color = class)) +
  geom_point(size = 2) +
  labs(
    title = "精细修改文字大小",
    x = "语文成绩",
    y = "数学成绩",
    color = "班级"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(size = 18, face = "bold"),
    axis.title = element_text(size = 14),
    axis.text = element_text(size = 12),
    legend.title = element_text(size = 13),
    legend.text = element_text(size = 11)
  )


10.9 旋转横轴文字

ggplot(student, aes(x = class, y = average, fill = class)) +
  geom_boxplot() +
  labs(
    title = "旋转横轴文字",
    x = "班级",
    y = "平均分"
  ) +
  theme_minimal() +
  theme(
    axis.text.x = element_text(angle = 45, hjust = 1)
  )

解释:

参数 含义
angle = 45 旋转 45 度
hjust = 1 右对齐

10.10 修改图形背景和网格线

ggplot(student, aes(x = chinese, y = math, color = class)) +
  geom_point(size = 2) +
  labs(
    title = "修改背景和网格线",
    x = "语文成绩",
    y = "数学成绩",
    color = "班级"
  ) +
  theme_minimal() +
  theme(
    panel.grid.major = element_line(color = "grey80"),
    panel.grid.minor = element_blank(),
    panel.background = element_rect(fill = "white", color = NA),
    plot.background = element_rect(fill = "white", color = NA)
  )


11. 保存图片

推荐先把图保存成对象。

p_scatter <- ggplot(student, aes(x = chinese, y = math, color = class)) +
  geom_point(size = 2, alpha = 0.7) +
  labs(
    title = "语文成绩与数学成绩的关系",
    x = "语文成绩",
    y = "数学成绩",
    color = "班级"
  ) +
  theme_minimal()

p_scatter

保存图片:

ggsave(
  filename = "scatter_plot.png",
  plot = p_scatter,
  width = 6,
  height = 4,
  dpi = 300
)

保存为 PDF:

ggsave(
  filename = "scatter_plot.pdf",
  plot = p_scatter,
  width = 6,
  height = 4
)

12. 常见错误

12.1 报错:could not find function “ggplot”

原因:没有加载 ggplot2

解决:

library(ggplot2)

12.2 报错:could not find function “ggpairs”

原因:没有安装或没有加载 GGally

解决:

install.packages("GGally")
library(GGally)

或者使用:

GGally::ggpairs(data)

12.3 报错:could not find function “corrplot”

原因:没有安装或没有加载 corrplot

解决:

install.packages("corrplot")
library(corrplot)

或者使用:

corrplot::corrplot(cor_matrix)

12.4 报错:object ‘x’ not found

原因:代码里用了不存在的变量名。

例如:

ggplot(student, aes(x = x, y = y)) +
  geom_point()

student 里面没有 xy 这两个变量。

解决:

names(student)

先查看真实变量名,然后改成真实变量:

ggplot(student, aes(x = chinese, y = math)) +
  geom_point()

12.5 报错:Discrete value supplied to continuous scale

意思是:

你把分类变量传给了连续型坐标轴或连续型颜色刻度。

例如:

ggplot(student, aes(x = class, y = average)) +
  geom_point() +
  scale_x_continuous()

class 是分类变量,不能用 scale_x_continuous()

应该用:

scale_x_discrete()

或者直接不写。


12.6 vcd::mosaic() 报错:missing value where TRUE/FALSE needed

原因通常是 vcd::mosaic() 在处理多维列联表、中文标签或切分方向时出现兼容性问题。

可能报错:

Error in if (split_vertical[i]) ...:
missing value where TRUE/FALSE needed

解决方法:

  1. 使用基础 R 的 mosaicplot()
  2. 或者在 vcd::mosaic() 中明确设置 direction
  3. 如果是在 R Markdown 中 Knit,建议先把 vcd::mosaic() 设置为 eval=FALSE
  4. 等确认控制台能正常运行后,再考虑打开执行。

示例:

vcd::mosaic(
  tab,
  shade = TRUE,
  legend = TRUE,
  direction = c("v", "h")
)

13. 小练习

创建一份销售数据:

set.seed(456)

sales <- data.frame(
  id = 1:150,
  region = sample(c("华东", "华北", "华南"), 150, replace = TRUE),
  channel = sample(c("线上", "线下"), 150, replace = TRUE),
  category = sample(c("食品", "服装", "电子"), 150, replace = TRUE),
  price = round(rnorm(150, mean = 100, sd = 20), 1),
  quantity = sample(1:10, 150, replace = TRUE)
)

sales$amount <- round(sales$price * sales$quantity, 1)

sales
     id region channel category price quantity amount
1     1   华东    线上     电子 108.1        4  432.4
2     2   华东    线下     服装 134.8        8 1078.4
3     3   华南    线上     服装 101.2        3  303.6
4     4   华北    线下     电子 112.1        7  784.7
5     5   华东    线下     服装  96.8        6  580.8
6     6   华南    线上     服装  88.7        7  620.9
7     7   华东    线上     食品  86.0        9  774.0
8     8   华北    线上     食品  92.7        1   92.7
9     9   华南    线上     电子  96.2        9  865.8
10   10   华北    线上     服装  73.5        7  514.5
11   11   华东    线上     电子 109.3        2  218.6
12   12   华南    线上     食品 133.7        7  935.9
13   13   华北    线下     服装 116.0        7  812.0
14   14   华南    线下     电子 118.1        2  236.2
15   15   华南    线上     食品 120.2        2  240.4
16   16   华南    线下     食品 120.1        4  480.4
17   17   华北    线上     服装 123.6        3  370.8
18   18   华北    线上     电子 105.9        7  741.3
19   19   华东    线下     服装 117.3        3  351.9
20   20   华东    线上     服装  74.8        1   74.8
21   21   华北    线上     电子  77.7        3  233.1
22   22   华南    线上     电子 133.5        2  267.0
23   23   华东    线上     电子  80.7        8  645.6
24   24   华东    线上     电子 127.6        2  255.2
25   25   华北    线下     食品 138.1        3  414.3
26   26   华东    线下     服装 118.7        3  356.1
27   27   华东    线下     食品  96.1        8  768.8
28   28   华北    线下     电子 119.9        3  359.7
29   29   华北    线下     服装 134.8        4  539.2
30   30   华南    线下     服装 128.4        9 1155.6
31   31   华北    线上     食品  90.2        3  270.6
32   32   华南    线下     食品 120.0        9 1080.0
33   33   华东    线下     电子  94.3        7  660.1
34   34   华北    线上     电子  98.2        6  589.2
35   35   华东    线上     电子 133.5        4  534.0
36   36   华南    线下     食品 123.1        2  246.2
37   37   华北    线下     服装 116.7        6  700.2
38   38   华南    线上     电子 128.6        4  514.4
39   39   华北    线下     服装 107.9       10 1079.0
40   40   华北    线下     电子  84.2        8  673.6
41   41   华南    线下     电子 116.6        4  466.4
42   42   华北    线上     电子  94.0        5  470.0
43   43   华南    线上     服装 101.1        7  707.7
44   44   华南    线上     服装 115.0        3  345.0
45   45   华东    线下     服装  84.2        2  168.4
46   46   华东    线上     电子 130.1        5  650.5
47   47   华东    线上     电子  89.4        6  536.4
48   48   华北    线上     服装 104.9        6  629.4
49   49   华北    线上     电子 103.7        1  103.7
50   50   华南    线下     食品 125.9        3  377.7
51   51   华南    线上     服装 127.0        1  127.0
52   52   华北    线下     食品  63.6        2  127.2
53   53   华北    线上     食品  79.7        7  557.9
54   54   华东    线上     电子 115.5        3  346.5
55   55   华南    线上     食品  95.1        8  760.8
56   56   华南    线下     服装  84.7        5  423.5
57   57   华北    线上     食品 123.7        2  247.4
58   58   华南    线下     服装 111.4        8  891.2
59   59   华南    线下     服装 105.0        7  735.0
60   60   华东    线上     食品  73.3        5  366.5
61   61   华南    线上     服装  77.0       10  770.0
62   62   华东    线上     服装 149.1        7 1043.7
63   63   华北    线上     电子 103.7        9  933.3
64   64   华东    线下     电子  91.2        3  273.6
65   65   华东    线下     服装  98.8        3  296.4
66   66   华北    线下     食品 146.4        6  878.4
67   67   华南    线下     食品 112.9       10 1129.0
68   68   华南    线下     服装 106.4        4  425.6
69   69   华东    线下     食品  78.8        6  472.8
70   70   华东    线下     服装  62.8        1   62.8
71   71   华北    线下     食品 105.6        8  844.8
72   72   华北    线上     电子  94.6        5  473.0
73   73   华南    线上     食品 112.6       10 1126.0
74   74   华东    线下     电子  59.0        2  118.0
75   75   华北    线上     电子 107.7        9  969.3
76   76   华南    线上     食品 118.8        7  831.6
77   77   华东    线上     服装 119.2       10 1192.0
78   78   华南    线上     服装  74.1        8  592.8
79   79   华北    线上     服装 104.0        4  416.0
80   80   华东    线下     服装 127.9       10 1279.0
81   81   华北    线下     食品  91.1        8  728.8
82   82   华北    线上     食品  93.1        4  372.4
83   83   华南    线上     食品  73.2       10  732.0
84   84   华东    线上     食品 106.5        2  213.0
85   85   华北    线上     电子 106.9        7  748.3
86   86   华南    线上     电子 121.8        7  852.6
87   87   华南    线下     食品  78.3        4  313.2
88   88   华北    线下     食品 123.0        2  246.0
89   89   华东    线下     服装  75.4       10  754.0
90   90   华东    线上     电子 126.9        1  126.9
91   91   华东    线下     服装  80.6        6  483.6
92   92   华东    线下     服装 138.1       10 1381.0
93   93   华东    线下     电子 106.7        5  533.5
94   94   华东    线上     食品  72.2        5  361.0
95   95   华东    线上     服装  91.4        3  274.2
96   96   华南    线上     电子  99.1       10  991.0
97   97   华北    线下     食品  94.3        4  377.2
98   98   华南    线上     服装  99.0        9  891.0
99   99   华北    线上     服装  78.2        2  156.4
100 100   华南    线上     食品  88.6        8  708.8
101 101   华南    线下     电子 122.1        8  976.8
102 102   华东    线上     食品 125.1        4  500.4
103 103   华东    线上     服装  70.2        9  631.8
104 104   华南    线上     服装 126.9        5  634.5
105 105   华东    线上     食品 101.5        5  507.5
106 106   华南    线下     电子  67.8        3  203.4
107 107   华东    线上     服装 109.8        7  768.6
108 108   华东    线下     服装 103.0        3  309.0
109 109   华东    线下     电子 110.4        6  662.4
110 110   华东    线下     食品  90.5        1   90.5
111 111   华北    线上     服装 102.7        9  924.3
112 112   华东    线下     电子 102.8        7  719.6
113 113   华东    线下     食品 113.0        1  113.0
114 114   华北    线下     电子 105.6        5  528.0
115 115   华北    线下     食品 100.0        6  600.0
116 116   华北    线下     服装  82.4       10  824.0
117 117   华东    线上     服装  53.5        2  107.0
118 118   华北    线上     服装 124.0        3  372.0
119 119   华北    线上     食品  90.3        3  270.9
120 120   华南    线上     食品 110.2        9  991.8
121 121   华东    线下     服装 105.1        3  315.3
122 122   华东    线上     食品  74.1        8  592.8
123 123   华东    线下     食品 110.0        3  330.0
124 124   华北    线下     食品 121.0        6  726.0
125 125   华南    线下     服装  95.1        3  285.3
126 126   华东    线下     电子  71.2       10  712.0
127 127   华东    线上     电子  81.9        4  327.6
128 128   华东    线下     食品 117.2        5  586.0
129 129   华东    线下     食品  83.6        3  250.8
130 130   华东    线下     服装  70.6       10  706.0
131 131   华北    线上     电子 103.6        9  932.4
132 132   华东    线下     食品 102.9        7  720.3
133 133   华南    线下     服装  78.9        2  157.8
134 134   华北    线上     电子  75.5        5  377.5
135 135   华东    线上     电子  87.2        7  610.4
136 136   华南    线下     电子 104.5        5  522.5
137 137   华北    线下     食品 106.3        4  425.2
138 138   华东    线下     电子  94.1        9  846.9
139 139   华北    线上     服装  66.7        5  333.5
140 140   华南    线上     食品 136.2        3  408.6
141 141   华东    线上     电子 119.1        4  476.4
142 142   华东    线上     电子  82.1        7  574.7
143 143   华南    线下     食品  75.7        9  681.3
144 144   华东    线上     电子 110.1        9  990.9
145 145   华北    线下     电子 117.8        5  589.0
146 146   华南    线上     电子  90.9        4  363.6
147 147   华东    线下     电子 105.8        2  211.6
148 148   华北    线上     食品  94.8        3  284.4
149 149   华东    线下     服装 109.5        7  766.5
150 150   华北    线下     电子  95.7        4  382.8

请完成:

  1. 画价格和销售额的散点图,并标注销售额最高的 5 个订单;
  2. 画气泡图:横轴价格,纵轴销售额,气泡大小为数量,颜色为地区;
  3. 画价格、数量、销售额的散点图矩阵;
  4. 画分组散点图:颜色为地区,形状为渠道;
  5. 计算价格、数量、销售额的相关矩阵并画相关图;
  6. 画地区和渠道的马赛克图;
  7. 修改图形标题、颜色、主题和图例位置。

14. 小练习参考答案

14.1 标注销售额最高的 5 个订单

top5_sales <- sales %>%
  arrange(desc(amount)) %>%
  slice(1:5)

top5_sales
  id region channel category price quantity amount
1 92   华东    线下     服装 138.1       10 1381.0
2 80   华东    线下     服装 127.9       10 1279.0
3 77   华东    线上     服装 119.2       10 1192.0
4 30   华南    线下     服装 128.4        9 1155.6
5 67   华南    线下     食品 112.9       10 1129.0
ggplot(sales, aes(x = price, y = amount)) +
  geom_point(color = "grey50", alpha = 0.7) +
  geom_point(
    data = top5_sales,
    color = "red",
    size = 3
  ) +
  geom_label(
    data = top5_sales,
    aes(label = paste0("ID=", id)),
    fill = "yellow",
    color = "red",
    size = 3
  ) +
  labs(
    title = "价格与销售额散点图:标注最高销售额订单",
    x = "价格",
    y = "销售额"
  ) +
  theme_minimal()


14.2 气泡图

ggplot(sales, aes(x = price, y = amount, size = quantity, color = region)) +
  geom_point(alpha = 0.6) +
  scale_size_continuous(range = c(2, 10)) +
  labs(
    title = "气泡图:价格、销售额与购买数量",
    x = "价格",
    y = "销售额",
    size = "数量",
    color = "地区"
  ) +
  theme_minimal()


14.3 散点图矩阵

if (requireNamespace("GGally", quietly = TRUE)) {
  GGally::ggpairs(
    sales,
    columns = c("price", "quantity", "amount")
  )
} else {
  message("未安装 GGally,因此不绘制销售数据散点图矩阵。")
}

分组散点图矩阵:

if (requireNamespace("GGally", quietly = TRUE)) {
  GGally::ggpairs(
    sales,
    columns = c("price", "quantity", "amount"),
    aes(color = region, alpha = 0.6)
  )
} else {
  message("未安装 GGally,因此不绘制销售数据分组散点图矩阵。")
}


14.4 分组散点图

ggplot(sales, aes(x = price, y = amount, color = region, shape = channel)) +
  geom_point(size = 2.5, alpha = 0.8) +
  labs(
    title = "价格与销售额分组散点图",
    x = "价格",
    y = "销售额",
    color = "地区",
    shape = "渠道"
  ) +
  theme_minimal()


14.5 相关图

sales_num <- sales %>%
  select(price, quantity, amount)

sales_cor <- cor(sales_num)

sales_cor
               price    quantity    amount
price     1.00000000 -0.06722087 0.2881969
quantity -0.06722087  1.00000000 0.9157241
amount    0.28819690  0.91572410 1.0000000
if (requireNamespace("corrplot", quietly = TRUE)) {
  corrplot::corrplot(
    sales_cor,
    method = "color",
    type = "upper",
    addCoef.col = "black",
    tl.col = "black",
    tl.srt = 45
  )
} else {
  message("未安装 corrplot,因此不绘制销售数据相关图。")
}


14.6 马赛克图

基础 R 写法:

tab_region_channel <- table(sales$region, sales$channel)

mosaicplot(
  tab_region_channel,
  main = "地区与渠道的马赛克图",
  xlab = "地区",
  ylab = "渠道",
  color = TRUE
)

解释:

  • 该图展示地区和渠道两个分类变量的联合分布;
  • 矩形面积越大,表示该地区与该渠道组合下的订单数越多。

14.7 使用 vcd 绘制马赛克图,代码展示,不自动执行

如果想使用 vcd::mosaic(),可以参考下面代码。

为避免 Knit 报错,这里设置为 eval=FALSE

library(vcd)

vcd::mosaic(
  tab_region_channel,
  shade = TRUE,
  legend = TRUE,
  direction = c("v", "h"),
  main = "地区与渠道的马赛克图"
)

说明:

  • shade = TRUE 表示根据残差着色;
  • legend = TRUE 表示显示残差图例;
  • direction = c("v", "h") 指定二维表的切分方向;
  • 如果控制台运行正常,可以再考虑让 R Markdown 执行该代码。

14.8 图形修改示例

ggplot(sales, aes(x = price, y = amount, color = region, shape = channel)) +
  geom_point(size = 3, alpha = 0.75) +
  scale_color_manual(
    values = c(
      "华东" = "#E64B35",
      "华北" = "#4DBBD5",
      "华南" = "#00A087"
    )
  ) +
  labs(
    title = "价格与销售额关系",
    subtitle = "颜色表示地区,形状表示渠道",
    caption = "数据来源:模拟销售数据",
    x = "商品价格",
    y = "销售额",
    color = "地区",
    shape = "渠道"
  ) +
  theme_classic(base_size = 14) +
  theme(
    legend.position = "bottom",
    plot.title = element_text(face = "bold", size = 18),
    plot.subtitle = element_text(size = 13),
    axis.title = element_text(size = 14)
  )


15. 本节核心代码总结

下面是模板代码,只展示,不运行。

# 加载包
library(ggplot2)
library(dplyr)

# 1. 散点图 + 标注
ggplot(df, aes(x = x_var, y = y_var)) +
  geom_point() +
  geom_text(aes(label = label_var))

# 2. 只标注部分点
label_df <- df %>%
  filter(condition)

ggplot(df, aes(x = x_var, y = y_var)) +
  geom_point() +
  geom_point(data = label_df, color = "red") +
  geom_label(data = label_df, aes(label = label_var))

# 3. 添加参考线
ggplot(df, aes(x = x_var, y = y_var)) +
  geom_point() +
  geom_hline(yintercept = 80, linetype = "dashed") +
  geom_vline(xintercept = 80, linetype = "dashed")

# 4. 添加说明文字
ggplot(df, aes(x = x_var, y = y_var)) +
  geom_point() +
  annotate("text", x = 10, y = 20, label = "说明文字")

# 5. 气泡图
ggplot(df, aes(x = x_var, y = y_var, size = size_var, color = group_var)) +
  geom_point(alpha = 0.6) +
  scale_size_continuous(range = c(2, 10))

# 6. 分组散点图
ggplot(df, aes(x = x_var, y = y_var, color = group_var, shape = type_var)) +
  geom_point()

# 7. 分组散点图 + 趋势线
ggplot(df, aes(x = x_var, y = y_var, color = group_var)) +
  geom_point() +
  geom_smooth(method = "lm", se = FALSE)

# 8. 分面散点图
ggplot(df, aes(x = x_var, y = y_var, color = group_var)) +
  geom_point() +
  facet_wrap(~ facet_var)

# 9. 散点图矩阵
GGally::ggpairs(
  df,
  columns = c("x1", "x2", "x3")
)

# 10. 分组散点图矩阵
GGally::ggpairs(
  df,
  columns = c("x1", "x2", "x3"),
  aes(color = group_var, alpha = 0.6)
)

# 11. 相关矩阵
num_df <- df %>%
  select(x1, x2, x3)

cor_matrix <- cor(num_df, use = "complete.obs")

# 12. 相关图
corrplot::corrplot(
  cor_matrix,
  method = "color",
  type = "upper",
  addCoef.col = "black"
)

# 13. 基础马赛克图
tab <- table(df$group1, df$group2)

mosaicplot(
  tab,
  main = "马赛克图",
  color = TRUE
)

# 14. vcd 马赛克图
# 注意:在某些中文标签或多维列联表场景下可能需要额外设置。
# 建议先在控制台单独测试,再放入 R Markdown 中执行。

library(vcd)

vcd::mosaic(
  tab,
  shade = TRUE,
  legend = TRUE,
  direction = c("v", "h"),
  main = "vcd 马赛克图"
)

# 15. 修改标题
ggplot(df, aes(x = x_var, y = y_var)) +
  geom_point() +
  labs(
    title = "标题",
    subtitle = "副标题",
    caption = "注释",
    x = "横轴名称",
    y = "纵轴名称"
  )

# 16. 修改颜色
ggplot(df, aes(x = x_var, y = y_var, color = group_var)) +
  geom_point() +
  scale_color_manual(values = c("A" = "red", "B" = "blue"))

# 17. 修改主题和图例
ggplot(df, aes(x = x_var, y = y_var, color = group_var)) +
  geom_point() +
  theme_minimal() +
  theme(
    legend.position = "bottom",
    plot.title = element_text(size = 18, face = "bold")
  )

# 18. 保存图片
ggsave(
  filename = "plot.png",
  plot = p,
  width = 6,
  height = 4,
  dpi = 300
)

16. 一句话总结

本节最常用代码如下:

geom_text()
geom_label()
annotate()

用于给图添加文字标注。

ggplot(df, aes(x, y, size = z)) +
  geom_point()

用于画气泡图。

GGally::ggpairs()

用于画散点图矩阵。

corrplot::corrplot()

用于画相关图。

mosaicplot()

用于绘制基础马赛克图。

vcd::mosaic()

也可以绘制更丰富的马赛克图,并支持残差着色;但在某些中文标签或多维表情况下可能需要额外设置。为了保证本文 Knit 稳定,正文中 vcd::mosaic() 只作为代码示例展示,不自动执行。

图形修改最常用的是:

labs()
theme()
scale_color_manual()
scale_fill_manual()
theme_minimal()
theme_classic()