R语言基础:二维数据可视化

图形类型、图形含义、plot 与 ggplot2 语法详解

尹俊贺

本节课内容

这节课讲二维数据可视化的核心内容:

  • 什么是二维图形
  • 为什么不同问题要用不同的图
  • base R 的 plot() 系统怎么理解
  • ggplot2 的图层结构怎么理解
  • 条形图、饼图、直方图、密度图、箱线图、散点图、折线图、分面图
  • 每一种图要看什么
  • 每一种图最常见的误区是什么

为什么可视化重要?

数据分析不是只会“算”。

更重要的是:

  • 发现结构
  • 展示关系
  • 比较差异
  • 观察分布
  • 解释结果

表格擅长展示精确值, 图形擅长展示整体模式。

所以可视化既是展示工具,也是分析工具。

什么叫二维图形?

二维图形,就是在一个平面中表达信息。

通常包含两个基本方向:

  • 横轴(x)
  • 纵轴(y)

有些图虽然还能映射颜色、形状、大小, 但它们的主要结构仍然是二维的。

二维图最常见的任务包括:

  • 比较类别
  • 观察分布
  • 分析两个变量关系
  • 看时间趋势
  • 看分组差异

想回答什么问题?

  • 比较
  • 比例
  • 分布
  • 关系
  • 变化

变量是什么类型?

  • 数值型变量
  • 类别型变量
  • 时间变量

读图时最重要的信息是什么?

  • 高低差异
  • 集中位置
  • 离散程度
  • 相关方向
  • 趋势变化

这张图会不会误导?

  • 图选对了吗?
  • 变量类型处理对了吗?
  • 坐标标签清楚吗?
  • 图形能否支持你想说的话?

本节课用到的数据

主要使用 R 自带数据集:

  • mtcars:汽车数据,适合讲散点图、条形图、箱线图
  • iris:分类数据,适合讲分组概念
  • airquality:连续变量,适合讲分布
  • economics:时间序列,适合讲折线图

先看数据

head(mtcars)
                   mpg cyl disp  hp drat    wt  qsec vs am gear carb
Mazda RX4         21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
Mazda RX4 Wag     21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
Datsun 710        22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
Hornet 4 Drive    21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
Hornet Sportabout 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
Valiant           18.1   6  225 105 2.76 3.460 20.22  1  0    3    1
head(iris)
  Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1          5.1         3.5          1.4         0.2  setosa
2          4.9         3.0          1.4         0.2  setosa
3          4.7         3.2          1.3         0.2  setosa
4          4.6         3.1          1.5         0.2  setosa
5          5.0         3.6          1.4         0.2  setosa
6          5.4         3.9          1.7         0.4  setosa
head(airquality)
  Ozone Solar.R Wind Temp Month Day
1    41     190  7.4   67     5   1
2    36     118  8.0   72     5   2
3    12     149 12.6   74     5   3
4    18     313 11.5   62     5   4
5    NA      NA 14.3   56     5   5
6    28      NA 14.9   66     5   6

变量类型必须先看清楚

str(mtcars)
'data.frame':   32 obs. of  11 variables:
 $ mpg : num  21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
 $ cyl : num  6 6 4 6 8 6 8 4 4 6 ...
 $ disp: num  160 160 108 258 360 ...
 $ hp  : num  110 110 93 110 175 105 245 62 95 123 ...
 $ drat: num  3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
 $ wt  : num  2.62 2.88 2.32 3.21 3.44 ...
 $ qsec: num  16.5 17 18.6 19.4 17 ...
 $ vs  : num  0 0 1 1 0 1 0 1 1 1 ...
 $ am  : num  1 1 1 0 0 0 0 0 0 0 ...
 $ gear: num  4 4 4 3 3 3 3 4 4 4 ...
 $ carb: num  4 4 1 1 2 1 4 2 2 4 ...

一个初学者非常容易犯的错是:

看到数字,就默认它是连续变量。

但其实有些数字只是“编码”,更适合当类别处理。

例如:

  • cyl:4、6、8,表示不同气缸类别
  • am:0、1,表示不同变速箱类型
  • gear:3、4、5,表示档位类别

这些变量在很多图里最好转成 factor。

先做一份适合画图的数据

mtcars2 <- mtcars |>
  mutate(
    cyl = factor(cyl),
    am = factor(am, labels = c("Automatic", "Manual")),
    gear = factor(gear)
  )

