前言

数据可视化是数据分析中最直观、最有效的沟通方式。一张好的图表胜过千言万语,能够帮助我们发现数据中的模式、趋势和异常。R语言拥有强大的可视化生态系统,从基础绘图到现代的ggplot2,从静态图表到交互式可视化,应有尽有。

本教程将系统介绍R语言数据可视化的各项技术,帮助你创建专业、美观、有效的数据可视化作品。

本教程的建议学习方法:先阅读并理解前四章内容即可,后面的内容可以在需要使用的时候再看,但依然建议粗略浏览以获得大致印象

本教程涵盖以下内容:

第一章:R语言可视化概述与基础绘图系统

小节 内容 链接
1.1 R可视化生态系统简介 概述
1.2 基础绘图系统核心思想 画家模式
1.3 高级绘图函数 plot/hist/boxplot/barplot
1.4 低级绘图函数 points/lines/text/legend
1.5 图形参数设置 par()参数
1.6 基础图形布局 layout()布局
1.7 保存基础图形 pdf/png/jpeg
1.8 基础绘图的局限性与转型至ggplot2 转型建议

第二章:ggplot2绘图语法基础

小节 内容 链接
2.1 ggplot2的安装与加载 入门
2.2 图形语法核心理念 图层概念
2.3 ggplot()函数与数据映射 aes()映射
2.4 几何对象 geom_*函数
2.5 统计变换 stat_*变换
2.6 标度概述 scale_*标度
2.7 坐标系概述 coord_*坐标系
2.8 分面概述 facet_*分面
2.9 主题概述 theme()主题
2.10 使用+符号构建图形 图层叠加

第三章:常用统计图形(基础)

小节 图形类型 链接
3.1 散点图 geom_point()
3.2 折线图 geom_line()
3.3 柱状图 geom_bar()/geom_col()
3.4 直方图 geom_histogram()
3.5 密度图 geom_density()
3.6 箱线图 geom_boxplot()
3.7 小提琴图 geom_violin()
3.8 点图 geom_dotplot()
3.9 面积图 geom_area()
3.10 饼图 coord_polar()
3.11 误差条 geom_errorbar()
3.12 平滑曲线 geom_smooth()
3.13 分位图 geom_quantile()
3.14 文本注释 geom_text()/geom_label()
3.15 热图 geom_tile()

第四章:图形属性与标度调整

小节 内容 链接
4.1 颜色标度 scale_color_*
4.2 形状标度 scale_shape_*
4.3 大小标度 scale_size_*
4.4 线条类型标度 scale_linetype_*
4.5 透明度标度 scale_alpha_*
4.6 坐标轴标度 scale_x/y_*
4.7 日期轴标度 scale_x_date()
4.8 手动设定标度 scale_*_manual()
4.9 坐标轴变换 scale_*_log10/trans
4.10 图例与标题的调整 guides()/labs()

第五章:坐标系与分面

小节 内容 链接
5.1 笛卡尔坐标系 coord_cartesian()
5.2 固定纵横比 coord_fixed()
5.3 极坐标系 coord_polar()
5.4 翻转坐标系 coord_flip()
5.5 地图投影 coord_map()
5.6 分面基础:facet_wrap 一维分面
5.7 分面进阶:facet_grid 二维分面
5.8 分面中的标度自由设定 scales参数
5.9 分面标签与间距调整 labeller参数
5.10 嵌套分面 facet_nested()

第六章:主题系统与图形定制

小节 内容 链接
6.1 内置主题 theme_bw/gray/minimal
6.2 主题元素调整 element_*函数
6.3 文本元素 element_text()
6.4 矩形元素 element_rect()
6.5 线条元素 element_line()
6.6 图例位置与样式 legend.position
6.7 间距与边距 margin/plot.margin
6.8 自定义完整主题 theme()函数
6.9 扩展包主题 ggthemes/hrbrthemes

第七章:多图组合与排版

小节 内容 链接
7.1 基础多图:par(mfrow) 基础方法
7.2 网格布局:gridExtra grid.arrange()
7.3 cowplot包 plot_grid()
7.4 patchwork包 +/|操作符
7.5 插入子图 inset plot
7.6 共用图例与轴 get_legend()
7.7 复杂布局设计 area()布局
7.8 多页PDF输出 pdf()设备

第八章:颜色、字体与标注的精细控制

小节 内容 链接
8.1 RColorBrewer调色板 配色方案
8.2 viridis色系 色盲友好配色
8.3 自定义颜色向量 colorRampPalette()
8.4 渐变色自定义 scale_*_gradient()
8.5 字体设置 showtext包
8.6 使用系统字体 extrafont包
8.7 标注与文本注释的高级用法 annotate()/geom_text()
8.8 数学表达式与公式标注 expression()
8.9 表格嵌入图形 gridExtra/tableGrob

第九章:交互式可视化

小节 内容 链接
9.1 plotly包基础 ggplotly()
9.2 plotly原生语法 plot_ly()
9.3 悬停信息定制 tooltip定制
9.4 缩放、平移、框选交互 交互模式
9.5 highcharter包 高级交互图表
9.6 echarts4r包 ECharts绑定
9.7 ggiraph包 交互式ggplot
9.8 shiny中的可视化集成 动态可视化
9.9 交互式时间序列 dygraphs包
9.10 交互式网络图 visNetwork包

第十章:高级图表类型

小节 图形类型 链接
10.1 统计分布图 geom_density_ridges()
10.2 二维密度图 geom_density_2d()
10.3 六边形热图 geom_hex()
10.4 韦恩图/欧拉图 VennDiagram/eulerr
10.5 词云 wordcloud包
10.6 雷达图/蜘蛛图 fmsb包
10.7 平行坐标图 GGally包
10.8 瀑布图 waterfalls包
10.9 相关系数矩阵图 corrplot包
10.10 热图聚类 pheatmap包
10.11 树状图 ggdendro包
10.12 时间序列分解图 forecast包
10.13 生存曲线图 survminer包
10.14 森林图 forestplot包

第十一章:动态可视化与动画

小节 内容 链接
11.1 gganimate基础 transition_*函数
11.2 过渡效果 transition_states()
11.3 出现与消失 enter/exit函数
11.4 视图过渡 view_*函数
11.5 影子效果 shadow_*函数
11.6 缓动函数 ease_aes()
11.7 tweenr平滑过渡 插值动画
11.8 transformr几何变换 形状变换
11.9 动画渲染设置 animate()参数
11.10 复杂动画案例 综合示例

第十二章:空间数据可视化(地图)

小节 内容 链接
12.1 sf包基础 简单要素
12.2 ggplot2绘制简单地图 geom_sf()
12.3 从外部读取地图数据 rnaturalearth/maps
12.4 地图数据可视化 填充地图
12.5 分层地图 多图层叠加
12.6 交互式地图:leaflet leaflet包
12.7 地图投影变换 coord_sf()
12.8 地理数据聚合 空间聚合

第十三章:网络与层次结构可视化

小节 内容 链接
13.1 igraph基础 网络对象创建
13.2 ggraph网络图 geom_edge_*
13.3 节点与边的美学 节点/边样式
13.4 网络布局算法 layout参数
13.5 层次结构树状图 dendrogram
13.6 树状图定制 ggraph树图

第十四章:模型诊断与统计结果可视化

小节 图形类型 链接
14.1 回归诊断图 plot(lm)
14.2 残差分析可视化 残差图
14.3 随机森林变量重要性图 varImpPlot()
14.4 混淆矩阵可视化 confusionMatrix图
14.5 ROC曲线与AUC pROC包
14.6 生存曲线 survfit()图
14.7 模型预测对比图 预测值vs实际值
14.8 贝叶斯模型后验分布图 bayesplot包

第十五章:可视化性能优化与最佳实践

小节 内容 链接
15.1 大数据集可视化策略 采样/聚合策略
15.2 geom_point的透明度与光栅化 透明度优化
15.3 使用data.table预先聚合 数据预处理
15.4 图形保存格式选择 矢量/位图格式
15.5 分辨率与尺寸设置 DPI设置
15.6 可视化配色原则 配色建议
15.7 图标题、轴标签的清晰性 标签规范
15.8 避免信息冗余与图表垃圾 简洁原则
15.9 可重复性:脚本化图形生成 自动化流程
15.10 自定义函数封装常用图形模板 函数封装

在Rstudio中安装本节课所有需要的包,运行以下指令:

install.packages(c(
  "ggplot2", "dplyr", "tidyr",
  "gridExtra", "cowplot", "patchwork", "grid",
  "RColorBrewer", "viridis",
  "ggrepel",
  "quantreg", "broom",
  "plotly", "highcharter", "echarts4r", "ggiraph", "dygraphs",
  "gganimate", "gapminder", "tweenr", "transformr",
  "sf", "maps", "rnaturalearth",
  "igraph", "ggraph", "ggforce",
  "factoextra",
  "randomForest",
  "pROC",
  "survival", "survminer",
  "ggalluvial", "treemapify",
  "ggforce"
))

第一章:R语言可视化概述与基础绘图系统

R语言提供了两套主要的绘图系统:基础绘图系统(base graphics)和基于图形语法的ggplot2系统。本章介绍基础绘图系统,它是理解R可视化的起点。

1.1 R可视化生态系统简介

R语言拥有丰富的可视化包和工具。

# R可视化的主要系统

# 1. 基础绘图系统(base graphics)
# R内置的绘图系统,简单直接
# 主要函数:plot()、hist()、boxplot()、barplot()等

# 2. lattice包
# 基于网格图形系统,适合多变量、多面板图形
# 主要函数:xyplot()、bwplot()、histogram()等

# 3. ggplot2包
# 基于图形语法(Grammar of Graphics),最流行的R可视化包
# 使用图层叠加的方式构建图形

# 4. 交互式可视化
# plotly:将ggplot2转为交互式
# highcharter:高级交互图表
# leaflet:交互式地图

# 5. 专用可视化
# 热图:pheatmap、ComplexHeatmap
# 网络图:igraph、ggraph
# 时间序列:forecast、dygraphs

小结:ggplot2是R可视化的主流选择,但基础绘图系统仍然重要。

1.2 基础绘图系统核心思想

基础绘图系统采用”画家模式”,逐步在画布上添加图形元素。

# 基础绘图的两种函数类型

# 1. 高级绘图函数:创建新图形
# 每次调用会创建新的图形窗口
# 例如:plot()、hist()、boxplot()、barplot()

# 2. 低级绘图函数:在现有图形上添加元素
# 在当前图形上添加内容,不会创建新图形
# 例如:points()、lines()、text()、legend()

# 示例:画家模式
# 创建示例数据
x <- 1:10
y <- x^2

# 第一步:创建基础图形
plot(x, y, type = "n", main = "画家模式示例")  # type="n"只创建框架不画点

# 第二步:逐步添加元素
points(x, y, pch = 19, col = "blue")  # 添加点
lines(x, y, col = "red")              # 添加线
text(5, 50, "y = x^2", col = "darkgreen")  # 添加文本
legend("topleft", legend = c("数据点", "连线"), 
       col = c("blue", "red"), pch = c(19, NA), lty = c(NA, 1))

小结:基础绘图系统像画家作画,逐步添加元素构建完整图形。

1.3 高级绘图函数

高级绘图函数创建新图形。

plot()函数

# plot()是最通用的高级绘图函数

# 创建示例数据
x <- 1:20
y <- rnorm(20)

# 基础散点图
plot(x, y)

# 指定标题和标签
plot(x, y, 
     main = "散点图示例",      # 主标题
     xlab = "X轴标签",         # X轴标签
     ylab = "Y轴标签",         # Y轴标签
     col = "steelblue",        # 点的颜色
     pch = 19,                 # 点的形状(实心圆)
     cex = 1.5)                # 点的大小

# 绘制函数曲线
curve(x^2, from = -5, to = 5, main = "y = x^2")

# 绘制折线图
plot(x, y, type = "l", main = "折线图")  # type="l"表示线条

# 绘制点线图
plot(x, y, type = "b", main = "点线图")  # type="b"表示点和线

hist()函数

# hist()绘制直方图

# 创建正态分布数据
data <- rnorm(1000, mean = 50, sd = 10)

# 基础直方图
hist(data)

# 自定义直方图
hist(data,
     main = "正态分布数据直方图",
     xlab = "数值",
     ylab = "频数",
     col = "lightblue",
     breaks = 30,              # 分组数量
     border = "white",         # 边框颜色
     probability = TRUE)       # 显示概率密度而非频数

# 添加密度曲线
lines(density(data), col = "red", lwd = 2)

boxplot()函数

# boxplot()绘制箱线图

# 创建分组数据
group_A <- rnorm(50, mean = 50, sd = 10)
group_B <- rnorm(50, mean = 60, sd = 15)
group_C <- rnorm(50, mean = 55, sd = 8)

# 基础箱线图
boxplot(group_A, group_B, group_C,
        main = "三组数据对比",
        names = c("组A", "组B", "组C"),
        col = c("lightblue", "lightgreen", "lightpink"))

# 使用公式语法
df <- data.frame(
  value = c(group_A, group_B, group_C),
  group = factor(rep(c("A", "B", "C"), each = 50))
)

boxplot(value ~ group, data = df,
        main = "按组分组箱线图",
        xlab = "组别",
        ylab = "数值",
        col = c("lightblue", "lightgreen", "lightpink"))

barplot()函数

# barplot()绘制柱状图

# 创建数据
categories <- c("产品A", "产品B", "产品C", "产品D")
sales <- c(150, 200, 120, 180)

# 基础柱状图
barplot(sales, names.arg = categories,
        main = "产品销售额",
        xlab = "产品",
        ylab = "销售额",
        col = "steelblue")

# 水平柱状图
barplot(sales, names.arg = categories,
        main = "产品销售额(水平)",
        horiz = TRUE,           # 水平方向
        col = "coral",
        las = 1)                # 标签方向

# 堆叠柱状图
sales_matrix <- matrix(c(100, 80, 70, 90,
                         50, 120, 50, 90), 
                       nrow = 2, byrow = TRUE)
rownames(sales_matrix) <- c("上半年", "下半年")
colnames(sales_matrix) <- categories

barplot(sales_matrix,
        main = "产品销售额对比",
        col = c("lightblue", "lightgreen"),
        legend.text = TRUE,
        beside = FALSE)  # beside=FALSE表示堆叠

# 分组柱状图
barplot(sales_matrix,
        main = "产品销售额对比(分组)",
        col = c("lightblue", "lightgreen"),
        legend.text = TRUE,
        beside = TRUE)  # beside=TRUE表示分组

pie()函数

# pie()绘制饼图

# 创建数据
categories <- c("产品A", "产品B", "产品C", "产品D")
sales <- c(150, 200, 120, 180)

# 基础饼图
pie(sales, labels = categories,
    main = "产品销售占比",
    col = c("lightblue", "lightgreen", "lightpink", "lightyellow"))

# 显示百分比
percent <- round(sales / sum(sales) * 100, 1)
labels <- paste(categories, "\n", percent, "%", sep = "")
pie(sales, labels = labels,
    main = "产品销售占比(带百分比)",
    col = c("lightblue", "lightgreen", "lightpink", "lightyellow"))

小结:高级绘图函数创建新图形,常用参数包括main、xlab、ylab、col、pch等。

1.4 低级绘图函数

低级绘图函数在现有图形上添加元素。

# 创建基础图形
x <- 1:10
y <- x + rnorm(10)
plot(x, y, type = "n", main = "低级绘图函数示例",
     xlab = "X", ylab = "Y", xlim = c(0, 11), ylim = c(-2, 12))

# points()添加点
points(x, y, pch = 19, col = "blue", cex = 1.5)

# lines()添加线
lines(x, x, col = "red", lwd = 2, lty = 2)

# abline()添加直线
abline(a = 0, b = 1, col = "green", lwd = 2)  # y = x
abline(h = 5, col = "gray", lty = 2)          # 水平线
abline(v = 5, col = "gray", lty = 3)          # 垂直线

# text()添加文本
text(8, 2, "y = x", col = "green", cex = 1.2)

# legend()添加图例
legend("topleft", 
       legend = c("数据点", "拟合线", "y=x"),
       col = c("blue", "red", "green"),
       pch = c(19, NA, NA),
       lty = c(NA, 2, 1),
       lwd = c(NA, 2, 2))

# title()添加标题(如果需要后加)
title(sub = "副标题", col.sub = "gray")

# axis()添加坐标轴
# 在右侧添加坐标轴
axis(4, at = seq(0, 10, 2), labels = letters[1:6])

# mtext()在边距添加文本
mtext("右侧标注", side = 4, line = 2, col = "blue")

# polygon()添加多边形
polygon(c(2, 4, 4, 2), c(2, 2, 4, 4), 
        col = rgb(1, 0, 0, 0.3), border = "red")

# segments()添加线段
segments(6, 8, 8, 10, col = "purple", lwd = 2)

# arrows()添加箭头
arrows(6, 6, 8, 8, col = "orange", lwd = 2, length = 0.1)

小结:低级绘图函数可以灵活地在图形上添加各种元素。

1.5 图形参数设置

使用par()函数设置全局图形参数。

# par()函数控制图形外观

# 查看当前参数设置
par("mfrow")    # 图形布局
## [1] 1 1
par("mar")      # 图形边距
## [1] 5.1 4.1 4.1 2.1
par("bg")       # 背景色
## [1] "white"
# 设置多图布局
par(mfrow = c(2, 2))  # 2行2列

# 绘制4个图形
plot(1:10, main = "图1")
plot(10:1, main = "图2")
hist(rnorm(100), main = "图3")
boxplot(rnorm(100), main = "图4")

# 恢复默认设置
par(mfrow = c(1, 1))

# 设置边距
par(mar = c(5, 4, 4, 2) + 0.1)  # 下、左、上、右
# 默认值:c(5, 4, 4, 2) + 0.1

# 设置外边距
par(oma = c(0, 0, 2, 0))  # 外边距

# 设置背景色
par(bg = "white")

# 设置字体大小
par(cex = 1.2)      # 全局放大
par(cex.axis = 1)   # 坐标轴
par(cex.lab = 1)    # 标签
par(cex.main = 1.2) # 标题

# 设置颜色
par(col = "black")       # 默认颜色
par(col.axis = "black")  # 坐标轴颜色
par(col.lab = "black")   # 标签颜色
par(col.main = "black")  # 标题颜色

# 设置字体
par(family = "serif")    # 衬线字体
# Windows下常用选项:"serif", "sans", "mono"

# 保存当前参数设置
old_par <- par(no.readonly = TRUE)

# 修改参数
par(mfrow = c(1, 2), mar = c(2, 2, 2, 2))

# 绘制图形
plot(1:10)
plot(10:1)

# 恢复原始参数
par(old_par)

小结par()函数可以控制图形的各种全局参数,建议保存并恢复原始设置。

1.6 基础图形布局

使用layout()函数创建复杂布局。

# layout()函数创建自定义布局
# 注意:如果加载了plotly包,需要使用graphics::layout()避免冲突

# 定义布局矩阵
# 0表示该位置不放置图形
layout_matrix <- matrix(c(1, 1, 2,
                          3, 3, 3,
                          4, 5, 5), nrow = 3, byrow = TRUE)

# 应用布局(使用graphics::layout避免与plotly冲突)
graphics::layout(layout_matrix)

# 设置边距
par(mar = c(2, 2, 2, 1))

# 绘制图形
plot(1:10, main = "图1(占2格)", col = "blue")
plot(1:10, main = "图2", col = "red")
hist(rnorm(100), main = "图3(占3格)", col = "green")
boxplot(rnorm(50), main = "图4", col = "purple")
pie(c(1, 2, 3), main = "图5(占2格)", col = c("red", "green", "blue"))

# 恢复默认布局
graphics::layout(1)
par(mar = c(5, 4, 4, 2) + 0.1)

# 查看布局
# layout.show(5)  # 显示5个区域的布局

小结layout()par(mfrow)更灵活,可以创建不规则布局。注意plotly包也有layout()函数,需使用graphics::layout()区分。

1.7 保存基础图形

将图形保存到文件。

# 保存为PDF
pdf("my_plot.pdf", width = 8, height = 6)  # 打开PDF设备
plot(1:10, main = "保存的图形")             # 绘制图形
dev.off()                                   # 关闭设备

# 保存为PNG
png("my_plot.png", width = 800, height = 600, res = 100)
plot(1:10, main = "PNG图形")
dev.off()

# 保存为JPEG
jpeg("my_plot.jpg", width = 800, height = 600, quality = 90)
plot(1:10, main = "JPEG图形")
dev.off()

# 保存为SVG(矢量图)
svg("my_plot.svg", width = 8, height = 6)
plot(1:10, main = "SVG图形")
dev.off()

# 使用dev.copy()复制当前图形
plot(1:10, main = "当前图形")
dev.copy(pdf, "copied_plot.pdf")
dev.off()

# 查看当前设备
dev.cur()

# 查看所有设备
dev.list()

小结:矢量图(PDF、SVG)适合出版,位图(PNG、JPEG)适合网页。

1.8 基础绘图的局限性与转型至ggplot2

基础绘图系统有一些局限性,ggplot2提供了更优雅的解决方案。

# 基础绘图的局限性

# 1. 代码冗长
# 基础绘图需要手动添加每个元素
par(mfrow = c(1, 2))

# 基础绘图方式
plot(1:10, (1:10)^2, type = "n", main = "基础绘图")
points(1:10, (1:10)^2, pch = 19, col = "blue")
lines(1:10, (1:10)^2, col = "red")
legend("topleft", legend = c("点", "线"), 
       pch = c(19, NA), lty = c(NA, 1), 
       col = c("blue", "red"))

# ggplot2方式(更简洁)
library(ggplot2)
df <- data.frame(x = 1:10, y = (1:10)^2)
ggplot(df, aes(x = x, y = y)) +
  geom_point(color = "blue") +
  geom_line(color = "red") +
  ggtitle("ggplot2绘图") +
  theme_minimal()

par(mfrow = c(1, 1))

# 2. 分组处理复杂
# 基础绘图需要循环处理分组
# ggplot2自动处理分组

# 3. 分面困难
# 基础绘图需要手动创建多个面板
# ggplot2的facet功能自动处理

# 4. 主题不统一
# 基础绘图需要手动设置每个元素
# ggplot2有内置主题系统

小结:ggplot2语法更简洁、更一致,是现代R可视化的首选。


第一章总结

