01映射、外观与图层

区分数据映射与固定样式,控制位置、透明度和点形状,并通过叠加图层突出数据子集。

2026-03-05
Rggplot2AestheticsLayersShapes
本章目录 · 5

ggplot2 把图形拆成数据、映射和图层。最常见的困惑不是某个参数叫什么,而是它应该放在 aes() 内还是外,以及一个图层应当使用全部数据还是局部数据。

映射与固定外观

aes() 描述变量如何映射到颜色、形状、大小等视觉属性。属性随数据变化时放在 aes() 内:

library(ggplot2)

ggplot(mpg, aes(displ, hwy, color = class)) +
  geom_point()

这里不同 class 得到不同颜色,并生成相应图例。

固定外观写在 aes() 外:

ggplot(mpg, aes(displ, hwy)) +
  geom_point(color = "blue", size = 3, shape = 16)

如果误将固定颜色写入映射:

ggplot(mpg, aes(displ, hwy, color = "blue")) +
  geom_point()

"blue" 会被当成只有一个取值的分类变量,图中出现图例,实际颜色则来自离散色标。判断方法很简单:属性是否来自数据列?是则放进 aes(),否则放在外面。

两种方式可以组合:

ggplot(mpg, aes(displ, hwy, color = class)) +
  geom_point(shape = 21, fill = "white", size = 3)

color 随类别变化,fillshapesize 固定。

位置调整

图层的 position 决定几何对象发生重叠时如何摆放:

效果 常见场景
"identity" 保持原始位置 透明图层叠加
"stack" 堆叠 条形图
"fill" 按比例堆叠 百分比构成
"dodge" 并排错开 分组条形图
"jitter" 添加微小扰动 重叠散点

例如,让两组密度图在原位置叠加:

ggplot(mpg, aes(hwy, fill = drv)) +
  geom_density(position = "identity", alpha = 0.25)

position = "identity" 不会自动解决遮挡,因此通常与透明度配合使用。

填充、边框与透明度

对同时支持内部填充和边框的几何对象,fill = NA 表示内部透明:

ggplot(mpg, aes(displ, hwy)) +
  geom_point(shape = 21, fill = NA, color = "black", size = 3)

点形状 21–25 可以分别控制 fillcoloralpha 的范围是 0 到 1,数值越小越透明:

ggplot(mpg, aes(hwy, fill = class)) +
  geom_density(alpha = 1 / 5)

透明度有助于观察重叠,但过低会让稀疏观测几乎消失。它解决的是遮挡,不替代合理的分组和位置设计。

点形状

geom_point() 使用 shape 控制符号。ggplot2 可接受 0–25 的内置形状编号,也可以使用单个字符。

查看图片ggplot2 点形状编号
ggplot2 点形状编号

将组别映射到形状:

set.seed(42)

points <- data.frame(
  x = rep(1:5, each = 3),
  y = rnorm(15),
  group = factor(rep(letters[1:3], times = 5))
)

ggplot(points, aes(x, y, shape = group, color = group)) +
  geom_point(size = 4)

使用手动标度可以明确每个类别的符号:

ggplot(points, aes(x, y, shape = group, color = group)) +
  geom_point(size = 4) +
  scale_shape_manual(values = c(a = 15, b = 17, c = 19))

形状在黑白打印或色觉差异场景中尤其有用。类别很多时,不应把 20 多种形状全部塞进一张图;即使技术上可以手动指定,读者也很难辨认。

默认离散 shape 标度只选择少量容易区分的形状。超出默认容量时,可以显式指定:

many_groups <- data.frame(
  x = rep(1:5, 4),
  y = rnorm(20),
  group = factor(rep(letters[1:10], each = 2))
)

ggplot(many_groups, aes(x, y, shape = group, color = group)) +
  geom_point(size = 3) +
  scale_shape_manual(values = 0:9)

但当类别数量本身已经妨碍阅读时,更好的选择通常是分面、筛选重点类别,或重新设计比较方式。

使用多个图层突出子集

每个 geom 都可以拥有自己的 data。先画完整数据,再只对目标子集增加图层,可以在保留上下文的同时突出重点:

library(dplyr)

two_seaters <- filter(mpg, class == "2seater")

ggplot(mpg, aes(displ, hwy)) +
  geom_point(color = "grey70") +
  geom_point(
    data = two_seaters,
    color = "red"
  ) +
  geom_point(
    data = two_seaters,
    shape = 1,
    size = 3,
    color = "red"
  )

第一层交代总体分布,第二层改变目标点颜色,第三层增加外圈。异常值、关注群体和特定类别都可以采用这一模式。

如果子集条件较复杂,先在图外生成一个命名对象,比在多个图层中重复筛选条件更容易核查。图层叠加的重点不是“多画一次”,而是让每层承担明确的视觉职责。