使用 plot3D 画三维图

R
可视化
plot3D
Author

Rui

Published

September 15, 2022

初识 plot3D

plot3D 程序包可用于用于可视化 2D 和 3D 数据,包括透视图、切片图、曲面图、散点图等。其中不少函数都是基于 base 中的 perspimage 编写的,可以认为是基础绘图函数的拓展。

Note

除此之外还有很多其他可以实现 3D 数据可视化的软件包(可能更适合你的工作),如:rglscatterplot3Dmisc3D 等。这些包以及对应的使用说明(manual)都可以在 CRAN 上搜索到。

plot3D 包含很多函数,其中基于 persp 函数的有:

  • persp3D: 基础包中 persp 函数的拓展

  • ribbon3D:绘制带状透视图

  • hist3D:绘制 3D 直方图

  • scatter3D, points3D, lines3D:绘制着色的 3D 散点图、点图、曲线图

  • 其他

基于 image 函数的有:

  • image2D:使用平面图像可视乎 2D 或 3D 数据

  • 其他

还有其他函数在这里不一一列出。本文主要围绕核心函数 persp3D 来展示 2 维函数的可视化方法。

persp3D 参数介绍

persp3D 函数的使用方法如下:

persp3D(x = seq(0, 1, length.out = nrow(z)),
        y = seq(0, 1, length.out = ncol(z)), z, 
        ...,
        colvar = z, phi = 40, theta = 40,
        col = NULL, NAcol = "white", breaks = NULL,
        border = NA, facets = TRUE, colkey = NULL, resfac = 1
        image = FALSE, contour = FALSE, panel.first = NULL,
        clim = NULL, clab = NULL, bty = "b",
        lighting = FALSE, shade = NA, ltheta = -135, lphi = 0,
        inttype = 1, curtain = FALSE, add = FALSE, plot = TRUE)

参数实在太多,挑几个重要并且常用的讲一讲:

  • xy:x 轴、y 轴取值,是一个向量

  • z:z 轴取值,为一个 2 维矩阵。相当于记录了每一对 (x,y) 所对应的函数值。所以要注意:x 长度(length(x))要等于 z 的行数(nrow(z)),y 的长度(length(y))要等于 z 的列数(ncol(z))。

  • colvar:用于着色的变量。如果给定,则它的维度应该与 z 的维度相同。若输入 NULL,NA 或 FALSE 将根据 colvar 切换颜色,仅当 boder 参数被指定颜色,shade > 0,或 lighting = TRUE才会产生好的效果。

  • col:用于 colvar 变量的调色板。 如果 col = NULL 并且 colvar 被 指定,将使用红-黄-蓝配色方案。如果 col =NULL 并且 colvar 没有被指定,那么 col 将为灰色。为了与 persp 函数一致,设定 colvar = NULLcol 为一个矩阵,其维度为 nrow(z)-1 行,ncol(z)-1 列。

  • NAcol:表示指定 colvar 中缺失值的颜色,默认值为 white。

  • breaks:为一有限向量用来表示 colvar 的断点,必须比 colvar 多一个断点并且按升序排列,无序向量会被自动排序。

  • colkey:为布尔值或 NULL (默认值)或参数列表(列表中包含的参数相当多,这里不再展开),用来指定图例参数。实际上 plot3D 中还存在一个 colkey() 的函数,其参数与传入 colkey 的参数列表相同。

  • add:为布尔值,表示是否将该绘图对象添加到现有的绘图对象中,默认 FALSE 新建图层,TRUE 则添加图层。

  • plot:为布尔值,表示是否绘图,默认 TRUE 则绘图,FALSE 则返回视角转换矩阵。

  • clab:表示指定图例标题内容。只有当 colkey = TRUE 时,标签才会写在 colkey 的顶部。 标签将写在与主标题相同的水平线上。 为了避免这种情况,可以设置 clab 为一个向量,第一个值为空字符串,以此来降低标签的水平位置。

  • clim:表示指定图例显示范围,当 colvar 被指定时生效,若 clim 范围超出 colvar 则超出部分显示为 NA。

  • thetaphi:指定观察透视图的方向,与 persp() 中一致。

  • border:指定曲面网格边线的颜色,默认值为 NA 不显示曲面网格边线。

  • facets:布尔值或 NA,表示是否指定曲面网格的颜色,TRUE 则用 col 参数指定曲面网格的颜色,FALSE 则为网格为颜色为白色且网格边线为 col 指定的颜色(前提是 border = NA)。

  • image:为布尔值,表示是否在绘图立方体插入另一个平面图, 如果设置为 TRUE,则会在 3D 图底部绘制图像,还允许传递 image2D() 函数的参数的列表,

