蛛网图, 又称雷达图. 缺点不少, 在数据科学领域不推荐使用.

14.1 PKG

Show/Hide Code
library(fmsb) # 用于绘制雷达图
library(RColorBrewer) # 用于生成颜色
library(scales)         # 用于设置透明度
library(tidyverse)      # 用于数据处理和可视化
library(hrbrthemes)     # 用于美化图表主题
library(colormap)      # 用于生成颜色映射
library(GGally)       # 用于绘制平行坐标图
library(viridis)      # 用于生成颜色映射
# remotes::install_github("ricardo-bion/ggradar")
library(ggradar)     # 用于绘制雷达图
library(palmerpenguins) # 用于示例企鹅数据集
library(scales)  # 用于设置透明度
library(showtext) # 用于加载字体
showtext_auto() # 自动加载字体

14.2 问题

  • 圆形布局 = 更难阅读
  • 不支持排名
  • 类别顺序影响巨大: 同样的数据不同的排序,形状差别巨大
  • 刻度不自由: 直观上 各类别的刻度应该是一样的, 设置每个类别的刻度不同, 会导致误解
  • 重叠绘图: 过多观测时不好展示
  • 过度评估差异: 雷达图中形状的面积也会以平方而非线性的方式增加,看起来差异比实际更显著
Show/Hide Code
# 设置随机种子,保证结果可复现
set.seed(1)

# 生成一个包含10个科目的数据框,每个科目随机生成一个2到20之间的整数
data <- as.data.frame(matrix(sample(2:20, 10, replace = TRUE), ncol = 10))

# 设置列名为各个科目
colnames(data) <- c(
    "math",        # 数学
    "english",     # 英语
    "biology",     # 生物
    "music",       # 音乐
    "R-coding",    # R编程
    "data-viz",    # 数据可视化
    "french",      # 法语
    "physic",      # 物理
    "statistic",   # 统计
    "sport"        # 体育
)

# 为了使用fmsb包绘制雷达图,需要在数据框前面添加最大值和最小值两行
data <- rbind(rep(20, 10), rep(0, 10), data)

# 自定义雷达图
par(mar = c(0, 0, 0, 0)) # 设置画布边距
radarchart(
    data,                # 输入数据
    axistype = 1,        # 坐标轴类型

    # 自定义多边形
    pcol = rgb(0.2, 0.5, 0.5, 0.9),   # 多边形边框颜色
    pfcol = rgb(0.2, 0.5, 0.5, 0.5),  # 多边形填充颜色
    plwd = 4,                         # 多边形边框线宽

    # 自定义网格
    cglcol = "grey",                  # 网格线颜色
    cglty = 1,                        # 网格线类型
    axislabcol = "grey",              # 轴标签颜色
    caxislabels = seq(0, 20, 5),      # 轴标签内容
    cglwd = 0.8,                      # 网格线宽

    # 自定义标签
    vlcex = 1.3                       # 变量标签字体大小
)

# 条形图:展示同一组数据的分布,更易于比较
data |>
    slice(3) |>                         # 选取第三行(即实际数据,前两行为最大最小值)
    t() |>                              # 转置数据框,方便后续处理
    as.data.frame() |>                  # 转换为数据框
    tibble::rownames_to_column() |>     # 将行名(科目名)转为一列
    arrange(V1) |>                      # 按分数升序排列
    mutate(rowname = factor(rowname, rowname)) |> # 保持原有顺序
    ggplot(aes(x = rowname, y = V1)) +  # 绘图,x轴为科目,y轴为分数
    geom_segment(
        aes(x = rowname, xend = rowname, y = 0, yend = V1),
        color = "grey"                    # 绘制灰色线段
    ) +
    geom_point(size = 5, color = "#69b3a2") + # 绘制数据点
    coord_flip() +                            # 翻转坐标轴,横向展示
    theme_ipsum() +                           # 使用hrbrthemes包的主题
    theme(
        panel.grid.minor.y = element_blank(),   # 去除y轴次网格线
        panel.grid.major.y = element_blank(),   # 去除y轴主网格线
        axis.text = element_text(size = 48),    # 设置坐标轴文字大小
        legend.position = "none"                # 不显示图例
    ) +
    ylim(0, 20) +                             # 设置y轴范围
    ylab("mark") +                            # y轴标签
    xlab("")                                  # x轴标签为空

