Skip to content

rototrans.py

Rototrans

__new__(cls, data=None, time=None, **kwargs) special staticmethod

Rototrans DataArray with row, col and time dimensions used for rototranslation matrix. rototrans

Parameters:

Name Type Description Default
data Optional[Union[<built-in function array>, numpy.ndarray, xarray.core.dataarray.DataArray]]

Array to be passed to xarray.DataArray

None
time Optional[Union[<built-in function array>, list, pandas.core.series.Series]]

Time vector in seconds associated with the data parameter

None
kwargs

Keyword argument(s) to be passed to xarray.DataArray

{}

Returns:

Type Description
DataArray

Rototrans xarray.DataArray with the specified data and coordinates

Example

To instantiate a Rototrans 4 by 4 and 100 frames filled with some random data:

from pyomeca import Rototrans
import numpy as np

# create random yet homogeneous data
n_frames = 100
data = Rototrans.from_random_data(size=(4, 4, 100)).data

rt = Rototrans(data)

You can an associate time vector:

rate = 100  # Hz
time = np.arange(start=0, stop=n_frames / rate, step=1 / rate)
rt = Rototrans(data, time=time)

Notes

Calling Rototrans() generate an empty array.

Source code in pyomeca/rototrans.py
def __new__(
    cls,
    data: Optional[Union[np.array, np.ndarray, xr.DataArray]] = None,
    time: Optional[Union[np.array, list, pd.Series]] = None,
    **kwargs,
) -> xr.DataArray:
    """
    Rototrans DataArray with `row`, `col` and `time` dimensions used for rototranslation matrix.
     ![rototrans](/images/objects/rototrans.svg)

    Arguments:
        data: Array to be passed to xarray.DataArray
        time: Time vector in seconds associated with the `data` parameter
        kwargs: Keyword argument(s) to be passed to xarray.DataArray

    Returns:
        Rototrans `xarray.DataArray` with the specified data and coordinates

    !!! example
        To instantiate a `Rototrans` 4 by 4 and 100 frames filled with some random data:

        ```python
        from pyomeca import Rototrans
        import numpy as np

        # create random yet homogeneous data
        n_frames = 100
        data = Rototrans.from_random_data(size=(4, 4, 100)).data

        rt = Rototrans(data)
        ```

        You can an associate time vector:

        ```python
        rate = 100  # Hz
        time = np.arange(start=0, stop=n_frames / rate, step=1 / rate)
        rt = Rototrans(data, time=time)
        ```

    !!! notes
        Calling `Rototrans()` generate an empty array.
    """
    coords = {}
    if data is None:
        data = np.eye(4)
    else:
        # if we provide data, we copy them to avoid making inplace changes
        data = data.copy()

        if data.shape[0] not in (3, 4) or data.shape[0] != data.shape[1]:
            raise IndexError(
                f"data must have first and second dimensions of length 4, you have: {data.shape}"
            )

    if data.ndim == 2:
        data = data[..., np.newaxis]

    if time is not None:
        coords["time"] = time

    # Make sure last line reads [0, 0, 0, 1]
    zeros = data[3, :3, :]
    ones = data[3, 3, :]
    if not np.alltrue(zeros == 0) or not np.alltrue(ones == 1):
        some_zeros = np.random.choice(zeros.ravel(), 5)
        some_ones = np.random.choice(ones.ravel(), 5)
        raise ValueError(
            "Last line does not read [0, 0, 0, 1].\n"
            f"Here are some values that should be 0: {some_zeros}\n"
            f"And others that should 1: {some_ones}"
        )

    return xr.DataArray(
        data=data,
        dims=("row", "col", "time"),
        coords=coords,
        name="rototrans",
        **kwargs,
    )

from_averaged_rototrans(rt) classmethod

Rototrans DataArray from an averaged Rototrans.

Parameters:

Name Type Description Default
rt DataArray

Rototrans to average

required

Returns:

Type Description
DataArray

Averaged Rototrans xarray.DataArray

Example

To average a Rototrans computed from random angles:

import numpy as np
from pyomeca import Angles, Rototrans

angles = Angles(np.random.rand(3, 1, 100))
seq = "xyz"

rt = Rototrans.from_euler_angles(angles, seq)
rt_mean = Rototrans.from_averaged_rototrans(rt)

Let's make sure the resulting angles are roughly equivalent to the averaged angles:

angles_mean = Angles.from_rototrans(rt_mean, seq).isel(time=0)
angles_mean_ref = Angles.from_rototrans(rt, seq).mean(dim="time")