函数类型 函数 用途
高级函数 plot() 通用绘图
高级函数 hist() 直方图
高级函数 boxplot() 箱线图
高级函数 barplot() 柱状图
高级函数 pie() 饼图
低级函数 points() 添加点
低级函数 lines() 添加线
低级函数 text() 添加文本
低级函数 legend() 添加图例
低级函数 abline() 添加直线
参数设置 par() 设置图形参数
布局 layout() 自定义布局

第二章:ggplot2绘图语法基础

ggplot2是R中最流行的可视化包,基于Leland Wilkinson的”图形语法”(Grammar of Graphics)理论。本章介绍ggplot2的核心概念和基本用法。

2.1 ggplot2的安装与加载

# 安装ggplot2(如果尚未安装)
# install.packages("ggplot2")

# 加载ggplot2
library(ggplot2)

# ggplot2是tidyverse的一部分
# 也可以加载整个tidyverse
# library(tidyverse)

# 查看ggplot2版本
packageVersion("ggplot2")
## [1] '4.0.2'

小结:ggplot2可以单独加载,也可以作为tidyverse的一部分加载。

2.2 图形语法核心理念

图形语法将图形分解为独立的组件。

# 图形语法的核心组件

# 1. 数据(Data):要可视化的数据集
# 2. 映射(Aesthetics):数据变量到图形属性的映射
# 3. 几何对象(Geometries):图形的几何形状(点、线、柱等)
# 4. 标度(Scales):控制图形属性的映射方式
# 5. 坐标系(Coordinates):数据到平面的映射
# 6. 分面(Facets):将数据分割成多个子图
# 7. 主题(Theme):控制图形的非数据元素

# 示例:理解各组件
ggplot(data = mpg,                    # 数据
       aes(x = displ, y = hwy)) +     # 映射
  geom_point() +                       # 几何对象
  scale_x_continuous() +               # 标度
  coord_cartesian() +                  # 坐标系
  facet_wrap(~ class) +                # 分面
  theme_minimal()                      # 主题

小结:图形语法将图形分解为独立组件,每个组件都可以单独调整。

2.3 ggplot()函数与数据映射

ggplot()是所有ggplot2图形的起点。

# ggplot()函数的基本用法

# 创建基础图形对象(不显示图形)
p <- ggplot(data = mpg)
p

# 添加映射
p <- ggplot(data = mpg, aes(x = displ, y = hwy))
p

# 添加几何对象后才能显示图形
p + geom_point()

# 在geom_*()中添加映射
ggplot(data = mpg) +
  geom_point(aes(x = displ, y = hwy))

# aes()中的映射
ggplot(data = mpg, aes(x = displ, y = hwy)) +
  geom_point(aes(color = class))  # 颜色映射到class变量

# 在ggplot()和geom_*()中都可以设置映射
# ggplot()中的映射是全局的,对所有图层生效
# geom_*()中的映射只对该图层生效

# 示例:全局映射 vs 局部映射
ggplot(mpg, aes(x = displ, y = hwy, color = class)) +
  geom_point() +
  geom_smooth(method = "lm", se = FALSE)  # 平滑线也按颜色分组
## `geom_smooth()` using formula = 'y ~ x'

# 只在点图层使用颜色映射
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point(aes(color = class)) +
  geom_smooth(method = "lm", se = FALSE, color = "black")  # 只有一条平滑线
## `geom_smooth()` using formula = 'y ~ x'

小结ggplot()创建图形对象,aes()定义数据到图形属性的映射。

2.4 几何对象

几何对象定义图形的形状。

# 常用几何对象

# geom_point():散点图
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point()

# geom_line():折线图
ggplot(economics, aes(x = date, y = unemploy)) +
  geom_line()

# geom_bar():柱状图(自动计数)
ggplot(mpg, aes(x = class)) +
  geom_bar()

# geom_col():柱状图(使用提供的y值)
df <- data.frame(
  category = c("A", "B", "C"),
  value = c(10, 20, 15)
)
ggplot(df, aes(x = category, y = value)) +
  geom_col()

# geom_histogram():直方图
ggplot(mpg, aes(x = hwy)) +
  geom_histogram(bins = 20)

# geom_density():密度图
ggplot(mpg, aes(x = hwy)) +
  geom_density()

# geom_boxplot():箱线图
ggplot(mpg, aes(x = class, y = hwy)) +
  geom_boxplot()

# geom_violin():小提琴图
ggplot(mpg, aes(x = class, y = hwy)) +
  geom_violin()

# geom_smooth():平滑曲线
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  geom_smooth()
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'

# geom_text():文本标签
ggplot(mpg[1:20, ], aes(x = displ, y = hwy)) +
  geom_point() +
  geom_text(aes(label = manufacturer), vjust = -0.5, size = 3)

# 组合多个几何对象
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point(aes(color = class)) +
  geom_smooth(method = "lm", se = TRUE) +
  geom_rug()  # 边缘地毯图
## `geom_smooth()` using formula = 'y ~ x'

小结:几何对象是图形的核心,可以通过+叠加多个图层。

2.5 统计变换

统计变换对数据进行计算后绘图。

# 统计变换示例

# stat_summary():汇总统计
ggplot(mpg, aes(x = class, y = hwy)) +
  stat_summary(fun = mean, geom = "point", size = 3, color = "red") +
  stat_summary(fun.data = mean_cl_normal, geom = "errorbar", width = 0.2)

# stat_smooth():平滑曲线(geom_smooth()的底层)
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  stat_smooth(method = "lm")
## `geom_smooth()` using formula = 'y ~ x'

# stat_density():密度估计
ggplot(mpg, aes(x = hwy)) +
  stat_density(geom = "line")

# stat_bin():分箱计数(geom_histogram()的底层)
ggplot(mpg, aes(x = hwy)) +
  stat_bin(geom = "bar", bins = 20)

# stat_identity():直接使用数据值
df <- data.frame(x = 1:5, y = c(10, 20, 15, 25, 18))
ggplot(df, aes(x = x, y = y)) +
  stat_identity(geom = "bar")

小结:统计变换在绘图前对数据进行计算,每个geom都有对应的stat。

2.6 标度概述

标度控制数据到图形属性的映射。

# 标度控制图形属性

# 颜色标度
ggplot(mpg, aes(x = displ, y = hwy, color = class)) +
  geom_point() +
  scale_color_brewer(palette = "Set1")  # 使用ColorBrewer调色板

# 填充标度
ggplot(mpg, aes(x = class, fill = drv)) +
  geom_bar() +
  scale_fill_brewer(palette = "Set2")

# 大小标度
ggplot(mpg, aes(x = displ, y = hwy, size = cyl)) +
  geom_point() +
  scale_size(range = c(1, 5))

# 形状标度
ggplot(mpg, aes(x = displ, y = hwy, shape = drv)) +
  geom_point() +
  scale_shape_manual(values = c(16, 17, 18))

# 坐标轴标度
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  scale_x_continuous(limits = c(0, 8), breaks = seq(0, 8, 2)) +
  scale_y_continuous(limits = c(0, 50))

小结:标度函数以scale_开头,控制数据到图形属性的映射方式。

2.7 坐标系概述

坐标系定义数据到平面的映射。

# 常用坐标系

# coord_cartesian():笛卡尔坐标系(默认)
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  coord_cartesian(xlim = c(2, 6), ylim = c(20, 40))  # 缩放视图但不删除数据

# coord_flip():翻转坐标系
ggplot(mpg, aes(x = class, y = hwy)) +
  geom_boxplot() +
  coord_flip()

# coord_polar():极坐标系
ggplot(mpg, aes(x = factor(1), fill = class)) +
  geom_bar(width = 1) +
  coord_polar(theta = "y")  # 饼图

# coord_fixed():固定纵横比
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  coord_fixed(ratio = 1)  # x轴和y轴单位长度相同

# coord_trans():坐标变换
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  coord_trans(x = "log10", y = "log10")
## Warning: `coord_trans()` was deprecated in ggplot2 4.0.0.
## ℹ Please use `coord_transform()` instead.
## This warning is displayed once per session.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

小结:坐标系函数以coord_开头,控制数据到平面的映射方式。

2.8 分面概述

分面将数据分割成多个子图。

# 分面类型

# facet_wrap():按单变量分面
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  facet_wrap(~ class, ncol = 4)  # 按class分面,4列

# facet_grid():按双变量分面
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  facet_grid(drv ~ cyl)  # 行按drv,列按cyl

# 分面参数
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  facet_wrap(~ class, 
             ncol = 3,           # 列数
             scales = "free",    # 各面板坐标轴独立
             labeller = label_both)  # 标签格式

小结:分面函数以facet_开头,用于创建多面板图形。

2.9 主题概述

主题控制图形的非数据元素。

# 内置主题

p <- ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point()

# theme_gray():默认灰色主题
p + theme_gray()

# theme_bw():黑白主题
p + theme_bw()

# theme_classic():经典主题
p + theme_classic()

# theme_minimal():极简主题
p + theme_minimal()

# theme_dark():深色主题
p + theme_dark()

# theme_void():空白主题
p + theme_void()

# theme_light():浅色主题
p + theme_light()

小结:主题控制图形的外观,ggplot2提供多种内置主题。

2.10 使用+符号构建图形

ggplot2使用+符号组合各组件。

# 使用+构建复杂图形

ggplot(mpg, aes(x = displ, y = hwy)) +
  # 图层1:散点图
  geom_point(aes(color = class, size = cyl), alpha = 0.6) +
  # 图层2:平滑曲线
  geom_smooth(method = "lm", se = TRUE, color = "black") +
  # 标度
  scale_color_brewer(palette = "Set1") +
  scale_size_continuous(range = c(1, 4)) +
  # 坐标轴标签
  labs(
    title = "发动机排量与高速公路油耗关系",
    subtitle = "按车型分类",
    x = "发动机排量 (L)",
    y = "高速公路油耗 (mpg)",
    color = "车型",
    size = "气缸数"
  ) +
  # 主题
  theme_minimal() +
  theme(
    plot.title = element_text(hjust = 0.5, size = 14, face = "bold"),
    legend.position = "right"
  )
## `geom_smooth()` using formula = 'y ~ x'

小结+符号将图形组件组合在一起,构建复杂图形。


第二章总结

组件 函数前缀 说明
数据映射 aes() 数据到图形属性的映射
几何对象 geom_*() 图形的几何形状
统计变换 stat_*() 数据计算
标度 scale_*() 控制映射方式
坐标系 coord_*() 数据到平面的映射
分面 facet_*() 多面板图形
主题 theme_*() 非数据元素外观

第三章:常用统计图形(基础)

本章介绍ggplot2中常用的统计图形,包括散点图、折线图、柱状图、直方图等。

3.1 散点图

散点图用于展示两个连续变量之间的关系。

# 基础散点图
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point()

# 添加颜色映射
ggplot(mpg, aes(x = displ, y = hwy, color = class)) +
  geom_point()

# 添加大小映射
ggplot(mpg, aes(x = displ, y = hwy, color = class, size = cyl)) +
  geom_point()

# 设置透明度(处理重叠点)
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point(alpha = 0.3)

# 使用形状区分组别
ggplot(mpg, aes(x = displ, y = hwy, shape = drv, color = drv)) +
  geom_point(size = 2)

# 添加文本标签
ggplot(mpg[1:30, ], aes(x = displ, y = hwy, label = manufacturer)) +
  geom_point() +
  geom_text(vjust = -0.5, size = 3)

# 使用geom_label()添加带背景的标签
ggplot(mpg[1:20, ], aes(x = displ, y = hwy, label = manufacturer)) +
  geom_point() +
  geom_label(vjust = -0.5, size = 3, alpha = 0.7)

# 散点图矩阵(使用GGally包)
# library(GGally)
# ggpairs(mpg[, c("displ", "hwy", "cty", "cyl")])

小结:散点图是最常用的图形之一,可以通过颜色、大小、形状展示多维信息。

3.2 折线图

折线图用于展示数据随时间或有序变量的变化趋势。

# 基础折线图
ggplot(economics, aes(x = date, y = unemploy)) +
  geom_line()

# 多条折线
ggplot(economics_long, aes(x = date, y = value01, color = variable)) +
  geom_line()

# 添加点
ggplot(economics[1:50, ], aes(x = date, y = unemploy)) +
  geom_line() +
  geom_point()

# 阶梯图
df <- data.frame(
  x = 1:10,
  y = c(1, 1, 2, 2, 3, 3, 4, 4, 5, 5)
)
ggplot(df, aes(x = x, y = y)) +
  geom_step()

# 面积图
ggplot(economics, aes(x = date, y = unemploy)) +
  geom_area(fill = "steelblue", alpha = 0.5)

# 堆叠面积图
ggplot(economics_long[1:200, ], aes(x = date, y = value01, fill = variable)) +
  geom_area(alpha = 0.5)

小结:折线图适合时间序列数据,可以展示趋势和变化。

3.3 柱状图

柱状图用于展示分类变量的频数或数值。

# geom_bar():自动计数
ggplot(mpg, aes(x = class)) +
  geom_bar()

# 添加颜色
ggplot(mpg, aes(x = class, fill = class)) +
  geom_bar() +
  theme(legend.position = "none")

# 堆叠柱状图
ggplot(mpg, aes(x = class, fill = drv)) +
  geom_bar()

# 分组柱状图
ggplot(mpg, aes(x = class, fill = drv)) +
  geom_bar(position = "dodge")

# 百分比堆叠柱状图
ggplot(mpg, aes(x = class, fill = drv)) +
  geom_bar(position = "fill") +
  ylab("比例")

# geom_col():使用提供的y值
df <- data.frame(
  category = c("A", "B", "C", "D"),
  value = c(10, 25, 15, 30)
)
ggplot(df, aes(x = category, y = value)) +
  geom_col(fill = "steelblue")

# 水平柱状图
ggplot(df, aes(x = category, y = value)) +
  geom_col(fill = "steelblue") +
  coord_flip()

# 添加数值标签
ggplot(df, aes(x = category, y = value)) +
  geom_col(fill = "steelblue") +
  geom_text(aes(label = value), vjust = -0.5)

小结geom_bar()自动计数,geom_col()使用提供的y值。

3.4 直方图

直方图用于展示连续变量的分布。

# 基础直方图
ggplot(mpg, aes(x = hwy)) +
  geom_histogram()
## `stat_bin()` using `bins = 30`. Pick better value `binwidth`.

# 设置分组数量
ggplot(mpg, aes(x = hwy)) +
  geom_histogram(bins = 20)

# 设置分组宽度
ggplot(mpg, aes(x = hwy)) +
  geom_histogram(binwidth = 2)

# 添加颜色
ggplot(mpg, aes(x = hwy, fill = drv)) +
  geom_histogram(bins = 20, position = "identity", alpha = 0.5)

# 堆叠直方图
ggplot(mpg, aes(x = hwy, fill = drv)) +
  geom_histogram(bins = 20)

# 添加密度曲线
ggplot(mpg, aes(x = hwy)) +
  geom_histogram(aes(y = after_stat(density)), bins = 20, fill = "steelblue") +
  geom_density(color = "red", linewidth = 1)

小结:直方图展示数据分布,可通过binsbinwidth控制分组。

3.5 密度图

密度图是直方图的平滑版本。

# 基础密度图
ggplot(mpg, aes(x = hwy)) +
  geom_density()

# 填充颜色
ggplot(mpg, aes(x = hwy)) +
  geom_density(fill = "steelblue", alpha = 0.5)

# 按组绘制
ggplot(mpg, aes(x = hwy, fill = drv)) +
  geom_density(alpha = 0.5)

# 直方图+密度图
ggplot(mpg, aes(x = hwy)) +
  geom_histogram(aes(y = after_stat(density)), bins = 20, 
                 fill = "lightgray", color = "white") +
  geom_density(color = "red", linewidth = 1)

小结:密度图是直方图的平滑版本,适合比较多个分布。

3.6 箱线图

箱线图用于展示数据分布和异常值。

# 基础箱线图
ggplot(mpg, aes(x = class, y = hwy)) +
  geom_boxplot()

# 添加颜色
ggplot(mpg, aes(x = class, y = hwy, fill = class)) +
  geom_boxplot() +
  theme(legend.position = "none")

# 水平箱线图
ggplot(mpg, aes(x = class, y = hwy)) +
  geom_boxplot() +
  coord_flip()

# 添加数据点
ggplot(mpg, aes(x = class, y = hwy)) +
  geom_boxplot() +
  geom_jitter(width = 0.2, alpha = 0.3)

# 按组分组
ggplot(mpg, aes(x = drv, y = hwy, fill = factor(cyl))) +
  geom_boxplot()

小结:箱线图展示数据分布的五数概括,适合比较多个组。

3.7 小提琴图

小提琴图结合了箱线图和密度图。

# 基础小提琴图
ggplot(mpg, aes(x = class, y = hwy)) +
  geom_violin()

# 添加箱线图
ggplot(mpg, aes(x = class, y = hwy)) +
  geom_violin() +
  geom_boxplot(width = 0.1)

# 添加颜色
ggplot(mpg, aes(x = class, y = hwy, fill = class)) +
  geom_violin() +
  theme(legend.position = "none")

# 小提琴图+数据点
ggplot(mpg, aes(x = class, y = hwy, fill = class)) +
  geom_violin(alpha = 0.5) +
  geom_jitter(width = 0.2, alpha = 0.3) +
  theme(legend.position = "none")

小结:小提琴图展示完整的分布形状,比箱线图信息更丰富。

3.8 点图

点图用于展示各组的数值分布。

# 基础点图
ggplot(mpg, aes(x = hwy)) +
  geom_dotplot()
## Bin width defaults to 1/30 of the range of the data. Pick better value with
## `binwidth`.

# 按组分组
ggplot(mpg, aes(x = class, y = hwy)) +
  geom_dotplot(binaxis = "y", stackdir = "center")
## Bin width defaults to 1/30 of the range of the data. Pick better value with
## `binwidth`.

# 添加颜色
ggplot(mpg, aes(x = class, y = hwy, fill = class)) +
  geom_dotplot(binaxis = "y", stackdir = "center", dotsize = 0.5) +
  theme(legend.position = "none")
## Bin width defaults to 1/30 of the range of the data. Pick better value with
## `binwidth`.

小结:点图适合展示小数据集的分布。

3.9 面积图

面积图强调数量随时间的变化。

# 基础面积图
ggplot(economics, aes(x = date, y = unemploy)) +
  geom_area()

# 自定义颜色
ggplot(economics, aes(x = date, y = unemploy)) +
  geom_area(fill = "steelblue", alpha = 0.5) +
  geom_line(color = "steelblue")

# 堆叠面积图
ggplot(economics_long[1:200, ], aes(x = date, y = value01, fill = variable)) +
  geom_area(alpha = 0.5)

小结:面积图强调数量变化,适合时间序列数据。

3.10 饼图

ggplot2通过极坐标创建饼图。

# 创建饼图
ggplot(mpg, aes(x = factor(1), fill = class)) +
  geom_bar(width = 1) +
  coord_polar(theta = "y") +
  theme_void()

# 添加标签
df <- mpg %>%
  count(class) %>%
  mutate(prop = n / sum(n) * 100)

ggplot(df, aes(x = "", y = n, fill = class)) +
  geom_bar(stat = "identity", width = 1) +
  coord_polar("y") +
  geom_text(aes(label = paste0(round(prop, 1), "%")), 
            position = position_stack(vjust = 0.5)) +
  theme_void()

小结:饼图通过coord_polar()实现,但通常柱状图更有效。

3.11 误差条

误差条展示测量的不确定性。

# 计算汇总统计
df_summary <- mpg %>%
  group_by(class) %>%
  summarise(
    mean_hwy = mean(hwy),
    sd_hwy = sd(hwy),
    n = n(),
    se = sd_hwy / sqrt(n)
  )

# 添加误差条的柱状图
ggplot(df_summary, aes(x = class, y = mean_hwy)) +
  geom_col(fill = "steelblue") +
  geom_errorbar(aes(ymin = mean_hwy - se, ymax = mean_hwy + se),
                width = 0.2)

# 点图+误差条
ggplot(df_summary, aes(x = class, y = mean_hwy)) +
  geom_point(size = 3) +
  geom_errorbar(aes(ymin = mean_hwy - se, ymax = mean_hwy + se),
                width = 0.2) +
  geom_linerange(aes(ymin = mean_hwy - se, ymax = mean_hwy + se),
                 color = "gray")

小结geom_errorbar()geom_linerange()用于添加误差条。

3.12 平滑曲线

平滑曲线展示数据的趋势。

# 默认平滑(loess)
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  geom_smooth()
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'

# 线性回归
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  geom_smooth(method = "lm")
## `geom_smooth()` using formula = 'y ~ x'

# 按组分组
ggplot(mpg, aes(x = displ, y = hwy, color = drv)) +
  geom_point() +
  geom_smooth(method = "lm", se = FALSE)
## `geom_smooth()` using formula = 'y ~ x'

# 自定义平滑参数
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  geom_smooth(method = "loess", span = 0.5, se = TRUE, level = 0.95)
## `geom_smooth()` using formula = 'y ~ x'

小结geom_smooth()自动添加趋势线,支持多种平滑方法。

3.13 分位图

分位图展示分位数回归结果。

# 分位数回归
# 注意:geom_quantile需要quantreg包
library(quantreg)

ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point(alpha = 0.3) +
  geom_quantile(quantiles = c(0.25, 0.5, 0.75)) +
  scale_color_manual(values = c("0.25" = "red", "0.5" = "blue", "0.75" = "green"))
## Smoothing formula not specified. Using: y ~ x
## Warning: No shared levels found between `names(values)` of the manual scale and the
## data's colour values.

小结:分位数回归展示不同分位数的趋势。需要安装quantreg包。

3.14 文本注释

添加文本和标签注释。

# geom_text()添加文本
ggplot(mpg[1:30, ], aes(x = displ, y = hwy)) +
  geom_point() +
  geom_text(aes(label = manufacturer), vjust = -0.5, size = 3)

# geom_label()添加带背景的标签
ggplot(mpg[1:20, ], aes(x = displ, y = hwy)) +
  geom_point() +
  geom_label(aes(label = manufacturer), vjust = -0.5, size = 3)

# annotate()添加固定文本
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  annotate("text", x = 6, y = 40, label = "高油耗车型", 
           color = "red", size = 5)

# 添加矩形注释
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  annotate("rect", xmin = 5, xmax = 7, ymin = 35, ymax = 45,
           alpha = 0.2, fill = "red")

# 添加箭头
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  annotate("segment", x = 5, xend = 6.5, y = 35, yend = 42,
           arrow = arrow(), color = "red")