str(mtcars2)
'data.frame':   32 obs. of  11 variables:
 $ mpg : num  21 21 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 ...
 $ cyl : Factor w/ 3 levels "4","6","8": 2 2 1 2 3 2 3 1 1 2 ...
 $ disp: num  160 160 108 258 360 ...
 $ hp  : num  110 110 93 110 175 105 245 62 95 123 ...
 $ drat: num  3.9 3.9 3.85 3.08 3.15 2.76 3.21 3.69 3.92 3.92 ...
 $ wt  : num  2.62 2.88 2.32 3.21 3.44 ...
 $ qsec: num  16.5 17 18.6 19.4 17 ...
 $ vs  : num  0 0 1 1 0 1 0 1 1 1 ...
 $ am  : Factor w/ 2 levels "Automatic","Manual": 2 2 2 1 1 1 1 1 1 1 ...
 $ gear: Factor w/ 3 levels "3","4","5": 2 2 2 1 1 1 1 2 2 2 ...
 $ carb: num  4 4 1 1 2 1 4 2 2 4 ...

一、base R 图形系统:plot() 怎么理解

plot() 不是“只有一种图”

很多人一开始会以为 plot() 就是“画散点图”。

更准确地说,plot() 是 base R 中最基础的通用绘图入口。 它会根据你传入的数据类型和参数,画出不同图形。

最基本形式是:

plot(x, y)

xy 都是数值向量时, 它通常会画出散点图。

plot() 的最基本含义

plot(mtcars$wt, mtcars$mpg)

这句代码的含义是:

  • 横轴使用 wt
  • 纵轴使用 mpg

图中的每一个点代表一个观测值,也就是一辆车。

这是最基本的二维关系图。

plot() 常见参数总览

plot(x, y,
     main = "title",
     xlab = "x label",
     ylab = "y label",
     col = "blue",
     pch = 19,
     cex = 1.2,
     lwd = 2,
     type = "p",
     xlim = c(...),
     ylim = c(...))

这些参数分别控制不同部分。

mainxlabylab

plot(
  mtcars$wt, mtcars$mpg,
  main = "Weight vs MPG",
  xlab = "Weight",
  ylab = "MPG"
)

含义:

  • main:图标题
  • xlab:x轴标签
  • ylab:y轴标签

这三个参数几乎是最基本的标注。

如果不写,图可以画出来; 但如果拿去上课或做报告,图往往不够完整。

colpchcex

plot(
  mtcars$wt, mtcars$mpg,
  main = "Weight vs MPG",
  xlab = "Weight",
  ylab = "MPG",
  col = "steelblue",
  pch = 19,
  cex = 1.3
)

含义:

  • col:颜色
  • pch:点的形状
  • cex:点的大小倍数

其中:

  • pch = 1 常见为空心圆
  • pch = 1619 常见为实心点
  • cex > 1 表示点变大
  • cex < 1 表示点变小

type 参数:决定图形呈现方式

plot() 很重要的一个参数是 type

常见取值:

  • "p":points,点图
  • "l":line,线图
  • "b":both,点和线
  • "h":vertical lines,垂直线
  • "n":先建立坐标系但不真正画图

type = "l":折线图

plot(
  AirPassengers,
  type = "l",
  main = "AirPassengers",
  ylab = "Passengers"
)

type = "l" 时, plot() 会把相邻观测用线连起来。

这就特别适合时间序列或有顺序的数据。

lwdxlimylim

plot(
  mtcars$wt, mtcars$mpg,
  main = "Weight vs MPG",
  xlab = "Weight",
  ylab = "MPG",
  col = "steelblue",
  pch = 19,
  cex = 1.2,
  xlim = c(1.5, 5.8),
  ylim = c(10, 35)
)

含义:

  • lwd:线宽,在线图中最明显
  • xlim:x轴显示范围
  • ylim:y轴显示范围

坐标范围的设置会影响图的视觉效果, 所以要谨慎,不要人为制造夸张差异。

一个较完整的 plot() 示例

plot(
  mtcars$wt, mtcars$mpg,
  main = "Weight vs MPG",
  xlab = "Weight",
  ylab = "Miles Per Gallon",
  col = "steelblue",
  pch = 19,
  cex = 1.2
)

这张图已经包含:

  • 数据映射
  • 标题
  • 坐标标签
  • 点样式

