使用 RGL 制作交互式 3D 散点图
介绍
本 R 教程 逐步描述了如何使用 rgl包 构建 3D 图形。
RGL 是一个 3D 图形包,可生成实时交互式 3D 绘图。
它允许交互式旋转、缩放图形和选择区域。
rgl 包还包括一个名为 R3D 的通用 3D 接口。
R3D 是本文末尾描述的通用 3D 对象和函数的集合。
内容14913字 32图!
安装 RGL 包
1 | install.packages("rgl") |
在 Linux 操作系统上,可以按如下方式安装rgl包:
1 | sudo apt-get install r-cran-rgl |
加载 RGL 包
1 | library("rgl") |
准备数据
我们将在以下示例中使用iris数据集:
1 | data(iris) |
启动和关闭 RGL device
要使用 RGL 制作 3D 绘图,应该首先在 R 中启动 RGL device
以下函数用于管理 RGL :
rgl.open()
:打开一个新设备rgl.close()
:关闭当前设备rgl.clear()
:清除当前设备rgl.cur()
:返回活动设备 IDrgl.quit()
:关闭 RGL
第一部分,为每个绘图打开一个新的 RGL 设备。
可以第一次使用函数 rgl.open()
–> 然后制作第一个 3D 绘图 –> 然后使用 rgl.clear()
清除场景 –> 并再次制作新的绘图。
3D 散点图
基本图
函数rgl.points()
用于绘制3D 散点图:
1 | rgl.open() # 打开一个新的 RGL device |
- x, y, z:数值向量,指定要绘制的点的坐标。参数 y 和 z 在以下情况下是可选的:
- x是包含至少 3 列的矩阵或数据框,将用作 x、y 和 z 坐标。例如:
rgl.points(iris)
- x是 zvar ~ xvar + yvar 形式的公式(参阅 ?xyz.coords )。例如:
rgl.points(z ~ x + y)
- …:材料特性。有关详细信息,请参阅 ?rgl.material
更改背景和点颜色
- 函数
rgl.bg(color)
可用于设置场景的背景环境 - 参数 color 在函数
rgl.points()
中用于更改点颜色
也可以使用参数 size 更改点的大小
1 | rgl.open()# 打开一个新的 RGL device |
上述3d 界面的函数是:
open3d()
: 打开一个新的 3D 设备bg3d(color)
: 设置场景的背景环境points3d(x, y, z, ...)
: 坐标 x, y, z 的绘图点
改变点的形状
可以使用函数rgl.spheres()
或spheres3d()
绘制球体:
1 | spheres3d(x, y = NULL, z = NULL, radius = 1, ...) |
rgl.spheres()
绘制具有中心 (x, y, z) 和半径 r 的球体。
- x, y, z :指定每个球体中心坐标的数值向量。
参数 y 和 z 在以下情况下是可选的:- x 是包含至少 3 列的矩阵或数据框,将用作 x、y 和 z 坐标。
例如:rgl.spheres(iris, r = 0.2)
- x 是 zvar ~ xvar + yvar 形式的公式(参见 ?xyz.coords)。
例如:rgl.spheres(z ~ x + y, r = 0.2)
- radius:表示球体半径的向量或单个值
- …:材料属性。 有关详细信息,请参阅 ?rgl.material
1 | rgl.open()# 打开一个新的 RGL device |
可以通过按住鼠标或触摸板手动旋转rgl图。
也可以使用鼠标上的滚轮或使用 PC 上的触摸板
或 Mac 上的两个手指(向上或向下)按 ctrl + 进行缩放。
rgl_init():用于初始化 RGL 设备的自定义函数
如果请求或没有打开的设备,函数 rgl_init()
将创建一个新的 RGL 设备:
1 | #' @param new.device 一个逻辑值。如果为 TRUE,则创建一个新设备 |
使用的 RGL 函数说明:
rgl.open()
: 打开一个新设备rgl.cur()
: 返回活动设备 IDpar3d(windowRect)
: 设置窗口大小rgl.viewpoint(theta, phi, fov, zoom)
: 设置视点。 参数 theta 和 phi 是极坐标。theta
和phi
是极坐标。 默认值分别为 0 和 15fov
是以度为单位的视场角。 默认值为 60zoom
是缩放系数。 默认值为 1rgl.bg(color)
: 定义设备的背景颜色rgl.clear(type)
:从指定堆栈中清除场景(“shapes”、“lights”、“bboxdeco”、“background”)
在上面的R 代码中,使用函数
rgl.viewpoint()
自动设置视点方向和缩放。RGL设备是交互式的,您可以使用鼠标调整视点和缩放绘图。
添加边界框装饰
使用函数rgl.bbox()
:
1 | rgl_init() |
函数rgl.bbox()
的简化格式是:
1 | rgl.bbox(xlen=5, ylen=5, zlen=5, marklen=15.9, ...) |
- xlen、ylen、zlen:分别指定 x、y 和 Z 轴上刻度线数量的值
- marklen : 指定刻度线长度的值
- …:其他 rgl 材料属性(参见?rgl.material)包括:
- color : 颜色向量。第一种颜色用于边界框的背景颜色。第二种颜色用于刻度线标签。
- emission, specular, shininess: 光照计算的属性
- alpha : 指定颜色透明度的值。该值应介于 0.0(完全透明)和 1.0(不透明)之间
1 | rgl_init() |
添加轴线和标签
函数rgl.lines(x, y = NULL, z = NULL, ...)
可用于添加轴线。
函数rgl.texts(x, y = NULL, z = NULL, text)
用于添加轴标签
对于函数rgl.lines()
,参数 x、y 和 z 是长度为 2 的数值向量(即: x = c(x1,x2), y = c(y1, y2), z = c(z1 , z2) )
- 值 x1、y1 和 y3 是线起点的3D 坐标
- x2、y2 和 y3 的值对应于线终点的3D 坐标
参数x可以是矩阵或数据框,其中至少包含 3 列分别对应于 x、y 和 z 坐标。在这种情况下,参数y和z可以省略
要绘制轴,应该将轴的范围(最小值和最大值)指定给函数rgl.lines()
:
1 | # 制作散点图 |
上图可以看到轴已绘制,但问题是它们不在点 c(0, 0, 0) 处相交
有两种解决方案来处理这种情况:
- 扩展数据以使事情变得简单。变换 x、y 和 z 变量,使它们的 min = 0 和 max = 1
- 使用 c(-max, +max) 作为轴的范围
缩放数据
1 | x1 <- (x - min(x))/(max(x) - min(x)) |
1 | # 制作散点图 |
使用 c(-max, max)
让我们定义一个辅助函数来计算轴限制:
1 | lim <- function(x){c(-max(abs(x)), max(abs(x))) * 1.1} |
1 | # 制作散点图 |
rgl_add_axes():添加 x、y 和 z 轴的自定义函数
1 | # x, y, z : 对应点坐标的数值向量 |
- 函数
rgl.texts(x, y, z, text)
用于向 RGL plot 添加文本。rgl.quads(x, y, z)
用于添加平面。x、y 和 z 是长度为 4 的数值向量,指定四边形的四个节点的坐标。
1 | rgl_init() |
显示刻度:刻度线
函数axis3d()可以如下使用:
1 | rgl_init() |
添加边界框装饰更容易:
1 | rgl_init() |
设置 x、y 和 z 轴的纵横比
在上图中,边界框显示为矩形。所有坐标都以相同的比例显示(iso-metric)。
函数 aspect3d(x, y = NULL, z = NULL)
可用于设置当前绘图的 x、y 和 z 轴的表观比率。
x、y 和 z 分别是 x、y 和 z 轴的比率。x 可以是长度为 3 的向量,指定 3 个轴的比率。
如果比率为 (1, 1, 1),则边界框将显示为立方体。
1 | rgl_init() |
比率的值可以设置为更大或更小以在给定轴上缩放:
1 | rgl_init() |
按组更改点的颜色
辅助函数可用于为每个组自动选择颜色:
1 | # 获取因子变量不同级别的颜色 |
按组更改颜色:
1 | rgl_init() |
使用自定义颜色:
1 | cols <- get_colors(iris$Species, c("#999999", "#E69F00", "#56B4E9")) |
也可以使用RColorBrewer包中的调色板:
1 | library("RColorBrewer") |
改变点的形状
RGL 包中有 6 个网格对象,可用作点形状:
- cube3d()
- tetrahedron3d()
- octahedron3d()
- icosahedron3d()
- dodecahedron3d()
- cuboctahedron3d()
要使用上面的对象进行绘图,可以使用函数shapelist3d()
如下:
1 | shapelist3d(shapes, x, y, z) |
- shapes:单个 shape3d(例如:
shapes = cube3d()
)
对象或它们的列表(例如:shapes = list(cube3d(), icosahedron3d())
) - x, y, z:要绘制的点的坐标
1 | rgl_init() |
添加一个椭圆的浓度
函数ellipse3d()
用于估计浓度椭圆。一个简化的格式是:
1 | ellipse3d(x, scale = c(1,1,1), centre = c(0,0,0), |
- x : x、y 和 z 之间的相关或协方差矩阵
- scale:如果 x 是相关矩阵,则可以在 scale 参数中给出每个参数的标准差。这默认为 c(1, 1, 1),因此不会进行重新缩放。
- center:椭圆的中心将在这个位置。
- level:置信区域的置信水平。这用于控制椭球的大小。
ellipse3d() 函数返回一个 mesh3d 类的对象,可以使用函数 shade3d() 和/或 Wired3d() 绘制
- 使用函数
shade3d()
绘制椭圆:
1 | rgl_init() |
- 使用函数
wired3d()
绘制椭圆:
1 | rgl_init() |
- 结合
shade3d()
和wired3d()
:
1 | rgl_init() |
- 为每个组添加椭圆:
1 | # Groups |
回归平面
函数planes3d()
或rgl.planes()
可用于将回归平面添加到 3D rgl 图中:
1 | rgl.planes(a, b = NULL, c = NULL, d = 0, ...) |
planes3d()
和rgl.planes()
使用参数ax + by + cz + d = 0绘制平面。
- a, b, c : 平面法线的坐标
- d : 偏移坐标
使用示例:
1 | rgl_init() |
上面的回归平面非常难看。让我们尝试做一个自定义的。遵循以下步骤:
- 使用函数 lm() 计算线性回归模型:ax + by + cz + d = 0
- 使用参数
rgl.surface()
添加回归曲面。
1 | rgl_init() |
创建 RGL 场景的动图
函数movie3d()
可以按如下方式使用:
1 | movie3d(f, duration, dir = tempdir(), convert = TRUE) |
- f 使用 spin3d(axis) 创建的函数
- axis:所需的旋转轴。默认值为 c(0, 0, 1)。
- duration : 动画的持续时间
- dir : 为电影的每一帧创建临时文件的目录
- convert:如果为 TRUE,则尝试将帧转换为单个 GIF 电影。它使用ImageMagick进行图像转换。
安装 ImageMagick(http://www.imagemagick.org/) 以便能够从 png 文件列表中创建电影。
1 | rgl_init() |
将图像导出为 png 或 pdf
绘图可以保存为 png 或 pdf。
- 函数
rgl.snapshot()
用于将屏幕截图保存为 png 文件:
1 | rgl.snapshot(filename = "plot.png") |
- 函数
rgl.postscript()
用于将屏幕截图保存为ps、eps、tex、pdf、svg 或 pgf格式的文件:
1 | rgl.postscript("plot.pdf",fmt="pdf") |
使用示例:
1 | rgl_init() |
将绘图导出为交互式 HTML 文件
函数writeWebGL()
用于将当前场景写入 HTML:
1 | writeWebGL(dir = "webGL", filename = file.path(dir, "index.html")) |
- dir : 写入文件的位置
- filename : 用于主文件的文件名
下面的 R 代码写入场景的副本,然后将其显示在浏览器中:
1 | rgl_init() |
在 RGL 场景中选择一个矩形
函数rgl.select3d()
或select3d()
可用于选择3 维区域。
它们返回一个函数 f(x, y, z),该函数测试每个点 (x, y, z) 是否在所选区域中。
下面的 R 代码允许用户选择一些点,然后用不同的颜色重新绘制它们:
1 | rgl_init() |
识别图中的点
使用函数identify3d()
:
1 | identify3d(x, y = NULL, z = NULL, labels, n) |
函数
identify3d()
的工作方式与基本图形中的 identify 函数类似。
下面的 R 代码,允许用户识别 5 个点:
1 | rgl_init() |
使用右键选择,中键退出。
R3D 界面
rgl包还包括一个更高级别的接口,称为 r3d 。该界面的设计更像是经典的 2D R 图形。
下一节将介绍如何使用 R3D 界面制作 3D 图形。
3D 散点图
使用函数plot3d()
:
1 | ## Default method |
- x, y, z:要绘制的点的向量。任何定义坐标的合理方式都是可以接受的。有关详细信息,请参阅函数 xyz.coords
- xlab, yab, zlab : x, y 和 z 轴标签
- type:
- 对于默认方法:允许的值是:“p”表示点,“s”表示球体,“l”表示线,“h”表示从 z = 0 开始的线段,“n”表示无。
- 对于 mesh3d 方法,“shade”、“wire”或“dots”之一
- col : 用于绘制项目的颜色
- size : 点的大小
- lwd : 绘制项的线宽
- radius : 球体的半径
- add:是否将点添加到现有绘图中
- aspect : 要么是一个逻辑的指示是否调整纵横比,要么是一个新的比例
- …:将传递给 par3d、material3d 或 decorate3d 的附加参数
- box, axes : 是否绘制框和轴。
- main, sub : 主标题和副标题
- top : 完成后是否将窗口置顶
建议使用函数 open3d() 来初始化 *3d 接口。但是,在以下 R 代码块中,我将继续使用自定义函数
rgl_init()
。
画点:
1 | rgl_init() |
移除盒子并绘制球体:
1 | rgl_init() |
要删除坐标区,请使用参数
axes = FALSE
轴标签:
1 | rgl_init() |
添加浓度椭圆:
1 | rgl_init() |
更改椭圆类型:参数类型的可能值= c(“shade”, “wire”, “dots”)
1 | rgl_init() |
bbox3d():添加边界框装饰
1 | rgl_init() |
一些重要的功能
- open3d() : 打开一个新设备
- 向当前场景添加一个形状:
- points3d(x, y, z, …)
- lines3d(x, y, z, …)
- segments3d(x, y, z, …)
- quads3d(x, y, z, …)
- texts3d(x, y, z, text) : 添加文本
- 绘制框、轴和其他文本:
- axes3d() : 添加标准轴
- title3d(main, sub, xlab, ylab, zlab) : 添加标题
- box3d():在绘图周围绘制一个框
- mtext3d() : 在绘图边距中放置文本
RGL 函数
下面列出了管理 RGL device 的一些重要功能:
设备管理
功能 | 描述 |
---|---|
rgl.open() | 打开一个新设备 |
rgl.close() | 关闭当前设备 |
rgl.cur() | 返回活动设备的 ID |
rgl.dev.list() | 返回所有设备 ID |
rgl.set(which) | 将设备设置为活动 |
rgl.quit() | 关闭 RGL 设备系统 |
形状函数
将形状节点添加到当前场景。
功能 | 描述 |
---|---|
rgl.points(x, y, z, …) | 在 x、y 和 z 处绘制一个点 |
rgl.lines(x, y, z, …) | 根据顶点对绘制线段 (x = c(x1,x2), y = c(y1,y2), z = c(z1, z2)) |
rgl.triangles(x, y, z, …) | 用节点 (xi, yi, zi) 绘制三角形,i = 1, 2, 3 |
rgl.quads(x, y, z) | 用节点 (xi, yi, zi) 绘制四边形,i = 1, 2, 3, 4 |
rgl.spheres(x, y, z, r, …) | 绘制具有中心 (x, y, z) 和半径 r 的球体 |
rgl.texts(x, y, z, text, …) | 向场景中添加文本 |
rgl.surface(x, y, z, …) | 将表面添加到当前场景。x 和 y 是定义网格的两个向量。z 是定义每个网格点高度的矩阵 |
场景管理
功能 | 描述 |
---|---|
rgl.clear(类型=“形状”) | 从指定堆栈中清除场景(“shapes”、“lights”、“bboxdeco”、“background”) |
rgl.pop(类型=“形状”) | 从堆栈中删除最后添加的节点 |
设置环境
功能 | 描述 |
---|---|
rgl.viewpoint(theta, phi, fov, zoom, …) | 设置视点方向。theta和phi是极坐标。fov是以度为单位的视场角。缩放:缩放系数。 |
rgl.light(theta, phi, …) | 向场景添加光源 |
rgl.bg(…) | 设置场景的背景环境 |
rgl.bbox(…) | 设置边界框装饰 |
外观设置
功能 | 描述 |
---|---|
rgl.material(…) | 设置几何外观的材料属性 |
方面3d(x,y,z) | 设置 x、y 和 z 轴的纵横比 |
导出截图
功能 | 描述 |
---|---|
rgl.snapshot(“plot.png”) | 将屏幕截图保存为 png 文件 |
rgl.postscript(“plot.pdf”,fmt=“pdf”) | 将屏幕截图保存为ps、eps、tex、pdf、svg 或 pgf格式的文件。 |
将焦点分配给 RGL 窗口
Rgl.bringtotop()
: ‘rgl.bringtotop’ 将当前 RGL 窗口带到窗口堆栈的前面(并赋予它焦点)。
参考
Daniel Alder et al., RGL: A R-library for 3D visualization with OpenGL, http://rgl.neoscientists.org/arc/doc/RGL_INTERFACE03.pdf