logo

第 5 章 数据可视化

作者
Modified on
Reading time
11 分钟阅读:..评论:..

数据可视化是数据分析过程中至关重要的一环。通过生动形象的图表,我们可以直观地展示数据背后的规律和趋势,让枯燥的数字"活"起来。本章将重点介绍 R 语言强大的可视化功能,带你从基础的绘图函数入手,逐步掌握 ggplot2 等高级可视化包的用法,并教你如何绘制动态交互式图表。

5.1 基本绘图函数

R 语言内置了一系列基本绘图函数,可以帮助我们快速绘制常见的图表类型,如散点图、柱状图、直方图、箱线图等。

5.1.1 plot 函数

plot() 是 R 语言最常用的通用绘图函数,根据输入数据的类型自动选择合适的图表样式。例如:

# 绘制散点图 x <- c(1, 2, 3, 4, 5) y <- c(2, 4, 6, 8, 10) plot(x, y)

5.1.2 barplot 函数

barplot() 用于绘制柱状图,可以方便地对比不同类别的数值大小。例如:

# 绘制柱状图 data <- c(10, 20, 30, 40, 50) barplot(data)

5.1.3 hist 函数

hist() 用于绘制直方图,展示数据的分布情况。例如:

# 绘制直方图 data <- rnorm(1000) # 生成1000个正态分布的随机数 hist(data)

5.1.4 boxplot 函数

boxplot() 用于绘制箱线图,直观地展示数据的分位数、异常值等信息。例如:

# 绘制箱线图 data <- list(group1 = rnorm(100), group2 = rnorm(100, mean = 1)) boxplot(data)

通过这些基本绘图函数,我们可以快速探索数据的特征。但是它们的定制性较差,难以满足更高的可视化需求。因此,我们需要使用更强大的可视化包,如 ggplot2。

5.2 ggplot2 包的使用

ggplot2 是 R 语言著名的可视化扩展包,提供了一套"图形语法",可以灵活地自定义图表的各个细节。下面让我们一起来学习 ggplot2 的用法。

5.2.1 ggplot2 的基本概念

ggplot2 的核心思想是将图表拆分为不同的组件,然后使用不同的函数进行组合,最终形成完整的图表。ggplot2 的基本组件包括:

  • 数据(data):待可视化的数据框(data.frame)。
  • 几何对象(geom):图表的基本图形元素,如点、线、条形等。
  • 美学映射(aes):指定数据变量如何映射到几何对象的视觉属性上,如位置、颜色、大小等。
  • 标度(scale):控制视觉属性的范围和显示方式,如坐标轴、图例等。
  • 分面(facet):按照某些变量将图表划分为多个子图。
  • 主题(theme):控制图表的整体外观,如背景、字体、边距等。

理解了这些概念后,我们就可以根据"图形语法"来创建图表了。

5.2.2 ggplot2 的基本语法

使用 ggplot2 绘图的基本语法结构为:

ggplot(data = <DATA>) + <GEOM_FUNCTION>(mapping = aes(<MAPPINGS>))

其中,<DATA> 为数据框,<GEOM_FUNCTION> 为几何对象函数,<MAPPINGS> 为美学映射。 例如,我们可以用以下代码绘制一个散点图:

library(ggplot2) # 创建数据框 df <- data.frame( x = c(1, 2, 3, 4, 5), y = c(2, 4, 6, 8, 10) ) # 绘制散点图 ggplot(data = df) + geom_point(mapping = aes(x = x, y = y))

可以看到,我们首先创建了一个数据框 df,然后使用 ggplot() 函数指定数据源,再使用 geom_point() 函数添加散点图层,并在 aes() 函数中指定数据变量和视觉属性的映射关系。 ggplot2 支持多种几何对象函数,可以绘制不同类型的图表,例如:

  • geom_line():绘制折线图
  • geom_bar():绘制柱状图
  • geom_histogram():绘制直方图
  • geom_boxplot():绘制箱线图
  • ...