左:雷达图;

右:棒棒糖图

雷达图不如棒棒糖直观

Show/Hide Code
# 创建数据:Jonathan在高中各科的成绩
set.seed(7)
data <- as.data.frame(matrix(sample(2:20, 10, replace = TRUE), ncol = 10))
colnames(data) <- c(
    "math",        # 数学
    "english",     # 英语
    "biology",     # 生物
    "music",       # 音乐
    "R-coding",    # R编程
    "data-viz",    # 数据可视化
    "french",      # 法语
    "physic",      # 物理
    "statistic",   # 统计
    "sport"        # 体育
)
# 将前三门科目的成绩设为19,6~8门成绩设为4,突出差异
data[1, 1:3] <- rep(19, 3)
data[1, 6:8] <- rep(4, 3)
# 按fmsb包要求,前两行为最大值和最小值
data <- rbind(rep(20, 10), rep(0, 10), data)

# 改变类别顺序,生成两组不同顺序的数据
data2 <- data[, sample(1:10, 10, replace = FALSE)]
data3 <- data[, sample(1:10, 10, replace = FALSE)]

# 自定义雷达图,展示同一组数据在不同类别顺序下的形状变化
par(mar = c(0, 0, 0, 0))      # 设置画布边距为0
par(mfrow = c(1, 3))          # 一行三列布局,便于对比

# 绘制第一组类别顺序的雷达图
radarchart(
    data,                       # 输入数据
    axistype = 1,               # 坐标轴类型
    pcol = rgb(0.2, 0.5, 0.5, 0.9),   # 多边形边框颜色
    pfcol = rgb(0.2, 0.5, 0.5, 0.5),  # 多边形填充颜色
    plwd = 4,                   # 多边形边框线宽
    cglcol = "grey",            # 网格线颜色
    cglty = 1,                  # 网格线类型
    axislabcol = "grey",        # 轴标签颜色
    caxislabels = seq(0, 20, 5),# 轴标签内容
    cglwd = 0.8,                # 网格线宽
    vlcex = 0.8                 # 变量标签字体大小
)

# 绘制第二组类别顺序的雷达图
radarchart(
    data2,                      # 输入数据(类别顺序已打乱)
    axistype = 1,
    pcol = rgb(0.2, 0.5, 0.5, 0.9),
    pfcol = rgb(0.2, 0.5, 0.5, 0.5),
    plwd = 4,
    cglcol = "grey",
    cglty = 1,
    axislabcol = "grey",
    caxislabels = seq(0, 20, 5),
    cglwd = 0.8,
    vlcex = 0.8
)

# 绘制第三组类别顺序的雷达图
radarchart(
    data3,                      # 输入数据(类别顺序再次打乱)
    axistype = 1,
    pcol = rgb(0.2, 0.5, 0.5, 0.9),
    pfcol = rgb(0.2, 0.5, 0.5, 0.5),
    plwd = 4,
    cglcol = "grey",
    cglty = 1,
    axislabcol = "grey",
    caxislabels = seq(0, 20, 5),
    cglwd = 0.8,
    vlcex = 0.8
)

类别顺序影响雷达图形状:同一组数据,不同类别顺序,形状差异巨大
Show/Hide Code
par(mfrow = c(1, 1)) # 重置布局
Show/Hide Code
# 生成一个包含5个科目的数据框,每个科目分数均为7
data <- as.data.frame(matrix(c(7, 7, 7, 7, 7), ncol = 5))

# 设置列名为各个科目
colnames(data) <- c("math", "english", "biology", "music", "R-coding")

# fmsb包要求数据框前两行为最大值和最小值,这里最大值为20,最小值为0
data <- rbind(rep(20, 5), rep(0, 5), data)

# 复制一份数据,作为第二组数据
data2 <- data
# 修改第三行(即实际数据),将分数全部设为14
data2[3, ] <- rep(14, 5)

# 设置画布边距为0,避免图形被裁剪
par(mar = rep(0, 4))