error = (angles_mean - angles_mean_ref).meca.abs().sum()
print(error)
Source code in pyomeca/rototrans.py
@classmethod
def from_averaged_rototrans(cls, rt: xr.DataArray) -> xr.DataArray:
    """
    Rototrans DataArray from an averaged Rototrans.

    Arguments:
        rt: Rototrans to average

    Returns:
        Averaged Rototrans `xarray.DataArray`

    !!! example
        To average a `Rototrans` computed from random angles:

        ```python
        import numpy as np
        from pyomeca import Angles, Rototrans

        angles = Angles(np.random.rand(3, 1, 100))
        seq = "xyz"

        rt = Rototrans.from_euler_angles(angles, seq)
        rt_mean = Rototrans.from_averaged_rototrans(rt)
        ```

        Let's make sure the resulting angles are roughly equivalent
        to the averaged angles:

        ```python
        angles_mean = Angles.from_rototrans(rt_mean, seq).isel(time=0)
        angles_mean_ref = Angles.from_rototrans(rt, seq).mean(dim="time")

        error = (angles_mean - angles_mean_ref).meca.abs().sum()
        print(error)
        ```
    """
    return rototrans.rototrans_from_averaged_rototrans(cls, rt)

from_euler_angles(angles=None, angle_sequence=None, translations=None) classmethod

Rototrans DataArray from euler angles and specified angle sequence.

Parameters:

Name Type Description Default
angles Optional[xarray.core.dataarray.DataArray]

Euler angles of the rototranslation matrix

None
angle_sequence Optional[str]

Euler sequence of angles. Valid values are all permutations of "xyz"

None
translations Optional[xarray.core.dataarray.DataArray]

Translation part of the Rototrans matrix

None

Returns:

Type Description
DataArray

Rototrans xarray.DataArray from the specified angles and angles sequence

Example

To get the rototranslation matrix from random euler angles with a given angle sequence type:

from pyomeca import Angles, Rototrans

size = (3, 1, 100)
angles = Angles.from_random_data(size=size)
angles_sequence = "xyz"

rt = Rototrans.from_euler_angles(angles=angles, angle_sequence=angles_sequence)

A translation vector can also be specified:

translation = Angles.from_random_data(size=size)
rt = Rototrans.from_euler_angles(
    angles=angles, angle_sequence=angles_sequence, translations=translation
)
Source code in pyomeca/rototrans.py
@classmethod
def from_euler_angles(
    cls,
    angles: Optional[xr.DataArray] = None,
    angle_sequence: Optional[str] = None,
    translations: Optional[xr.DataArray] = None,
) -> xr.DataArray:
    """
    Rototrans DataArray from euler angles and specified angle sequence.

    Arguments:
        angles: Euler angles of the rototranslation matrix
        angle_sequence: Euler sequence of angles. Valid values are all permutations of "xyz"
        translations: Translation part of the Rototrans matrix

    Returns:
        Rototrans `xarray.DataArray` from the specified angles and angles sequence

    !!! example
        To get the rototranslation matrix from random euler angles with a given angle sequence type:

        ```python
        from pyomeca import Angles, Rototrans

        size = (3, 1, 100)
        angles = Angles.from_random_data(size=size)
        angles_sequence = "xyz"

        rt = Rototrans.from_euler_angles(angles=angles, angle_sequence=angles_sequence)
        ```

        A translation vector can also be specified:

        ```python
        translation = Angles.from_random_data(size=size)
        rt = Rototrans.from_euler_angles(
            angles=angles, angle_sequence=angles_sequence, translations=translation
        )
        ```
    """
    return rototrans.rototrans_from_euler_angles(
        cls, angles, angle_sequence, translations
    )

from_markers(origin, axis_1, axis_2, axes_name, axis_to_recalculate) classmethod

Rototrans DataArray from a specified set of markers.

Parameters:

Name Type Description Default
origin DataArray

A marker constructed with pyomeca.Markers() corresponding to the origin in the global reference frame

required
axis_1 DataArray

Two markers that describe the first axis. The first markers being the beginning of the vector and the second being the end.

required
axis_2 DataArray

Two markers that describe the second axis. The first markers being the beginning of the vector and the second being the end.

required
axes_name str

Any combination of x, y and z describing the first and second axes.

required
axis_to_recalculate str

Which of the two axes to recalculate

required

Returns:

Type Description
DataArray

Rototrans xarray.DataArray from the specified angles and angles sequence

Example

To create a system of axes from random markers:

from pyomeca import Markers, Rototrans

markers = Markers.from_random_data()