小结geom_text()映射变量,annotate()添加固定注释。

3.15 热图

热图用颜色展示二维数据。

# 创建矩阵数据
df <- expand.grid(x = 1:5, y = 1:5)
df$value <- rnorm(25)

# geom_tile()
ggplot(df, aes(x = x, y = y, fill = value)) +
  geom_tile()

# geom_raster()(更高效)
ggplot(df, aes(x = x, y = y, fill = value)) +
  geom_raster()

# 相关性热图
cor_matrix <- cor(mtcars[, 1:6])
cor_df <- reshape2::melt(cor_matrix)

ggplot(cor_df, aes(x = Var1, y = Var2, fill = value)) +
  geom_tile() +
  scale_fill_gradient2(low = "blue", mid = "white", high = "red",
                       midpoint = 0) +
  theme_minimal()

小结geom_tile()geom_raster()用于创建热图。


第三章总结

图形类型 几何对象 用途
散点图 geom_point() 两变量关系
折线图 geom_line() 时间序列
柱状图 geom_bar()/geom_col() 分类变量频数
直方图 geom_histogram() 连续变量分布
密度图 geom_density() 分布密度
箱线图 geom_boxplot() 分布和异常值
小提琴图 geom_violin() 分布形状
面积图 geom_area() 数量变化
饼图 geom_bar() + coord_polar() 占比
热图 geom_tile() 二维数据

第四章:图形属性与标度调整

标度(Scales)控制数据值到图形属性的映射方式。本章详细介绍各种标度函数的使用方法。

4.1 颜色标度

颜色是最常用的图形属性之一。

离散颜色标度

# 离散变量的颜色映射

# scale_color_brewer():使用ColorBrewer调色板
ggplot(mpg, aes(x = displ, y = hwy, color = class)) +
  geom_point(size = 2) +
  scale_color_brewer(palette = "Set1")

# 查看可用的调色板
# RColorBrewer::display.brewer.all()

# 常用调色板
# 分类调色板:Set1, Set2, Set3, Dark2, Paired等
# 序列调色板:Blues, Greens, Reds, Oranges等
# 发散调色板:RdBu, RdYlBu, Spectral等

# scale_color_hue():使用HCL色彩空间
ggplot(mpg, aes(x = displ, y = hwy, color = class)) +
  geom_point(size = 2) +
  scale_color_hue(h = c(0, 360) + 15, l = 65, c = 100)

# scale_color_grey():灰度调色板
ggplot(mpg, aes(x = displ, y = hwy, color = class)) +
  geom_point(size = 2) +
  scale_color_grey(start = 0.2, end = 0.8)

# 填充颜色(用于柱状图、箱线图等)
ggplot(mpg, aes(x = class, fill = drv)) +
  geom_bar() +
  scale_fill_brewer(palette = "Set2")

连续颜色标度

# 连续变量的颜色映射

# scale_color_gradient():双色渐变
ggplot(mpg, aes(x = displ, y = hwy, color = cty)) +
  geom_point(size = 2) +
  scale_color_gradient(low = "blue", high = "red")

# scale_color_gradient2():三色渐变(发散)
ggplot(mpg, aes(x = displ, y = hwy, color = cty)) +
  geom_point(size = 2) +
  scale_color_gradient2(low = "blue", mid = "white", high = "red",
                        midpoint = median(mpg$cty))

# scale_color_gradientn():多色渐变
ggplot(mpg, aes(x = displ, y = hwy, color = cty)) +
  geom_point(size = 2) +
  scale_color_gradientn(colors = c("blue", "green", "yellow", "red"))

# scale_color_viridis_c():viridis色系(色盲友好)
# 需要安装viridis包
# library(viridis)
# ggplot(mpg, aes(x = displ, y = hwy, color = cty)) +
#   geom_point(size = 2) +
#   scale_color_viridis_c()

# scale_color_distiller():ColorBrewer连续调色板
ggplot(mpg, aes(x = displ, y = hwy, color = cty)) +
  geom_point(size = 2) +
  scale_color_distiller(palette = "RdYlBu", direction = -1)

小结:离散变量使用scale_color_brewer(),连续变量使用scale_color_gradient()系列。

4.2 形状标度

形状标度控制点的形状。

# scale_shape():离散形状标度
ggplot(mpg, aes(x = displ, y = hwy, shape = drv)) +
  geom_point(size = 2) +
  scale_shape()

# scale_shape_manual():手动指定形状
ggplot(mpg, aes(x = displ, y = hwy, shape = drv)) +
  geom_point(size = 2) +
  scale_shape_manual(values = c(16, 17, 18))

# 查看可用的形状
df_shapes <- data.frame(
  shape = 0:25,
  x = rep(1:13, 2),
  y = rep(2:1, each = 13)
)
ggplot(df_shapes, aes(x = x, y = y, shape = shape)) +
  geom_point(size = 3) +
  scale_shape_identity() +
  geom_text(aes(label = shape), vjust = -1, size = 3) +
  theme_void()

# 形状0-20:空心形状(可填充)
# 形状21-25:实心形状(有边框和填充)
ggplot(mpg, aes(x = displ, y = hwy, shape = drv, fill = drv)) +
  geom_point(size = 3) +
  scale_shape_manual(values = c(21, 22, 23))

小结:R提供26种预设形状,形状21-25支持边框和填充颜色。

4.3 大小标度

大小标度控制点或线条的粗细。

# scale_size():连续大小标度
ggplot(mpg, aes(x = displ, y = hwy, size = cty)) +
  geom_point() +
  scale_size()

# scale_size_continuous():指定范围
ggplot(mpg, aes(x = displ, y = hwy, size = cty)) +
  geom_point() +
  scale_size_continuous(range = c(1, 6))

# scale_size_area():面积比例(半径平方)
ggplot(mpg, aes(x = displ, y = hwy, size = cty)) +
  geom_point() +
  scale_size_area(max_size = 6)

# scale_size_binned():分箱大小
ggplot(mpg, aes(x = displ, y = hwy, size = cty)) +
  geom_point() +
  scale_size_binned(breaks = c(10, 15, 20, 25, 30))

# scale_size_manual():离散大小
# 注意:values的数量要与离散变量的水平数一致
ggplot(mpg, aes(x = displ, y = hwy, size = factor(cyl))) +
  geom_point(alpha = 0.5) +
  scale_size_manual(values = c(2, 3, 4, 6))

小结scale_size()控制点的大小,range参数设置最小和最大值。使用scale_size_manual()时,values数量要与离散变量水平数一致。

4.4 线条类型标度

线条类型标度控制线条的样式。

# scale_linetype():离散线条类型
df <- data.frame(
  x = rep(1:10, 3),
  y = c(1:10, 1:10 + 2, 1:10 + 4),
  group = rep(c("A", "B", "C"), each = 10)
)

ggplot(df, aes(x = x, y = y, linetype = group)) +
  geom_line(linewidth = 1) +
  scale_linetype()

# scale_linetype_manual():手动指定
ggplot(df, aes(x = x, y = y, linetype = group)) +
  geom_line(linewidth = 1) +
  scale_linetype_manual(values = c("solid", "dashed", "dotted"))

# 线条类型:
# 0 = blank, 1 = solid, 2 = dashed, 3 = dotted
# 4 = dotdash, 5 = longdash, 6 = twodash

小结:R提供6种预设线条类型,可通过名称或数字指定。

4.5 透明度标度

透明度标度控制图形元素的透明度。

# scale_alpha():连续透明度
ggplot(mpg, aes(x = displ, y = hwy, alpha = cty)) +
  geom_point(size = 3) +
  scale_alpha(range = c(0.1, 1))

# scale_alpha_manual():离散透明度
ggplot(mpg, aes(x = displ, y = hwy, alpha = drv)) +
  geom_point(size = 3) +
  scale_alpha_manual(values = c(0.3, 0.6, 0.9))

# 直接设置透明度(不映射变量)
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point(alpha = 0.3, size = 3)

小结:透明度范围0-1,值越小越透明,适合处理重叠点。

4.6 坐标轴标度

坐标轴标度控制坐标轴的范围、断点和标签。

连续坐标轴

# scale_x_continuous()和scale_y_continuous()

# 设置范围
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  scale_x_continuous(limits = c(0, 10)) +
  scale_y_continuous(limits = c(0, 50))

# 设置断点
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  scale_x_continuous(breaks = seq(0, 8, 2)) +
  scale_y_continuous(breaks = c(10, 20, 30, 40))

# 设置标签
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  scale_x_continuous(breaks = 1:8, labels = paste0(1:8, "L")) +
  scale_y_continuous(labels = scales::number_format(suffix = " mpg"))

# 同时设置断点和标签
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  scale_y_continuous(
    breaks = c(15, 25, 35, 45),
    labels = c("低", "中", "高", "很高")
  )

# 扩展坐标轴范围
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  scale_x_continuous(expand = expansion(mult = 0.1))  # 扩展10%

# 次要断点
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  scale_x_continuous(minor_breaks = seq(0, 8, 0.5))

离散坐标轴

# scale_x_discrete()和scale_y_discrete()

# 设置显示的类别
ggplot(mpg, aes(x = class, y = hwy)) +
  geom_boxplot() +
  scale_x_discrete(limits = c("compact", "midsize", "suv"))
## Warning: Removed 84 rows containing missing values or values outside the scale range
## (`stat_boxplot()`).

# 重新排序类别
ggplot(mpg, aes(x = class, y = hwy)) +
  geom_boxplot() +
  scale_x_discrete(limits = rev(unique(mpg$class)))

# 修改标签
ggplot(mpg, aes(x = class, y = hwy)) +
  geom_boxplot() +
  scale_x_discrete(labels = toupper(unique(mpg$class)))

小结limits控制范围,breaks控制断点,labels控制标签。

4.7 日期轴标度

日期轴需要特殊的标度处理。

# scale_x_date():日期轴

# 创建时间序列数据
df <- data.frame(
  date = seq(as.Date("2020-01-01"), as.Date("2020-12-31"), by = "month"),
  value = rnorm(12, mean = 100, sd = 20)
)

# 基础日期图
ggplot(df, aes(x = date, y = value)) +
  geom_line() +
  geom_point()

# 设置日期断点
ggplot(df, aes(x = date, y = value)) +
  geom_line() +
  geom_point() +
  scale_x_date(date_breaks = "2 months")

# 设置日期标签格式
ggplot(df, aes(x = date, y = value)) +
  geom_line() +
  geom_point() +
  scale_x_date(date_breaks = "2 months", date_labels = "%Y-%m")

# 常用日期格式:
# %Y:四位年份,%y:两位年份
# %m:两位月份,%b:缩写月份,%B:完整月份
# %d:两位日期,%a:缩写星期,%A:完整星期

# 日期范围
ggplot(df, aes(x = date, y = value)) +
  geom_line() +
  geom_point() +
  scale_x_date(limits = as.Date(c("2020-03-01", "2020-09-30")))
## Warning: Removed 5 rows containing missing values or values outside the scale range
## (`geom_line()`).
## Warning: Removed 5 rows containing missing values or values outside the scale range
## (`geom_point()`).

# scale_x_datetime():日期时间轴
# scale_x_time():时间轴

小结date_breaks设置断点间隔,date_labels设置显示格式。

4.8 手动设定标度

手动标度函数允许完全自定义映射。

# scale_*_manual():手动指定值

# 手动颜色
ggplot(mpg, aes(x = displ, y = hwy, color = drv)) +
  geom_point(size = 2) +
  scale_color_manual(
    values = c("4" = "red", "f" = "green", "r" = "blue"),
    name = "驱动方式",
    labels = c("四驱", "前驱", "后驱")
  )

# 手动填充
ggplot(mpg, aes(x = class, fill = drv)) +
  geom_bar() +
  scale_fill_manual(
    values = c("4" = "steelblue", "f" = "coral", "r" = "gold"),
    name = "驱动方式"
  )

# scale_*_identity():直接使用数据值
df <- data.frame(
  x = 1:5,
  y = 1:5,
  color = c("red", "blue", "green", "orange", "purple")
)

ggplot(df, aes(x = x, y = y, color = color)) +
  geom_point(size = 4) +
  scale_color_identity()

小结scale_*_manual()手动指定映射值,scale_*_identity()直接使用数据值。

4.9 坐标轴变换

通过标度函数实现坐标轴变换。

# 对数坐标
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  scale_x_log10() +
  scale_y_log10()

# 等价于
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  coord_trans(x = "log10", y = "log10")

# sqrt变换
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  scale_x_sqrt()

# 倒数变换
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  scale_x_reverse()

# 使用scales包的变换
# library(scales)
# scale_x_continuous(trans = "logit")  # logit变换

小结scale_*_log10()scale_*_sqrt()scale_*_reverse()实现常用变换。

4.10 图例与标题的调整

使用labs()函数调整图例和标题。

# labs()函数设置标题和标签
ggplot(mpg, aes(x = displ, y = hwy, color = class)) +
  geom_point() +
  labs(
    title = "发动机排量与油耗关系",      # 主标题
    subtitle = "数据来源:mpg数据集",    # 副标题
    caption = "图1:散点图示例",         # 说明文字
    x = "发动机排量 (L)",                # X轴标签
    y = "高速公路油耗 (mpg)",            # Y轴标签
    color = "车型类别"                   # 图例标题
  )

# 单独设置
ggplot(mpg, aes(x = displ, y = hwy, color = class)) +
  geom_point() +
  ggtitle("散点图标题") +
  xlab("X轴") +
  ylab("Y轴")

# 移除标签
ggplot(mpg, aes(x = displ, y = hwy, color = class)) +
  geom_point() +
  labs(x = NULL, y = NULL, color = NULL)

# 图例位置
ggplot(mpg, aes(x = displ, y = hwy, color = class)) +
  geom_point() +
  theme(legend.position = "bottom")  # "top", "bottom", "left", "right", "none"

# 图例位置坐标
ggplot(mpg, aes(x = displ, y = hwy, color = class)) +
  geom_point() +
  theme(legend.position = c(0.9, 0.8))  # 0-1之间的坐标

# 图例方向
ggplot(mpg, aes(x = displ, y = hwy, color = class)) +
  geom_point() +
  theme(
    legend.position = "bottom",
    legend.direction = "vertical"
  )

# 移除图例
ggplot(mpg, aes(x = displ, y = hwy, color = class)) +
  geom_point() +
  guides(color = "none")

# 或者使用scale函数
ggplot(mpg, aes(x = displ, y = hwy, color = class)) +
  geom_point() +
  scale_color_discrete(guide = "none")

小结labs()设置标题和标签,theme()控制图例位置,guides()控制图例显示。


第四章总结

标度类型 函数 用途
离散颜色 scale_color_brewer() ColorBrewer调色板
连续颜色 scale_color_gradient() 双色渐变
形状 scale_shape_manual() 手动指定形状
大小 scale_size_continuous() 连续大小映射
线条 scale_linetype() 线条类型
透明度 scale_alpha() 透明度映射
坐标轴 scale_x/y_continuous() 连续坐标轴
日期轴 scale_x_date() 日期坐标轴
手动 scale_*_manual() 手动指定值
变换 scale_*_log10() 对数变换

第五章:坐标系与分面

坐标系定义数据到平面的映射方式,分面将数据分割成多个子图。

5.1 笛卡尔坐标系

笛卡尔坐标系是最常用的坐标系。

# coord_cartesian():笛卡尔坐标系(默认)

# 缩放视图(不删除数据)
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  coord_cartesian(xlim = c(2, 6), ylim = c(20, 40))

# 与limits的区别
# scale_x_continuous(limits = ...)会删除范围外的数据
# coord_cartesian(xlim = ...)只是缩放视图,不删除数据

# 示例:平滑曲线
p <- ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  geom_smooth(method = "lm")

# 使用limits(平滑线基于可见数据)
p + scale_x_continuous(limits = c(2, 6))
## `geom_smooth()` using formula = 'y ~ x'
## Warning: Removed 27 rows containing non-finite outside the scale range
## (`stat_smooth()`).
## Warning: Removed 27 rows containing missing values or values outside the scale range
## (`geom_point()`).

# 使用coord_cartesian(平滑线基于全部数据)
p + coord_cartesian(xlim = c(2, 6))
## `geom_smooth()` using formula = 'y ~ x'

小结coord_cartesian()缩放视图但不删除数据,适合查看局部细节。

5.2 固定纵横比

固定纵横比确保x轴和y轴单位长度相同。

# coord_fixed():固定纵横比

# 默认ratio=1(x轴和y轴单位长度相同)
ggplot(mpg, aes(x = cty, y = hwy)) +
  geom_point() +
  coord_fixed()

# 设置不同的比例
ggplot(mpg, aes(x = cty, y = hwy)) +
  geom_point() +
  coord_fixed(ratio = 0.5)  # y轴单位长度是x轴的一半

# 地图示例(保持地理比例)
# ggplot(map_data, aes(x = long, y = lat)) +
#   geom_path() +
#   coord_fixed(ratio = 1.3)

小结coord_fixed()适合需要保持真实比例的图形,如地图。

5.3 极坐标系

极坐标系将数据映射到圆形。

# coord_polar():极坐标系

# 饼图
ggplot(mpg, aes(x = factor(1), fill = class)) +
  geom_bar(width = 1) +
  coord_polar(theta = "y") +
  theme_void()

# 玫瑰图(南丁格尔图)
ggplot(mpg, aes(x = class, fill = class)) +
  geom_bar() +
  coord_polar() +
  theme_void()

# 雷达图
df <- data.frame(
  category = rep(c("A", "B", "C", "D", "E"), 2),
  value = c(3, 4, 2, 5, 4, 2, 3, 4, 3, 5),
  group = rep(c("Group1", "Group2"), each = 5)
)

ggplot(df, aes(x = category, y = value, color = group, group = group)) +
  geom_line() +
  coord_polar()

# 设置起始角度
ggplot(mpg, aes(x = factor(1), fill = class)) +
  geom_bar(width = 1) +
  coord_polar(theta = "y", start = 0)  # 从12点钟方向开始

小结:极坐标系用于创建饼图、玫瑰图和雷达图。

5.4 翻转坐标系

翻转坐标系交换x轴和y轴。

# coord_flip():翻转坐标系

# 水平箱线图
ggplot(mpg, aes(x = class, y = hwy)) +
  geom_boxplot() +
  coord_flip()

# 水平柱状图
ggplot(mpg, aes(x = class)) +
  geom_bar() +
  coord_flip()

# 注意:coord_flip()在新版本ggplot2中已弃用
# 推荐使用orientation参数
ggplot(mpg, aes(x = hwy, y = class)) +
  geom_boxplot(orientation = "y")

小结coord_flip()交换坐标轴,适合创建水平图形。

5.5 地图投影

地图投影将地球表面映射到平面。

# coord_map():地图投影(需要mapproj包)
# library(mapproj)

# 世界地图
# world <- map_data("world")
# ggplot(world, aes(x = long, y = lat, group = group)) +
#   geom_polygon(fill = "lightgray", color = "black") +
#   coord_map(projection = "mercator")

# 不同投影
# coord_map(projection = "mercator")    # 墨卡托投影
# coord_map(projection = "ortho")       # 正射投影
# coord_map(projection = "gilbert")     # 吉尔伯特投影

# coord_sf():使用sf包的坐标系
# library(sf)
# ggplot(sf_data) +
#   geom_sf() +
#   coord_sf(crs = 4326)  # WGS84坐标系

小结coord_map()coord_sf()用于地图投影。

5.6 分面基础:facet_wrap

facet_wrap()按单个变量创建多个面板。

# facet_wrap():按单变量分面

# 基础分面
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  facet_wrap(~ class)

# 设置列数
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  facet_wrap(~ class, ncol = 4)

# 设置行数
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  facet_wrap(~ class, nrow = 3)

# 分面方向
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  facet_wrap(~ class, dir = "v")  # 垂直方向排列

# 分面标签格式
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  facet_wrap(~ class, labeller = label_both)

# 自定义标签
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  facet_wrap(~ class, 
             labeller = labeller(class = c(
               "compact" = "紧凑型",
               "midsize" = "中型",
               "suv" = "SUV"
             )))

小结facet_wrap()按单变量分面,可控制行列数和标签格式。

5.7 分面进阶:facet_grid

facet_grid()按两个变量创建网格分面。

# facet_grid():按双变量分面

# 行按drv,列按cyl
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  facet_grid(drv ~ cyl)

# 只按行分面
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  facet_grid(drv ~ .)

# 只按列分面
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  facet_grid(. ~ cyl)

# 分面标签
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  facet_grid(drv ~ cyl, 
             labeller = label_both,
             switch = "both")  # 标签位置

小结facet_grid()创建二维网格分面,适合展示两个变量的交叉效应。

5.8 分面中的标度自由设定

分面可以设置各面板使用独立的标度。

# scales参数控制标度

# 各面板独立坐标轴
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  facet_wrap(~ class, scales = "free")

# 只x轴独立
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  facet_wrap(~ class, scales = "free_x")

# 只y轴独立
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  facet_wrap(~ class, scales = "free_y")

# 空间比例
# 注意:facet_wrap的space参数只支持"free_x", "free_y", "fixed"
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  facet_wrap(~ class, scales = "free", space = "free_x")

# 如果需要两个方向都自由,可以使用facet_grid
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  facet_grid(drv ~ class, scales = "free", space = "free")

小结scales = "free"使各面板坐标轴独立。facet_wrap()space参数只支持”free_x”、“free_y”、“fixed”,如需双向自由空间请使用facet_grid()

5.9 分面标签与间距调整

调整分面标签和面板间距。

# 分面标签位置
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  facet_wrap(~ class, strip.position = "bottom")

# 标签文本样式
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  facet_wrap(~ class) +
  theme(
    strip.text = element_text(size = 10, face = "bold", color = "white"),
    strip.background = element_rect(fill = "steelblue")
  )

# 面板间距
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  facet_wrap(~ class) +
  theme(panel.spacing = unit(1, "cm"))

# 分面边框
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  facet_wrap(~ class) +
  theme(panel.border = element_rect(color = "gray", fill = NA))

小结:通过theme()函数调整分面标签和间距。

5.10 嵌套分面

使用ggh4x包创建嵌套分面。

# ggh4x包提供嵌套分面功能
# library(ggh4x)

# 嵌套分面示例
# ggplot(mpg, aes(x = displ, y = hwy)) +
#   geom_point() +
#   facet_nested(~ drv + cyl)