它是一张完整的基础散点图。

plot() 后继续加元素

base R 的一个重要特点是:

先画一张图,再往上加东西。

例如可以加:

  • 回归线:abline()
  • 新的点:points()
  • 文字:text()
  • 图例:legend()

plot() 加回归线

plot(
  mtcars$wt, mtcars$mpg,
  main = "Weight vs MPG",
  xlab = "Weight",
  ylab = "MPG",
  col = "steelblue",
  pch = 19
)

abline(lm(mpg ~ wt, data = mtcars), col = "red", lwd = 2)

这里:

  • lm(mpg ~ wt, data = mtcars) 是拟合线性模型
  • abline() 把这条回归直线画上去
  • col 控制回归线颜色
  • lwd 控制回归线粗细

二、ggplot2 图形系统:整体结构

ggplot2 的核心思想

ggplot2 和 base R 最大的区别是:

  • base R 更像“直接下命令画图”
  • ggplot2 更像“先搭图,再叠图层”

它的基本逻辑是:

图 = 数据 + 映射 + 几何对象 + 标签 + 主题

ggplot2 的基本模板

ggplot(data = 数据框, aes(x = 变量1, y = 变量2)) +
  geom_某种图形() +
  labs(...) +
  theme(...)

这是理解 ggplot2 的核心模板。

ggplot():指定数据

ggplot(mtcars, aes(x = wt, y = mpg))

这句本身不会完整生成最终图, 它更像是在告诉 R:

  • 我要用 mtcars 这个数据集
  • 我要把 wt 放到 x 轴
  • 我要把 mpg 放到 y 轴

也就是说,它先建立“绘图框架”。

aes():美学映射

aes() 是 aesthetics 的缩写。 通常翻译为“美学映射”或“图形映射”。

它的意思是:

把变量映射到视觉属性上。

最常见的是:

  • x
  • y
  • color
  • fill
  • shape
  • size
  • alpha

aes(x = wt, y = mpg) 的含义

ggplot(mtcars, aes(x = wt, y = mpg)) +
  geom_point()

这里表示:

  • wt 映射到 x 轴
  • mpg 映射到 y 轴

再加上 geom_point(), 就表示把这些点画成散点图。

aes() 里和外的区别

这是 ggplot2 最重要也最容易混淆的地方之一。

写在 aes() 里面

表示“映射”

例如:

aes(color = cyl)

表示颜色随着 cyl 不同而变化。

写在 aes() 外面

表示“固定设置”

例如:

color = "red"

表示所有点都用红色。

例子:映射颜色

ggplot(mtcars2, aes(x = wt, y = mpg, color = cyl)) +
  geom_point(size = 3)

这里:

  • 颜色是变量 cyl 的视觉映射
  • 不同气缸数组会显示不同颜色

因此,颜色在这里携带信息。

例子:固定颜色

ggplot(mtcars2, aes(x = wt, y = mpg)) +
  geom_point(size = 3, color = "steelblue")

这里:

  • 颜色只是样式设置
  • 它不代表任何变量信息

所以你要让学生分清楚:

映射是“数据驱动”,固定是“样式设置”。

geom_*():几何对象

geom 是 geometry 的缩写。 它表示:要把数据画成什么图形。

常见的 geom 包括:

  • geom_bar():条形图
  • geom_point():散点图
  • geom_line():折线图
  • geom_histogram():直方图
  • geom_boxplot():箱线图
  • geom_density():密度图
  • geom_smooth():拟合线

labs():标签系统

labs() 用来设置:

  • 标题 title
  • 副标题 subtitle
  • x轴名 x
  • y轴名 y
  • 图例标题 color / fill

例如:

labs(
  title = "Weight vs MPG",
  subtitle = "Scatter plot",
  x = "Weight",
  y = "MPG",
  color = "Cylinder"
)

theme():整体样式

theme() 用来控制图的非数据部分外观, 例如:

  • 字体
  • 网格线
  • 图例位置
  • 标题样式
  • 背景

theme_minimal()theme_classic()theme_bw() 等是预设主题。

一个完整的 ggplot 示例

ggplot(mtcars2, aes(x = wt, y = mpg, color = cyl)) +
  geom_point(size = 3) +
  labs(
    title = "Weight vs MPG",
    subtitle = "Color represents cylinder categories",
    x = "Weight",
    y = "MPG",
    color = "Cylinders"
  )