# 绘制第一组数据的雷达图
radarchart(
    data,                   # 输入数据
    axistype = 1,           # 坐标轴类型
    pcol = rgb(0.2, 0.5, 0.5, 0.9),   # 多边形边框颜色
    pfcol = rgb(0.2, 0.5, 0.5, 0.5),  # 多边形填充颜色
    plwd = 4,               # 多边形边框线宽
    cglcol = "grey",        # 网格线颜色
    cglty = 1,              # 网格线类型
    axislabcol = "grey",    # 轴标签颜色
    caxislabels = seq(0, 20, 5), # 轴标签内容
    cglwd = 0.8,            # 网格线宽
    vlcex = 0.8             # 变量标签字体大小
)

# 绘制第二组数据的雷达图
radarchart(
    data2,                  # 输入数据
    axistype = 1,           # 坐标轴类型
    pcol = rgb(0.2, 0.5, 0.5, 0.9),   # 多边形边框颜色
    pfcol = rgb(0.2, 0.5, 0.5, 0.5),  # 多边形填充颜色
    plwd = 4,               # 多边形边框线宽
    cglcol = "grey",        # 网格线颜色
    cglty = 1,              # 网格线类型
    axislabcol = "grey",    # 轴标签颜色
    caxislabels = seq(0, 20, 5), # 轴标签内容
    cglwd = 0.8,            # 网格线宽
    vlcex = 0.8             # 变量标签字体大小
)

左:所有科目分数均为7;

右:所有科目分数均为14。

雷达图过度评估了差距

14.3 改进

如果刻度相同, 可以使用条形图、棒棒糖图(吸管图)代替雷达图, 并进行排序

Show/Hide Code
# 设置随机种子,保证结果可复现
set.seed(1)

# 生成一个包含10个科目的数据框,每个科目随机生成一个2到20之间的整数
data <- as.data.frame(matrix(sample(2:20, 10, replace = TRUE), ncol = 10))

# 设置列名为各个科目
colnames(data) <- c(
    "math",        # 数学
    "english",     # 英语
    "biology",     # 生物
    "music",       # 音乐
    "R-coding",    # R编程
    "data-viz",    # 数据可视化
    "french",      # 法语
    "physic",      # 物理
    "statistic",   # 统计
    "sport"        # 体育
)

# 为了与雷达图数据结构一致,前两行为最大值和最小值
data <- rbind(rep(20, 10), rep(0, 10), data)

# 棒棒糖图:展示同一组数据的分布,更易于比较
data |>
    slice(3) |>                         # 选取第三行(即实际数据,前两行为最大最小值)
    t() |>                              # 转置数据框,方便后续处理
    as.data.frame() |>                  # 转换为数据框
    tibble::rownames_to_column() |>     # 将行名(科目名)转为一列
    arrange(V1) |>                      # 按分数升序排列
    mutate(rowname = factor(rowname, rowname)) |> # 保持原有顺序
    ggplot(aes(x = rowname, y = V1)) +  # 绘图,x轴为科目,y轴为分数
    geom_segment(
        aes(x = rowname, xend = rowname, y = 0, yend = V1),
        color = "grey"                    # 绘制灰色线段
    ) +
    geom_point(size = 5, color = "#69b3a2") + # 绘制数据点
    coord_flip() +                            # 翻转坐标轴,横向展示
    theme_ipsum() +                           # 使用hrbrthemes包的主题
    theme(
        panel.grid.minor.y = element_blank(),   # 去除y轴次网格线
        panel.grid.major.y = element_blank(),   # 去除y轴主网格线
        axis.text = element_text(size = 48),    # 设置坐标轴文字大小
        legend.position = "none"                # 不显示图例
    ) +
    ylim(0, 20) +                             # 设置y轴范围
    ylab("mark") +                            # y轴标签
    xlab("")                                  # x轴标签为空

棒棒糖图:同一组数据的分数分布,更易于比较

两个观测进行对比(哑铃图), 设置颜色或透明度来区分两组:

Show/Hide Code
# 设置随机种子,保证结果可复现
set.seed(1)

# 生成一个包含10个科目的数据框,每个科目随机生成一个2到20之间的整数,共两组观测
data <- as.data.frame(matrix(sample(2:20, 20, replace = TRUE), ncol = 10))

# 设置列名为各个科目
colnames(data) <- c(
    "math",        # 数学
    "english",     # 英语
    "biology",     # 生物
    "music",       # 音乐
    "R-coding",    # R编程
    "data-viz",    # 数据可视化
    "french",      # 法语
    "physic",      # 物理
    "statistic",   # 统计
    "sport"        # 体育
)

