scipy.spatial.transform.Rotation#
- class scipy.spatial.transform.Rotation#
Rotation in 3 dimensions.
This class provides an interface to initialize from and represent rotations with:
Quaternions
Rotation Matrices
Rotation Vectors
Modified Rodrigues Parameters
Euler Angles
The following operations on rotations are supported:
Application on vectors
Rotation Composition
Rotation Inversion
Rotation Indexing
Indexing within a rotation is supported since multiple rotation transforms can be stored within a single
Rotation
instance.To create
Rotation
objects usefrom_...
methods (see examples below).Rotation(...)
is not supposed to be instantiated directly.See also
Notes
New in version 1.2.0.
Examples
>>> from scipy.spatial.transform import Rotation as R >>> import numpy as np
A
Rotation
instance can be initialized in any of the above formats and converted to any of the others. The underlying object is independent of the representation used for initialization.Consider a counter-clockwise rotation of 90 degrees about the z-axis. This corresponds to the following quaternion (in scalar-last format):
>>> r = R.from_quat([0, 0, np.sin(np.pi/4), np.cos(np.pi/4)])
The rotation can be expressed in any of the other formats:
>>> r.as_matrix() array([[ 2.22044605e-16, -1.00000000e+00, 0.00000000e+00], [ 1.00000000e+00, 2.22044605e-16, 0.00000000e+00], [ 0.00000000e+00, 0.00000000e+00, 1.00000000e+00]]) >>> r.as_rotvec() array([0. , 0. , 1.57079633]) >>> r.as_euler('zyx', degrees=True) array([90., 0., 0.])
The same rotation can be initialized using a rotation matrix:
>>> r = R.from_matrix([[0, -1, 0], ... [1, 0, 0], ... [0, 0, 1]])
Representation in other formats:
>>> r.as_quat() array([0. , 0. , 0.70710678, 0.70710678]) >>> r.as_rotvec() array([0. , 0. , 1.57079633]) >>> r.as_euler('zyx', degrees=True) array([90., 0., 0.])
The rotation vector corresponding to this rotation is given by:
>>> r = R.from_rotvec(np.pi/2 * np.array([0, 0, 1]))
Representation in other formats:
>>> r.as_quat() array([0. , 0. , 0.70710678, 0.70710678]) >>> r.as_matrix() array([[ 2.22044605e-16, -1.00000000e+00, 0.00000000e+00], [ 1.00000000e+00, 2.22044605e-16, 0.00000000e+00], [ 0.00000000e+00, 0.00000000e+00, 1.00000000e+00]]) >>> r.as_euler('zyx', degrees=True) array([90., 0., 0.])
The
from_euler
method is quite flexible in the range of input formats it supports. Here we initialize a single rotation about a single axis:>>> r = R.from_euler('z', 90, degrees=True)
Again, the object is representation independent and can be converted to any other format:
>>> r.as_quat() array([0. , 0. , 0.70710678, 0.70710678]) >>> r.as_matrix() array([[ 2.22044605e-16, -1.00000000e+00, 0.00000000e+00], [ 1.00000000e+00, 2.22044605e-16, 0.00000000e+00], [ 0.00000000e+00, 0.00000000e+00, 1.00000000e+00]]) >>> r.as_rotvec() array([0. , 0. , 1.57079633])
It is also possible to initialize multiple rotations in a single instance using any of the
from_...
functions. Here we initialize a stack of 3 rotations using thefrom_euler
method:>>> r = R.from_euler('zyx', [ ... [90, 0, 0], ... [0, 45, 0], ... [45, 60, 30]], degrees=True)
The other representations also now return a stack of 3 rotations. For example:
>>> r.as_quat() array([[0. , 0. , 0.70710678, 0.70710678], [0. , 0.38268343, 0. , 0.92387953], [0.39190384, 0.36042341, 0.43967974, 0.72331741]])
Applying the above rotations onto a vector:
>>> v = [1, 2, 3] >>> r.apply(v) array([[-2. , 1. , 3. ], [ 2.82842712, 2. , 1.41421356], [ 2.24452282, 0.78093109, 2.89002836]])
A
Rotation
instance can be indexed and sliced as if it were a single 1D array or list:>>> r.as_quat() array([[0. , 0. , 0.70710678, 0.70710678], [0. , 0.38268343, 0. , 0.92387953], [0.39190384, 0.36042341, 0.43967974, 0.72331741]]) >>> p = r[0] >>> p.as_matrix() array([[ 2.22044605e-16, -1.00000000e+00, 0.00000000e+00], [ 1.00000000e+00, 2.22044605e-16, 0.00000000e+00], [ 0.00000000e+00, 0.00000000e+00, 1.00000000e+00]]) >>> q = r[1:3] >>> q.as_quat() array([[0. , 0.38268343, 0. , 0.92387953], [0.39190384, 0.36042341, 0.43967974, 0.72331741]])
In fact it can be converted to numpy.array:
>>> r_array = np.asarray(r) >>> r_array.shape (3,) >>> r_array[0].as_matrix() array([[ 2.22044605e-16, -1.00000000e+00, 0.00000000e+00], [ 1.00000000e+00, 2.22044605e-16, 0.00000000e+00], [ 0.00000000e+00, 0.00000000e+00, 1.00000000e+00]])
Multiple rotations can be composed using the
*
operator:>>> r1 = R.from_euler('z', 90, degrees=True) >>> r2 = R.from_rotvec([np.pi/4, 0, 0]) >>> v = [1, 2, 3] >>> r2.apply(r1.apply(v)) array([-2. , -1.41421356, 2.82842712]) >>> r3 = r2 * r1 # Note the order >>> r3.apply(v) array([-2. , -1.41421356, 2.82842712])
Finally, it is also possible to invert rotations:
>>> r1 = R.from_euler('z', [90, 45], degrees=True) >>> r2 = r1.inv() >>> r2.as_euler('zyx', degrees=True) array([[-90., 0., 0.], [-45., 0., 0.]])
The following function can be used to plot rotations with Matplotlib by showing how they transform the standard x, y, z coordinate axes:
>>> import matplotlib.pyplot as plt
>>> def plot_rotated_axes(ax, r, name=None, offset=(0, 0, 0), scale=1): ... colors = ("#FF6666", "#005533", "#1199EE") # Colorblind-safe RGB ... loc = np.array([offset, offset]) ... for i, (axis, c) in enumerate(zip((ax.xaxis, ax.yaxis, ax.zaxis), ... colors)): ... axlabel = axis.axis_name ... axis.set_label_text(axlabel) ... axis.label.set_color(c) ... axis.line.set_color(c) ... axis.set_tick_params(colors=c) ... line = np.zeros((2, 3)) ... line[1, i] = scale ... line_rot = r.apply(line) ... line_plot = line_rot + loc ... ax.plot(line_plot[:, 0], line_plot[:, 1], line_plot[:, 2], c) ... text_loc = line[1]*1.2 ... text_loc_rot = r.apply(text_loc) ... text_plot = text_loc_rot + loc[0] ... ax.text(*text_plot, axlabel.upper(), color=c, ... va="center", ha="center") ... ax.text(*offset, name, color="k", va="center", ha="center", ... bbox={"fc": "w", "alpha": 0.8, "boxstyle": "circle"})
Create three rotations - the identity and two Euler rotations using intrinsic and extrinsic conventions:
>>> r0 = R.identity() >>> r1 = R.from_euler("ZYX", [90, -30, 0], degrees=True) # intrinsic >>> r2 = R.from_euler("zyx", [90, -30, 0], degrees=True) # extrinsic
Add all three rotations to a single plot:
>>> ax = plt.figure().add_subplot(projection="3d", proj_type="ortho") >>> plot_rotated_axes(ax, r0, name="r0", offset=(0, 0, 0)) >>> plot_rotated_axes(ax, r1, name="r1", offset=(3, 0, 0)) >>> plot_rotated_axes(ax, r2, name="r2", offset=(6, 0, 0)) >>> _ = ax.annotate( ... "r0: Identity Rotation\n" ... "r1: Intrinsic Euler Rotation (ZYX)\n" ... "r2: Extrinsic Euler Rotation (zyx)", ... xy=(0.6, 0.7), xycoords="axes fraction", ha="left" ... ) >>> ax.set(xlim=(-1.25, 7.25), ylim=(-1.25, 1.25), zlim=(-1.25, 1.25)) >>> ax.set(xticks=range(-1, 8), yticks=[-1, 0, 1], zticks=[-1, 0, 1]) >>> ax.set_aspect("equal", adjustable="box") >>> ax.figure.set_size_inches(6, 5) >>> plt.tight_layout()
Show the plot:
>>> plt.show()
These examples serve as an overview into the
Rotation
class and highlight major functionalities. For more thorough examples of the range of input and output formats supported, consult the individual method’s examples.- Attributes:
single
Whether this instance represents a single rotation.
Methods
Number of rotations contained in this object.
from_quat
(type cls, quat)Initialize from quaternions.
from_matrix
(type cls, matrix)Initialize from rotation matrix.
from_rotvec
(type cls, rotvec[, degrees])Initialize from rotation vectors.
from_mrp
(type cls, mrp)Initialize from Modified Rodrigues Parameters (MRPs).
from_euler
(type cls, seq, angles[, degrees])Initialize from Euler angles.
as_quat
(self[, canonical])Represent as quaternions.
as_matrix
(self)Represent as rotation matrix.
as_rotvec
(self[, degrees])Represent as rotation vectors.
as_mrp
(self)Represent as Modified Rodrigues Parameters (MRPs).
as_euler
(self, seq[, degrees])Represent as Euler angles.
concatenate
(type cls, rotations)Concatenate a sequence of
Rotation
objects.apply
(self, vectors[, inverse])Apply this rotation to a set of vectors.
Compose this rotation with the other.
inv
(self)Invert this rotation.
magnitude
(self)Get the magnitude(s) of the rotation(s).
mean
(self[, weights])Get the mean of the rotations.
reduce
(self[, left, right, return_indices])Reduce this rotation with the provided rotation groups.
create_group
(type cls, group[, axis])Create a 3D rotation group.
Extract rotation(s) at given index(es) from object.
identity
(type cls[, num])Get identity rotation(s).
random
(type cls[, num, random_state])Generate uniformly distributed rotations.
align_vectors
(type cls, a, b[, weights, ...])Estimate a rotation to optimally align two sets of vectors.