Paraview is a great tool for visualising 3D datasets.
It also offers a few features to transform the data through filters, among which the *Transform* filter, which allows to interactively apply rotations and translations.

If you want to apply the same transformation outside of paraview, it becomes be a little tricky. While paraview gives you a nice GUI showing the rotation angles and the translation vector, it is unclear in which order the transformations are applied. Do we apply translation first? What is the order of the rotations?

It took me some time to figure it out, but the answer is:

- Translation
**Z Rotation**- X Rotation
- Y Rotation

I am sure there is a valid reason for this Z, X, Y order but boy did it take me some precious time to figure this out. Here's a little dirty python snippet that I am happy to share:

import numpy as np def paraview_transform(points, translation, xrot, yrot, zrot): """ points: array of shape (n_points, 3) translation: array of shape (3,) to copy from the paraview GUI xrot, yrot, zrot: floats to copy from the paraview GUI """ new_points = transform_points( points, get_transform_matrix( translation=translation, rotation_x=xrot, rotation_y=yrot, rotation_z=zrot ), ) return new_points def get_transform_matrix( translation=(0.0, 0.0, 0.0), rotation_x=0.0, rotation_y=0.0, rotation_z=0.0, radians=False, z_first=True, ): t = np.eye(4) t[:3, 3] = translation if not radians: rotation_x = np.deg2rad(rotation_x) rotation_y = np.deg2rad(rotation_y) rotation_z = np.deg2rad(rotation_z) x = np.eye(4) x[1, 1] = x[2, 2] = np.cos(rotation_x) x[2, 1] = np.sin(rotation_x) x[1, 2] = -np.sin(rotation_x) y = np.eye(4) y[0, 0] = y[2, 2] = np.cos(rotation_y) y[2, 0] = -np.sin(rotation_y) y[0, 2] = np.sin(rotation_y) z = np.eye(4) z[0, 0] = z[1, 1] = np.cos(rotation_z) z[1, 0] = np.sin(rotation_z) z[0, 1] = -np.sin(rotation_z) if z_first: res = t @ z @ x @ y else: res = t @ x @ y @ z return res.T def transform_points(points, transformation_matrix): source = np.ones((len(points), 4)) source[:, :3] = points new_points = source @ transformation_matrix return new_points[:, :3]

## Edit