# 为了与雷达图数据结构一致,前两行为最大值和最小值
data <- rbind(rep(20, 10), rep(0, 10), data)

# 哑铃图:对比两组观测在各科目的分数差异
data |>
    slice(c(3, 4)) |>                         # 选取第三、四行(即两组实际观测数据)
    t() |>                                    # 转置数据框,方便后续处理
    as.data.frame() |>                        # 转换为数据框
    tibble::rownames_to_column() |>           # 将行名(科目名)转为一列
    arrange(V1) |>                            # 按第一组分数升序排列
    mutate(rowname = factor(rowname, rowname)) |> # 保持原有顺序
    ggplot(aes(x = rowname, y = V1)) +        # 绘图,x轴为科目,y轴为第一组分数
    geom_segment(
        aes(x = rowname, xend = rowname, y = V2, yend = V1),
        color = "grey"                        # 绘制两组分数之间的线段
    ) +
    geom_point(size = 5, color = "#69b3a2") + # 绘制第一组分数的数据点
    geom_point(aes(y = V2), size = 5, color = "#69b3a2", alpha = 0.5) + # 绘制第二组分数的数据点(透明)
    coord_flip() +                            # 翻转坐标轴,横向展示
    theme_ipsum() +                           # 使用hrbrthemes包的主题
    theme(
        panel.grid.minor.y = element_blank(),   # 去除y轴次网格线
        panel.grid.major.y = element_blank(),   # 去除y轴主网格线
        axis.text = element_text(size = 48)     # 设置坐标轴文字大小
    ) +
    ylim(0, 20) +                             # 设置y轴范围
    ylab("mark") +                            # y轴标签
    xlab("")                                  # x轴标签为空

哑铃图:对比两组观测在各科目的分数差异

观测很多考虑分面:

Show/Hide Code
# 设置随机种子,保证结果可复现
set.seed(1)

# 生成一个包含4位同学、10个科目的数据框,每个科目随机生成一个2到20之间的整数
data <- as.data.frame(matrix(sample(2:20, 40, replace = TRUE), ncol = 10))

# 设置列名为各个科目
colnames(data) <- c(
    "math",        # 数学
    "english",     # 英语
    "biology",     # 生物
    "music",       # 音乐
    "R-coding",    # R编程
    "data-viz",    # 数据可视化
    "french",      # 法语
    "physic",      # 物理
    "statistic",   # 统计
    "sport"        # 体育
)

# 为了使用fmsb包绘制雷达图,需要在数据框前面添加最大值和最小值两行
data <- rbind(rep(20, 10), rep(0, 10), data)

# 设置行名为4位同学
rownames(data) <- c("-", "--", "John", "Angli", "Baptiste", "Alfred")

# 数据整理:选取4位同学的数据,转置后整理为长格式,便于ggplot分面绘图
data |>
    slice(3:6) |>                        # 选取第3到第6行(4位同学的成绩)
    t() |>                               # 转置数据框,行变为科目,列为同学
    as.data.frame() |>                   # 转换为数据框
    tibble::rownames_to_column() |>      # 将行名(科目名)转为一列
    tidyr::gather(key = name, value = mark, -rowname) |> # 宽数据转为长数据
    mutate(
        # 重编码同学姓名,便于分面标签美观
        name = dplyr::recode(
            name,
            V1 = "John",
            V2 = "Angli",
            V3 = "Baptiste",
            V4 = "Alfred"
        ),
        # 保持科目顺序
        # rowname = factor(rowname, rowname)
    ) |>
    # 绘图:分面棒棒糖图
    ggplot(aes(x = rowname, y = mark)) +
    geom_bar(stat = "identity", fill = "#69b3a2", width = 0.6) + # 绘制条形
    coord_flip() +                                               # 翻转坐标轴,横向展示
    theme_ipsum() +                                              # 使用hrbrthemes包的主题
    theme(
        panel.grid.minor.y = element_blank(),   # 去除y轴次网格线
        panel.grid.major.y = element_blank(),   # 去除y轴主网格线
        axis.text = element_text(size = 48)     # 设置坐标轴文字大小
    ) +
    ylim(0, 20) +                             # 设置y轴范围
    ylab("mark") +                            # y轴标签
    xlab("") +                                # x轴标签为空
    facet_wrap(~name, ncol = 4)               # 按同学分面展示,每行4个分面

