In this article we introduce the rotations package which provides users with the ability to simulate, analyze and visualize three-dimensional rotation data. More specifically it includes four commonly used distributions from which to simulate data, four estimators of the central orientation, six confidence region estimation procedures and two approaches to visualizing rotation data. All of these features are available for two different parameterizations of rotations: three-by-three matrices and quaternions. In addition, two datasets are included that illustrate the use of rotation data in practice.
Data in the form of three-dimensional rotations have applications in many scientific areas, such as bio-medical engineering, computer vision, and geological and materials sciences where such data represent the positions of objects within a three-dimensional reference frame. For example, (Humbert et al. 1996), (Bingham et al. 2009) and (Bachmann et al. 2010) apply rotation data to study the orientation of cubic crystals on the surfaces of metal. (Rancourt et al. 2000) use rotations to represent variations in human movement while performing a task.
A common goal shared in the analysis of rotation data across all fields
is to estimate the main or central orientation for a sample of
rotations. More formally, let
where
Assuming the perturbations
While there is a multitude of packages and functions available in R to estimate the mean in a location model, the toolbox for rotational data is limited. The orientlib (Murdoch 2003) package includes the definition of an orientation class along with a few methods to summarize and visualize rotation data. A strength of the orientlib package is its thorough exploration of rotation representations, but the estimation and visualization techniques are lacking and no methods for inference are available. The onion (Hankin 2011) package includes functions for rotation algebra but only the quaternion form is available and data analysis is not possible. The uarsbayes (Qiu 2013) package includes functions for data generation and Bayes inference but this package is currently not publicly available. Packages for circular and spherical data, e.g. circular (Agostinelli and Lund 2013) and SpherWave (Oh and Kim 2013), can possibly be used but their extension to rotation data is not straightforward.
The rotations
(Stanfill et al. 2014a) package fills this void by providing users with the
tools necessary to simulate rotations from (1) with four
distribution choices for the perturbation matrices help(package = "rotations")
.
Several parameterizations of rotations exist. We consider two of the
most commonly used: orthogonal
Rotations in three-dimensions can be represented by
Since
where
Given a rotation matrix
where
The rotations package defines the S3
class "SO3"
, which internally
stores a sample of "SO3"
is printed as a "SO3"
with the as.SO3
and is.SO3
functions,
respectively. Any object passed to is.SO3
is tested for three
characteristics: dimensionality, orthogonality and determinant one.
The as.SO3
function coerces the input into the class "SO3"
. There
are three types of input supported by the as.SO3
function. Given a
singe angle as.SO3
will form a rotation
matrix according to (3). Equivalently one could supply a
three-dimensional vector as.SO3
function will
return the matrix equivalent of as.SO3
returns an "SO3"
where
each row corresponds to a rotation matrix. Below we illustrate the use
of the as.SO3
function by constructing the
> r <- pi/2
> U <- c(0, 1, 0)
> W <- U * r
> R <- as.SO3(W)
> R
[,1] [,2] [,3]
[1,] 0 0 1
[2,] 0 1 0
[3,] -1 0 0
> identical(R, as.SO3(U, r))
[1] TRUE
Given a rotation matrix mis.angle
and
mis.axis
will determine the misorientation angle and axis of an object
with class "SO3"
as illustrated in the next example.
> mis.angle(R) * 2/pi
[1] 1
> mis.axis(R)
[,1] [,2] [,3]
[1,] 0 1 0
Quaternions are unit vectors in
where
A rotation around axis
The S3
class "Q4"
is defined for the quaternion representation of
rotations. All the functionality of the "SO3"
class also exists for
the "Q4"
class, e.g. is.Q4
and as.Q4
will test for and coerce to
class "Q4"
, respectively. Internally, a sample of Real
, i
, j
and k
to
distinguish between the four components.
The following code creates the same rotation from the previous section
in the form of a quaternion with the as.Q4
function. This function
works much the same way as the as.SO3
function in terms of possible
inputs but returns a vector of length four of the class "Q4"
.
> as.Q4(U, r)
0.707 + 0 * i + 0.707 * j + 0 * k
> as.Q4(as.SO3(U, r))
0.707 + 0 * i + 0.707 * j + 0 * k
If the rotation
where
The rotations package gives the user access to four members of the
UARS class. Each member is differentiated by the distribution function
for .haar
(see Table 1).
The spread of the Cayley, matrix Fisher and circular-von Mises
distributions is controlled by the concentration parameter
Name | Density |
Circular variance |
Function | |||
---|---|---|---|---|---|---|
Uniform | .haar |
|||||
Cayley | .cayley |
|||||
matrix Fisher | .fisher |
|||||
circular-von Mises | .vmises |
For a given concentration d
, p
and r
take the same meaning as for
the more familiar distributions such as dnorm
. To simulate a sample of
ruars
function takes arguments n
, rangle
, and
kappa
to specify the sample size, angular distribution and
concentration as shown below. Alternatively, one can specify the
circular variance space
argument determines the parameterization to form. When a sample of
rotations is printed then a R11
as illustrated below.
> Rs <- ruars(n = 20, rangle = rcayley, kappa = 1, space = "SO3")
> Qs <- ruars(n = 20, rangle = rcayley, kappa = 1, space = "Q4")
> Rs <- ruars(n = 20, rangle = rcayley, nu = 1, space = "SO3")
> Qs <- ruars(n = 20, rangle = rcayley, nu = 1, space = "Q4")
> head(Rs, 3)
R11 R21 R31 R12 R22 R32 R13 R23 R33
[1,] -0.425 -0.850 0.310 0.475 -0.501 -0.723 0.770 -0.160 0.617
[2,] -0.564 -0.733 0.379 0.745 -0.256 0.615 -0.354 0.630 0.691
[3,] 0.087 -0.716 0.692 0.117 0.698 0.707 -0.989 0.019 0.145
In this section we present functions in the rotations package to
compute point estimates and confidence regions for the central
orientation
Given a sample of
The choice of geometry results in two different metrics to measure the
distance between rotation matrices
Estimators based on the Euclidean distance form the class of projected
estimators. The name is derived from the method used to compute these
estimators. That is, each estimator in this class is the projection of
the the generic "SO3"
the median
or mean
function with argument type = "projected"
will return a
By staying in the Riemannian space
Estimators based on the Riemannian distance metric are called geometric
estimators because they preserve the geometry of mean
and median
functions with the argument
type = "geometric"
. Table 2 summarizes the four
estimators including their formal definition and how they can be
computed.
The estimators in Table 2 find estimates based on
minimization of gradient.search
provides the option to optimize for any other
arbitrary minimization criterion. As the name suggests, the minimization
is done along the gradient of the minimization function in the rotation
space. Starting from an initial, user-specified rotation, the algorithm
finds a (local) minimum by stepping iteratively in the direction of the
steepest descent. Step size is regulated internally by adjusting for
curvature of the minimization function.
We highlight this process in the example below. The function L1.error
is defined to minimize the intrinsic minerr
) used for convergence of the
gradient search. What is gained in flexibility of the optimization is,
of course, paid for in terms of speed: the built-in median function is
faster by far than the gradient search.
Also illustrated in the example below is the rot.dist
function, which
computes the distance between two objects of class "SO3"
, e.g. R1
and R2
. The argument method
specifies which type of distance to
compute: the "extrinsic"
option will return the Euclidean distance and
the "intrinsic"
option will return the Riemannian distance. If R1
is
an rot.dist
will return a vector of length R2
and the R1
.
> # error function definition
> L1.error <- function(sample, Shat) {
+ sum(rot.dist(sample, Shat, method = "intrinsic", p = 1))
+ }
> cayley.sample <- ruars(n = 50, rangle = rcayley, nu = 1, space = "SO3")
> # gradient based optimization
> system.time(SL1 <- gradient.search(cayley.sample, L1.error))
user system elapsed
3.464 0.007 3.473
> # in-built function
> system.time(S <- median(cayley.sample, type = "geometric"))
user system elapsed
0.004 0.000 0.005
> rot.dist(S, SL1$Shat)
[1] 1.492e-05
Estimator name | Definition | Code | ||||
---|---|---|---|---|---|---|
Projected Mean | mean(Rs, type = "projected") |
|||||
Projected Median | median(Rs, type = "projected") |
|||||
Geometric Mean | mean(Rs, type = "geometric") |
|||||
Geometric Median | median(Rs, type = "geometric") |
Asymptotic results for the distribution of the projected mean
In the context of directional statistics, (Prentice 1984) used results
found in (Tyler 1981) and the fact that
It has also been shown that both estimators
The six possible confidence regions that result from these two methods
are available through the wrapper function region
. They are
differentiated based on the method
, type
and estimator
arguments.
Set estimator = "mean"
or estimator = "median"
to estimate a region
based on method = "transformation"
for the transformation-based methods or
method = "direct"
for the direct method. Since the
transformation-based methods cannot be applied to
estimator = "median"
and method = "transformation"
are combined. A
bootstrap version of the specified method is implemented if
type = "bootstrap"
or the normal limiting distribution can be chosen
with type = "asymptotic"
. If a bootstrap type region is specified one
can additionally specify the bootstrap sample size with the m
argument, which is set to 300 by default. Regardless of the method and
type chosen a single value is returned on the interval
In the example code below a sample of
> Rs <- ruars(50, rcayley, kappa = 10)
> region(Rs, method = "direct", type = "asymptotic",
+ estimator = "mean", alp = 0.05)
[1] 0.189
> region(Rs, method = "direct", type = "bootstrap", estimator = "mean",
+ alp = 0.05, m = 300)
[1] 0.201
> region(Rs, method = "direct", type = "asymptotic",
+ estimator = "median", alp = 0.05)
[1] 0.201
> region(Rs, method = "direct", type = "bootstrap", estimator = "median",
+ alp = 0.05, m = 300)
[1] 0.249
The rotations package offers two methods to visualize rotation data in
three-dimensions. Because rotation matrices are orthogonal, each column
of a rotation matrix has length one and is perpendicular to the other
axes. Therefore each column of a rotation matrix can be illustrated as a
point on the surface of a unit sphere, which represents the position of
the
An existing function that can be used to illustrate rotation data is the
boat3d
function included in the orientlib package. Given a sample of
rotations, the boat3d
function produces either a static or interactive
three-dimensional boat to represent the provided data. If only one
rotation is of interest, the boat3d
function is superior to the
proposed method because it conveniently illustrates rotational data in a
single image. If multiple rotations are provided, however, the boat3d
function will produce separate side-by-side boats, which can be hard to
interpret. In addition, the illustration of a estimated central
orientation or a confidence region in boat3d
function
is not presently possible.
The rotations package can be used to produce high-quality static plots within the framework of the ggplot2 package (Wickham 2009). Static plots are specifically designed for datasets that are highly concentrated and for use in presentations or publications. Alternatively, the rotations package can produce interactive plots using functions included in the sphereplot package (Robotham 2013). Interactive plots are designed so that the user can explore a dataset and visualize a diffuse sample.
Calling the plot
function with a "SO3"
or "Q4"
object will result
in an interactive or static sphere, differentiated by setting the
argument interactive
to TRUE
or FALSE
, respectively. The center
argument defines the center of the plot and is usually set to the
identity rotation id.SO3
or an estimate of the central orientation,
e.g. mean(Rs)
. The user can specify which columns to visualize with
the col
argument with options col
; only one column
will be displayed at a time for interactive plots. Also available to
static plots is the argument to
range
, which when set to TRUE
will display the portion of the sphere where the observations are
present.
All four estimates of the central orientation can be plotted along with
a sample of rotations. Setting the argument
estimates
show = "all"
will display all four simultaneously. If
only a few estimates are of interest then any combination of
"proj.mean"
, "proj.median"
, "geom.mean"
or "geom.median"
are
valid inputs. The estimators are indicated by color and a legend is
provided, see Figure 1. Finally, the mean
regions
and median
regions
options allow the user to draw a circle on the
surface of the sphere representing the confidence region for that axis,
centered at plot
function for objects of class "SO3"
and Figure
1 illustrates the results of these commands.
> plot(Rs, center = mean(Rs), col = 1, show_estimates = "all",
+ interactive = FALSE)
> plot(Rs, center = mean(Rs), col = 1, show_estimates = "proj.mean",
+ mean_regions = "all", alp = .05, interactive = FALSE)
|
|
(a)Point estimates, static. | (b)Confidence region estimates, static. |
Datasets drill
and nickel
are included in the rotations package to
illustrate how the two representations of orientation data discussed
here are used in practice. The drill
dataset was collected to assess
variation in human movement while performing a task (Rancourt 1995).
Eight subjects drilled into a metal plate while being monitored by
infrared cameras. Quaternions are used to represent the orientation of
each subjects’ wrist, elbow and shoulder in one of six positions. For
some subjects several replicates are available. See (Rancourt et al. 2000) for
one approach to analyzing these data. In the example below we load the
drill
dataset, coerce the observations for subject one’s wrist into a
form usable by the rotations package via as.Q4
, then estimate the
central orientation with the projected mean.
> data(drill)
> head(drill)
Subject Joint Position Replicate Q1 Q2 Q3 Q4
1 1 Wrist 1 1 0.944 -0.192 -0.156 0.217
2 1 Wrist 1 2 0.974 -0.120 -0.111 0.158
3 1 Wrist 1 3 0.965 -0.133 -0.141 0.177
4 1 Wrist 1 4 0.956 -0.134 -0.115 0.233
5 1 Wrist 1 5 0.953 -0.199 -0.061 0.222
6 1 Wrist 2 1 0.963 -0.159 -0.127 0.177
> Subj1Wrist<-subset(drill, Subject == '1' & Joint == 'Wrist')
> Subj1Wdata <- as.Q4(Subj1Wrist[, 5:8])
> mean(Subj1Wdata)
0.987 - 0.070 * i - 0.134 * j + 0.049 * k
In the nickel
dataset, rotation matrices are used to represent the
orientation of cubic crystals on the surface of a nickel sample measured
with Electron Backscatter Diffraction. Each location
on the surface of
the nickel is identified by the xpos
and ypos
columns while the
rep
column identifies which of the fourteen replicate scans that
measurement corresponds to. The last nine columns, denoted v1
-v9
,
represent the elements of the rotation matrix at that location in vector
form. See (Bingham et al. 2009; Bingham et al. 2010) and (Stanfill et al. 2013) for more
details. In the example below we estimate the central orientation at
location one.
> data(nickel)
> head(nickel[, 1:6])
xpos ypos location rep V1 V2
1 0 0.346 1 1 -0.648 0.686
2 0 0.346 1 2 -0.645 0.688
3 0 0.346 1 3 -0.645 0.688
4 0 0.346 1 4 -0.646 0.688
5 0 0.346 1 5 -0.646 0.686
6 0 0.346 1 6 -0.644 0.690
> Location1<-subset(nickel, location == 1)
> Loc1data<-as.SO3(Location1[, 5:13])
> mean(Loc1data)
[,1] [,2] [,3]
[1,] -0.645 -0.286 -0.708
[2,] 0.687 -0.623 -0.374
[3,] -0.334 -0.728 0.599
In this manuscript we introduced the rotations package and
demonstrated how it can be used to generate, analyze and visualize
rotation data. The rotations package is compatible with the quaternion
specific onion package by applying its as.quaternion
function to a
transposed "Q4"
object. Connecting to the onion package gives the
user access to a wide range of algebraic functions unique to
quaternions. Also compatible with the rotations package is the
orientlib package, which includes additional parameterizations of
rotations. To translate rotation matrices generated by the rotations
package into a form usable by the orientlib package, first coerce a
"SO3"
object into a matrix of the same dimension, i.e. rotvector
function provided by the orientlib package.
Quaternions are defined in the orientlib package by
help(package = "onion")
and help(package = "orientlib")
for more on these packages.
> Qs <- ruars(20, rcayley, space = 'Q4')
> Rs <- as.SO3(Qs)
> suppressMessages(require(onion))
> onionQs <- as.quaternion(t(Qs))
> suppressMessages(require(orientlib))
> orientRs <- rotvector(matrix(Rs, ncol = 9))
Computational speed of the rotations package has been enhanced through use of the Rcpp and RcppArmadillo packages (Eddelbuettel 2013; Eddelbuettel and Sanderson 2014). In future versions of the package we plan to extend the parameterization and estimator sections to include robust estimators currently being developed by the authors.
We would like to thank the reviewers for their comments and suggestions. The rotations package and this article have benefited greatly from their time and effort.
orientlib, onion, circular, SpherWave, rotations, ggplot2, sphereplot, Rcpp, RcppArmadillo
Distributions, Environmetrics, HighPerformanceComputing, NumericalMathematics, Phylogenetics, Spatial, TeachingStatistics
This article is converted from a Legacy LaTeX article using the texor package. The pdf version is the official version. To report a problem with the html, refer to CONTRIBUTE on the R Journal homepage.
Text and figures are licensed under Creative Commons Attribution CC BY 4.0. The figures that have been reused from other sources don't fall under this license and can be recognized by a note in their caption: "Figure from ...".
For attribution, please cite this work as
Stanfill, et al., "rotations: An R Package for SO(3) Data", The R Journal, 2014
BibTeX citation
@article{RJ-2014-007, author = {Stanfill, Bryan and Hofmann, Heike and Genschel, Ulrike}, title = {rotations: An R Package for SO(3) Data}, journal = {The R Journal}, year = {2014}, note = {https://rjournal.github.io/}, volume = {6}, issue = {1}, issn = {2073-4859}, pages = {68-78} }