# 嵌套分面可以更好地展示层次结构

小结:ggh4x包扩展了分面功能,支持嵌套分面。


第五章总结

坐标系/分面 函数 用途
笛卡尔 coord_cartesian() 缩放视图
固定比例 coord_fixed() 固定纵横比
极坐标 coord_polar() 饼图、雷达图
翻转 coord_flip() 交换坐标轴
地图投影 coord_map() 地图投影
单变量分面 facet_wrap() 按单变量分面
双变量分面 facet_grid() 按双变量分面

第六章:主题系统与图形定制

主题控制图形的非数据元素外观,包括背景、网格线、字体等。

6.1 内置主题

ggplot2提供多种内置主题。

# 创建基础图形
p <- ggplot(mpg, aes(x = displ, y = hwy, color = class)) +
  geom_point() +
  labs(title = "发动机排量与油耗关系")

# theme_gray():默认灰色主题
p + theme_gray()

# theme_bw():黑白主题
p + theme_bw()

# theme_classic():经典主题(无网格)
p + theme_classic()

# theme_minimal():极简主题
p + theme_minimal()

# theme_dark():深色主题
p + theme_dark()

# theme_light():浅色主题
p + theme_light()

# theme_void():空白主题
p + theme_void()

# theme_test():测试主题
p + theme_test()

小结:内置主题提供快速的风格切换,theme_minimal()theme_classic()最常用。

6.2 主题元素调整

使用theme()函数调整主题元素。

# theme()函数的基本用法

p <- ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point()

# 调整单个元素
p + theme(
  plot.title = element_text(size = 14, face = "bold")
)

# 链式调整
p +
  ggtitle("标题") +
  theme_minimal() +
  theme(
    plot.title = element_text(hjust = 0.5),
    axis.title = element_text(size = 12)
  )

# 注意:theme()的设置会覆盖theme_*()的设置
# 建议先设置主题,再调整具体元素

小结theme()函数可以精细控制图形的各个元素。

6.3 文本元素

文本元素包括标题、轴标签、刻度标签等。

# 文本元素调整

p <- ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  labs(title = "主标题", subtitle = "副标题", 
       x = "X轴标签", y = "Y轴标签",
       caption = "说明文字")

p + theme(
  # 主标题
  plot.title = element_text(
    size = 16,           # 字体大小
    face = "bold",       # 字体样式:plain, bold, italic, bold.italic
    color = "darkblue",  # 颜色
    hjust = 0.5,         # 水平对齐(0-1)
    vjust = 1,           # 垂直对齐
    angle = 0,           # 旋转角度
    margin = ggplot2::margin(t = 10, b = 10)  # 边距
  ),
  
  # 副标题
  plot.subtitle = element_text(size = 12, color = "gray"),
  
  # 说明文字
  plot.caption = element_text(size = 10, hjust = 1, color = "gray"),
  
  # 轴标题
  axis.title = element_text(size = 12, face = "bold"),
  axis.title.x = element_text(margin = ggplot2::margin(t = 10)),
  axis.title.y = element_text(margin = ggplot2::margin(r = 10)),
  
  # 轴刻度标签
  axis.text = element_text(size = 10, color = "black"),
  axis.text.x = element_text(angle = 45, hjust = 1),
  
  # 图例文本
  legend.text = element_text(size = 10),
  legend.title = element_text(size = 12, face = "bold")
)

小结:文本元素使用element_text()调整,可控制大小、颜色、角度等。

6.4 矩形元素

矩形元素包括背景、面板等。

# 矩形元素调整

p <- ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point()

p + theme(
  # 图形背景
  plot.background = element_rect(
    fill = "white",      # 填充色
    color = "black",     # 边框色
    linewidth = 1        # 边框宽度
  ),
  
  # 面板背景
  panel.background = element_rect(fill = "lightgray"),
  
  # 分面背景
  strip.background = element_rect(fill = "steelblue", color = NA),
  
  # 图例背景
  legend.background = element_rect(fill = "white", color = "gray"),
  
  # 图例框
  legend.box.background = element_rect(fill = "lightyellow")
)

# 移除背景
p + theme(
  panel.background = element_blank(),
  plot.background = element_blank()
)

小结:矩形元素使用element_rect()调整,可控制填充色和边框。

6.5 线条元素

线条元素包括网格线、坐标轴线等。

# 线条元素调整

p <- ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point()

p + theme(
  # 主网格线
  panel.grid.major = element_line(color = "gray", linewidth = 0.5),
  panel.grid.major.x = element_line(color = "red"),
  panel.grid.major.y = element_line(color = "blue"),
  
  # 次网格线
  panel.grid.minor = element_line(color = "lightgray", linewidth = 0.25),
  
  # 坐标轴线
  axis.line = element_line(color = "black", linewidth = 1),
  axis.line.x = element_line(color = "red"),
  axis.line.y = element_line(color = "blue"),
  
  # 刻度线
  axis.ticks = element_line(color = "black"),
  axis.ticks.x = element_line(color = "red"),
  axis.ticks.y = element_line(color = "blue"),
  
  # 分面边框
  panel.border = element_rect(color = "black", fill = NA, linewidth = 1)
)

# 移除网格线
p + theme(panel.grid = element_blank())

# 只保留y轴网格线
p + theme(panel.grid.x = element_blank())
## Warning in plot_theme(plot): The `panel.grid.x` theme element is not defined in
## the element hierarchy.

小结:线条元素使用element_line()调整,可控制颜色、宽度和类型。

6.6 图例位置与样式

图例是重要的图形元素,需要精细调整。

# 图例位置
p <- ggplot(mpg, aes(x = displ, y = hwy, color = class)) +
  geom_point()

# 预设位置
p + theme(legend.position = "right")   # 默认

p + theme(legend.position = "left")

p + theme(legend.position = "top")

p + theme(legend.position = "bottom")

p + theme(legend.position = "none")    # 移除图例

# 坐标位置(0-1)
p + theme(legend.position = c(0.9, 0.8))

# 图例方向
p + theme(
  legend.position = "bottom",
  legend.direction = "vertical"
)

# 图例对齐
p + theme(
  legend.position = "bottom",
  legend.box = "horizontal"  # 多个图例水平排列
)

# 图例标题和标签
p + theme(
  legend.title = element_text(face = "bold"),
  legend.text = element_text(size = 10),
  legend.title.align = 0.5  # 标题居中
)

# 图例背景和边距
p + theme(
  legend.background = element_rect(fill = "white", color = "gray"),
  legend.margin = ggplot2::margin(t = 5, r = 5, b = 5, l = 5)
)

# 图例间距
p + theme(
  legend.spacing = unit(1, "cm"),
  legend.spacing.x = unit(0.5, "cm"),
  legend.spacing.y = unit(0.5, "cm")
)

# 图例键大小
p + theme(
  legend.key.size = unit(1, "cm"),
  legend.key.width = unit(1.5, "cm"),
  legend.key.height = unit(0.5, "cm")
)

# 移除图例键背景
p + theme(legend.key = element_blank())

小结legend.position控制位置,legend.*系列参数控制样式。

6.7 间距与边距

调整图形各部分的间距和边距。

# plot.margin:图形边距
p <- ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point()

p + theme(plot.margin = ggplot2::margin(t = 20, r = 20, b = 20, l = 20))

# 使用单位
p + theme(plot.margin = unit(c(1, 1, 1, 1), "cm"))

# panel.spacing:面板间距
p + facet_wrap(~ drv) +
  theme(panel.spacing = unit(1, "cm"))

# axis.title margin:轴标题边距
p + theme(
  axis.title.x = element_text(margin = ggplot2::margin(t = 10)),
  axis.title.y = element_text(margin = ggplot2::margin(r = 10))
)

# 完整边距示例
p + theme(
  plot.margin = ggplot2::margin(20, 20, 20, 20),
  plot.title = element_text(margin = ggplot2::margin(b = 10)),
  axis.title.x = element_text(margin = ggplot2::margin(t = 10)),
  axis.title.y = element_text(margin = ggplot2::margin(r = 10))
)

小结margin()函数设置边距,参数顺序为上、右、下、左。

6.8 自定义完整主题

创建可复用的自定义主题。

# 定义自定义主题函数
theme_custom <- function(base_size = 11, base_family = "") {
  theme_minimal(base_size = base_size, base_family = base_family) +
    theme(
      # 标题
      plot.title = element_text(size = 16, face = "bold", hjust = 0.5),
      plot.subtitle = element_text(size = 12, color = "gray50"),
      
      # 轴
      axis.title = element_text(size = 12, face = "bold"),
      axis.text = element_text(size = 10),
      axis.line = element_line(color = "gray30"),
      
      # 网格
      panel.grid.minor = element_blank(),
      panel.grid.major = element_line(color = "gray90"),
      
      # 图例
      legend.position = "bottom",
      legend.title = element_text(face = "bold"),
      
      # 背景
      plot.background = element_rect(fill = "white", color = NA),
      panel.background = element_rect(fill = "white", color = NA)
    )
}

# 使用自定义主题
ggplot(mpg, aes(x = displ, y = hwy, color = drv)) +
  geom_point() +
  labs(title = "自定义主题示例") +
  theme_custom()

# 带参数的自定义主题
ggplot(mpg, aes(x = displ, y = hwy, color = drv)) +
  geom_point() +
  labs(title = "大字体版本") +
  theme_custom(base_size = 14)

小结:自定义主题函数可以封装常用设置,提高代码复用性。

6.9 扩展包主题

使用扩展包提供的主题。

# ggthemes包
# library(ggthemes)

# p + theme_tufte()      # Tufte风格
# p + theme_economist()  # 经济学人风格
# p + theme_stata()      # Stata风格
# p + theme_excel()      # Excel风格
# p + theme_fivethirtyeight()  # FiveThirtyEight风格
# p + theme_wsj()        # 华尔街日报风格

# hrbrthemes包
# library(hrbrthemes)

# p + theme_ipsum()      # 极简现代风格
# p + theme_ft_rc()      # FT风格

# tvthemes包
# library(tvthemes)

# p + theme_simpsons()   # 辛普森一家风格
# p + theme_rickAndMorty()  # 瑞克和莫蒂风格

小结:扩展包提供丰富的主题选择,适合快速创建专业风格图形。


第六章总结

元素类型 函数 用途
文本 element_text() 标题、标签、图例文本
矩形 element_rect() 背景、面板
线条 element_line() 网格线、坐标轴线
空白 element_blank() 移除元素
边距 margin() 设置边距
图例位置 legend.position 图例位置

第七章:多图组合与排版

实际工作中常需要将多个图形组合在一起展示。本章介绍多种多图组合方法。

7.1 基础多图:par(mfrow)

回顾基础绘图系统的多图方法。

# par(mfrow)和par(mfcol)

# 保存原始参数
old_par <- par(no.readonly = TRUE)

# 2x2布局
par(mfrow = c(2, 2))

plot(1:10, main = "图1")
hist(rnorm(100), main = "图2")
boxplot(rnorm(50), main = "图3")
pie(c(1, 2, 3), main = "图4")

# 恢复参数
par(old_par)

# mfrow vs mfcol
# mfrow:按行填充
# mfcol:按列填充

小结par(mfrow)适合基础绘图系统,对ggplot2图形不适用。

7.2 网格布局:gridExtra

gridExtra包提供灵活的多图布局。

# gridExtra::grid.arrange()

library(gridExtra)

# 创建多个ggplot2图形
p1 <- ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  ggtitle("散点图")

p2 <- ggplot(mpg, aes(x = class)) +
  geom_bar() +
  ggtitle("柱状图") +
  coord_flip()

p3 <- ggplot(mpg, aes(x = hwy)) +
  geom_histogram(bins = 20) +
  ggtitle("直方图")

p4 <- ggplot(mpg, aes(x = class, y = hwy)) +
  geom_boxplot() +
  ggtitle("箱线图")

# 基础排列
grid.arrange(p1, p2, p3, p4, ncol = 2)

# 指定行数
grid.arrange(p1, p2, p3, p4, nrow = 2)

# 使用布局矩阵
layout_matrix <- matrix(c(1, 1, 2, 3, 4, 4), nrow = 2, byrow = TRUE)
grid.arrange(p1, p2, p3, p4, layout_matrix = layout_matrix)

# 指定宽高比例
grid.arrange(p1, p2, p3, p4, 
             widths = c(2, 1),
             heights = c(1, 2))

小结grid.arrange()可以灵活排列多个ggplot2图形。

7.3 cowplot包

cowplot包提供更多排版功能。

# cowplot包
library(cowplot)

# plot_grid():基础排列
plot_grid(p1, p2, p3, p4, ncol = 2)

# 添加标签
plot_grid(p1, p2, p3, p4, 
          ncol = 2,
          labels = c("A", "B", "C", "D"),
          label_size = 12)

# 自定义标签位置
plot_grid(p1, p2, p3, p4,
          ncol = 2,
          labels = "AUTO",  # 自动生成A, B, C, D
          label_x = 0.1,    # 标签x位置
          label_y = 0.9,    # 标签y位置
          hjust = 0)        # 对齐方式

# 指定相对大小
plot_grid(p1, p2, p3, p4,
          ncol = 2,
          rel_widths = c(2, 1),
          rel_heights = c(1, 2))

# 对齐图形
plot_grid(p1, p2, p3, p4,
          ncol = 2,
          align = "hv",     # 水平和垂直对齐
          axis = "tblr")    # 对齐轴

# draw_plot():自由布局
ggdraw() +
  draw_plot(p1, x = 0, y = 0.5, width = 0.5, height = 0.5) +
  draw_plot(p2, x = 0.5, y = 0.5, width = 0.5, height = 0.5) +
  draw_plot(p3, x = 0, y = 0, width = 1, height = 0.5)

# draw_label():添加标签
ggdraw() +
  draw_plot(p1) +
  draw_label("自定义标签", x = 0.5, y = 0.9, size = 14, color = "red")

小结:cowplot提供plot_grid()draw_plot()两种排版方式。

7.4 patchwork包

patchwork包使用操作符组合图形,语法简洁。

# patchwork包
library(patchwork)

# 使用+组合图形
p1 + p2

# 使用/垂直排列
p1 / p2

# 使用|水平排列
p1 | p2

# 组合使用
(p1 | p2) / p3

# 复杂布局
p1 + p2 + p3 + p4 +
  plot_layout(nrow = 2, ncol = 2)

# 指定宽高比例
p1 + p2 +
  plot_layout(widths = c(2, 1))

# 嵌套布局
p1 + (p2 + p3) + p4 +
  plot_layout(nrow = 1)

# 添加整体标题
p1 + p2 + p3 + p4 +
  plot_annotation(
    title = "整体标题",
    subtitle = "副标题",
    caption = "说明文字",
    tag_levels = "A"  # 自动添加A, B, C, D标签
  )

# 自定义标签
p1 + p2 + p3 + p4 +
  plot_annotation(tag_levels = list(c("图1", "图2", "图3", "图4")))

小结:patchwork使用+|/操作符,语法简洁直观。

7.5 插入子图

在主图中插入子图。

# 使用cowplot插入子图

# 主图
main_plot <- ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  theme_bw()

# 子图
inset_plot <- ggplot(mpg, aes(x = hwy)) +
  geom_histogram(bins = 20, fill = "steelblue") +
  theme_void()

# 插入子图
ggdraw(main_plot) +
  draw_plot(inset_plot, x = 0.6, y = 0.6, width = 0.35, height = 0.35)

# 使用patchwork
main_plot +
  inset_element(inset_plot, 
                left = 0.6, right = 1, 
                bottom = 0.6, top = 1)

小结:cowplot的draw_plot()和patchwork的inset_element()都可以插入子图。

7.6 共用图例与轴

多个图形共用图例或坐标轴。

# 共用图例(cowplot)

# 创建带图例的图形
p1 <- ggplot(mpg, aes(x = displ, y = hwy, color = drv)) +
  geom_point()

p2 <- ggplot(mpg, aes(x = cty, y = hwy, color = drv)) +
  geom_point()

# 提取图例
legend <- get_legend(p1)

# 移除图例后组合
p1_no_legend <- p1 + theme(legend.position = "none")
p2_no_legend <- p2 + theme(legend.position = "none")

# 组合并添加图例
plot_grid(p1_no_legend, p2_no_legend, legend, 
          ncol = 3, rel_widths = c(1, 1, 0.3))

# 共用坐标轴(patchwork)
p1 + p2 +
  plot_layout(ncol = 2) &
  theme(plot.margin = ggplot2::margin(0, 0, 0, 0))

# 使用guide_area()(patchwork)
p1 + p2 + guide_area() +
  plot_layout(guides = "collect")

小结:cowplot的get_legend()提取图例,patchwork的guides = "collect"收集图例。

7.7 复杂布局设计

使用patchwork创建复杂布局。

# plot_spacer():空白区域
p1 + plot_spacer() + p2

# area():指定区域
layout <- c(
  area(1, 1, 2, 2),  # 图1占据第1-2行,第1-2列
  area(1, 3),        # 图2占据第1行,第3列
  area(2, 3),        # 图3占据第2行,第3列
  area(3, 1, 3, 3)   # 图4占据第3行,第1-3列
)

p1 + p2 + p3 + p4 + plot_layout(design = layout)

# 使用字符串定义布局
layout <- "
##BB
AACC
####
DDEE
"

# 注意:字符串中每个字母对应一个图形
# 这里只使用p1-p4,对应A, B, C, D
p1 + p2 + p3 + p4 + plot_layout(design = layout)

# wrap_elements():包装任意图形
library(grid)
text_grob <- textGrob("自定义文本", gp = gpar(fontsize = 20))

p1 + wrap_elements(text_grob) + p2

小结plot_spacer()area()和字符串布局提供灵活的布局控制。

7.8 多页PDF输出

将多个图形输出到多页PDF。

# 使用pdf()设备
pdf("multipage.pdf", width = 8, height = 6)

print(p1)
print(p2)
print(p3)

dev.off()

# 使用ggsave()保存组合图形
combined <- p1 + p2 + p3 + p4
ggsave("combined.pdf", combined, width = 12, height = 8)

# 使用cowplot的save_plot()
# save_plot("combined.pdf", combined, ncol = 2, nrow = 2)

小结pdf()设备可以输出多页PDF,ggsave()保存单个图形。


第七章总结

方法 特点
grid.arrange() gridExtra 灵活布局
plot_grid() cowplot 标签、对齐
+, |, / patchwork 操作符语法
draw_plot() cowplot 自由定位
inset_element() patchwork 插入子图

第八章:颜色、字体与标注的精细控制

本章深入介绍颜色选择、字体设置和标注技巧,帮助创建更专业的图形。

8.1 RColorBrewer调色板

RColorBrewer提供经过精心设计的调色板。

# RColorBrewer包
library(RColorBrewer)

# 查看所有调色板
display.brewer.all()

# 查看特定调色板的颜色
display.brewer.pal(8, "Set1")

# 获取调色板颜色
colors <- brewer.pal(8, "Set1")
colors
## [1] "#E41A1C" "#377EB8" "#4DAF4A" "#984EA3" "#FF7F00" "#FFFF33" "#A65628"
## [8] "#F781BF"
# 调色板类型
# 分类调色板(qualitative):Set1, Set2, Set3, Dark2, Paired, Accent等
# 序列调色板(sequential):Blues, Greens, Reds, Oranges, Purples等
# 发散调色板(diverging):RdBu, RdYlBu, Spectral, BrBG等

# 获取调色板信息
brewer.pal.info
##          maxcolors category colorblind
## BrBG            11      div       TRUE
## PiYG            11      div       TRUE
## PRGn            11      div       TRUE
## PuOr            11      div       TRUE
## RdBu            11      div       TRUE
## RdGy            11      div      FALSE
## RdYlBu          11      div       TRUE
## RdYlGn          11      div      FALSE
## Spectral        11      div      FALSE
## Accent           8     qual      FALSE
## Dark2            8     qual       TRUE
## Paired          12     qual       TRUE
## Pastel1          9     qual      FALSE
## Pastel2          8     qual      FALSE
## Set1             9     qual      FALSE
## Set2             8     qual       TRUE
## Set3            12     qual      FALSE
## Blues            9      seq       TRUE
## BuGn             9      seq       TRUE
## BuPu             9      seq       TRUE
## GnBu             9      seq       TRUE
## Greens           9      seq       TRUE
## Greys            9      seq       TRUE
## Oranges          9      seq       TRUE
## OrRd             9      seq       TRUE
## PuBu             9      seq       TRUE
## PuBuGn           9      seq       TRUE
## PuRd             9      seq       TRUE
## Purples          9      seq       TRUE
## RdPu             9      seq       TRUE
## Reds             9      seq       TRUE
## YlGn             9      seq       TRUE
## YlGnBu           9      seq       TRUE
## YlOrBr           9      seq       TRUE
## YlOrRd           9      seq       TRUE
# 在ggplot2中使用
ggplot(mpg, aes(x = displ, y = hwy, color = class)) +
  geom_point(size = 2) +
  scale_color_brewer(palette = "Set1")

# 获取色盲友好的调色板
display.brewer.all(colorblindFriendly = TRUE)

# 色盲友好调色板:Set2, Paired, Dark2等

小结:RColorBrewer提供分类、序列、发散三类调色板,部分调色板色盲友好。

8.2 viridis色系

viridis色系是色盲友好的现代配色方案。

# viridis包
library(viridis)

# 查看viridis色系
viridis.map

# 在ggplot2中使用
# 连续变量
ggplot(mpg, aes(x = displ, y = hwy, color = cty)) +
  geom_point(size = 2) +
  scale_color_viridis_c()  # 连续

# 离散变量
ggplot(mpg, aes(x = displ, y = hwy, color = drv)) +
  geom_point(size = 2) +
  scale_color_viridis_d()  # 离散

# 选择不同的色系
# option = "A" (magma), "B" (inferno), "C" (plasma), "D" (viridis), "E" (cividis)
ggplot(mpg, aes(x = displ, y = hwy, color = cty)) +
  geom_point(size = 2) +
  scale_color_viridis_c(option = "plasma")

# 设置方向
ggplot(mpg, aes(x = displ, y = hwy, color = cty)) +
  geom_point(size = 2) +
  scale_color_viridis_c(direction = -1)  # 反转颜色顺序

小结:viridis色系色盲友好,适合连续和离散变量。

8.3 自定义颜色向量

创建自定义颜色向量。

# 使用颜色名称
colors <- c("red", "blue", "green", "orange", "purple")