这个例子里:

  • ggplot():指定数据与映射
  • geom_point():决定画成散点图
  • labs():补全标题和标签
  • 颜色映射表达第三个变量

三、条形图 Bar Chart

条形图的用途

条形图最适合展示:

类别之间的比较

它擅长回答:

  • 哪一类最多?
  • 哪一类最少?
  • 类别之间差距大不大?

它不适合表达连续变量的细致分布。

什么时候用条形图?

典型场景:

  • 不同专业人数
  • 不同政党席位数
  • 不同地区样本量
  • 问卷选项频数

条形图的核心是:比较离散类别

先统计不同 cyl 的数量

table(mtcars2$cyl)

 4  6  8 
11  7 14 

这一步不是画图, 而是先看清楚频数结构。

base R:条形图

barplot(
  table(mtcars2$cyl),
  main = "Number of Cars by Cylinder",
  xlab = "Cylinder",
  ylab = "Count",
  col = c("#a8dadc", "#457b9d", "#1d3557")
)

base R barplot() 代码解释

这里的组成是:

  • table(mtcars2$cyl):先统计每个类别的数量
  • main:图标题
  • xlab:横轴名称
  • ylab:纵轴名称
  • col:柱子的颜色

也就是说,barplot() 本身通常需要一个已经统计好的向量或表。

ggplot2:条形图

ggplot(mtcars2, aes(x = cyl, fill = cyl)) +
  geom_bar(width = 0.7, alpha = 0.9) +
  labs(
    title = "不同气缸数汽车的数量比较",
    subtitle = "条形图用于展示类别频数差异",
    x = "气缸数",
    y = "数量"
  ) +
  guides(fill = "none")

geom_bar() 的语法解释

这里:

  • ggplot(mtcars2, aes(x = cyl, fill = cyl))

    • 数据是 mtcars2
    • 横轴是 cyl
    • 填充颜色也根据 cyl 变化
  • geom_bar()

    • 默认会自动统计每个类别的数量
    • 所以这里不需要提前 table()
  • width = 0.7

    • 控制柱子宽度
  • alpha = 0.9

    • 控制透明度

条形图应该怎么看?

看到条形图,重点看:

  1. 哪个柱子最高
  2. 哪个柱子最低
  3. 组间差距是否明显
  4. 某些类别是否样本过少

它表达的是“类别之间的差异”, 而不是变量的连续变化过程。

条形图最容易和什么混淆?

最容易和直方图混淆。

条形图

  • 横轴是类别
  • 柱子彼此分开
  • 看类别比较

直方图

  • 横轴是连续区间
  • 柱子通常连在一起
  • 看分布

这点一定要专门讲。

四、饼图 Pie Chart

饼图的用途

饼图用来展示:

整体中各部分所占比例

整个圆代表 100%, 每一个扇形代表某一类占整体的份额。

什么时候适合用饼图?

饼图适合:

  • 类别较少
  • 强调整体构成
  • 强调比例而不是精确比较

例如:

  • 各专业占比
  • 市场份额
  • 支出结构
  • 投票比例

什么时候不适合用饼图?

饼图不适合:

  • 类别太多
  • 需要精确比较
  • 各组差异很小
  • 想表达时间趋势

如果你想做精确比较, 条形图通常比饼图更清楚。

base R:饼图

counts <- c(15, 25, 30, 20)
labels <- c("Economics", "Finance", "CS", "Math")

pie(
  counts,
  labels = labels,
  col = c("#8ecae6", "#219ebc", "#023047", "#ffb703"),
  main = "Major Distribution"
)

pie() 代码解释

这里:

  • counts

    • 每一类的数量
  • labels

    • 每个扇形的标签
  • col

    • 每个扇形的颜色
  • main

    • 图标题

pie() 会自动把数量换算成比例面积。

带百分比的饼图

counts <- c(15, 25, 30, 20)
pct <- round(counts / sum(counts) * 100)
labels_pct <- paste(c("Economics", "Finance", "CS", "Math"), pct, "%")

pie(
  counts,
  labels = labels_pct,
  col = c("#8ecae6", "#219ebc", "#023047", "#ffb703"),
  main = "Major Distribution with Percentages"
)

这段代码为什么这样写?

这里的关键步骤是:

  • sum(counts):计算总数
  • counts / sum(counts):得到比例
  • * 100:转为百分比
  • round():四舍五入
  • paste(...):把类别名和百分比拼成标签