此列表的一个参数 side 表示将 image2D() 图置于何处位置。 side = z-value,表示将该图置于 z 轴 value 值位置处。 side = "zmin"side = "zmax" 分别将该图置于底部和顶部,默认置于底部。

  • contour:为布尔值,表示是否在绘图立方体中插入等高线, 如果设定为 TRUE, 则默认在 3D 图底部插入等高线图(也是一个平面图),也可以通过 contour() 函数传递参数。 同样存在位置参数side, side = "zmin", side = "zmax" 分别将该图置于底部和顶部,默认置于底部。

  • 其他参数将在下一节示例中演示

Note

ribbon3Dhist3D 的参数传导类似,不再具体说明

动手绘制 3D 图

Example 1

Code
library(plot3D)
 
# 设定主标题,图例标题, 设定标度断点以着色, 默认scale = TRUE表示3个坐标轴独立缩放
persp3D(
  z = volcano, 
  scale = TRUE,
  main = "volcano", 
  clab = c("height(m)"), 
  breaks = seq(100, 200, by = 10), # 设置颜色标度断点
) 

也可以不指定颜色断点:

Code
persp3D(
  z = volcano, 
  x = 1: nrow(volcano), 
  y = 1:ncol(volcano), 
  expand = 0.5, 
  main = "volcano", 
  scale = FALSE, 
  clab = "height(m)"
)

volcano 为该包中自带的数据集,这里省略了 x 和 y 的取值范围。scale 接受一个布尔值用于缩放坐标轴比例,TRUE (默认值)代表 3 个坐标轴各自独立缩放(不等比例缩放)

没有指定调色板 col,所以默认使用红黄蓝配色。

其中,expand 参数用于缩放 z 轴,expand < 1 则缩小 z 轴。

Example 2

在描述 clab 参数时可能没太明白什么意思,其实根据上图就很好理解:图的主标题“volcano”应该位于整个图的最高点,而图例的标题与主标题位于同一水平线上显然不太合理。于是可以设置 clab 为一个向量,并且第一个元素为一个空字符串,如此可以降低图例标题的高度:

Code
persp3D(
  z = volcano, 
  scale = TRUE,
  main = "volcano", 
  clab = c(" ", "height(m)"), 
) 

但可以看出效果不太理想。使用 manual 中的另一种方法:通过设置 colkey 传入的参数列表中的 line.clab 来降低图例标题的高度。

Code
persp3D(
  z = volcano, 
  scale = TRUE,
  main = "volcano", 
  colkey = list(line.clab=-0.5),
  clab = c("height(m)"), 
) 

效果还是不理想,line.clab 只降低了图例标题的高度却导致与图例重合。多次尝试后选择设置 shift 参数来同时调整图例标题与图例的高度。

Code
persp3D(
  z = volcano, 
  scale = TRUE,
  main = "volcano", 
  colkey = list(shift=-0.05, dist=-0.1),
  clab = c("height(m)"), 
) 

效果很好!同时设置 dist 参数来调节主图与图例的距离,dist 为负数则使图例靠近主图,为正数则远离主图,建议范围为 [-0.5, 0.05]。