5.2.3 常用图形的绘制

下面我们通过一些具体的例子,来学习如何使用 ggplot2 绘制常见的图表类型。

折线图

# 生成时间序列数据 df <- data.frame( date = seq(as.Date("2023-01-01"), as.Date("2023-12-31"), by = "month"), value = cumsum(rnorm(12)) ) # 绘制折线图 ggplot(data = df) + geom_line(mapping = aes(x = date, y = value))

柱状图

# 生成分类数据 df <- data.frame( category = c("A", "B", "C", "D", "E"), value = c(10, 20, 30, 40, 50) ) # 绘制柱状图 ggplot(data = df) + geom_bar(mapping = aes(x = category, y = value), stat = "identity")

注意,这里我们需要设置 stat = "identity",告诉 ggplot2 使用数据本身的 y 值,而不是默认的计数。

堆叠柱状图

# 生成分类数据 df <- data.frame( category = rep(c("A", "B", "C"), each = 2), group = rep(c("X", "Y"), times = 3), value = c(1, 3, 2, 4, 3, 5) ) # 绘制堆叠柱状图 ggplot(data = df) + geom_bar(mapping = aes(x = category, y = value, fill = group), stat = "identity")

通过设置 fill 参数,我们可以按照 group 变量对柱状图进行着色,形成堆叠柱状图。

直方图

# 生成随机数 data <- rnorm(1000) # 绘制直方图 ggplot(data = data.frame(x = data)) + geom_histogram(mapping = aes(x = x), bins = 30)

直方图可以展示数据的分布情况。通过设置 bins 参数,我们可以控制直方图的分箱数。

箱线图

# 生成分组数据 df <- data.frame( group = rep(c("A", "B", "C"), each = 100), value = c(rnorm(100), rnorm(100, mean = 1), rnorm(100, mean = 2)) ) # 绘制箱线图 ggplot(data = df) + geom_boxplot(mapping = aes(x = group, y = value))

箱线图可以比较不同组别数据的分布情况。这里我们按照 group 变量对数据进行分组。 以上只是 ggplot2 的冰山一角,它还有许多强大的功能等待你去探索,如分面、主题、标度等。建议大家多查阅 ggplot2 的官方文档和示例,学习更多的用法。

5.2.4 图形的美化与自定义

除了绘制基本的图形,我们还可以使用 ggplot2 提供的各种函数对图形进行美化和自定义,使其更加易读和专业。以下是一些常用的美化技巧:

添加标题和标签

ggplot(data = df) + geom_point(mapping = aes(x = x, y = y)) + labs(title = "Scatter Plot", x = "X variable", y = "Y variable")

使用 labs() 函数可以方便地添加图表标题和轴标签。

修改图例

ggplot(data = df) + geom_bar(mapping = aes(x = category, y = value, fill = group), stat = "identity") + scale_fill_manual(values = c("X" = "blue", "Y" = "red")) + guides(fill = guide_legend(title = "Group"))

使用 scale_fill_manual() 函数可以自定义图例的颜色,使用 guides() 函数可以修改图例的标题。

调整坐标轴

ggplot(data = df) + geom_line(mapping = aes(x = date, y = value)) + scale_x_date(date_labels = "%Y-%m", date_breaks = "2 months") + scale_y_continuous(limits = c(0, 100), breaks = seq(0, 100, 20))

使用 scale_x_date()scale_y_continuous() 函数可以分别控制 x 轴和 y 轴的刻度、标签和范围等。

应用主题

ggplot(data = df) + geom_point(mapping = aes(x = x, y = y)) + theme_minimal()

ggplot2 内置了多个主题函数,如 theme_minimal()theme_bw() 等,可以一键改变图表的整体外观。我们也可以使用 theme() 函数来自定义主题的各个细节。

5.3 高级图形和自定义

除了常见的图表类型,我们有时还需要绘制一些更复杂、更个性化的图形。ggplot2 提供了强大的扩展机制,允许我们灵活地组合不同的图层和几何对象。