这样画出来的饼图更容易直接读。

ggplot2:饼图的原理

ggplot2 没有单独的“饼图函数”。

它的思路是:

先画条形图,再把坐标系转成极坐标

也就是说,饼图本质上是“条形图的极坐标版本”。

ggplot2:饼图代码

df_pie <- data.frame(
  category = c("A", "B", "C", "D"),
  value = c(10, 20, 30, 40)
)

ggplot(df_pie, aes(x = "", y = value, fill = category)) +
  geom_bar(stat = "identity", width = 1) +
  coord_polar("y") +
  theme_void() +
  labs(
    title = "Pie Chart with ggplot2",
    fill = "Category"
  )

ggplot2 饼图逐行解释

  • aes(x = "", y = value, fill = category)

    • x 写成空字符串,表示所有柱子堆叠在同一位置
    • y 是真实数值
    • fill 决定不同类别颜色
  • geom_bar(stat = "identity", width = 1)

    • stat = "identity" 表示使用数据本身的数值
    • width = 1 让柱子填满整个圆周
  • coord_polar("y")

    • 把直角坐标变成极坐标
    • 条形图因此变成饼图
  • theme_void()

    • 去掉背景和坐标轴

饼图应该怎么看?

重点看:

  1. 哪个扇区最大
  2. 哪个扇区最小
  3. 是否存在主导类别
  4. 整体是否相对均衡

它强调的是“整体构成”, 而不是非常精细的数值差别。

五、直方图 Histogram

直方图的用途

直方图用来展示:

一个连续变量在不同区间中的分布情况

它回答的问题包括:

  • 数据集中在哪?
  • 分布宽不宽?
  • 是否对称?
  • 是否偏斜?
  • 是否可能有多个峰?

为什么直方图重要?

因为在做数据分析时, 你经常要先问:

这个变量长什么样?

直方图就是最经典的单变量分布观察工具之一。

base R:直方图

hist(
  mtcars2$mpg,
  breaks = 8,
  main = "Distribution of MPG",
  xlab = "Miles Per Gallon",
  col = "#8ecae6",
  border = "white"
)

hist() 代码解释

  • mtcars2$mpg

    • 要观察分布的连续变量
  • breaks = 8

    • 把数据分成 8 组区间
  • main

    • 标题
  • xlab

    • 横轴名称
  • col

    • 柱子填充色
  • border

    • 柱子边框颜色

直方图怎么看?

横轴表示:

  • 连续变量的区间

纵轴表示:

  • 落在该区间内的观测数量

所以它看的不是“类别多少”, 而是“数据集中在哪些范围”。

读直方图时看什么?

重点看五件事:

  1. 集中位置:大多数数据在哪个区间
  2. 离散程度:分布宽还是窄
  3. 对称性:左右是否平衡
  4. 偏态:左尾长还是右尾长
  5. 峰数:单峰还是多峰

这几乎就是认识一个变量分布的基本框架。

ggplot2:直方图

ggplot(mtcars2, aes(x = mpg)) +
  geom_histogram(
    binwidth = 2,
    fill = "#48bfe3",
    color = "white",
    linewidth = 0.6
  ) +
  labs(
    title = "MPG 的分布",
    subtitle = "直方图用于展示连续变量在区间上的频数分布",
    x = "MPG",
    y = "频数"
  )

geom_histogram() 代码解释

这里:

  • aes(x = mpg):指定要观察分布的连续变量
  • geom_histogram():画直方图
  • binwidth = 2:每个区间宽度为 2
  • fill:柱子颜色
  • color:边框颜色
  • linewidth:边框线粗细

和 base R 的 breaks 类似, binwidth 也会直接影响图的样子。

为什么 binwidth 很重要?

如果 binwidth 太小:

  • 图会过碎
  • 噪声会变多

如果 binwidth 太大:

  • 图会太粗
  • 细节会消失

所以直方图并不是“唯一客观”的, 它会受到分组方式影响。

六、密度图 Density Plot

密度图的用途

密度图也用于观察连续变量分布。

和直方图相比:

  • 直方图强调区间频数
  • 密度图强调平滑后的整体形状

它更适合看:

  • 分布峰的位置
  • 分布是否平滑
  • 两组分布是否不同

ggplot2:单变量密度图