除此之外还可以通过 side 设置图例放置的位置, 1 = bottom, 2 = left, 3 = top, 4 = rightlength 调整图例长度。

Code
persp3D(
  z = volcano, 
  scale = TRUE,
  expand = 0.5,
  main = "volcano", 
  colkey = list(side = 1, length = 0.5),
  clab = c("height(m)"), 
  facets = FALSE, 
) 

Example 3

使用 contour 添加等高线图,contour 也接受一个参数向量,参数向量同函数 contour2D 接受的参数一致。

Code
x <- seq(1, nrow(volcano), by = 3)
y <- seq(1, ncol(volcano), by = 3)
Volcano <- volcano[x, y]

persp3D(z = Volcano, contour = TRUE, zlim= c(-200, 200), image = FALSE)

zlim 用来指定 z 轴的坐标范围。既然要插入平面图,那么就应该手动调整 z 轴范围为图像留有足够空间。

设置 contour = TRUE 仅仅是使用绘制等高线的默认设置,可以看出默认设置下等高线为黑色且等高线平面位于 3D 图像的底部。若要画出精致的图像则需要进一步设置。

设置 nlevels 来指定等高线数量,col 设置等高线颜色。

Code
persp3D(
  z = Volcano, x = x, y = y, 
  scale = FALSE,
  contour = list(nlevels = 20, col = "red"),
  zlim = c(-200, 200), 
  expand = 0.2
)

Example 4

使用 image 添加平面图像,image 也接受一个参数向量,参数向量同函数 image2D 接受的参数一致。

Code
persp3D(z = Volcano, zlim = c(-200, 200), image = TRUE)

通过 col 设置平面图像的背景色。

Code
persp3D(
  z = Volcano, x = x, y = y, 
  scale = FALSE, 
  zlim = c(-200, 200), 
  expand = 0.2,
  image = list(col = grey(seq(0, 1, length.out = 100)))
)

还可以联合使用等高线图与平面图,只需要让等高线图与平面图位于同一 z 轴高度(默认设置下就可以):

Code
persp3D(
  z = Volcano, x = x, y = y, 
  scale = FALSE,
  contour = list(nlevels = 20, col = "red"),
  zlim = c(-200, 200), 
  expand = 0.2,
  image = list(col = grey (seq(0, 1, length.out = 100)))
)

还可以通过设置不同的水平高度将等高线图与平面图分离开:

Code
persp3D(
  z = Volcano, 
  contour = list(side = c("zmin", "z", "350")),
  zlim = c(-100, 400), 
  phi = 20, 
  image = list(side = 350)
)

Example 5

关于 ribbon3Dhist3D 不再具体说明。

Code
ribbon3D(z = Volcano, contour = TRUE, zlim= c(-100, 200), image = TRUE)

Code
VV <- volcano[seq(1, 87, 10), seq(1, 61, 10)]
hist3D(z = VV, scale = FALSE, expand = 0.01, border = "black")

Rastrigin 函数

为了方便展示,这里使用二元 Rastrigin 函数,区间范围设置为 [-5, 5]:

\[ f(X)=\sum_{i=1}^{2}(x_i^2-10\cos(2\pi x_i)+10) \]

Code
a <- 5
x <- y <- seq(-a, a, 0.05)
f <- function(x, y){
  x^2 - 10*cos(2*pi*x) + y^2 - 10*cos(2*pi*y) + 20
}
z <- outer(x, y, f)

平面图像:

Code
image(x, y, z, col = heat.colors(24))

Code
library(plot3D)

persp3D(
  z = z, 
  x = x, 
  y = y,
  zlim = c(-20, 90),
  main = "Rastrigin", 
  scale = FALSE, 
  expand = 0.1,
  clab = "value",
  colkey = list(shift=-0.05, dist=-0.1, length = 0.8),
  image = list(col = grey (seq(0, 1, length.out = 100))),
  phi = 30
)