5.3.1 多图层绘制

在 ggplot2 中,我们可以通过叠加多个图层来创建复合图形。例如,我们可以在散点图的基础上添加趋势线:

ggplot(data = df) + geom_point(mapping = aes(x = x, y = y)) + geom_smooth(mapping = aes(x = x, y = y), method = "lm")

这里我们使用 geom_smooth() 函数添加了一个趋势线图层,并指定了拟合方法为 "lm"(线性回归)。

5.3.2 自定义几何对象

除了内置的几何对象,我们还可以自定义新的几何对象来满足特殊的可视化需求。例如,我们可以定义一个"半透明柱状图"的几何对象:

library(ggplot2) library(ggproto) # 定义半透明柱状图的几何对象 GeomTransparentBar <- ggproto("GeomTransparentBar", GeomBar, setup_data = function(data, params) { data$width <- data$width %||% params$width %||% resolution(data$x, FALSE) * 0.9 transform(data, ymin = pmin(y, 0), ymax = pmax(y, 0), xmin = x - width / 2, xmax = x + width / 2, width = NULL ) }, draw_panel = function(self, data, panel_params, coord) { # 设置透明度 data$alpha <- 0.5 ggplot2:::ggname("geom_transparent_bar", gTree(children = gList( GeomRect$draw_panel(data, panel_params, coord) ))) } ) geom_transparent_bar <- function(mapping = NULL, data = NULL, stat = "count", position = "stack", ..., width = NULL, binwidth = NULL, na.rm = FALSE, show.legend = NA, inherit.aes = TRUE) { layer( data = data, mapping = mapping, stat = stat, geom = GeomTransparentBar, position = position, show.legend = show.legend, inherit.aes = inherit.aes, params = list( width = width, na.rm = na.rm, ... ) ) } # 使用半透明柱状图 ggplot(data = df) + geom_transparent_bar(mapping = aes(x = category, y = value, fill = group))

通过定义 GeomTransparentBar 对象并重写其 draw_panel() 方法,我们实现了半透明效果。然后使用 geom_transparent_bar() 函数来调用这个自定义的几何对象。

5.3.3 主题与配色

ggplot2 提供了强大的主题定制功能,允许我们修改图表的各个细节,如字体、边距、背景等。除了使用内置的主题函数外,我们还可以使用 theme() 函数来自定义主题:

custom_theme <- theme( plot.title = element_text(size = 20, face = "bold"), axis.title = element_text(size = 16), axis.text = element_text(size = 12), panel.background = element_rect(fill = "white"), panel.grid.major = element_line(color = "gray90"), panel.grid.minor = element_blank() ) ggplot(data = df) + geom_point(mapping = aes(x = x, y = y)) + custom_theme

此外,ggplot2 还支持灵活的配色方案。除了使用内置的调色板外,我们还可以使用 scale_color_manual()scale_fill_manual() 函数来自定义颜色:

ggplot(data = df) + geom_bar(mapping = aes(x = category, y = value, fill = group), stat = "identity") + scale_fill_manual(values = c("X" = "#1F77B4", "Y" = "#FF7F0E"))

5.3.4 动态图形

除了静态图形,ggplot2 还支持创建动态交互式图形。我们可以使用 gganimate 包来为 ggplot2 图形添加动画效果,使用 plotly 包来创建可交互的 web 图形。 下面是一个使用 gganimate 创建动画气泡图的示例:

library(ggplot2) library(gganimate) # 创建数据 df <- data.frame( x = runif(20), y = runif(20), size = runif(20), frame = rep(1:10, each = 2) ) # 绘制动画气泡图 ggplot(data = df) + geom_point(mapping = aes(x = x, y = y, size = size), color = "steelblue") + transition_manual(frame) + labs(title = "Frame: {current_frame}")

gganimate 提供了多种过渡效果函数,如 transition_manual()transition_time() 等,可以根据数据的不同属性来控制动画的帧。 下面是一个使用 plotly 创建交互式散点图的示例:

library(ggplot2) library(plotly) # 绘制散点图 p <- ggplot(data = df) + geom_point(mapping = aes(x = x, y = y, size = size, color = group)) + scale_color_manual(values = c("X" = "blue", "Y" = "red")) # 转换为交互式图形 ggplotly(p)

plotly 可以自动将 ggplot2 图形转换为交互式的 web 图形,支持缩放、悬停、选择等交互操作。

5.4 动态可视化

在数据分析和展示中,动态可视化越来越受到重视。相比静态图表,动态图表可以更生动地展示数据的变化趋势和互动关系。前面我们已经初步了解了 gganimateplotly 的用法,下面我们再深入介绍一些动态可视化的高级技巧。

5.4.1 使用 plotly 进行动态绘图

plotly 是一个强大的交互式绘图库,支持多种图表类型和丰富的自定义选项。除了直接在 R 中使用 plotly 包外,我们还可以在 RStudio 的 Viewer 窗口中预览 plotly 图形,或将其嵌入到 R Markdown 文档中。 下面是一个使用 plotly 绘制三维散点图的示例:

library(plotly) # 创建数据 df <- data.frame( x = rnorm(100), y = rnorm(100), z = rnorm(100), group = rep(c("A", "B"), each = 50) ) # 绘制三维散点图 plot_ly(data = df, x = ~x, y = ~y, z = ~z, color = ~group, marker = list(size = 5), type = "scatter3d", mode = "markers")

plot_ly() 函数用于创建 plotly 图形,我们可以通过设置不同的参数来控制图形的各个细节,如数据映射、图表类型、标记样式等。

5.4.2 动态交互图形

plotly 支持丰富的交互操作,如缩放、平移、悬停、选择等。我们可以通过添加适当的参数来启用这些交互功能。例如:

library(plotly) # 绘制散点图矩阵 plot_ly(data = iris, type = "splom", dimensions = list( list(label = "Sepal Length", values = ~Sepal.Length), list(label = "Sepal Width", values = ~Sepal.Width), list(label = "Petal Length", values = ~Petal.Length), list(label = "Petal Width", values = ~Petal.Width) ), marker = list(size = 5, color = ~as.numeric(Species), colorscale = "Viridis"), text = ~paste("Species:", Species), hoverinfo = "text" )

这里我们绘制了鸢尾花数据集的散点图矩阵,并启用了悬停交互。当鼠标悬停在某个点上时,会显示该点所属的鸢尾花品种。

5.4.3 实时数据可视化

在某些场景下,我们需要实时地展示数据的变化情况,如股票价格、传感器读数等。plotly 提供了 plotlyProxy() 函数,可以在不重绘整个图形的情况下高效地更新数据。 下面是一个模拟实时数据并动态更新图表的示例:

library(plotly) # 初始化数据 x <- 0 y <- 0 # 创建plotly图形 p <- plot_ly(x = ~x, y = ~y, type = "scatter", mode = "lines") # 创建plotly代理 pp <- plotlyProxy(p, session = "session1") # 模拟实时数据更新 for (i in 1:100) { x <- c(x, i) y <- c(y, rnorm(1)) # 使用plotlyProxy更新数据 pp <- plotlyProxyInvoke(pp, list( list(method = "extendTraces", args = list(list(x = list(list(i)), y = list(list(tail(y, 1)))), list(0)), label = "extend"), list(method = "relayout", args = list(list(xaxis = list(range = c(max(0, i - 50), i))), label = "relayout")) )) Sys.sleep(0.1) }

在这个示例中,我们首先创建了一个空的折线图,然后使用 plotlyProxy() 创建了一个图形代理。接下来,我们在一个循环中模拟实时数据的生成,并使用 plotlyProxyInvoke() 函数来更新图形的数据和布局。通过设置 xaxis.range,我们可以让图形自动滚动,始终显示最新的数据。 如果你在学习过程中遇到任何问题,欢迎在评论区留言讨论。