分面棒棒糖图:多位同学各科成绩分布对比

多系列且不同刻度:

Show/Hide Code
# 加载GGally包用于平行坐标图
library(GGally)
# 加载示例数据集iris
data <- iris

# 使用ggparcoord绘制平行坐标图
data |>
    ggparcoord(
        columns = 1:4,           # 选择前4列(花萼长度、花萼宽度、花瓣长度、花瓣宽度)
        groupColumn = 5,         # 按第5列(Species,花的种类)分组上色
        order = "anyClass",      # 变量顺序自动排列
        showPoints = TRUE,       # 显示每个观测点
        title = "Parallel Coordinate Plot for the Iris Data", # 图标题
        alphaLines = 0.3         # 线条透明度
    ) +
    scale_color_viridis(discrete = TRUE) + # 使用viridis配色方案
    theme_ipsum()                          # 使用hrbrthemes包的美化主题

鸢尾花数据集的平行坐标图:不同种类的花在各特征上的分布对比

14.4 单组

14.4.1 基本

Show/Hide Code
# 生成一个包含10个科目的数据框,每个科目随机生成一个2到20之间的整数
data <- matrix(sample(2:20, 10, replace = TRUE), ncol = 10) |>
    as.data.frame()

# 设置列名为各个科目
colnames(data) <- c(
    "math",        # 数学
    "english",     # 英语
    "biology",     # 生物
    "music",       # 音乐
    "R-coding",    # R编程
    "data-viz",    # 数据可视化
    "french",      # 法语
    "physic",      # 物理
    "statistic",   # 统计
    "sport"        # 体育
)

# 为了使用fmsb包绘制雷达图,需要在数据框前面添加最大值和最小值两行
data <- rbind(rep(20, 10), rep(0, 10), data)

# 检查数据格式是否正确
# head(data)

# 绘制默认的雷达图
radarchart(data)

基本雷达图

14.4.2 定制

Show/Hide Code
# 使用 radarchart 绘制定制雷达图
radarchart(
    data,                # 输入数据
    axistype = 1,        # 坐标轴类型

    # 自定义多边形
    pcol = rgb(0.2, 0.5, 0.5, 0.9),   # 多边形边框颜色
    pfcol = rgb(0.2, 0.5, 0.5, 0.5),  # 多边形填充颜色
    plwd = 4,                         # 多边形边框线宽

    # 自定义网格
    cglcol = "grey",                  # 网格线颜色
    cglty = 1,                        # 网格线类型
    axislabcol = "grey",              # 轴标签颜色
    caxislabels = seq(0, 20, 5),      # 轴标签内容
    cglwd = 0.8,                      # 网格线宽

    # 自定义标签
    vlcex = 0.8                       # 变量标签字体大小
)

定制雷达图:自定义多边形颜色、线宽、网格和标签

14.5 多组

14.5.1 基本

Show/Hide Code
# 设置随机种子,保证结果可复现
set.seed(99)

# 生成一个3行5列的数据框,表示3位同学在5个科目的分数(0~20之间不重复的整数)
data <- matrix(sample(0:20, 15, replace = FALSE), ncol = 5) |>
    as.data.frame()

# 设置列名为各个科目
colnames(data) <- c("math", "english", "biology", "music", "R-coding")

# 设置行名为三位同学
rownames(data) <- paste("mister", letters[1:3], sep = "-")

# fmsb包要求数据框前两行为最大值和最小值
data <- rbind(rep(20, 5), rep(0, 5), data)

# 绘制多组雷达图,展示三位同学的成绩分布
radarchart(data)

多组雷达图:展示三位同学在五个科目的表现

14.5.2 定制

Show/Hide Code
# 定义多边形边框颜色向量
colors_border <- c(
    rgb(0.2, 0.5, 0.5, 0.9),  # 第一位同学的边框颜色
    rgb(0.8, 0.2, 0.5, 0.9),  # 第二位同学的边框颜色
    rgb(0.7, 0.5, 0.1, 0.9)   # 第三位同学的边框颜色
)