ggplot(mtcars2, aes(x = mpg)) +
  geom_density(
    fill = "#b7e4c7",
    alpha = 0.7,
    linewidth = 1
  ) +
  labs(
    title = "MPG 的密度分布",
    subtitle = "密度图展示连续变量的平滑分布形状",
    x = "MPG",
    y = "Density"
  )

geom_density() 代码解释

  • aes(x = mpg):指定连续变量
  • geom_density():画密度曲线
  • fill:曲线下面填充颜色
  • alpha:透明度
  • linewidth:曲线线宽

与直方图不同,这里不需要指定区间数量, 因为它用的是平滑估计。

密度图应该怎么读?

密度图的纵轴不是“人数”或“频数”, 而是“密度”。

初学阶段不用把它讲得太数学化。 只需要记住:

  • 曲线越高,数据在该区域越集中
  • 曲线越低,数据在该区域越少
  • 峰值位置代表常见数值区域

分组密度图

ggplot(mtcars2, aes(x = mpg, fill = am)) +
  geom_density(alpha = 0.4, linewidth = 1) +
  labs(
    title = "不同变速箱类型下 MPG 的分布",
    subtitle = "分组密度图适合比较不同类别的连续变量分布",
    x = "MPG",
    y = "Density",
    fill = "Transmission"
  )

分组密度图怎么看?

你可以看:

  1. 哪一组整体更靠左或更靠右
  2. 哪一组更宽,说明组内差异更大
  3. 是否有多峰,说明内部可能有子结构

这比只比较平均值更丰富, 因为它展示的是“整个分布”。

七、箱线图 Boxplot

箱线图的用途

箱线图是一种压缩型分布图。 它特别适合做组间比较。

它能够同时展示:

  • 中心位置
  • 离散程度
  • 偏态
  • 异常值

为什么箱线图重要?

如果你只用条形图比较均值, 很多分布信息都会丢失。

箱线图能让你看到:

  • 组内是否稳定
  • 组间差异来自哪里
  • 是否存在异常值

所以它在正式分析中很常见。

base R:单变量箱线图

boxplot(
  mtcars2$mpg,
  main = "Boxplot of MPG",
  ylab = "MPG",
  col = "#ffd166"
)

boxplot() 这张图怎么看?

箱线图里最重要的几部分:

  • 中间那条线:中位数
  • 箱体下边:第一四分位数
  • 箱体上边:第三四分位数
  • 箱体本身:中间 50% 数据范围
  • 须:正常范围内更远的数据
  • 单独的小点:可能的异常值

ggplot2:分组箱线图

ggplot(mtcars2, aes(x = am, y = mpg, fill = am)) +
  geom_boxplot(width = 0.6, alpha = 0.85) +
  labs(
    title = "不同变速箱类型的 MPG 分布",
    subtitle = "箱线图适合比较组间中心位置、离散程度与异常值",
    x = "变速箱类型",
    y = "MPG",
    fill = "Transmission"
  )

geom_boxplot() 代码解释

  • x = am

    • 表示按变速箱类型分组
  • y = mpg

    • 表示每组内观察 mpg 分布
  • fill = am

    • 不同组用不同填充色
  • width = 0.6

    • 箱体宽度
  • alpha = 0.85

    • 透明度

分组箱线图要看什么?

重点看:

  1. 中位数谁更高
  2. 哪组箱体更高,说明更分散
  3. 哪组须更长,说明总体波动更大
  4. 是否有异常值

所以箱线图不是单纯比较“高低”, 而是在比较“分布结构”。

八、散点图 Scatter Plot

散点图的用途

散点图用于分析:

两个连续变量之间的关系

它擅长回答:

  • 是否相关?
  • 是正相关还是负相关?
  • 关系强不强?
  • 是否接近线性?
  • 是否有异常点?
  • 是否可能有不同群组?

为什么散点图很基础?

只要你开始关心:

X 和 Y 之间有什么关系?

散点图通常就是第一张图。 它是理解相关结构最基础的工具。

base R:散点图

plot(
  mtcars2$wt, mtcars2$mpg,
  main = "Weight vs MPG",
  xlab = "Weight",
  ylab = "MPG",
  pch = 19,
  col = "#1d3557"
)

这张散点图怎么读?

  • 每个点代表一辆车
  • 横轴是重量 wt
  • 纵轴是油耗 mpg

所以每个点表示:

某辆车同时有某个重量和某个油耗值。