# 使用十六进制颜色码
colors_hex <- c("#FF6B6B", "#4ECDC4", "#45B7D1", "#96CEB4", "#FFEAA7")

# 使用RGB值
colors_rgb <- rgb(red = c(1, 0, 0), green = c(0, 1, 0), blue = c(0, 0, 1))

# 创建颜色调色板
my_palette <- colorRampPalette(c("blue", "white", "red"))
my_colors <- my_palette(10)

# 在ggplot2中使用
ggplot(mpg, aes(x = displ, y = hwy, color = drv)) +
  geom_point(size = 2) +
  scale_color_manual(values = c("4" = "#FF6B6B", 
                                 "f" = "#4ECDC4", 
                                 "r" = "#45B7D1"))

# 使用颜色渐变函数
ggplot(mpg, aes(x = displ, y = hwy, color = cty)) +
  geom_point(size = 2) +
  scale_color_gradientn(colors = c("blue", "green", "yellow", "red"))

# 从图片提取颜色(使用colorfindr包)
# library(colorfindr)
# colors <- get_colors("image.jpg") %>% make_palette()

小结:可以使用颜色名称、十六进制码或RGB值自定义颜色。

8.4 渐变色自定义

创建自定义渐变色。

# scale_fill_gradient():双色渐变
ggplot(mpg, aes(x = class, y = hwy, fill = hwy)) +
  geom_col() +
  scale_fill_gradient(low = "lightblue", high = "darkblue")

# scale_fill_gradient2():三色渐变(发散)
ggplot(mpg, aes(x = class, y = hwy, fill = hwy)) +
  geom_col() +
  scale_fill_gradient2(low = "blue", mid = "white", high = "red",
                       midpoint = median(mpg$hwy))

# scale_fill_gradientn():多色渐变
ggplot(mpg, aes(x = class, y = hwy, fill = hwy)) +
  geom_col() +
  scale_fill_gradientn(colors = c("blue", "cyan", "yellow", "red"))

# 使用colorRampPalette创建渐变
my_gradient <- colorRampPalette(c("navy", "steelblue", "lightblue"))
ggplot(mpg, aes(x = class, y = hwy, fill = hwy)) +
  geom_col() +
  scale_fill_gradientn(colors = my_gradient(100))

# 使用colorspace包创建感知均匀的渐变
# library(colorspace)
# scale_fill_continuous_sequential(palette = "Viridis")

小结gradient系列函数创建渐变色,gradient2适合有中心点的数据。

8.5 字体设置

设置图形中的字体。

# 查看可用字体
# Windows系统
windowsFonts()

# 基础绘图系统设置字体
par(family = "serif")    # 衬线字体
par(family = "sans")     # 无衬线字体
par(family = "mono")     # 等宽字体

# ggplot2中设置字体
library(ggplot2)

# 方法1:在theme中设置
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  theme(text = element_text(family = "serif"))

# 方法2:使用showtext包
# library(showtext)
# showtext_auto()
# font_add("custom", "path/to/font.ttf")

# 方法3:使用extrafont包
# library(extrafont)
# font_import()  # 导入系统字体
# loadfonts()    # 加载字体
# fonts()        # 查看可用字体

# ggplot(mpg, aes(x = displ, y = hwy)) +
#   geom_point() +
#   theme(text = element_text(family = "Arial"))

# 使用hrbrthemes包的字体主题
# library(hrbrthemes)
# ggplot(mpg, aes(x = displ, y = hwy)) +
#   geom_point() +
#   theme_ipsum()  # 使用Roboto Condensed字体

小结:可以通过theme()或extrafont/showtext包设置字体。

8.6 使用系统字体

在图形中使用系统安装的字体。

# extrafont包:使用系统字体
# library(extrafont)

# 导入字体(只需运行一次)
# font_import()

# 加载字体
# loadfonts()

# 查看可用字体
# fonts()

# 在ggplot2中使用
# ggplot(mpg, aes(x = displ, y = hwy)) +
#   geom_point() +
#   ggtitle("标题") +
#   theme(
#     plot.title = element_text(family = "SimHei", size = 16),  # 黑体
#     axis.title = element_text(family = "SimSun")              # 宋体
#   )

# showtext包:更灵活的字体支持
# library(showtext)

# 添加字体文件
# font_add("heiti", "C:/Windows/Fonts/simhei.ttf")
# font_add("songti", "C:/Windows/Fonts/simsun.ttc")

# 自动使用showtext
# showtext_auto()

# ggplot(mpg, aes(x = displ, y = hwy)) +
#   geom_point() +
#   theme(text = element_text(family = "heiti"))

# 中文字体常用选项
# SimHei:黑体
# SimSun:宋体
# Microsoft YaHei:微软雅黑
# KaiTi:楷体

小结:extrafont和showtext包可以在R图形中使用系统字体。

8.7 标注与文本注释的高级用法

使用高级标注功能。

# annotate():添加固定注释
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  annotate("text", x = 6, y = 40, label = "高油耗区域", 
           color = "red", size = 5, fontface = "bold") +
  annotate("rect", xmin = 5, xmax = 7, ymin = 35, ymax = 45,
           alpha = 0.2, fill = "red") +
  annotate("segment", x = 2, xend = 5, y = 15, yend = 20,
           arrow = arrow(), color = "blue")

# ggrepel包:避免标签重叠
library(ggrepel)

# 基础文本标签(可能重叠)
ggplot(mpg[1:30, ], aes(x = displ, y = hwy, label = manufacturer)) +
  geom_point() +
  geom_text()

# 使用geom_text_repel避免重叠
ggplot(mpg[1:30, ], aes(x = displ, y = hwy, label = manufacturer)) +
  geom_point() +
  geom_text_repel()

# 使用geom_label_repel
ggplot(mpg[1:30, ], aes(x = displ, y = hwy, label = manufacturer)) +
  geom_point() +
  geom_label_repel()

# 自定义repel参数
ggplot(mpg[1:30, ], aes(x = displ, y = hwy, label = manufacturer)) +
  geom_point() +
  geom_text_repel(
    size = 3,              # 字体大小
    color = "blue",        # 颜色
    max.overlaps = 20,     # 最大重叠数
    box.padding = 0.5,     # 标签间距
    point.padding = 0.3,   # 点与标签间距
    segment.color = "gray" # 连接线颜色
  )

# 只标注特定点
mpg_highlight <- mpg %>%
  mutate(label = ifelse(hwy > 40, manufacturer, ""))

ggplot(mpg_highlight, aes(x = displ, y = hwy, label = label)) +
  geom_point() +
  geom_text_repel()

小结annotate()添加固定注释,ggrepel包避免标签重叠。

8.8 数学表达式与公式标注

在图形中添加数学公式。

# 使用expression()添加数学表达式
# 注意:ggplot2新版本中annotate与expression有兼容性问题,建议使用geom_text

# 创建包含数学表达式的数据框
math_df <- data.frame(
  x = c(0.5, 0.5, 0.5, 0.5),
  y = c(0.8, 0.6, 0.4, 0.2),
  label = c("alpha + beta", "frac(1, sigma)", "sqrt(x^2 + y^2)", "integral(f(x)*dx, a, b)")
)

# 使用geom_text显示数学表达式
ggplot(math_df, aes(x = x, y = y, label = label)) +
  geom_text(parse = TRUE, size = 6) +
  xlim(0, 1) +
  ylim(0, 1) +
  labs(title = "数学表达式示例", x = "", y = "")

# 常用数学符号
# 希腊字母:alpha, beta, gamma, delta, pi, sigma, omega等
# 运算符:+、-、*、/、^、%
# 特殊符号:infinity, partial, nabla
# 分数:frac(a, b)
# 根号:sqrt(x)
# 上下标:x^2, x_i
# 求和:sum(x[i], i=1, n)
# 积分:integral(f(x)*dx, a, b)

# 在轴标签中使用(推荐方式)
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  labs(
    x = expression(paste("Displacement (", cm^3, ")")),
    y = expression(paste("Fuel Efficiency (", km/L, ")")),
    title = expression(paste(alpha, " vs ", beta))
  )

# 组合文本和表达式
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  geom_smooth(method = "lm", formula = y ~ x) +
  geom_text(x = 5, y = 40, label = "R^2 == 0.60", parse = TRUE, size = 5)

# 使用substitute()动态生成表达式
r_squared <- 0.65
label_text <- substitute(paste(R^2, " = ", r), list(r = r_squared))
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  geom_text(x = 5, y = 40, label = deparse(label_text), parse = TRUE, size = 5)

小结expression()parse = TRUE可以在图形中添加数学公式。推荐在labs()中使用expression,在图形中使用geom_text(parse = TRUE)

8.9 表格嵌入图形

在图形中嵌入表格。

# 使用gridExtra包嵌入表格
library(gridExtra)

# 创建表格
df_table <- data.frame(
  Variable = c("displ", "hwy", "cty"),
  Mean = c(mean(mpg$displ), mean(mpg$hwy), mean(mpg$cty)),
  SD = c(sd(mpg$displ), sd(mpg$hwy), sd(mpg$cty))
)

# 创建表格图形
table_grob <- tableGrob(df_table, rows = NULL)

# 创建散点图
p <- ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  theme_bw()

# 组合图形和表格
grid.arrange(p, table_grob, nrow = 2, heights = c(3, 1))

# 使用ggpubr包添加统计信息
# library(ggpubr)

# ggplot(mpg, aes(x = displ, y = hwy)) +
#   geom_point() +
#   stat_cor(method = "pearson", label.x = 5, label.y = 45)  # 添加相关系数

# 使用ggpmisc包添加拟合公式
# library(ggpmisc)

# ggplot(mpg, aes(x = displ, y = hwy)) +
#   geom_point() +
#   geom_smooth(method = "lm", formula = y ~ x) +
#   stat_poly_eq(formula = y ~ x, 
#                aes(label = paste(..eq.label.., ..rr.label.., sep = "~~~")),
#                parse = TRUE)

# 在图形下方添加表格
# library(cowplot)
# ggdraw(p) +
#   draw_grob(table_grob, x = 0.1, y = 0, width = 0.8, height = 0.2)

小结:gridExtra和ggpubr包可以在图形中嵌入表格和统计信息。


第八章总结

功能 函数/包 用途
调色板 RColorBrewer 专业配色
色盲友好 viridis 色盲友好配色
自定义颜色 scale_*_manual() 手动指定颜色
渐变色 scale_*_gradient() 颜色渐变
字体 extrafont/showtext 使用系统字体
避免标签重叠 ggrepel 标签自动避让
数学公式 expression() 数学表达式
表格嵌入 gridExtra 嵌入表格

第九章:交互式可视化

交互式可视化允许用户与图形进行交互,如缩放、悬停、筛选等。

9.1 plotly包基础

plotly是最流行的R交互可视化包。

# 安装和加载plotly
# install.packages("plotly")
library(plotly)

# 将ggplot2转换为交互式
p <- ggplot(mpg, aes(x = displ, y = hwy, color = class)) +
  geom_point()

ggplotly(p)

# 自定义tooltip
p <- ggplot(mpg, aes(x = displ, y = hwy, color = class,
                     text = paste("车型:", manufacturer,
                                  "<br>排量:", displ,
                                  "<br>油耗:", hwy))) +
  geom_point()

ggplotly(p, tooltip = "text")

# 保存交互图形
htmlwidgets::saveWidget(ggplotly(p), "interactive_plot.html")

小结ggplotly()可以快速将ggplot2图形转换为交互式。

9.2 plotly原生语法

使用plotly原生语法创建图形。

library(plotly)

# 散点图
plot_ly(mpg, x = ~displ, y = ~hwy, color = ~class, type = "scatter", mode = "markers")

# 折线图
plot_ly(economics, x = ~date, y = ~unemploy, type = "scatter", mode = "lines")

# 柱状图
plot_ly(mpg, x = ~class, type = "histogram")

# 箱线图
plot_ly(mpg, x = ~class, y = ~hwy, type = "box")

# 热图
plot_ly(z = ~volcano, type = "heatmap")

# 3D散点图
plot_ly(mpg, x = ~displ, y = ~hwy, z = ~cty, color = ~class, type = "scatter3d")

# 使用管道操作符
mpg %>%
  plot_ly(x = ~displ, y = ~hwy) %>%
  add_markers(color = ~class) %>%
  layout(title = "交互式散点图")

小结:plotly原生语法更灵活,可以创建各种交互图形。

9.3 悬停信息定制

定制悬停时显示的信息。

library(plotly)

# 自定义tooltip内容
p <- ggplot(mpg, aes(x = displ, y = hwy, color = class)) +
  geom_point(aes(text = paste("车型:", manufacturer,
                               "<br>排量:", displ,
                               "<br>油耗:", hwy)))

ggplotly(p, tooltip = c("text"))

# 使用plotly原生语法定制
plot_ly(mpg, x = ~displ, y = ~hwy, color = ~class,
        hoverinfo = "text",
        text = ~paste("车型:", manufacturer,
                      "<br>排量:", displ,
                      "<br>油耗:", hwy)) %>%
  add_markers()

# 自定义tooltip样式
plot_ly(mpg, x = ~displ, y = ~hwy,
        hoverinfo = "x+y",
        hoverlabel = list(bgcolor = "white",
                          bordercolor = "black",
                          font = list(size = 15))) %>%
  add_markers()

小结:通过tooltiphoverinfo参数定制悬停信息。

9.4 缩放、平移、框选交互

控制图形的交互行为。

library(plotly)

# 基础交互
p <- plot_ly(mpg, x = ~displ, y = ~hwy, color = ~class) %>%
  add_markers()

# 配置交互模式
p %>% config(
  scrollZoom = TRUE,      # 滚轮缩放
  displayModeBar = TRUE,  # 显示工具栏
  modeBarButtonsToRemove = c("lasso2d", "select2d")  # 移除特定按钮
)

# 添加选择功能
p %>% layout(
  dragmode = "select",    # 框选模式
  selectdirection = "h"   # 水平选择
)

# 添加范围滑块
plot_ly(economics, x = ~date, y = ~unemploy) %>%
  add_lines() %>%
  rangeslider()

# 添加时间范围选择器
plot_ly(economics, x = ~date, y = ~unemploy) %>%
  add_lines() %>%
  rangeslider() %>%
  layout(
    xaxis = list(
      rangeselector = list(
        buttons = list(
          list(count = 3, label = "3个月", step = "month", stepmode = "backward"),
          list(count = 6, label = "6个月", step = "month", stepmode = "backward"),
          list(count = 1, label = "1年", step = "year", stepmode = "backward"),
          list(step = "all", label = "全部")
        )
      )
    )
  )

小结config()layout()函数控制交互行为。

9.5 highcharter包

highcharter是基于Highcharts.js的R包。

# 安装和加载
# install.packages("highcharter")
library(highcharter)

# 散点图
hchart(mpg, "scatter", hcaes(x = displ, y = hwy, group = class))

# 折线图
hchart(economics, "line", hcaes(x = date, y = unemploy))

# 柱状图
hchart(mpg, "column", hcaes(x = class, y = hwy))

# 箱线图
hchart(mpg, "boxplot", hcaes(x = class, y = hwy))

# 热图
hchart(volcano)

# 主题设置
hchart(mpg, "scatter", hcaes(x = displ, y = hwy)) %>%
  hc_theme_darkunica()

# 导出选项
hchart(mpg, "scatter", hcaes(x = displ, y = hwy)) %>%
  hc_exporting(enabled = TRUE)

小结:highcharter提供美观的默认样式和丰富的图表类型。

9.6 echarts4r包

echarts4r是基于Apache ECharts的R包。

# 安装和加载
# install.packages("echarts4r")
library(echarts4r)

# 散点图
mpg %>%
  e_chart(x = displ) %>%
  e_scatter(y = hwy, color = class)

# 折线图
economics %>%
  e_chart(x = date) %>%
  e_line(y = unemploy)

# 柱状图
mpg %>%
  count(class) %>%
  e_chart(x = class) %>%
  e_bar(y = n)

# 饼图
mpg %>%
  count(class) %>%
  e_chart(x = class) %>%
  e_pie(y = n)

# 热力图
volcano %>%
  as.data.frame() %>%
  e_chart() %>%
  e_heatmap() %>%
  e_visual_map()

# 3D散点图
mpg %>%
  e_chart(displ) %>%
  e_scatter_3d(hwy, cty) %>%
  e_theme("dark")

小结:echarts4r语法简洁,支持丰富的图表类型和主题。

9.7 ggiraph包

ggiraph为ggplot2添加交互功能。

# 安装和加载
# install.packages("ggiraph")
library(ggiraph)

# 创建交互式散点图
p <- ggplot(mpg, aes(x = displ, y = hwy, color = class,
                      tooltip = manufacturer,
                      data_id = manufacturer)) +
  geom_point_interactive()

girafe(ggobj = p)

# 交互式柱状图
p <- ggplot(mpg, aes(x = class, fill = drv,
                      tooltip = class,
                      data_id = class)) +
  geom_bar_interactive()

girafe(ggobj = p)

# 添加悬停效果
girafe(ggobj = p,
       options = list(
         opts_hover(css = "fill:orange;stroke:black;")
       ))

小结:ggiraph为ggplot2图形添加tooltip和悬停效果。

9.8 shiny中的可视化集成

在shiny应用中集成可视化。

# shiny与plotly集成示例
# library(shiny)
# library(plotly)

# ui <- fluidPage(
#   selectInput("variable", "选择变量:",
#               choices = c("hwy", "cty", "displ")),
#   plotlyOutput("plot")
# )
# 
# server <- function(input, output) {
#   output$plot <- renderPlotly({
#     p <- ggplot(mpg, aes_string(x = "displ", y = input$variable)) +
#       geom_point(aes(color = class))
#     ggplotly(p)
#   })
# }
# 
# shinyApp(ui, server)

# shiny与echarts4r集成
# library(echarts4r)
# 
# ui <- fluidPage(
#   echarts4rOutput("chart")
# )
# 
# server <- function(input, output) {
#   output$chart <- renderEcharts4r({
#     mpg %>%
#       e_chart(displ) %>%
#       e_scatter(hwy)
#   })
# }
# 
# shinyApp(ui, server)

小结:plotly和echarts4r都可以与shiny无缝集成。

9.9 交互式时间序列

使用dygraphs创建交互式时间序列。

# 安装和加载
# install.packages("dygraphs")
library(dygraphs)

# 创建时间序列对象
ts_data <- ts(economics$unemploy, start = c(1967, 7), frequency = 12)

# 基础交互式时间序列
dygraph(ts_data)

# 添加范围选择器
dygraph(ts_data) %>%
  dyRangeSelector()

# 添加滚动条
dygraph(ts_data) %>%
  dyRangeSelector() %>%
  dyRoller()

# 多系列时间序列
lungDeaths <- cbind(mdeaths, fdeaths)
dygraph(lungDeaths) %>%
  dySeries("mdeaths", label = "男性") %>%
  dySeries("fdeaths", label = "女性") %>%
  dyLegend(show = "always")

# 添加事件标注
dygraph(ts_data) %>%
  dyEvent("1980-1-1", "事件标注", labelLoc = "bottom")

# 添加阴影区域
dygraph(ts_data) %>%
  dyShading(from = "1980-1-1", to = "1985-1-1")

小结:dygraphs专门用于交互式时间序列可视化。

9.10 交互式网络图

创建交互式网络图。

# visNetwork包
# install.packages("visNetwork")
# library(visNetwork)

# 创建节点和边数据
# nodes <- data.frame(id = 1:5, label = paste("节点", 1:5))
# edges <- data.frame(from = c(1, 2, 2, 3, 4), to = c(2, 3, 4, 5, 5))
# 
# visNetwork(nodes, edges)

# networkD3包
# install.packages("networkD3")
# library(networkD3)

# 创建力导向图
# simpleNetwork(edges)

# 创建桑基图
# sankeyNetwork(Links = edges, Nodes = nodes, 
#               Source = "from", Target = "to",
#               NodeID = "label", Value = "value")

小结:visNetwork和networkD3可以创建交互式网络图。


第九章总结

特点 用途
plotly ggplot2转换 通用交互图形
highcharter 美观默认样式 商业图表
echarts4r 语法简洁 丰富图表类型
ggiraph ggplot2扩展 添加交互元素
dygraphs 时间序列专用 时间序列交互
visNetwork 网络图专用 交互式网络图

第十章:高级图表类型

本章介绍一些高级和专用的图表类型。

10.1 统计分布图

展示数据分布的高级图形。

# 密度曲线+直方图组合
ggplot(mpg, aes(x = hwy)) +
  geom_histogram(aes(y = after_stat(density)), bins = 20,
                 fill = "steelblue", alpha = 0.5) +
  geom_density(color = "red", linewidth = 1) +
  theme_minimal()

# 边际分布图(使用ggExtra包)
# library(ggExtra)

# p <- ggplot(mpg, aes(x = displ, y = hwy)) +
#   geom_point()
# 
# ggMarginal(p, type = "histogram")  # 边际直方图
# ggMarginal(p, type = "density")    # 边际密度图
# ggMarginal(p, type = "boxplot")    # 边际箱线图

# 分组边际图
# p <- ggplot(mpg, aes(x = displ, y = hwy, color = drv)) +
#   geom_point()
# 
# ggMarginal(p, type = "density", groupColour = TRUE, groupFill = TRUE)

小结:边际分布图可以同时展示双变量关系和单变量分布。

10.2 二维密度图

展示二维数据的密度分布。

# geom_bin2d():矩形分箱
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_bin2d(bins = 20) +
  scale_fill_viridis_b()

# stat_density2d():二维密度估计
ggplot(mpg, aes(x = displ, y = hwy)) +
  stat_density2d()

# 等高线图
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point(alpha = 0.3) +
  stat_density2d(color = "red")

# 填充等高线
ggplot(mpg, aes(x = displ, y = hwy)) +
  stat_density2d(aes(fill = after_stat(level)), geom = "polygon") +
  scale_fill_viridis_c()

# 热力密度图
ggplot(mpg, aes(x = displ, y = hwy)) +
  stat_density2d(aes(fill = after_stat(density)), geom = "raster", contour = FALSE) +
  scale_fill_viridis_c()

小结:二维密度图适合展示大数据集的分布模式。

10.3 六边形热图

使用六边形分箱展示二维数据。

# geom_hex():六边形分箱
# 需要安装hexbin包
# install.packages("hexbin")

ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_hex(bins = 20) +
  scale_fill_viridis_c()
## Warning: Computation failed in `stat_binhex()`.
## Caused by error in `compute_group()`:
## ! The package "hexbin" is required for `stat_bin_hex()`.