rt = Rototrans.from_markers(
    origin=markers.isel(channel=[0]),  # first marker
    axis_1=markers.isel(channel=[0, 1]),  # vector from the first and second markers
    axis_2=markers.isel(channel=[0, 2]),  # vector from the first and third markers
    axes_name="xy",  # axis_1 is x and axis_2 is y
    axis_to_recalculate="y",  # we want to recalculate y
)
Source code in pyomeca/rototrans.py
@classmethod
def from_markers(
    cls,
    origin: xr.DataArray,
    axis_1: xr.DataArray,
    axis_2: xr.DataArray,
    axes_name: str,
    axis_to_recalculate: str,
) -> xr.DataArray:
    """
    Rototrans DataArray from a specified set of markers.

    Arguments:
        origin: A marker constructed with `pyomeca.Markers()` corresponding
            to the origin in the global reference frame
        axis_1: Two markers that describe the first axis.
            The first markers being the beginning of the vector and the second being the end.
        axis_2: Two markers that describe the second axis.
            The first markers being the beginning of the vector and the second being the end.
        axes_name: Any combination of `x`, `y` and `z` describing the first and second axes.
        axis_to_recalculate: Which of the two axes to recalculate

    Returns:
        Rototrans `xarray.DataArray` from the specified angles and angles sequence

    !!! example
        To create a system of axes from random markers:

        ```python
        from pyomeca import Markers, Rototrans

        markers = Markers.from_random_data()

        rt = Rototrans.from_markers(
            origin=markers.isel(channel=[0]),  # first marker
            axis_1=markers.isel(channel=[0, 1]),  # vector from the first and second markers
            axis_2=markers.isel(channel=[0, 2]),  # vector from the first and third markers
            axes_name="xy",  # axis_1 is x and axis_2 is y
            axis_to_recalculate="y",  # we want to recalculate y
        )
        ```
    """
    return rototrans.rototrans_from_markers(
        cls, origin, axis_1, axis_2, axes_name, axis_to_recalculate
    )

from_random_data(distribution='normal', size=(3, 1, 100), **kwargs) classmethod

Create random data from a specified distribution (normal by default) using random walk.

Parameters:

Name Type Description Default
distribution str

Distribution available in numpy.random

'normal'
size tuple

Shape of the desired array

(3, 1, 100)
kwargs

Keyword argument(s) to be passed to numpy.random.distribution

{}

Returns:

Type Description
DataArray

Random rototrans xarray.DataArray sampled from a given distribution

Example

To instantiate a Rototrans with some random data sampled from a normal distribution:

from pyomeca import Rototrans

n_frames = 100
size = 4, 4, n_frames
rt = Rototrans.from_random_data(size=size)

You can choose any distribution available in numpy.random:

rt = Rototrans.from_random_data(distribution="uniform", size=size, low=1, high=10)
Source code in pyomeca/rototrans.py
@classmethod
def from_random_data(
    cls, distribution: str = "normal", size: tuple = (3, 1, 100), **kwargs
) -> xr.DataArray:
    """
    Create random data from a specified distribution (normal by default) using random walk.

    Arguments:
        distribution: Distribution available in
            [numpy.random](https://docs.scipy.org/doc/numpy-1.14.0/reference/routines.random.html#distributions)
        size: Shape of the desired array
        kwargs: Keyword argument(s) to be passed to numpy.random.`distribution`

    Returns:
        Random rototrans `xarray.DataArray` sampled from a given distribution

    !!! example
        To instantiate a `Rototrans` with some random data sampled from a normal distribution:

        ```python
        from pyomeca import Rototrans

        n_frames = 100
        size = 4, 4, n_frames
        rt = Rototrans.from_random_data(size=size)
        ```

        You can choose any distribution available in
            [numpy.random](https://docs.scipy.org/doc/numpy-1.14.0/reference/routines.random.html#distributions):

        ```python
        rt = Rototrans.from_random_data(distribution="uniform", size=size, low=1, high=10)
        ```
    """
    return Rototrans.from_euler_angles(
        Angles.from_random_data(distribution, size=(3, 1, size[-1]), **kwargs),
        "xyz",
    )

from_transposed_rototrans(rt) classmethod

Rototrans DataArray from a tranposed Rototrans.

Parameters:

Name Type Description Default
rt DataArray

Rototrans to transpose

required

Returns:

Type Description
DataArray

Transposed Rototrans xarray.DataArray

Example

from pyomeca import Rototrans

rt = Rototrans.from_random_data()

rt_t = Rototrans.from_transposed_rototrans(rt)

Notes

The inverse Rototrans is, by definition, equivalent to the tranposed Rototrans.

Source code in pyomeca/rototrans.py
@classmethod
def from_transposed_rototrans(cls, rt: xr.DataArray) -> xr.DataArray:
    """
    Rototrans DataArray from a tranposed Rototrans.

    Arguments:
        rt: Rototrans to transpose

    Returns:
        Transposed Rototrans `xarray.DataArray`

    !!! example
        ```python
        from pyomeca import Rototrans

        rt = Rototrans.from_random_data()

        rt_t = Rototrans.from_transposed_rototrans(rt)
        ```

    !!! notes
        The inverse Rototrans is, by definition, equivalent to the tranposed Rototrans.
    """
    return rototrans.rototrans_from_transposed_rototrans(cls, rt)