读散点图时看什么?

按这个顺序看:

  1. 整体方向:右上还是右下
  2. 关系强弱:点很紧还是很散
  3. 形状:线性、弯曲还是无规律
  4. 异常值:是否有特别远的点
  5. 分组结构:是否分成几个簇

ggplot2:散点图

ggplot(mtcars2, aes(x = wt, y = mpg)) +
  geom_point(size = 3, color = "#1d3557", alpha = 0.85) +
  labs(
    title = "汽车重量与油耗的关系",
    subtitle = "散点图用于研究两个连续变量之间的关联结构",
    x = "重量(wt)",
    y = "油耗(mpg)"
  )

geom_point() 代码解释

  • aes(x = wt, y = mpg)

    • 指定两个连续变量
  • geom_point()

    • 把观测画成点
  • size

    • 点大小
  • color

    • 固定颜色
  • alpha

    • 透明度

散点图中加入拟合线

ggplot(mtcars2, aes(x = wt, y = mpg)) +
  geom_point(size = 3, color = "#1d3557", alpha = 0.85) +
  geom_smooth(method = "lm", se = TRUE, color = "#e63946", linewidth = 1.2) +
  labs(
    title = "汽车重量与油耗:带线性拟合线",
    subtitle = "拟合线帮助我们更清楚地看整体趋势",
    x = "重量(wt)",
    y = "油耗(mpg)"
  )

geom_smooth() 代码解释

  • method = "lm"

    • 使用线性回归拟合
  • se = TRUE

    • 显示置信区间阴影
  • color

    • 线颜色
  • linewidth

    • 线宽

这层的作用是帮助我们更清楚地看整体趋势。

用颜色映射第三个变量

ggplot(mtcars2, aes(x = wt, y = mpg, color = cyl)) +
  geom_point(size = 3.2, alpha = 0.9) +
  labs(
    title = "重量、油耗与气缸数",
    subtitle = "颜色映射让一张二维图同时表达第三个变量",
    x = "重量(wt)",
    y = "油耗(mpg)",
    color = "气缸数"
  )

这张图为什么信息更多?

因为它同时表达了:

  • x轴:重量
  • y轴:油耗
  • 颜色:气缸类别

所以你不仅看到两个变量关系, 还看到不同类别是否聚在不同区域。

这就是二维图中的多变量表达。

九、折线图 Line Chart

折线图的用途

折线图最适合展示:

一个变量随时间或顺序的变化

它擅长表达:

  • 趋势
  • 波动
  • 转折点
  • 周期性

为什么时间数据常用折线图?

因为折线图强调“连续过程”。

当相邻点被线连接时, 读者会自然把它理解成一个变化轨迹。

因此只要横轴是时间, 折线图往往是首选。

载入时间序列数据

data(economics, package = "ggplot2")
head(economics)
# A tibble: 6 × 6
  date         pce    pop psavert uempmed unemploy
  <date>     <dbl>  <dbl>   <dbl>   <dbl>    <dbl>
1 1967-07-01  507. 198712    12.6     4.5     2944
2 1967-08-01  510. 198911    12.6     4.7     2945
3 1967-09-01  516. 199113    11.9     4.6     2958
4 1967-10-01  512. 199311    12.9     4.9     3143
5 1967-11-01  517. 199498    12.8     4.7     3066
6 1967-12-01  525. 199657    11.8     4.8     3018

ggplot2:折线图

ggplot(economics, aes(x = date, y = unemploy)) +
  geom_line(color = "#264653", linewidth = 1) +
  labs(
    title = "失业人数随时间的变化",
    subtitle = "折线图适合展示趋势、波动与转折",
    x = "日期",
    y = "失业人数"
  )

geom_line() 代码解释

  • aes(x = date, y = unemploy)

    • 横轴是时间
    • 纵轴是失业人数
  • geom_line()

    • 用线连接相邻时间点
  • color

    • 线颜色
  • linewidth

    • 线宽

折线图怎么读?

看四件事:

  1. 总体趋势:上升还是下降
  2. 波动大小:平稳还是起伏大
  3. 转折点:哪段变化明显
  4. 周期性:是否有重复模式

折线图最擅长讲“过程”。

base R:基础折线图

plot(
  AirPassengers,
  type = "l",
  lwd = 2,
  col = "#2a9d8f",
  main = "AirPassengers Time Series",
  ylab = "Passengers"
)