# 定义多边形填充颜色向量
colors_in <- c(
    rgb(0.2, 0.5, 0.5, 0.4),  # 第一位同学的填充颜色
    rgb(0.8, 0.2, 0.5, 0.4),  # 第二位同学的填充颜色
    rgb(0.7, 0.5, 0.1, 0.4)   # 第三位同学的填充颜色
)

# 绘制定制多组雷达图
radarchart(
    data,                # 输入数据
    axistype = 1,        # 坐标轴类型

    # 自定义多边形
    pcol = colors_border,    # 多边形边框颜色
    pfcol = colors_in,       # 多边形填充颜色
    plwd = 4,                # 多边形边框线宽
    plty = 1,                # 多边形线型

    # 自定义网格
    cglcol = "grey",         # 网格线颜色
    cglty = 1,               # 网格线类型
    axislabcol = "grey",     # 轴标签颜色
    caxislabels = seq(0, 20, 5), # 轴标签内容
    cglwd = 0.8,             # 网格线宽

    # 自定义标签
    vlcex = 0.8              # 变量标签字体大小
)

# 添加图例,标注每位同学对应的颜色
legend(
    x = 0.7,                             # 图例x坐标
    y = 1,                               # 图例y坐标
    legend = rownames(data[-c(1, 2), ]), # 图例标签(去除最大最小值行)
    bty = "n",                           # 无边框
    pch = 20,                            # 图例点类型
    col = colors_in,                     # 图例点颜色
    text.col = "grey",                   # 图例文字颜色
    cex = 1.2,                           # 图例字体大小
    pt.cex = 3                           # 图例点大小
)

定制多组雷达图:不同颜色区分三位同学的成绩,并添加图例

14.5.3 坐标轴

如果没有输入坐标轴最大值和最小值, 则会自动计算.

Show/Hide Code
# 设置随机种子,保证结果可复现
set.seed(99)

# 生成一个3行5列的数据框,表示3位同学在5个科目的分数(0~20之间不重复的整数)
data <- matrix(sample(0:20, 15, replace = FALSE), ncol = 5) |>
    as.data.frame()

# 设置列名为各个科目
colnames(data) <- c("math", "english", "biology", "music", "R-coding")

# 设置行名为三位同学
rownames(data) <- paste("mister", letters[1:3], sep = "-")

# 生成配色方案
coul <- brewer.pal(3, "BuPu")      # 选取3种颜色
colors_border <- coul              # 多边形边框颜色
colors_in <- alpha(coul, 0.3)      # 多边形填充颜色,带透明度

# 不添加最大最小值行,radarchart会自动根据数据计算坐标轴范围
radarchart(
    data,                # 输入数据(不含最大最小值行)
    axistype = 0,        # 坐标轴类型
    maxmin = FALSE,      # 不手动指定最大最小值,自动计算

    # 自定义多边形
    pcol = colors_border,    # 多边形边框颜色
    pfcol = colors_in,       # 多边形填充颜色
    plwd = 4,                # 多边形边框线宽
    plty = 1,                # 多边形线型

    # 自定义网格
    cglcol = "grey",         # 网格线颜色
    cglty = 1,               # 网格线类型
    axislabcol = "black",    # 轴标签颜色
    cglwd = 0.8,             # 网格线宽

    # 自定义标签
    vlcex = 0.8              # 变量标签字体大小
)

# 添加图例,标注每位同学对应的颜色
legend(
    x = 0.7,                             # 图例x坐标
    y = 1,                               # 图例y坐标
    legend = rownames(data),             # 图例标签
    bty = "n",                           # 无边框
    pch = 20,                            # 图例点类型
    col = colors_in,                     # 图例点颜色
    text.col = "grey",                   # 图例文字颜色
    cex = 1.2,                           # 图例字体大小
    pt.cex = 3                           # 图例点大小
)

自动计算坐标轴范围的雷达图:不手动输入最大最小值

14.6 超多组

不建议放到一个图中, 但可以分面展示(不是ggplot 分面语法):

Show/Hide Code
# 设置随机种子,保证结果可复现
set.seed(1)

# 生成一个6行10列的数据框,表示6位同学在10个科目的分数(2~20之间可重复)
data <- matrix(
    sample(2:20, 60, replace = TRUE), # 随机生成60个2~20之间的整数
    ncol = 10,                        # 每行10个科目
    byrow = TRUE                      # 按行填充
) |> 
    as.data.frame()                   # 转换为数据框