# 自定义颜色
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_hex(bins = 30) +
  scale_fill_gradient(low = "lightblue", high = "darkblue")
## Warning: Computation failed in `stat_binhex()`.
## Caused by error in `compute_group()`:
## ! The package "hexbin" is required for `stat_bin_hex()`.

# 大数据集示例
# ggplot(diamonds, aes(x = carat, y = price)) +
#   geom_hex(bins = 50) +
#   scale_fill_viridis_c()

小结:六边形分箱比矩形分箱更美观,适合大数据集。

10.4 韦恩图/欧拉图

展示集合关系。

# VennDiagram包
# install.packages("VennDiagram")
# library(VennDiagram)

# 二元韦恩图
# venn.diagram(
#   x = list(A = 1:10, B = 5:15),
#   filename = "venn2.png"
# )

# 三元韦恩图
# venn.diagram(
#   x = list(A = 1:10, B = 5:15, C = 10:20),
#   filename = "venn3.png"
# )

# eulerr包(更美观)
# install.packages("eulerr")
# library(eulerr)

# euler()函数创建欧拉图
# fit <- euler(c(A = 10, B = 15, "A&B" = 5))
# plot(fit)

# 使用ggplot2风格
# library(ggforce)
# ggplot() +
#   geom_circle(aes(x0 = 0, y0 = 0, r = 1))

小结:VennDiagram和eulerr包可以创建韦恩图和欧拉图。

10.5 词云

创建词云可视化。

# wordcloud包
# install.packages("wordcloud")
# library(wordcloud)

# 创建词频数据
# words <- c("R", "Python", "数据", "分析", "可视化", "统计", "机器学习", "深度学习")
# freq <- c(50, 40, 35, 30, 28, 25, 20, 15)

# 基础词云
# wordcloud(words, freq)

# 自定义颜色
# wordcloud(words, freq, colors = brewer.pal(8, "Dark2"))

# wordcloud2包(交互式)
# install.packages("wordcloud2")
# library(wordcloud2)

# data <- data.frame(word = words, freq = freq)
# wordcloud2(data)

# 自定义形状
# wordcloud2(data, shape = "star")
# wordcloud2(data, shape = "diamond")

小结:wordcloud创建静态词云,wordcloud2创建交互式词云。

10.6 雷达图/蜘蛛图

展示多变量数据。

# fmsb包
# install.packages("fmsb")
# library(fmsb)

# 创建数据框(需要包含最大值和最小值行)
# data <- data.frame(
#   rbind(
#     c(5, 5, 5, 5, 5),  # 最大值
#     c(0, 0, 0, 0, 0),  # 最小值
#     c(3, 4, 2, 5, 4),  # 数据1
#     c(2, 3, 4, 3, 5)   # 数据2
#   )
# )
# colnames(data) <- c("变量1", "变量2", "变量3", "变量4", "变量5")
# rownames(data) <- c("max", "min", "组A", "组B")

# radarchart(data)

# ggradar包(ggplot2风格)
# install.packages("ggradar")
# library(ggradar)

# data <- data.frame(
#   group = c("A", "B"),
#   var1 = c(3, 2),
#   var2 = c(4, 3),
#   var3 = c(2, 4),
#   var4 = c(5, 3),
#   var5 = c(4, 5)
# )
# 
# ggradar(data)

小结:fmsb和ggradar包可以创建雷达图。

10.7 平行坐标图

展示多变量关系。

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

# 平行坐标图
# ggparcoord(mpg, columns = c(3, 4, 5, 8, 9))

# 按组着色
# ggparcoord(mpg, columns = c(3, 4, 5, 8, 9), groupColumn = "class")

# 显示阴影
# ggparcoord(mpg, columns = c(3, 4, 5, 8, 9), 
#            alphaLines = 0.3,
#            scale = "globalminmax")

小结:平行坐标图适合展示高维数据。

10.8 瀑布图

展示累计变化。

# waterfalls包
# install.packages("waterfalls")
# library(waterfalls)

# 创建数据
# data <- data.frame(
#   category = c("起始", "收入A", "收入B", "支出A", "支出B", "结余"),
#   value = c(100, 50, 30, -40, -20, 0)
# )

# 瀑布图
# waterfall(data)

# 使用ggplot2手动创建
# library(dplyr)
# 
# data <- data.frame(
#   category = c("起始", "收入A", "收入B", "支出A", "支出B"),
#   value = c(100, 50, 30, -40, -20)
# ) %>%
#   mutate(
#     end = cumsum(value),
#     start = lag(end, default = 0),
#     sign = ifelse(value >= 0, "正", "负")
#   )
# 
# ggplot(data, aes(x = category, fill = sign)) +
#   geom_rect(aes(xmin = category, xmax = category,
#                 ymin = start, ymax = end))

小结:瀑布图展示数值的累计变化过程。

10.9 相关系数矩阵图

可视化相关系数矩阵。

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

# 计算相关系数
# cor_matrix <- cor(mtcars)

# 基础相关图
# corrplot(cor_matrix)

# 添加数值
# corrplot(cor_matrix, method = "number")

# 圆形方法
# corrplot(cor_matrix, method = "circle")

# 组合方法
# corrplot(cor_matrix, method = "circle", type = "upper")
# corrplot(cor_matrix, method = "number", type = "lower", add = TRUE)

# ggcorrplot包(ggplot2风格)
# install.packages("ggcorrplot")
# library(gcorrplot)

# ggcorrplot(cor_matrix)
# ggcorrplot(cor_matrix, method = "circle")
# ggcorrplot(cor_matrix, hc.order = TRUE)  # 聚类排序

小结:corrplot和ggcorrplot可以可视化相关系数矩阵。

10.10 热图聚类

创建带聚类的热图。

# pheatmap包
# install.packages("pheatmap")
# library(pheatmap)

# 创建数据矩阵
# data_matrix <- as.matrix(mtcars)

# 基础热图
# pheatmap(data_matrix)

# 标准化
# pheatmap(data_matrix, scale = "column")

# 自定义颜色
# pheatmap(data_matrix, scale = "column",
#          color = colorRampPalette(c("navy", "white", "firebrick3"))(100))

# ComplexHeatmap包(更强大)
# install.packages("ComplexHeatmap")
# library(ComplexHeatmap)

# Heatmap(data_matrix)

小结:pheatmap和ComplexHeatmap可以创建带聚类的热图。

10.11 树状图

可视化层次聚类结果。

# ggdendro包
# install.packages("ggdendro")
# library(ggdendro)

# 层次聚类
# hc <- hclust(dist(mtcars))

# 基础树状图
# plot(hc)

# ggplot2风格树状图
# ggdendrogram(hc)

# factoextra包
# install.packages("factoextra")
# library(factoextra)

# fviz_dend(hc, k = 4, cex = 0.5)  # 分成4类

小结:ggdendro和factoextra可以创建美观的树状图。

10.12 时间序列分解图

展示时间序列的分解结果。

# feasts包
# install.packages("feasts")
# library(feasts)
# library(fable)

# 创建tsibble对象
# ts_data <- as_tsibble(AirPassengers)

# 时间序列分解
# ts_data %>%
#   model(STL(value ~ season(window = 7))) %>%
#   components() %>%
#   autoplot()

# 使用forecast包
# library(forecast)

# 分解
# decomp <- stl(AirPassengers, s.window = "periodic")
# autoplot(decomp)

小结:feasts和forecast包可以创建时间序列分解图。

10.13 生存曲线图

展示生存分析结果。

# survminer包
# install.packages("survminer")
# library(survminer)
# library(survival)

# 创建生存对象
# fit <- survfit(Surv(time, status) ~ sex, data = lung)

# 基础生存曲线
# ggsurvplot(fit)

# 添加风险表
# ggsurvplot(fit, risk.table = TRUE)

# 添加置信区间
# ggsurvplot(fit, conf.int = TRUE, pval = TRUE)

小结:survminer包可以创建专业的生存曲线图。

10.14 森林图

展示效应量和置信区间。

# forestplot包
# install.packages("forestplot")
# library(forestplot)

# 创建数据
# data <- data.frame(
#   name = c("研究1", "研究2", "研究3", "汇总"),
#   mean = c(0.5, 0.7, 0.3, 0.5),
#   lower = c(0.2, 0.4, 0.1, 0.3),
#   upper = c(0.8, 1.0, 0.5, 0.7)
# )

# 森林图
# forestplot(data)

# 使用ggplot2手动创建
# ggplot(data, aes(x = mean, y = name)) +
#   geom_point() +
#   geom_errorbarh(aes(xmin = lower, xmax = upper), height = 0.2) +
#   geom_vline(xintercept = 0, linetype = "dashed") +
#   theme_minimal()

小结:forestplot包或ggplot2可以创建森林图。


第十章总结

图表类型 用途
边际分布图 ggExtra 双变量+边际分布
二维密度图 ggplot2 二维数据密度
六边形热图 hexbin 大数据分箱
韦恩图 VennDiagram 集合关系
词云 wordcloud 文本可视化
雷达图 fmsb/ggradar 多变量比较
平行坐标图 GGally 高维数据
相关系数图 corrplot 相关系数矩阵
热图聚类 pheatmap 聚类热图
树状图 ggdendro 层次聚类
生存曲线 survminer 生存分析
森林图 forestplot 效应量展示

第十一章:动态可视化与动画

本章介绍如何创建动画可视化,使数据展示更加生动。

11.1 gganimate包基础

gganimate是ggplot2的动画扩展。

# 安装和加载
# install.packages("gganimate")
library(gganimate)

# 基础动画示例
library(gapminder)

p <- ggplot(gapminder, aes(x = gdpPercap, y = lifeExp, size = pop, color = continent)) +
  geom_point() +
  scale_x_log10() +
  theme_minimal()

# 添加动画
p + transition_time(year)

# 添加标题显示年份
p + 
  transition_time(year) +
  labs(title = "Year: {frame_time}")

小结transition_time()按时间变量创建动画。

11.2 动画元素:过渡类型

不同的过渡方式。

library(gganimate)

# transition_time():时间过渡
ggplot(gapminder, aes(x = gdpPercap, y = lifeExp, size = pop)) +
  geom_point() +
  scale_x_log10() +
  transition_time(year) +
  labs(title = "Year: {frame_time}")

# transition_states():状态过渡
ggplot(mtcars, aes(x = mpg, y = disp)) +
  geom_point() +
  transition_states(cyl, transition_length = 1, state_length = 2) +
  labs(title = "Cylinders: {closest_state}")

# transition_reveal():沿轴揭示
ggplot(economics, aes(x = date, y = unemploy)) +
  geom_line() +
  transition_reveal(date)

# transition_layers():逐层显示
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point(aes(color = class), show.legend = FALSE) +
  transition_layers(layer_length = 1, from_blank = FALSE)

小结:不同过渡函数适用于不同类型的动画。

11.3 进入/退出效果

控制元素的出现和消失。

library(gganimate)

# 进入和退出效果
ggplot(gapminder, aes(x = gdpPercap, y = lifeExp, size = pop)) +
  geom_point() +
  scale_x_log10() +
  transition_time(year) +
  enter_fade() +      # 淡入
  exit_fade()         # 淡出

# 其他进入效果
# enter_appear():直接出现
# enter_grow():从小变大
# enter_recolor():颜色变化
# enter_fly():飞入
# enter_drift():漂移进入

# 其他退出效果
# exit_disappear():直接消失
# exit_shrink():变小消失
# exit_recolor():颜色变化
# exit_fly():飞出
# exit_drift():漂移退出

# 组合效果
ggplot(gapminder, aes(x = gdpPercap, y = lifeExp, size = pop)) +
  geom_point() +
  scale_x_log10() +
  transition_time(year) +
  enter_fade() +
  enter_grow() +
  exit_shrink() +
  exit_fade()

小结enter_*()exit_*()函数控制元素的出现和消失效果。

11.4 阴影与轨迹

添加阴影和轨迹效果。

library(gganimate)

# shadow_wake():尾迹效果
ggplot(gapminder, aes(x = gdpPercap, y = lifeExp, size = pop)) +
  geom_point() +
  scale_x_log10() +
  transition_time(year) +
  shadow_wake(wake_length = 0.1, alpha = 0.5)

# shadow_trail():轨迹点
ggplot(gapminder, aes(x = gdpPercap, y = lifeExp, size = pop)) +
  geom_point() +
  scale_x_log10() +
  transition_time(year) +
  shadow_trail(max_frames = 10, alpha = 0.3)

# shadow_mark():保留历史标记
ggplot(gapminder, aes(x = gdpPercap, y = lifeExp, size = pop)) +
  geom_point() +
  scale_x_log10() +
  transition_time(year) +
  shadow_mark(alpha = 0.3, size = 0.5)

小结:阴影效果可以展示数据的历史轨迹。

11.5 动画保存

保存动画为GIF或视频。

library(gganimate)

# 创建动画
anim <- ggplot(gapminder, aes(x = gdpPercap, y = lifeExp, size = pop)) +
  geom_point() +
  scale_x_log10() +
  transition_time(year)

# 保存为GIF
anim_save("animation.gif", animation = anim)

# 保存为MP4视频
anim_save("animation.mp4", animation = anim)

# 自定义参数
anim_save(
  "animation.gif",
  animation = anim,
  nframes = 100,      # 帧数
  fps = 10,           # 每秒帧数
  width = 800,        # 宽度
  height = 600        # 高度
)

# 使用gifski渲染器
anim_save("animation.gif", animation = anim, renderer = gifski_renderer())

# 使用av渲染器(视频)
anim_save("animation.mp4", animation = anim, renderer = av_renderer())

小结anim_save()保存动画,支持GIF和视频格式。

11.6 tweenr包:数据插值

在动画帧之间进行平滑插值。

# 安装和加载
# install.packages("tweenr")
library(tweenr)

# 创建两个数据状态
state1 <- data.frame(
  x = 1:10,
  y = rnorm(10),
  group = rep(1:2, 5)
)

state2 <- data.frame(
  x = 1:10,
  y = rnorm(10, 2),
  group = rep(1:2, 5)
)

# 插值
tweened <- tween_state(state1, state2, ease = "linear", nframes = 20)

# 在gganimate中使用
# tweenr会自动处理插值

小结:tweenr可以在数据状态之间进行平滑过渡。

11.7 transformr包:形状变换

在形状之间进行变换。

# 安装和加载
# install.packages("transformr")
library(transformr)

# transformr扩展了gganimate的变换能力
# 支持多边形、路径等几何对象的变换

# 示例:形状变换动画
# library(gganimate)
# 
# shape1 <- data.frame(
#   x = c(0, 1, 1, 0),
#   y = c(0, 0, 1, 1),
#   id = 1
# )
# 
# shape2 <- data.frame(
#   x = c(0, 0.5, 1, 0.5),
#   y = c(0, 1, 0, -0.5),
#   id = 2
# )
# 
# shapes <- rbind(shape1, shape2)
# 
# ggplot(shapes, aes(x = x, y = y, group = id)) +
#   geom_polygon() +
#   transition_states(id)

小结:transformr支持复杂形状之间的平滑变换。

11.8 时间序列滚动动画

创建时间序列的滚动动画。

library(gganimate)

# 滚动窗口动画
ggplot(economics, aes(x = date, y = unemploy)) +
  geom_line() +
  geom_point() +
  transition_reveal(date) +
  coord_cartesian(clip = "off")

# 带尾迹的时间序列
ggplot(economics, aes(x = date, y = unemploy)) +
  geom_line() +
  transition_reveal(date) +
  shadow_trail(max_frames = 50)

# 多变量时间序列动画
economics_long <- economics %>%
  pivot_longer(cols = c(pce, pop, psavert),
               names_to = "variable",
               values_to = "value")

ggplot(economics_long, aes(x = date, y = value, color = variable)) +
  geom_line() +
  facet_wrap(~variable, scales = "free_y") +
  transition_reveal(date)

小结transition_reveal()适合创建时间序列滚动动画。

11.9 空间数据动态展示

创建地图动画。

library(gganimate)

# 美国州级数据动画示例
# library(maps)
# 
# states <- map_data("state")
# 
# # 创建时间序列数据
# states$time <- rep(1:10, each = nrow(states) / 10)
# states$value <- runif(nrow(states))
# 
# ggplot(states, aes(x = long, y = lat, group = group, fill = value)) +
#   geom_polygon() +
#   transition_time(time) +
#   coord_map()

# 使用gapminder数据
# library(gapminder)
# library(sf)
# 
# # 需要地图数据
# # 创建国家数据动画
# ggplot(country_data) +
#   geom_sf(aes(fill = lifeExp)) +
#   transition_time(year)

小结:地图动画可以展示空间数据随时间的变化。


第十一章总结

功能 函数/包 用途
时间过渡 transition_time() 按时间变量动画
状态过渡 transition_states() 按分类变量动画
轨迹揭示 transition_reveal() 沿轴揭示
进入效果 enter_*() 元素出现效果
退出效果 exit_*() 元素消失效果
阴影效果 shadow_*() 历史轨迹
保存动画 anim_save() 保存GIF/视频
数据插值 tweenr 平滑过渡
形状变换 transformr 形状变换

第十二章:空间数据可视化(地图)

本章介绍如何在R中创建地图可视化。

12.1 空间数据格式简介

了解常用的空间数据格式。

# sf包:简单特征
# install.packages("sf")
library(sf)

# 读取shapefile
# shapefile <- st_read("path/to/file.shp")

# 读取GeoJSON
# geojson <- st_read("path/to/file.geojson")

# 创建简单特征对象
point <- st_point(c(1, 2))
line <- st_linestring(matrix(c(0, 0, 1, 1, 2, 0), ncol = 2, byrow = TRUE))
polygon <- st_polygon(list(matrix(c(0, 0, 1, 0, 1, 1, 0, 1, 0, 0), ncol = 2, byrow = TRUE)))

# sp包(旧格式)
# library(sp)
# SpatialPoints, SpatialLines, SpatialPolygons

# 查看坐标系
# st_crs(sf_object)

# 设置坐标系
# st_set_crs(sf_object, 4326)  # WGS84

# 转换坐标系
# st_transform(sf_object, 3857)  # Web Mercator

小结:sf包是现代R空间数据处理的标准。

12.2 ggplot2绘制简单地图

使用geom_sf绘制地图。

library(ggplot2)
library(sf)

# 使用内置数据
library(maps)

# 获取世界地图数据
world <- map_data("world")

# 基础世界地图
ggplot(world, aes(x = long, y = lat, group = group)) +
  geom_polygon(fill = "lightgray", color = "black") +
  coord_fixed(1.3)

# 使用sf对象
# ggplot(sf_object) +
#   geom_sf()

# 添加坐标轴标签
ggplot(world, aes(x = long, y = lat, group = group)) +
  geom_polygon(fill = "lightgray", color = "black") +
  coord_fixed(1.3) +
  labs(x = "经度", y = "纬度")

# 美国地图
usa <- map_data("usa")
ggplot(usa, aes(x = long, y = lat, group = group)) +
  geom_polygon(fill = "steelblue", color = "white") +
  coord_fixed(1.3)

小结geom_polygon()geom_sf()都可以绘制地图。

12.3 从外部读取地图数据

获取外部地图数据。

# rnaturalearth包:自然地球数据
# install.packages("rnaturalearth")
# install.packages("rnaturalearthdata")
library(rnaturalearth)

# 获取国家边界
# countries <- ne_countries(scale = 110, returnclass = "sf")

# 获取河流
# rivers <- ne_rivers(scale = 110, returnclass = "sf")

# 获取湖泊
# lakes <- ne_lakes(scale = 110, returnclass = "sf")

# ggplot() +
#   geom_sf(data = countries) +
#   geom_sf(data = rivers, color = "blue") +
#   theme_minimal()

# ggmap包:从Google Maps获取地图
# install.packages("ggmap")
# library(ggmap)

# 需要API密钥
# register_google(key = "your_api_key")
# map <- get_map("New York", zoom = 10)
# ggmap(map)

# maps包:内置地图数据
library(maps)

# 世界地图
world_map <- map_data("world")

# 美国州地图
us_states <- map_data("state")

# 中国地图(需要额外数据)
# china <- map_data("china")

小结:rnaturalearth和maps包提供常用地图数据。

12.4 点、线、面地图图层

在地图上添加不同类型的图层。

library(ggplot2)
library(maps)

# 基础地图
world <- map_data("world")

# 添加点(城市位置)
cities <- data.frame(
  city = c("New York", "London", "Tokyo", "Sydney"),
  lon = c(-74, 0, 140, 151),
  lat = c(41, 51, 36, -34)
)

ggplot() +
  geom_polygon(data = world, aes(x = long, y = lat, group = group),
               fill = "lightgray", color = "white") +
  geom_point(data = cities, aes(x = lon, y = lat), 
             color = "red", size = 3) +
  coord_fixed(1.3)

# 添加线(航线)
routes <- data.frame(
  from_lon = c(-74, 0, 140),
  from_lat = c(41, 51, 36),
  to_lon = c(0, 140, 151),
  to_lat = c(51, 36, -34)
)

# 添加多边形(区域)
regions <- data.frame(
  lon = c(-120, -80, -80, -120),
  lat = c(30, 30, 50, 50)
)

ggplot() +
  geom_polygon(data = world, aes(x = long, y = lat, group = group),
               fill = "lightgray", color = "white") +
  geom_polygon(data = regions, aes(x = lon, y = lat),
               fill = "red", alpha = 0.3) +
  coord_fixed(1.3)

小结:可以在地图上叠加点、线、面等几何对象。

12.5 地图投影与坐标变换

设置地图投影。

library(ggplot2)
library(maps)

world <- map_data("world")

# 默认投影(等距圆柱投影)
ggplot(world, aes(x = long, y = lat, group = group)) +
  geom_polygon(fill = "lightgray", color = "white") +
  coord_fixed(1.3)

# 使用coord_sf设置投影
# library(sf)
# 
# world_sf <- st_as_sf(world, coords = c("long", "lat"), crs = 4326)
# 
# ggplot(world_sf) +
#   geom_sf() +
#   coord_sf(crs = st_crs(3857))  # Web Mercator

# 常用投影代码
# 4326: WGS84(经纬度)
# 3857: Web Mercator
# 2163: US National Atlas Equal Area

# 使用mapproj包
# install.packages("mapproj")
# library(mapproj)

# ggplot(world, aes(x = long, y = lat, group = group)) +
#   geom_polygon(fill = "lightgray", color = "white") +
#   coord_map(projection = "mercator")