这段 base R 折线图代码解释

  • AirPassengers

    • 时间序列对象
  • type = "l"

    • 指定为线图
  • lwd = 2

    • 线宽
  • col

    • 线颜色
  • main

    • 标题
  • ylab

    • y轴名称

十、分面图 Facet Plot

分面图是什么?

分面图不是新的图种, 而是一种展示方式。

它的作用是:

把不同组拆成多个小图, 让你在相同坐标框架下比较它们。

为什么分面图很有用?

有些图如果所有组放在一张图里,会出现:

  • 颜色太多
  • 点重叠严重
  • 组别互相干扰

分面图能让每个组单独显示, 同时又保持可比性。

ggplot2:分面散点图

ggplot(mtcars2, aes(x = wt, y = mpg)) +
  geom_point(color = "#457b9d", size = 2.8, alpha = 0.85) +
  geom_smooth(method = "lm", se = FALSE, color = "#e63946") +
  facet_wrap(~ cyl) +
  labs(
    title = "不同气缸数组中的重量与油耗关系",
    subtitle = "分面图帮助我们比较不同组的内部模式",
    x = "重量(wt)",
    y = "MPG"
  )

facet_wrap(~ cyl) 代码解释

  • facet_wrap(~ cyl)

    • cyl 分组
    • 每个类别生成一个小图

这里的小图共用统一逻辑, 所以组间比较会更清楚。

分面图应该怎么看?

重点看:

  1. 每组内部趋势是否一致
  2. 哪组点更分散
  3. 哪组关系更明显
  4. 哪组是否有异常值

分面图的好处是把“组内结构”和“组间比较”放在一起。

十一、可视化选择逻辑

看到问题,先想图形

目的 图形
比较类别数量 条形图
看整体构成比例 饼图
看连续变量分布 直方图
看平滑分布形态 密度图
看组间分布差异 箱线图
看两个连续变量关系 散点图
看随时间变化趋势 折线图
看不同组内部模式 分面图

十二、初学者常见错误

错误一:图选错了

例如:

  • 用条形图看连续变量分布
  • 用折线图画没有顺序的类别
  • 用散点图画两个类别变量

错误二:变量类型没处理好

例如:

  • 把 0/1 编码直接当连续变量
  • 没把类别变量转成 factor
  • 把类别变量拿去画直方图

错误三:标签不完整

一张图至少要清楚说明:

  • 图标题
  • 横轴是什么
  • 纵轴是什么
  • 图例表示什么

如果这些都不写, 读者只能猜。

错误四:把相关说成因果

特别是在散点图里, 学生很容易看到趋势就说“X 导致 Y”。

图可以告诉你:

  • 是否存在关联
  • 方向如何
  • 关系强弱如何

但图本身通常不能直接证明因果。

十三、怎么口头解释一张图?

一个标准框架

  1. 先说这张图展示了什么变量
  2. 再说为什么选这种图
  3. 再说图中观察到的模式
  4. 最后说图不能说明什么

这是最稳妥、最像学术表达的方式。

例子:怎么解释散点图

这张散点图展示了汽车重量与油耗之间的关系。横轴是重量,纵轴是每加仑英里数。点整体呈现向右下分布,说明较重的汽车通常对应较低的 mpg,即油耗表现相对较差。加入拟合线后,这种负向关系更加清楚。但需要注意,这张图只能说明相关结构,不能单凭图本身证明因果关系。

例子:怎么解释箱线图

这张箱线图比较了不同变速箱类型下 mpg 的分布。它不仅展示了两组的中位数差异,也展示了组内离散程度以及可能存在的异常值。因此,箱线图比只比较均值更完整地反映了分布差异。

本节课总结

今天我们讲了:

  • base R 的 plot() 结构
  • ggplot2 的图层结构
  • 条形图
  • 饼图
  • 直方图
  • 密度图
  • 箱线图
  • 散点图
  • 折线图
  • 分面图
  • 图形解释方式
  • 常见错误

总结

  • 条形图:看类别比较
  • 饼图:看整体占比
  • 直方图:看连续变量分布
  • 密度图:看平滑分布形态
  • 箱线图:看中心、离散与异常值
  • 散点图:看两个连续变量关系
  • 折线图:看趋势和变化过程
  • 分面图:看不同组内部模式

谢谢大家

下一节课:更进一步的可视化表达(三维,地图,动态图)