# 设置列名为各个科目
colnames(data) <- c(
    "math",        # 数学
    "english",     # 英语
    "biology",     # 生物
    "music",       # 音乐
    "R-coding",    # R编程
    "data-viz",    # 数据可视化
    "french",      # 法语
    "physic",      # 物理
    "statistic",   # 统计
    "sport"        # 体育
)

# fmsb包要求数据框前两行为最大值和最小值
data <- rbind(rep(20, 10), rep(0, 10), data)

# 生成配色方案,6种颜色
colors_border <- colormap(colormap = colormaps$viridis, nshades = 6, alpha = 1)
colors_in <- colormap(colormap = colormaps$viridis, nshades = 6, alpha = 0.3)

# 设置每个子图的标题
mytitle <- c("Max", "George", "Xue", "Tom", "Alice", "bob")

# 设置画布边距
par(mar = rep(0.8, 4))
# 将画布分为2行3列,准备绘制6个子图
par(mfrow = c(2, 3))

# 循环绘制每位同学的雷达图
for (i in 1:6) {
    radarchart(
        data[c(1, 2, i + 2), ],   # 选取最大值、最小值和第i位同学的数据
        axistype = 1,             # 坐标轴类型

        # 多边形样式
        pcol = colors_border[i],  # 多边形边框颜色
        pfcol = colors_in[i],     # 多边形填充颜色
        plwd = 4,                 # 多边形边框线宽
        plty = 1,                 # 多边形线型

        # 网格样式
        cglcol = "grey",          # 网格线颜色
        cglty = 1,                # 网格线类型
        axislabcol = "grey",      # 轴标签颜色
        caxislabels = seq(0, 20, 5), # 轴标签内容
        cglwd = 0.8,              # 网格线宽

        # 标签样式
        vlcex = 0.8,              # 变量标签字体大小

        # 子图标题
        title = mytitle[i]
    )
}

超多组雷达图:6位同学各自成绩的雷达图分面展示
Show/Hide Code
# 恢复默认的画布设置
par(mfrow = c(1, 1))

14.7 ggradar

首先准备数据:

Show/Hide Code
# 加载palmerpenguins数据集
data("penguins", package = "palmerpenguins")

# 数据整理:去除缺失值,按species分组,计算各特征均值,并标准化到[0,1]区间
penguins_radar <- penguins |>
    drop_na() |>
    group_by(species) |>
    summarise(
        avg_bill_length = mean(bill_length_mm),   # 喙长均值
        avg_bill_dept = mean(bill_depth_mm),      # 喙深均值
        avg_flipper_length = mean(flipper_length_mm), # 翼长均值
        avg_body_mass = mean(body_mass_g)         # 体重均值
    ) |>
    ungroup() |>
    mutate(across(-species, rescale))           # 除species外所有列标准化到[0,1]
Show/Hide Code
# 使用ggradar包绘制企鹅三种类在各特征上的标准化均值雷达图
plt <- penguins_radar |> ggradar()
plt

企鹅三种类在各特征上的标准化均值雷达图(ggradar)
Show/Hide Code
# 对ggradar绘图对象进行美化,调整图例位置、字体和背景
plt <- plt + 
  theme(
    legend.position = c(0.85, 0.1),   # 图例位置
    legend.text = element_text(size = 28), # 图例文字大小
    legend.key = element_rect(fill = NA, color = NA), # 图例键背景
    legend.background = element_blank() # 图例背景
  )
plt

美化后的企鹅三种类标准化均值雷达图(ggradar)
Show/Hide Code
plt <- plt + 
  labs(title = "Radar plot of penguins species") + 
  theme(
      plot.background = element_rect(fill = "#fbf9f4", color = "#fbf9f4"),
      panel.background = element_rect(fill = "#fbf9f4", color = "#fbf9f4"),
      plot.title.position = "plot", # slightly different from default
      plot.title = element_text(
        family = "lobstertwo", 
        size = 62,
        face = "bold", 
        color = "#2a475e"
    )
  )
plt

美化最终版后的企鹅三种类标准化均值雷达图(ggradar)

14.8 Pearl

Hiking Locations in Washington