小结coord_sf()coord_map()可以设置地图投影。

12.6 分级统计图(Choropleth Map)

创建分级统计地图。

library(ggplot2)
library(maps)

# 美国州级数据
us_states <- map_data("state")

# 创建模拟数据
set.seed(123)
state_data <- data.frame(
  region = tolower(state.name),
  value = runif(50, 0, 100)
)

# 合并数据
us_data <- merge(us_states, state_data, by = "region", all.x = TRUE)

# 分级统计图
ggplot(us_data, aes(x = long, y = lat, group = group, fill = value)) +
  geom_polygon(color = "white") +
  coord_fixed(1.3) +
  scale_fill_viridis_c() +
  theme_minimal() +
  labs(fill = "数值")

# 使用离散分类
us_data$category <- cut(us_data$value, 
                        breaks = c(0, 25, 50, 75, 100),
                        labels = c("低", "中低", "中高", "高"))

ggplot(us_data, aes(x = long, y = lat, group = group, fill = category)) +
  geom_polygon(color = "white") +
  coord_fixed(1.3) +
  scale_fill_brewer(palette = "RdYlBu") +
  theme_minimal()

小结:分级统计图用颜色深浅表示数值大小。

12.7 地图与散点图结合

在地图上展示数据分布。

library(ggplot2)
library(maps)

world <- map_data("world")

# 创建点数据
set.seed(123)
points <- data.frame(
  lon = runif(100, -180, 180),
  lat = runif(100, -60, 80),
  value = rnorm(100, 50, 20)
)

# 基础地图+散点
ggplot() +
  geom_polygon(data = world, aes(x = long, y = lat, group = group),
               fill = "lightgray", color = "white") +
  geom_point(data = points, aes(x = lon, y = lat, color = value, size = value),
             alpha = 0.7) +
  scale_color_viridis_c() +
  coord_fixed(1.3) +
  theme_minimal()

# 气泡地图
ggplot() +
  geom_polygon(data = world, aes(x = long, y = lat, group = group),
               fill = "gray90", color = "white") +
  geom_point(data = points, aes(x = lon, y = lat, size = value),
             color = "red", alpha = 0.5) +
  scale_size_continuous(range = c(1, 10)) +
  coord_fixed(1.3) +
  theme_void()

小结:散点图与地图结合可以展示地理分布数据。

12.8 热力地图

创建热力地图。

library(ggplot2)
library(maps)

world <- map_data("world")

# 创建密集点数据
set.seed(123)
heat_points <- data.frame(
  lon = rnorm(1000, 0, 50),
  lat = rnorm(1000, 30, 20)
)

# 使用二维密度
ggplot() +
  geom_polygon(data = world, aes(x = long, y = lat, group = group),
               fill = "white", color = "gray") +
  stat_density2d(data = heat_points, 
                 aes(x = lon, y = lat, fill = after_stat(level)),
                 geom = "polygon", alpha = 0.5) +
  scale_fill_viridis_c() +
  coord_fixed(1.3) +
  theme_minimal()

# 使用分箱
ggplot() +
  geom_polygon(data = world, aes(x = long, y = lat, group = group),
               fill = "white", color = "gray") +
  geom_bin2d(data = heat_points, aes(x = lon, y = lat), bins = 50) +
  scale_fill_viridis_c() +
  coord_fixed(1.3)

小结:热力地图展示数据点的密度分布。

12.9 交互式地图:leaflet包

创建交互式地图。

# 安装和加载
# install.packages("leaflet")
library(leaflet)

# 基础地图
leaflet() %>%
  addTiles() %>%
  setView(lng = 0, lat = 30, zoom = 3)

# 添加标记
leaflet() %>%
  addTiles() %>%
  addMarkers(lng = c(-74, 0, 140), lat = c(41, 51, 36),
             popup = c("New York", "London", "Tokyo"))

# 添加圆形标记
leaflet() %>%
  addTiles() %>%
  addCircleMarkers(lng = c(-74, 0, 140), lat = c(41, 51, 36),
                   radius = 10, color = "red", fillOpacity = 0.5)

# 添加多边形
leaflet() %>%
  addTiles() %>%
  addPolygons(lng = c(-74, -73, -73, -74), lat = c(41, 41, 40, 40),
              fillColor = "red", fillOpacity = 0.5)

# 使用不同的底图
leaflet() %>%
  addProviderTiles(providers$CartoDB.DarkMatter) %>%
  setView(lng = 0, lat = 30, zoom = 3)

# 添加图例
leaflet() %>%
  addTiles() %>%
  addCircleMarkers(lng = c(-74, 0, 140), lat = c(41, 51, 36),
                   radius = c(5, 10, 15), color = c("red", "blue", "green")) %>%
  addLegend(position = "bottomright",
            colors = c("red", "blue", "green"),
            labels = c("A", "B", "C"))

小结:leaflet创建交互式Web地图。

12.10 瓦片地图

使用瓦片地图服务。

# ggmap包
# install.packages("ggmap")
# library(ggmap)

# 需要API密钥
# register_google(key = "your_api_key")

# 获取地图
# map <- get_map("New York", zoom = 10, source = "google")

# ggmap(map)

# 使用OpenStreetMap
# map <- get_map("New York", zoom = 10, source = "osm")
# ggmap(map)

# rosm包
# install.packages("rosm")
# library(rosm)

# 预览瓦片
# osm.plot(c(-74.1, -73.9, 40.7, 40.8))

小结:ggmap和rosm可以获取在线瓦片地图。

12.11 地图标注与比例尺

添加地图元素。

library(ggplot2)
library(maps)

world <- map_data("world")

# 添加比例尺
# library(ggsn)
# 
# ggplot(world, aes(x = long, y = lat, group = group)) +
#   geom_polygon(fill = "lightgray", color = "white") +
#   coord_fixed(1.3) +
#   scalebar(dist = 1000, dist_unit = "km", transform = TRUE,
#            model = "WGS84")

# 添加指北针
# library(ggspatial)
# 
# ggplot(world, aes(x = long, y = lat, group = group)) +
#   geom_polygon(fill = "lightgray", color = "white") +
#   coord_fixed(1.3) +
#   annotation_north_arrow(location = "tl")

# 添加文本标注
cities <- data.frame(
  city = c("New York", "London"),
  lon = c(-74, 0),
  lat = c(41, 51)
)

ggplot() +
  geom_polygon(data = world, aes(x = long, y = lat, group = group),
               fill = "lightgray", color = "white") +
  geom_point(data = cities, aes(x = lon, y = lat), color = "red") +
  geom_text(data = cities, aes(x = lon, y = lat, label = city),
            vjust = -1, size = 3) +
  coord_fixed(1.3)

小结:ggsn和ggspatial包可以添加比例尺和指北针。


第十二章总结

功能 用途
空间数据 sf 空间数据处理
基础地图 maps 内置地图数据
自然地球 rnaturalearth 高质量地图数据
地图绘制 geom_sf ggplot2地图
分级统计图 ggplot2 颜色编码数值
交互地图 leaflet 交互式Web地图
瓦片地图 ggmap 在线地图服务
比例尺 ggsn 添加比例尺
指北针 ggspatial 添加指北针

第十三章:网络与层次结构可视化

本章介绍网络图和层次结构数据的可视化方法。

13.1 网络图数据准备

创建网络数据对象。

# igraph包已在setup中加载
# 从边列表创建网络
edges <- data.frame(
  from = c("A", "A", "B", "B", "C", "C", "D"),
  to = c("B", "C", "C", "D", "D", "E", "E")
)

g <- graph_from_data_frame(edges, directed = FALSE)

# 从邻接矩阵创建
adj_matrix <- matrix(c(
  0, 1, 1, 0, 0,
  1, 0, 1, 1, 0,
  1, 1, 0, 1, 1,
  0, 1, 1, 0, 1,
  0, 0, 1, 1, 0
), nrow = 5)

g <- graph_from_adjacency_matrix(adj_matrix, mode = "undirected")

# 查看网络信息
print(g)
## IGRAPH f3af620 U--- 5 7 -- 
## + edges from f3af620:
## [1] 1--2 1--3 2--3 2--4 3--4 3--5 4--5
V(g)  # 节点
## + 5/5 vertices, from f3af620:
## [1] 1 2 3 4 5
E(g)  # 边
## + 7/7 edges from f3af620:
## [1] 1--2 1--3 2--3 2--4 3--4 3--5 4--5
# 添加节点属性
V(g)$name <- c("A", "B", "C", "D", "E")
V(g)$size <- c(10, 15, 20, 15, 10)
V(g)$color <- c("red", "blue", "green", "blue", "red")

# 添加边属性
E(g)$weight <- c(1, 2, 1, 3, 2, 1, 2)

小结:igraph是R中最常用的网络分析包。

13.2 基础网络图绘制

使用igraph绘制网络图。

# 创建网络
g <- make_ring(10)

# 基础绘图
plot(g)

# 自定义样式
plot(g,
     vertex.size = 20,
     vertex.color = "steelblue",
     vertex.label = NA,
     edge.color = "gray",
     edge.width = 2)

# 带标签的网络
g <- make_star(10)
V(g)$name <- LETTERS[1:10]

plot(g,
     vertex.size = 25,
     vertex.color = "lightblue",
     vertex.label.color = "black",
     vertex.label.cex = 0.8)

# 有向图
g <- make_tree(10, children = 2)
plot(g, edge.arrow.size = 0.5)

# 设置布局
plot(g, layout = layout_in_circle)

plot(g, layout = layout_with_fr)

plot(g, layout = layout_as_tree)

小结:igraph的plot()函数可以快速绘制网络图。

13.3 ggraph包:ggplot2风格网络图

使用ggplot2语法绘制网络图。

# ggraph包已在setup中加载
# 创建网络
g <- make_ring(10)

# 基础ggraph
ggraph(g, layout = "fr") +
  geom_edge_link() +
  geom_node_point() +
  theme_graph()

# 自定义样式
V(g)$name <- LETTERS[1:10]
E(g)$weight <- runif(ecount(g), 1, 5)

ggraph(g, layout = "fr") +
  geom_edge_link(aes(width = weight), alpha = 0.5) +
  geom_node_point(aes(color = name), size = 5) +
  geom_node_text(aes(label = name), repel = TRUE) +
  scale_edge_width(range = c(0.5, 2)) +
  scale_color_brewer(palette = "Set1") +
  theme_graph()
## Warning in RColorBrewer::brewer.pal(n, pal): n too large, allowed maximum for palette Set1 is 9
## Returning the palette you asked for with that many colors
## Warning: Removed 1 row containing missing values or values outside the scale range
## (`geom_point()`).
## Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): font family
## not found in Windows font database
## Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): font family
## not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database

# 边的样式
ggraph(g, layout = "circle") +
  geom_edge_arc(aes(width = weight), strength = 0.5) +
  geom_node_point(size = 5) +
  theme_graph()
## Warning: The `trans` argument of `continuous_scale()` is deprecated as of ggplot2 3.5.0.
## ℹ Please use the `transform` argument instead.
## This warning is displayed once per session.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database

# 有向边
g <- make_tree(10, children = 2)
ggraph(g, layout = "dendrogram") +
  geom_edge_diagonal() +
  geom_node_point(size = 3) +
  theme_graph()

小结:ggraph提供ggplot2风格的网络图绘制。

13.4 布局算法

选择合适的网络布局。

# 创建网络
set.seed(123)
g <- sample_pa(50, directed = FALSE)

# 力导向布局(Fruchterman-Reingold)
ggraph(g, layout = "fr") +
  geom_edge_link(alpha = 0.3) +
  geom_node_point(size = 2, color = "steelblue") +
  labs(title = "力导向布局 (FR)") +
  theme_graph()
## Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): font family
## not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database

# 圆形布局
ggraph(g, layout = "circle") +
  geom_edge_link(alpha = 0.3) +
  geom_node_point(size = 2, color = "steelblue") +
  labs(title = "圆形布局") +
  theme_graph()

# 树形布局
g_tree <- make_tree(20, children = 2)
ggraph(g_tree, layout = "dendrogram") +
  geom_edge_diagonal() +
  geom_node_point(size = 2, color = "steelblue") +
  labs(title = "树形布局") +
  theme_graph()

# 网格布局
ggraph(g, layout = "grid") +
  geom_edge_link(alpha = 0.3) +
  geom_node_point(size = 2, color = "steelblue") +
  labs(title = "网格布局") +
  theme_graph()

小结:不同布局算法适用于不同类型的网络。

13.5 边与节点的美学映射

自定义网络图的外观。

# 创建带属性的网络
set.seed(123)
g <- sample_pa(30, directed = FALSE)

# 添加节点属性
V(g)$degree <- degree(g)
V(g)$community <- membership(cluster_louvain(g))
V(g)$name <- paste0("N", 1:30)

# 添加边属性
E(g)$weight <- runif(ecount(g), 1, 5)

# 节点大小映射度数
ggraph(g, layout = "fr") +
  geom_edge_link(aes(width = weight), alpha = 0.3) +
  geom_node_point(aes(size = degree, color = factor(community))) +
  scale_size_continuous(range = c(2, 10)) +
  scale_color_brewer(palette = "Set1") +
  labs(title = "节点大小映射度数") +
  theme_graph()
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database

# 添加标签
ggraph(g, layout = "fr") +
  geom_edge_link(alpha = 0.3) +
  geom_node_point(aes(size = degree, color = factor(community))) +
  geom_node_text(aes(label = name), size = 2, repel = TRUE) +
  scale_size_continuous(range = c(2, 8)) +
  labs(title = "带标签的网络图") +
  theme_graph()
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database

小结:可以通过aes()映射节点和边的属性。

13.6 网络中的分组与社区高亮

展示网络的社区结构。

# 创建网络并检测社区
set.seed(123)
g <- sample_pa(50, directed = FALSE)
comm <- cluster_louvain(g)
V(g)$community <- membership(comm)

# 按社区着色
ggraph(g, layout = "fr") +
  geom_edge_link(alpha = 0.3) +
  geom_node_point(aes(color = factor(community)), size = 3) +
  scale_color_brewer(palette = "Set1", name = "社区") +
  labs(title = "社区结构可视化") +
  theme_graph()
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database

# 高亮社区边界
ggraph(g, layout = "fr") +
  geom_mark_hull(aes(x = x, y = y, fill = factor(community)),
                 alpha = 0.2) +
  geom_edge_link(alpha = 0.3) +
  geom_node_point(aes(color = factor(community)), size = 3) +
  scale_fill_brewer(palette = "Set1", name = "社区") +
  scale_color_brewer(palette = "Set1", name = "社区") +
  labs(title = "社区边界高亮") +
  theme_graph()
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database

# 分组布局
ggraph(g, layout = "fr") +
  geom_edge_link(alpha = 0.3) +
  geom_node_point(aes(color = factor(community)), size = 3) +
  facet_nodes(~community) +
  scale_color_brewer(palette = "Set1") +
  theme_graph()
## Warning in grid.Call(C_stringMetric, as.graphicsAnnot(x$label)): font family
## not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database

小结:社区检测和高亮可以展示网络的结构特征。

13.7 层次结构:树状图

可视化层次结构数据。

# 创建树形结构
g <- make_tree(20, children = 2)

# 树状图
ggraph(g, layout = "dendrogram") +
  geom_edge_diagonal() +
  geom_node_point(size = 2, color = "steelblue") +
  labs(title = "树状图") +
  theme_graph()
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database

# 圆形树状图
ggraph(g, layout = "dendrogram", circular = TRUE) +
  geom_edge_diagonal() +
  geom_node_point(aes(filter = leaf), size = 2, color = "steelblue") +
  coord_fixed() +
  labs(title = "圆形树状图") +
  theme_graph()

# 添加标签
V(g)$name <- paste0("Node", 1:20)

ggraph(g, layout = "dendrogram") +
  geom_edge_diagonal() +
  geom_node_text(aes(label = name, filter = leaf), size = 2, hjust = 1) +
  labs(title = "带标签的树状图") +
  theme_graph()
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database

小结:树状图适合展示层次结构数据。

13.8 旭日图(Sunburst Plot)

创建旭日图。

# 创建层次数据
edges <- data.frame(
  from = c("Root", "Root", "Root", "A", "A", "B", "B", "B"),
  to = c("A", "B", "C", "A1", "A2", "B1", "B2", "B3")
)

g <- graph_from_data_frame(edges)

# 旭日图
ggraph(g, layout = "partition", circular = TRUE) +
  geom_node_arc_bar(aes(fill = depth), color = "white") +
  coord_fixed() +
  scale_fill_viridis(option = "D", name = "层级") +
  labs(title = "旭日图") +
  theme_graph()
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database

# 矩形分区图
ggraph(g, layout = "partition") +
  geom_node_tile(aes(fill = depth), color = "white") +
  scale_fill_viridis(option = "D", name = "层级") +
  labs(title = "矩形分区图") +
  theme_graph()
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call(C_textBounds, as.graphicsAnnot(x$label), x$x, x$y, : font
## family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database
## Warning in grid.Call.graphics(C_text, as.graphicsAnnot(x$label), x$x, x$y, :
## font family not found in Windows font database

小结:旭日图展示层次结构的比例关系。

13.9 矩形树图(Treemap)

创建矩形树图。

# treemapify包已在setup中加载
# 创建数据
data <- data.frame(
  group = c("A", "A", "B", "B", "C", "C"),
  subgroup = c("A1", "A2", "B1", "B2", "C1", "C2"),
  value = c(30, 20, 25, 15, 20, 10)
)

# 矩形树图
ggplot(data, aes(area = value, fill = group, label = subgroup)) +
  geom_treemap() +
  geom_treemap_text() +
  scale_fill_brewer(palette = "Set1", name = "组别") +
  labs(title = "矩形树图")

# 嵌套矩形树图
ggplot(data, aes(area = value, fill = group, subgroup = subgroup, label = subgroup)) +
  geom_treemap() +
  geom_treemap_subgroup_border() +
  geom_treemap_subgroup_text() +
  geom_treemap_text() +
  scale_fill_brewer(palette = "Set1", name = "组别") +
  labs(title = "嵌套矩形树图")

小结:矩形树图展示层次结构的比例关系。

13.10 桑基图(Sankey Diagram)

创建桑基图。

# 使用ggalluvial包创建桑基图
library(ggalluvial)

# 创建桑基数据
data <- data.frame(
  node1 = c("A", "A", "B", "B"),
  node2 = c("X", "Y", "X", "Y"),
  value = c(10, 20, 15, 25)
)

# 桑基图
ggplot(data, aes(axis1 = node1, axis2 = node2, y = value)) +
  geom_alluvium(aes(fill = node1), width = 1/12) +
  geom_stratum(width = 1/12, fill = "grey", color = "white") +
  geom_text(stat = "stratum", aes(label = after_stat(stratum))) +
  scale_x_discrete(limits = c("来源", "目标"), expand = c(0.05, 0.05)) +
  scale_fill_brewer(palette = "Set1", name = "来源") +
  labs(title = "桑基图", y = "数量") +
  theme_minimal()

# 多层桑基图
data_multi <- data.frame(
  stage1 = c("A", "A", "A", "B", "B", "B"),
  stage2 = c("X", "X", "Y", "X", "Y", "Y"),
  stage3 = c("M", "N", "M", "N", "M", "N"),
  value = c(10, 15, 20, 12, 18, 25)
)

ggplot(data_multi, aes(axis1 = stage1, axis2 = stage2, axis3 = stage3, y = value)) +
  geom_alluvium(aes(fill = stage1), width = 1/12) +
  geom_stratum(width = 1/12, fill = "grey", color = "white") +
  geom_text(stat = "stratum", aes(label = after_stat(stratum))) +
  scale_x_discrete(limits = c("阶段1", "阶段2", "阶段3"), expand = c(0.05, 0.05)) +
  scale_fill_brewer(palette = "Set1", name = "阶段1") +
  labs(title = "多层桑基图", y = "数量") +
  theme_minimal()

小结:桑基图展示流量和转移关系。


第十三章总结

功能 用途
网络分析 igraph 网络数据处理
网络绘图 ggraph ggplot2风格网络图
布局算法 layout_* 网络布局
树状图 ggraph 层次结构
旭日图 ggraph 层次比例
矩形树图 treemapify 层次比例
桑基图 ggsankey 流量关系

第十四章:模型诊断与统计结果可视化

本章介绍如何可视化统计模型的结果和诊断信息。

14.1 线性回归诊断图

可视化线性回归的诊断信息。

# 基础诊断图
model <- lm(hwy ~ displ + cyl, data = mpg)

# 基础R诊断图
par(mfrow = c(2, 2))
plot(model)

par(mfrow = c(1, 1))

# 使用ggplot2
library(ggplot2)
library(broom)

# 获取诊断数据
diag_data <- augment(model)

# 残差vs拟合值
ggplot(diag_data, aes(x = .fitted, y = .resid)) +
  geom_point() +
  geom_smooth(se = FALSE) +
  geom_hline(yintercept = 0, linetype = "dashed") +
  labs(x = "拟合值", y = "残差")
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'

# Q-Q图
ggplot(diag_data, aes(sample = .resid)) +
  stat_qq() +
  stat_qq_line() +
  labs(x = "理论分位数", y = "样本分位数")

# 使用autoplot
# library(ggfortify)
# autoplot(model)

小结:残差图和Q-Q图是诊断线性回归的重要工具。

14.2 残差分析图

详细的残差分析。

library(ggplot2)
library(broom)

model <- lm(hwy ~ displ + cyl, data = mpg)
diag_data <- augment(model)

# 残差vs拟合值
ggplot(diag_data, aes(x = .fitted, y = .resid)) +
  geom_point(alpha = 0.5) +
  geom_smooth(se = FALSE, color = "red") +
  geom_hline(yintercept = 0, linetype = "dashed", color = "blue") +
  labs(title = "残差 vs 拟合值", x = "拟合值", y = "残差")
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'

# 标准化残差
ggplot(diag_data, aes(x = .fitted, y = .std.resid)) +
  geom_point(alpha = 0.5) +
  geom_hline(yintercept = c(-2, 0, 2), linetype = "dashed", color = "red") +
  labs(title = "标准化残差", x = "拟合值", y = "标准化残差")

# 尺度位置图
ggplot(diag_data, aes(x = .fitted, y = sqrt(abs(.std.resid)))) +
  geom_point(alpha = 0.5) +
  geom_smooth(se = FALSE, color = "red") +
  labs(title = "尺度位置图", x = "拟合值", y = expression(sqrt("|标准化残差|")))
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'

# 残差vs杠杆
ggplot(diag_data, aes(x = .hat, y = .std.resid)) +
  geom_point(alpha = 0.5) +
  geom_smooth(se = FALSE, color = "red") +
  geom_hline(yintercept = 0, linetype = "dashed") +
  labs(title = "残差 vs 杠杆值", x = "杠杆值", y = "标准化残差")
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'

小结:残差分析帮助检验模型假设。

14.3 模型系数可视化

可视化回归系数。

library(ggplot2)
library(broom)

model <- lm(hwy ~ displ + cyl + drv, data = mpg)
coef_data <- tidy(model, conf.int = TRUE)

# 系数点图
ggplot(coef_data, aes(x = estimate, y = term)) +
  geom_point() +
  geom_errorbarh(aes(xmin = conf.low, xmax = conf.high), height = 0.2) +
  geom_vline(xintercept = 0, linetype = "dashed") +
  labs(x = "系数估计", y = "")
## Warning: `geom_errorbarh()` was deprecated in ggplot2 4.0.0.
## ℹ Please use the `orientation` argument of `geom_errorbar()` instead.
## This warning is displayed once per session.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## `height` was translated to `width`.

# 森林图风格
ggplot(coef_data, aes(x = estimate, y = term)) +
  geom_point(size = 3) +
  geom_errorbarh(aes(xmin = conf.low, xmax = conf.high), height = 0.2) +
  geom_vline(xintercept = 0, linetype = "dashed", color = "red") +
  theme_minimal() +
  labs(x = "系数估计", y = "", title = "回归系数")
## `height` was translated to `width`.

# 使用dotwhisker包
# library(dotwhisker)
# dwplot(model)

小结:系数图直观展示回归系数和置信区间。

14.4 方差分析结果可视化

可视化ANOVA结果。

library(ggplot2)

# 单因素方差分析
aov_result <- aov(hwy ~ class, data = mpg)

# 均值比较图
ggplot(mpg, aes(x = class, y = hwy)) +
  geom_boxplot() +
  stat_summary(fun = mean, geom = "point", color = "red", size = 3)

# 带置信区间的均值图
library(dplyr)

means <- mpg %>%
  group_by(class) %>%
  summarise(
    mean = mean(hwy),
    se = sd(hwy) / sqrt(n()),
    n = n()
  )

ggplot(means, aes(x = class, y = mean)) +
  geom_point(size = 3) +
  geom_errorbar(aes(ymin = mean - se, ymax = mean + se), width = 0.2) +
  labs(y = "平均油耗", x = "车型类别")

# 使用ggpubr添加显著性标记
# library(ggpubr)
# ggboxplot(mpg, x = "class", y = "hwy", add = "jitter") +
#   stat_compare_means(method = "anova")

小结:ANOVA结果可以用箱线图和均值图展示。

14.5 主成分分析(PCA)双标图

可视化PCA结果。

# 使用prcomp进行PCA
pca_result <- prcomp(mtcars[, 1:7], scale. = TRUE)

# 基础双标图
biplot(pca_result, main = "PCA双标图")

# 使用factoextra包可视化
# 变量贡献图
fviz_pca_var(pca_result, 
             col.var = "contrib",
             gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
             title = "变量贡献图")

# 个体图
fviz_pca_ind(pca_result,
             col.ind = "cos2",
             gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
             title = "样本分布图")

# 双标图
fviz_pca_biplot(pca_result, 
                repel = TRUE,
                title = "PCA双标图")

小结:双标图展示PCA的变量和样本信息。

14.6 聚类树状图

可视化聚类结果。

# 层次聚类
hc <- hclust(dist(mtcars), method = "ward.D2")

# 基础树状图
plot(hc, main = "层次聚类树状图", xlab = "样本", sub = "")

# 使用factoextra可视化
# 矩形树状图
fviz_dend(hc, k = 4, cex = 0.5, k_colors = c("#2E9FDF", "#00AFBB", "#E7B800", "#FC4E07"),
          color_labels_by_k = TRUE, rect = TRUE, rect_border = c("#2E9FDF", "#00AFBB", "#E7B800", "#FC4E07"),
          main = "聚类树状图(4类)")

# 环形树状图
fviz_dend(hc, k = 4, cex = 0.5, type = "circular",
          k_colors = c("#2E9FDF", "#00AFBB", "#E7B800", "#FC4E07"),
          main = "环形聚类树状图")

# K均值聚类
set.seed(123)
km <- kmeans(mtcars[, 1:4], centers = 3, nstart = 25)

# 聚类结果可视化
fviz_cluster(km, data = mtcars[, 1:4],
             ellipse.type = "convex",
             palette = "jco",
             ggtheme = theme_minimal(),
             main = "K均值聚类结果")

小结:树状图和聚类图展示聚类结构。

14.7 随机森林变量重要性图

可视化随机森林的变量重要性。

# 随机森林模型
set.seed(123)
# importance=TRUE 才会输出完整的重要性矩阵
rf <- randomForest(Species ~ ., data = iris, ntree = 100, importance = TRUE)

# 查看变量重要性的列名
colnames(importance(rf))
## [1] "setosa"               "versicolor"           "virginica"           
## [4] "MeanDecreaseAccuracy" "MeanDecreaseGini"
# 变量重要性矩阵
importance(rf)
##                 setosa versicolor virginica MeanDecreaseAccuracy
## Sepal.Length  2.334999  3.8525315  3.909442             5.331391
## Sepal.Width   1.873228 -0.2344981  2.931587             2.299106
## Petal.Length  9.062834 14.1250709 10.997897            13.197705
## Petal.Width  11.214854 14.2553890 16.251155            16.117169
##              MeanDecreaseGini
## Sepal.Length        10.133410
## Sepal.Width          2.021934
## Petal.Length        39.955902
## Petal.Width         47.133554
# 基础变量重要性图
varImpPlot(rf, main = "随机森林变量重要性")

# 使用ggplot2可视化 MeanDecreaseGini
imp_df <- data.frame(
  variable = rownames(importance(rf)),
  importance = importance(rf)[, "MeanDecreaseGini"]
)

ggplot(imp_df, aes(x = reorder(variable, importance), y = importance)) +
  geom_col(fill = "steelblue") +
  coord_flip() +
  labs(x = "变量", y = "重要性 (MeanDecreaseGini)", 
       title = "随机森林变量重要性") +
  theme_minimal()

# 使用ggplot2可视化 MeanDecreaseAccuracy
imp_df2 <- data.frame(
  variable = rownames(importance(rf)),
  importance = importance(rf)[, "MeanDecreaseAccuracy"]
)

ggplot(imp_df2, aes(x = reorder(variable, importance), y = importance)) +
  geom_col(fill = "coral") +
  coord_flip() +
  labs(x = "变量", y = "重要性 (MeanDecreaseAccuracy)", 
       title = "随机森林变量重要性(准确率下降)") +
  theme_minimal()

小结:变量重要性图展示各变量的贡献程度。

14.8 混淆矩阵可视化

可视化分类模型的混淆矩阵。

# 创建混淆矩阵数据
conf_matrix <- data.frame(
  Predicted = rep(c("A", "B", "C"), each = 3),
  Actual = rep(c("A", "B", "C"), 3),
  Count = c(50, 5, 2, 3, 45, 4, 1, 3, 40)
)

# 热图展示
ggplot(conf_matrix, aes(x = Predicted, y = Actual, fill = Count)) +
  geom_tile() +
  geom_text(aes(label = Count), color = "white", size = 5) +
  scale_fill_gradient(low = "white", high = "steelblue") +
  theme_minimal()

# 使用caret包
# library(caret)
# confusion_matrix <- confusionMatrix(predictions, actual)
# fourfoldplot(confusion_matrix$table)

小结:混淆矩阵热图直观展示分类结果。

14.9 ROC曲线与AUC

可视化ROC曲线。

# 创建模拟数据
set.seed(123)
actual <- sample(c(0, 1), 100, replace = TRUE)
predicted_prob <- runif(100)

# 创建ROC对象
roc_obj <- roc(actual, predicted_prob, quiet = TRUE)

# 基础ROC曲线
plot(roc_obj, main = "ROC曲线", col = "#2E9FDF", lwd = 2)

# 计算AUC
auc_value <- auc(roc_obj)
text(0.6, 0.3, paste("AUC =", round(auc_value, 3)), cex = 1.2)

# 使用ggplot2绑定ROC曲线
roc_df <- data.frame(
  specificity = 1 - roc_obj$specificities,
  sensitivity = roc_obj$sensitivities
)

ggplot(roc_df, aes(x = specificity, y = sensitivity)) +
  geom_line(color = "#2E9FDF", size = 1.2) +
  geom_abline(slope = 1, intercept = 0, linetype = "dashed", color = "gray") +
  annotate("text", x = 0.7, y = 0.3, 
           label = paste("AUC =", round(auc_value, 3)), 
           size = 5) +
  labs(x = "1 - 特异度", y = "敏感度", title = "ROC曲线") +
  theme_minimal() +
  coord_equal()
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once per session.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

# 多模型比较(模拟)
roc_obj2 <- roc(actual, runif(100), quiet = TRUE)

ggroc(list(模型1 = roc_obj, 模型2 = roc_obj2)) +
  scale_color_brewer(palette = "Set1", name = "模型") +
  geom_abline(slope = 1, intercept = 0, linetype = "dashed", color = "gray") +
  labs(title = "多模型ROC曲线比较") +
  theme_minimal()

小结:ROC曲线评估分类模型性能。

14.10 生存曲线

可视化生存分析结果。

# 使用survival和survminer包(已在setup中加载)

# 使用lung数据集
data(lung)
## Warning in data(lung): data set 'lung' not found
# 创建生存对象
fit <- survfit(Surv(time, status) ~ sex, data = lung)

# 基础生存曲线
ggsurvplot(fit, 
           data = lung,
           title = "生存曲线",
           xlab = "时间(天)",
           ylab = "生存概率",
           legend.title = "性别",
           legend.labs = c("男性", "女性"),
           ggtheme = theme_minimal())

# 完整生存曲线
ggsurvplot(fit, 
           data = lung,
           pval = TRUE,           # 添加p值
           conf.int = TRUE,       # 添加置信区间
           risk.table = TRUE,     # 添加风险表
           title = "完整生存曲线",
           xlab = "时间(天)",
           ylab = "生存概率",
           legend.title = "性别",
           legend.labs = c("男性", "女性"),
           ggtheme = theme_minimal())
## Ignoring unknown labels:
## • colour : "性别"

# 累积风险曲线
ggsurvplot(fit, 
           fun = "cumhaz",
           data = lung,
           title = "累积风险曲线",
           xlab = "时间(天)",
           ylab = "累积风险",
           legend.title = "性别",
           legend.labs = c("男性", "女性"),
           ggtheme = theme_minimal())

小结:生存曲线展示生存分析结果。

14.11 模型预测对比图

对比预测值和实际值。

library(ggplot2)

model <- lm(hwy ~ displ + cyl, data = mpg)
pred_data <- data.frame(
  actual = mpg$hwy,
  predicted = predict(model)
)

# 散点图对比
ggplot(pred_data, aes(x = actual, y = predicted)) +
  geom_point(alpha = 0.5) +
  geom_abline(slope = 1, intercept = 0, color = "red", linetype = "dashed") +
  labs(x = "实际值", y = "预测值", title = "预测 vs 实际")

# 残差分布
pred_data$residual <- pred_data$actual - pred_data$predicted

ggplot(pred_data, aes(x = residual)) +
  geom_histogram(bins = 30, fill = "steelblue", alpha = 0.7) +
  geom_vline(xintercept = 0, color = "red", linetype = "dashed") +
  labs(x = "残差", y = "频数")

小结:预测对比图评估模型预测能力。

14.12 贝叶斯模型后验分布图

可视化贝叶斯模型结果。

# 使用bayesplot包
# install.packages("bayesplot")
# library(bayesplot)

# 假设有MCMC样本
# mcmc_trace(samples)  # 轨迹图
# mcmc_dens(samples)   # 密度图
# mcmc_hist(samples)   # 直方图

# 后验预测检验
# pp_check(model)

小结:bayesplot包可视化贝叶斯模型结果。


第十四章总结

功能 用途
回归诊断 broom, ggplot2 残差分析
系数可视化 dotwhisker 系数图
PCA可视化 factoextra 双标图
聚类可视化 factoextra 树状图
混淆矩阵 caret, ggplot2 分类评估
ROC曲线 pROC, plotROC 分类性能
生存曲线 survminer 生存分析
贝叶斯可视化 bayesplot 后验分布

第十五章:可视化性能优化与最佳实践

本章介绍如何优化可视化性能和遵循最佳实践。

15.1 大数据集可视化策略

处理大数据集的策略。

library(ggplot2)

# 创建大数据集
set.seed(123)
big_data <- data.frame(
  x = rnorm(100000),
  y = rnorm(100000),
  group = sample(letters[1:5], 100000, replace = TRUE)
)

# 策略1:抽样
sample_data <- big_data[sample(nrow(big_data), 5000), ]

ggplot(sample_data, aes(x = x, y = y)) +
  geom_point(alpha = 0.3)

# 策略2:分箱
ggplot(big_data, aes(x = x, y = y)) +
  geom_bin2d(bins = 50)

# 策略3:透明度
ggplot(big_data, aes(x = x, y = y)) +
  geom_point(alpha = 0.01)

# 策略4:六边形分箱
# ggplot(big_data, aes(x = x, y = y)) +
#   geom_hex(bins = 50)

小结:抽样、分箱和透明度是处理大数据集的常用策略。

15.2 geom_point的透明度与光栅化

优化散点图性能。

library(ggplot2)

set.seed(123)
big_data <- data.frame(
  x = rnorm(50000),
  y = rnorm(50000)
)

# 低透明度
ggplot(big_data, aes(x = x, y = y)) +
  geom_point(alpha = 0.05)

# 使用光栅化(需要ragg包)
# install.packages("ragg")
# library(ragg)

# ggsave("plot.png", 
#        ggplot(big_data, aes(x = x, y = y)) +
#          geom_point(alpha = 0.05),
#        device = agg_png,
#        width = 8, height = 6, dpi = 300)

小结:透明度和光栅化可以优化大数据散点图。

15.3 使用data.table预先聚合

预先聚合数据提高性能。

# 使用data.table
# install.packages("data.table")
# library(data.table)

# 创建大数据
# big_dt <- data.table(x = rnorm(1e6), group = sample(letters, 1e6, replace = TRUE))

# 聚合
# agg_data <- big_dt[, .(mean = mean(x), sd = sd(x), n = .N), by = group]

# 可视化聚合结果
# ggplot(agg_data, aes(x = group, y = mean)) +
#   geom_col()

小结:预先聚合可以大幅提高可视化性能。

15.4 图形保存格式选择

选择合适的图形格式。

library(ggplot2)

p <- ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point()

# 矢量图格式
# PDF:适合打印和出版
ggsave("plot.pdf", p, width = 8, height = 6)

# SVG:适合网页
ggsave("plot.svg", p, width = 8, height = 6)

# 位图格式
# PNG:通用格式,支持透明
ggsave("plot.png", p, width = 8, height = 6, dpi = 300)

# JPEG:照片类图像,不支持透明
ggsave("plot.jpg", p, width = 8, height = 6, dpi = 300)

# TIFF:高质量印刷
ggsave("plot.tiff", p, width = 8, height = 6, dpi = 300)

# 格式选择建议
# 矢量图(PDF/SVG):适合线条图、小数据量
# 位图(PNG):适合大数据量、网页展示
# 高分辨率(300+ dpi):适合印刷

小结:矢量图适合印刷,位图适合大数据和网页。

15.5 分辨率与尺寸设置

正确设置图形参数。

library(ggplot2)

p <- ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point()

# 设置DPI
ggsave("plot_low.png", p, dpi = 72)    # 网页
ggsave("plot_high.png", p, dpi = 300)  # 印刷
ggsave("plot_print.png", p, dpi = 600) # 高质量印刷

# 设置尺寸(英寸)
ggsave("plot.png", p, width = 10, height = 8, dpi = 300)

# 设置单位
ggsave("plot_cm.png", p, width = 25, height = 20, units = "cm", dpi = 300)

# 使用cairo设备(更好的字体支持)
ggsave("plot_cairo.png", p, type = "cairo", dpi = 300)

小结:根据用途选择合适的DPI和尺寸。

15.6 可视化配色原则

遵循配色最佳实践。

library(ggplot2)

# 色盲友好配色
# 使用viridis或ColorBrewer色盲友好调色板

# 分类数据
ggplot(mpg, aes(x = displ, y = hwy, color = drv)) +
  geom_point() +
  scale_color_brewer(palette = "Set2")  # 色盲友好

# 连续数据
ggplot(mpg, aes(x = displ, y = hwy, color = cty)) +
  geom_point() +
  scale_color_viridis_c()  # 色盲友好

# 配色原则
# 1. 避免使用红绿对比(色盲问题)
# 2. 使用感知均匀的颜色渐变
# 3. 分类颜色应有足够对比度
# 4. 考虑黑白打印效果

小结:使用色盲友好的配色方案。

15.7 图标题、轴标签的清晰性

创建清晰的标签。

library(ggplot2)

# 清晰的标签示例
ggplot(mpg, aes(x = displ, y = hwy)) +
  geom_point() +
  labs(
    title = "发动机排量与油耗的关系",
    subtitle = "数据来源:EPA燃料经济数据",
    x = "发动机排量 (升)",
    y = "高速公路油耗 (英里/加仑)",
    caption = "图1:散点图展示排量与油耗的负相关关系"
  ) +
  theme_minimal()

# 标签原则
# 1. 使用描述性标题
# 2. 包含单位
# 3. 添加数据来源
# 4. 使用适当的字体大小

小结:清晰的标签帮助读者理解图形。

15.8 避免信息冗余与图表垃圾

保持图形简洁。

library(ggplot2)

# 过度装饰的图形(避免)
ggplot(mpg, aes(x = class, y = hwy)) +
  geom_bar(stat = "identity", fill = "steelblue") +
  labs(title = "各类车型油耗", x = "车型", y = "油耗") +
  theme(
    panel.background = element_rect(fill = "lightyellow"),
    panel.grid.major = element_line(color = "pink"),
    panel.grid.minor = element_line(color = "lightpink"),
    plot.background = element_rect(fill = "lightgray")
  )

# 简洁清晰的图形(推荐)
ggplot(mpg, aes(x = reorder(class, hwy), y = hwy)) +
  geom_bar(stat = "identity", fill = "steelblue") +
  labs(title = "各类车型平均油耗", x = "车型", y = "油耗 (英里/加仑)") +
  theme_minimal() +
  coord_flip()

小结:简洁的图形更有效传达信息。

15.9 可重复性:脚本化图形生成

确保图形可重复。

# 创建可重复的图形脚本

# 1. 设置随机种子
set.seed(123)

# 2. 记录包版本
# sessionInfo()

# 3. 使用相对路径
# data <- read.csv("data/mydata.csv")

# 4. 封装绘图函数
create_scatter_plot <- function(data, x_var, y_var, color_var = NULL) {
  p <- ggplot(data, aes_string(x = x_var, y = y_var, color = color_var)) +
    geom_point() +
    theme_minimal()
  return(p)
}

# 使用函数
# p <- create_scatter_plot(mpg, "displ", "hwy", "drv")
# print(p)

# 5. 保存图形和代码
# ggsave("output/plot.png", p)
# saveRDS(p, "output/plot.rds")  # 保存图形对象

小结:脚本化确保图形可重复生成。

15.10 自定义函数封装常用图形模板

创建可重用的图形模板。

library(ggplot2)

# 定义主题模板
theme_publication <- function() {
  theme_minimal() +
  theme(
    plot.title = element_text(size = 14, face = "bold"),
    axis.title = element_text(size = 12),
    axis.text = element_text(size = 10),
    legend.position = "bottom",
    panel.grid.minor = element_blank()
  )
}

# 定义散点图模板
scatter_template <- function(data, x, y, color = NULL, 
                              title = "", xlab = "", ylab = "") {
  ggplot(data, aes_string(x = x, y = y, color = color)) +
    geom_point(alpha = 0.7, size = 2) +
    geom_smooth(method = "lm", se = TRUE, alpha = 0.2) +
    labs(title = title, x = xlab, y = ylab) +
    theme_publication()
}

# 使用模板
scatter_template(mpg, "displ", "hwy", "drv",
                 title = "排量与油耗关系",
                 xlab = "发动机排量 (升)",
                 ylab = "高速公路油耗")
## Warning: `aes_string()` was deprecated in ggplot2 3.0.0.
## ℹ Please use tidy evaluation idioms with `aes()`.
## ℹ See also `vignette("ggplot2-in-packages")` for more information.
## This warning is displayed once per session.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## `geom_smooth()` using formula = 'y ~ x'

# 定义柱状图模板
bar_template <- function(data, x, y, fill = NULL,
                         title = "", xlab = "", ylab = "") {
  ggplot(data, aes_string(x = x, y = y, fill = fill)) +
    geom_bar(stat = "identity", position = "dodge") +
    labs(title = title, x = xlab, y = ylab) +
    theme_publication() +
    theme(axis.text.x = element_text(angle = 45, hjust = 1))
}

小结:自定义模板提高效率和一致性。


第十五章总结

主题 策略
大数据集 抽样、分箱、透明度
图形格式 矢量图(印刷)、位图(网页)
分辨率 72dpi(网页)、300dpi(印刷)
配色 色盲友好、感知均匀
标签 清晰描述、包含单位
简洁性 避免过度装饰
可重复性 脚本化、记录版本
模板 封装常用图形

总结

本教程全面介绍了R语言数据可视化的核心内容:

基础部分: - 基础绘图系统(base graphics) - ggplot2图形语法 - 常用统计图形

进阶部分: - 图形属性与标度 - 坐标系与分面 - 主题定制 - 多图组合

高级部分: - 颜色与字体控制 - 交互式可视化 - 高级图表类型 - 动态可视化 - 空间数据可视化 - 网络可视化 - 模型诊断可视化

最佳实践: - 性能优化 - 配色原则 - 可重复性

希望本教程能帮助您掌握R语言数据可视化的核心技能!


作者:小天使格礼

参考资源: - ggplot2官方文档:https://ggplot2.tidyverse.org/ - R Graph Gallery:https://r-graph-gallery.com/ - R Color Brewer:https://colorbrewer2.org/