Getting the circumcentres from a delaunay triangulation generated using matplotlib - python

If I use matplotlib to generate a delaunay triangulation for a group of points, what is the most appropraite way of getting the circumcentres of the triangles that have been geenrated? I haven't yet managed to find an obvious method in the Triangulation library to do this.

You should be able to calculate it using matplotlib.delaunay.triangulate.Triangulation:
Triangulation(x, y)
x, y -- the coordinates of the points as 1-D arrays of floats
.
.
.
Attributes: (all should be treated as
read-only to maintain consistency)
x, y -- the coordinates of the points as 1-D arrays of floats.
circumcenters -- (ntriangles, 2) array of floats giving the (x,y)
coordinates of the circumcenters of each triangle (indexed by a triangle_id).
Adapted from one of the matplotlib examples (there is probably a cleaner way to do this, but it should work):
import matplotlib.pyplot as plt
import matplotlib.delaunay
import matplotlib.tri as tri
import numpy as np
import math
# Creating a Triangulation without specifying the triangles results in the
# Delaunay triangulation of the points.
# First create the x and y coordinates of the points.
n_angles = 36
n_radii = 8
min_radius = 0.25
radii = np.linspace(min_radius, 0.95, n_radii)
angles = np.linspace(0, 2*math.pi, n_angles, endpoint=False)
angles = np.repeat(angles[...,np.newaxis], n_radii, axis=1)
angles[:,1::2] += math.pi/n_angles
x = (radii*np.cos(angles)).flatten()
y = (radii*np.sin(angles)).flatten()
tt = matplotlib.delaunay.triangulate.Triangulation(x,y)
triang = tri.Triangulation(x, y)
# Plot the triangulation.
plt.figure()
plt.gca().set_aspect('equal')
plt.triplot(triang, 'bo-')
plt.plot(tt.circumcenters[:,0],tt.circumcenters[:,1],'r.')
plt.show()

Here is a function that computes them. It can also be used on other triangulation structures, e.g. scipy's Delaunay triangulation (see below).
def compute_triangle_circumcenters(xy_pts, tri_arr):
"""
Compute the centers of the circumscribing circle of each triangle in a triangulation.
:param np.array xy_pts : points array of shape (n, 2)
:param np.array tri_arr : triangles array of shape (m, 3), each row is a triple of indices in the xy_pts array
:return: circumcenter points array of shape (m, 2)
"""
tri_pts = xy_pts[tri_arr] # (m, 3, 2) - triangles as points (not indices)
# finding the circumcenter (x, y) of a triangle defined by three points:
# (x-x0)**2 + (y-y0)**2 = (x-x1)**2 + (y-y1)**2
# (x-x0)**2 + (y-y0)**2 = (x-x2)**2 + (y-y2)**2
#
# becomes two linear equations (squares are canceled):
# 2(x1-x0)*x + 2(y1-y0)*y = (x1**2 + y1**2) - (x0**2 + y0**2)
# 2(x2-x0)*x + 2(y2-y0)*y = (x2**2 + y2**2) - (x0**2 + y0**2)
a = 2 * (tri_pts[:, 1, 0] - tri_pts[:, 0, 0])
b = 2 * (tri_pts[:, 1, 1] - tri_pts[:, 0, 1])
c = 2 * (tri_pts[:, 2, 0] - tri_pts[:, 0, 0])
d = 2 * (tri_pts[:, 2, 1] - tri_pts[:, 0, 1])
v1 = (tri_pts[:, 1, 0] ** 2 + tri_pts[:, 1, 1] ** 2) - (tri_pts[:, 0, 0] ** 2 + tri_pts[:, 0, 1] ** 2)
v2 = (tri_pts[:, 2, 0] ** 2 + tri_pts[:, 2, 1] ** 2) - (tri_pts[:, 0, 0] ** 2 + tri_pts[:, 0, 1] ** 2)
# solve 2x2 system (see https://en.wikipedia.org/wiki/Invertible_matrix#Inversion_of_2_%C3%97_2_matrices)
det = (a * d - b * c)
detx = (v1 * d - v2 * b)
dety = (a * v2 - c * v1)
x = detx / det
y = dety / det
return (np.vstack((x, y))).T
On the data from #JoshAdel's answer above, adding the following code:
cc = compute_triangle_circumcenters(np.vstack([tt.x, tt.y]).T, tt.triangle_nodes)
plt.plot(cc[:, 0], cc[:, 1], ".k")
I get the following figure:
It can also be used on scipy.spatial.Delaunay like this:
from scipy.spatial import Delaunay
xy_pts = np.vstack([x, y]).T
dt = Delaunay(xy_pts)
cc = compute_triangle_circumcenters(dt.points, dt.simplices)

Related

Rotation in 3D coordinate system

I have some fixed points and axes in the 3D coordinate system.
I compute the angle between these axes and some specific points in t = 0, and I am trying to predict their coordinates in any t knowing that my points rotate according to one particular ax with an alpha angle. How can I compute the predicted coordinates using rotation matrices?
I tried something like this :
def rotate(axis=(1., 0., 0.), angle=0.0, radians=None):
""" 4x4 rotation matrix around 'axis' with 'angle' degrees or 'radians' """
x, y, z = normalized(vec(axis))
s, c = sincos(angle, radians)
nc = 1 - c
return np.array([[x*x*nc + c, x*y*nc - z*s, x*z*nc + y*s, 0],
[y*x*nc + z*s, y*y*nc + c, y*z*nc - x*s, 0],
[x*z*nc - y*s, y*z*nc + x*s, z*z*nc + c, 0],
[0, 0, 0, 1]], 'f')
.
.
.
.
x = item.x
y = item.y
shape = image.shape
relative_x = int(x * shape[1])
relative_y = int(y * shape[0])
theta = atan(relative_y/relative_x)
predicted = [np.array([200,200,0,0]),np.array([400,400,0,0])] # an example of pts
r = rotate(axis=(1., 0 , 0 ), radians=theta)
predicted = [r # predicted[0] ,r # predicted[1]]
but the result is false. Is the computation of the rotation matrix valid? Thank you

Rotating a crystal in NumPy

I want to rotate a 5-atom crystal defined by X,Y,Z coordinates of atoms by a random angle. My initial idea was to use an external package to generate a rotation matrix (https://github.com/qobilidop/randrot) and then multiplying this matrix by a vector, which defines the coordinates of a single atom. However, that did not work at all and all the atoms got dispersed. Here's a function I wrote for that purpose:
def rotation():
crystal = []
rotmat = np.asarray(randrot.generate(3)) #generates 3x3 rotation matrix
for x,y,z in zip(new_x, new_y, new_z):
vec = np.array([x,y,z])
rot = vec.dot(rotmat)
for elem in rot:
crystal.append(elem)
return np.array(crystal).reshape([5,3])
rotated = rotation()
ax.scatter(rotated[0], rotated[1], rotated[2], marker='.', s=100, color='green')
Here's how it looks (red is the initial placement, green is after rotation):
pyplot
Here is an example code that rotates given 3d points about a randomly generated rotation matrix, rotation matrix creation is taken from another answer.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import math
# taken from https://stackoverflow.com/questions/6802577/rotation-of-3d-vector
def rotation_matrix(axis, theta):
"""
Return the rotation matrix associated with counterclockwise rotation about
the given axis by theta radians.
"""
axis = np.asarray(axis)
axis = axis / math.sqrt(np.dot(axis, axis))
a = math.cos(theta / 2.0)
b, c, d = -axis * math.sin(theta / 2.0)
aa, bb, cc, dd = a * a, b * b, c * c, d * d
bc, ad, ac, ab, bd, cd = b * c, a * d, a * c, a * b, b * d, c * d
return np.array([[aa + bb - cc - dd, 2 * (bc + ad), 2 * (bd - ac)],
[2 * (bc - ad), aa + cc - bb - dd, 2 * (cd + ab)],
[2 * (bd + ac), 2 * (cd - ab), aa + dd - bb - cc]])
# initial xyz coordinates
xs = [0, 1, 1, 1, 1, -1, -1, -1, -1]
ys = [0, 1, 1, -1, -1, 1, 1, -1, -1]
zs = [0, 1, -1, 1, -1, 1, -1, 1, -1]
atoms_initial = np.array([xs, ys, zs]).T
# specify rotation matrix parameters
# let us generate a random axis and angle for rotation
rotation_axis = np.random.uniform(low=0, high=1, size=3) # three numbers between 0 and 1
rotation_angle = np.random.uniform(low=0, high=2*np.pi, size=1) # random number between 0 and 2pi
print("Rotation axis:{}, rotation angle:{} radians".format(rotation_axis, rotation_angle))
# create our rotation matrix
rotmat = rotation_matrix(rotation_axis, rotation_angle)
# apply rotation matrix to our points
atoms_rotated = np.dot(atoms_initial, rotmat)
# draw
fig = plt.figure()
ax = Axes3D(fig)
ax.scatter(atoms_initial[:,0], atoms_initial[:,1], atoms_initial[:,2], marker='.', s=100, color='red')
ax.scatter(atoms_rotated[:,0], atoms_rotated[:,1], atoms_rotated[:,2], marker='.', s=100, color="green")
plt.show()

Numpy mask from cylinder coordinates

I generated the coordinates of a cylinder. Its two faces connect two arbitrary points already given.
Is it possible to build a 3D numpy mask of the filled cylinder from the coordinates with standard Python libraries? Creating a 2D mask seems simple enough, but I'm encountering some difficulties with 3D.
Here the code for generating the cylinder, taken from here and here:
import scipy
import scipy.linalg
import numpy as np
import nibabel as nib
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# defining mask
shape = (100, 100, 100)
image = np.zeros(shape=shape)
# set radius and centres values
r = 3
start = [30, 45, 60]
end = [40, 58, 70]
p1 = np.array(start)
p2 = np.array(end)
# # calculate p2-p1 distance
# dx = p2[0] - p1[0]
# dy = p2[1] - p1[1]
# dz = p2[2] - p1[2]
# dist = math.sqrt(dx**2 + dy**2 + dz**2)
# vector in direction of axis
v = p2 - p1
# find magnitude of vector
mag = scipy.linalg.norm(v)
# unit vector in direction of axis
v = v / mag
# make some vector not in the same direction as v
not_v = np.array([1, 0, 0])
if (v == not_v).all():
not_v = np.array([0, 1, 0])
# make vector perpendicular to v
n1 = np.cross(v, not_v)
# normalize n1
n1 /= scipy.linalg.norm(n1)
# make unit vector perpendicular to v and n1
n2 = np.cross(v, n1)
#surface ranges over t from 0 to length of axis and 0 to 2*pi
t = np.linspace(0, mag, 100)
theta = np.linspace(0, 2 * np.pi, 100)
rsample = np.linspace(0, r, 2)
#use meshgrid to make 2d arrays
t, theta2 = np.meshgrid(t, theta)
rsample, theta = np.meshgrid(rsample, theta)
# generate coordinates for surface
# "Tube"
X, Y, Z = [p1[i] + v[i] * t + r * np.sin(theta2) * n1[i] + r * np.cos(theta2) * n2[i] for i in [0, 1, 2]]
# "Bottom"
X2, Y2, Z2 = [p1[i] + rsample[i] * np.sin(theta) * n1[i] + rsample[i] * np.cos(theta) * n2[i] for i in [0, 1, 2]]
# "Top"
X3, Y3, Z3 = [p1[i] + v[i] * mag + rsample[i] * np.sin(theta) * n1[i] + rsample[i] * np.cos(theta) * n2[i] for i in [0, 1, 2]]
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_surface(X, Y, Z)
ax.plot_surface(X2, Y2, Z2)
ax.plot_surface(X3, Y3, Z3)
plt.show()
I need the 3D numpy mask to select all the values inside the cylinder of a 3D image. The shape of mask and image is the same.
In the end I looped through the coordinates of tube and faces.
I got the coordinates following this link: 3D points from Numpy meshgrid coordinates
tube = np.stack((X.ravel(), Y.ravel(), Z.ravel()), axis=1)
face1 = np.stack((X2.ravel(), Y2.ravel(), Z2.ravel()), axis=1)
face2 = np.stack((X3.ravel(), Y3.ravel(), Z3.ravel()), axis=1)
# filling numpy mask
for i in range(len(tube)):
image[int(tube[i][0]), int(tube[i][1]), int(tube[i][2])] = 255
for j in range(len(face1)):
image[int(face1[j][0]), int(face1[j][1]), int(face1[j][2])] = 255
for k in range(len(face2)):
image[int(face2[k][0]), int(face2[k][1]), int(face2[k][2])] = 255
mask_new = nib.Nifti1Image(image.astype(np.float32), ctsurg_file.affine)
nib.save(mask_new, os.path.join(currdir, 'mask_cyl.nii.gz'))

curve_fit a 2D function containing numpy arrays --> shapes (3,3,9) and (3,1) not aligned: 9 (dim 2) != 3 (dim 0)

This is my first question here. I hope I provide sufficient information for you guys.
I ran into problems when using curve_fit with a function that uses numpy arrays. Using the function with fixed parameters works fine.
The task:
I want to find two vectors. What I know is how the vectors are rotated around each other and the coordinate system and the resulting angle between one vector and the coordinate system y-axis.
The problem:
my_func is the function I want to use but it throws an error only when putting it into curve_fit.
my_func2 should be a breakdown of the problem that works. As far as I can see the functions in principal are the same except for my_func2 having less and less complex formulas.
This is the code I wrote:
import numpy as np
from scipy.optimize import curve_fit
'''The function I want to optimize. 2D-xdata with 6 free parameters.'''
def my_func(X, hx, hy, hz, lx, ly, lz):
# These are the two independently measured angles (2D-xdata).
phi, alpha = X
# y-axis of the coordinate system.
yaxis = np.array([[0],
[1],
[0]])
# First wanted vector h (first three parameters).
h = np.array([[hx],
[hy],
[hz]])
# Second wanted vector l (last three parameters).
l = np.array([[lx],
[ly],
[lz]])
# Projection matrix.
Pxy = np.array([[1, 0, 0],
[0, 1, 0],
[0, 0, 0]])
# Needed to generate the rotation matrix around the unknown vector h.
h_norm = h / np.linalg.norm(h)
n1, n2, n3 = h_norm[0][0], h_norm[1][0], h_norm[2][0]
# Rotation matrix for rotation around the vector h by angle alpha.
R_h = np.array([[n1 ** 2 * (1 - np.cos(alpha)) + np.cos(alpha), n1 * n2 * (1 - np.cos(alpha)) - n3 * np.sin(alpha), n1 * n3 * (1 - np.cos(alpha)) + n2 * np.sin(alpha)],
[n1 * n2 * (1 - np.cos(alpha)) + n3 * np.sin(alpha), n2 ** 2 * (1 - np.cos(alpha)) + np.cos(alpha), n2 * n3 * (1 - np.cos(alpha)) - n1 * np.sin(alpha)],
[n1 * n3 * (1 - np.cos(alpha)) - n2 * np.sin(alpha), n2 * n3 * (1 - np.cos(alpha)) + n1 * np.sin(alpha), n3 ** 2 * (1 - np.cos(alpha)) + np.cos(alpha)]])
# Rotate the vector l around the vector h by angle alpha.
l_rot = np.dot(R_h, l)
# Rotation matrix for rotation around x-axis by angle phi.
R_x = np.array([[1, 0, 0],
[0, np.cos(phi), -np.sin(phi)],
[0, np.sin(phi), np.cos(phi)]])
# Rotate the vector l_rot around the x-axis by angle phi.
l_final = np.dot(R_x, l_rot)
# Project the vector l_final into the xy-plane.
l_final_xy = np.dot(Pxy, l_final)
# Get the angle between the projected vector l_final_xy and the y-axis.
angle = np.arccos(np.vdot(l_final_xy, yaxis) / (np.linalg.norm(l_final_xy)))
# Return angle in degree.
return angle * 180 / np.pi
'''A simplified version of the function above with less complex formulas.'''
def my_func2(X, a1, a2, a3, b1, b2, b3):
# Represents phi and alpha of my_func.
x1, x2 = X
# Represents the first wanted vector of my_func.
va = np.array([[a1],
[a2],
[a3]])
# Represents the second wanted vector of my_func.
vb = np.array([[b1],
[b2],
[b3]])
# Represents the rotation matrix of my_func. It depends on the x-data and the parameters.
M1 = np.array([[x1 * a1, x2 * b1, 0],
[0, x1 * a2, x2 * b2],
[x2 * b3, 0, x1 * a3]])
# Some simplified math with the wanted vectors and the generated matrix.
v_new = np.vdot(np.dot(M1, va), vb)
return v_new
Here comes some testing.
# Some x-data: phi and alpha.
xdata = [[0, 0, 0, 30, 30, 30, 60, 60, 60],
[0, 90, 180, 0, 90, 180, 0, 90, 180]]
# Some y-data.
ydata = [10, 11, 12, 13, 14, 15, 16, 17, 18]
# Test if my_func works as expected.
print(my_func([np.pi / 4, np.pi / 4], 1, 0, 0, 1, 1, 1))
This line prints 135.0 which is correct. I also tested other values and the result always looks correct.
print(curve_fit(my_func2, xdata, ydata)[0])
This line prints [-0.88635298 2.75337506 0.66050304 0.13882423 0.01404608 0.02166652]. So the fitting of the simplified problem works.
print(curve_fit(my_func, xdata, ydata)[0])
This line throws the following error:
l_rot = np.dot(R_h, l)
ValueError: shapes (3,3,9) and (3,1) not aligned: 9 (dim 2) != 3 (dim 0)
So the final question is: Why do I run into dimensional problems only when using curve_fit and how can I circumvent?
Thanks to Mr.T I noticed that my understanding of curve fit was wrong. I thought it would iterate over the passed x- and y-data and enter each set of values into the function.
In reality curve fit enters the hole x-data, which is a list / array. The function has to be able to handle that list / array itself, as Mr.T explained in his second comment.
To solve my problem I just added a for-loop to my function that iterates over the x-data list / array. The return is now a list of values instead of a single value. One value for each x-data set.
I'm not sure if that is the nicest solution but the working program is below.
import numpy as np
from scipy.optimize import curve_fit
'''The function I want to optimize. 2D-xdata with 6 free parameters.'''
def my_func(X, hx, hy, hz, lx, ly, lz):
angles = []
for index in range(len(X)):
# These are the two independently measured angles (2D-xdata).
phi, alpha = X[index]
# y-axis of the coordinate system.
yaxis = np.array([[0],
[1],
[0]])
# First wanted vector h (first three parameters).
h = np.array([[hx],
[hy],
[hz]])
# Second wanted vector l (last three parameters).
l = np.array([[lx],
[ly],
[lz]])
# Projection matrix.
Pxy = np.array([[1, 0, 0],
[0, 1, 0],
[0, 0, 0]])
# Needed to generate the rotation matrix around the unknown vector h.
h_norm = h / np.linalg.norm(h)
n1, n2, n3 = h_norm[0][0], h_norm[1][0], h_norm[2][0]
# Rotation matrix for rotation around the vector h by angle alpha.
R_h = np.array([[n1 ** 2 * (1 - np.cos(alpha)) + np.cos(alpha), n1 * n2 * (1 - np.cos(alpha)) - n3 * np.sin(alpha), n1 * n3 * (1 - np.cos(alpha)) + n2 * np.sin(alpha)],
[n1 * n2 * (1 - np.cos(alpha)) + n3 * np.sin(alpha), n2 ** 2 * (1 - np.cos(alpha)) + np.cos(alpha), n2 * n3 * (1 - np.cos(alpha)) - n1 * np.sin(alpha)],
[n1 * n3 * (1 - np.cos(alpha)) - n2 * np.sin(alpha), n2 * n3 * (1 - np.cos(alpha)) + n1 * np.sin(alpha), n3 ** 2 * (1 - np.cos(alpha)) + np.cos(alpha)]])
# Rotate the vector l around the vector h by angle alpha.
l_rot = np.dot(R_h, l)
# Rotation matrix for rotation around x-axis by angle phi.
R_x = np.array([[1, 0, 0],
[0, np.cos(phi), -np.sin(phi)],
[0, np.sin(phi), np.cos(phi)]])
# Rotate the vector l_rot around the x-axis by angle phi.
l_final = np.dot(R_x, l_rot)
# Project the vector l_final into the xy-plane.
l_final_xy = np.dot(Pxy, l_final)
# Get the angle between the projected vector l_final_xy and the y-axis.
angle = np.arccos(np.vdot(l_final_xy, yaxis) / (np.linalg.norm(l_final_xy)))
angles.append(angle * 180 / np.pi)
# Return angle in degree.
return angles
# Some x-data: phi and alpha.
xdata = [[0, 0],
[0, 90],
[0, 180],
[30, 0],
[30, 90],
[30, 180],
[60, 0],
[60, 90],
[60, 180]]
# Some y-data.
ydata = [10, 11, 12, 13, 14, 15, 16, 17, 18]
print(curve_fit(my_func, xdata, ydata)[0])

efficiently calculate list of 3d rotation matrices in numpy or scipy

I have a list of N unit-normalized 3D vectors p stored in a numpy ndarray with shape (N, 3). I have another such list, q. I want to calculate an ndarray U of shape (N, 3, 3) storing the rotation matrices that rotate each point in p to the corresponding point q.
The list of rotation matrices U should satisfy:
np.all(np.einsum('ijk,ik->ij', U, p) == q)
On a point-by-point basis, the problem reduces to being able to compute a rotation matrix for a rotation of some angle about some axis. Code solving the single-point case appears below:
def rotation_matrix(angle, direction):
direction = np.atleast_1d(direction).astype('f4')
sina = np.sin(angle)
cosa = np.cos(angle)
direction = direction/np.sqrt(np.sum(direction*direction))
R = np.diag([cosa, cosa, cosa])
R += np.outer(direction, direction) * (1.0 - cosa)
direction *= sina
R += np.array(((0.0, -direction[2], direction[1]),
(direction[2], 0.0, -direction[0]),
(-direction[1], direction[0], 0.0)))
return R
What I need is a function that behaves exactly as the above function, but instead of accepting a single angle and a single direction, it accepts an angles array of shape (npts, ) and a directions array of shape (npts, 3). The code below is only partially finished - the problem is that neither np.diag nor np.outer accept an axis argument
def rotation_matrices(angles, directions):
directions = np.atleast_2d(directions)
angles = np.atleast_1d(angles)
npts = directions.shape[0]
directions = directions/np.sqrt(np.sum(directions*directions, axis=1)).reshape((npts, 1))
sina = np.sin(angles)
cosa = np.cos(angles)
# Lines below require extension to 2d case - np.diag and np.outer do not support axis arguments
R = np.diag([cosa, cosa, cosa])
R += np.outer(directions, directions) * (1.0 - cosa)
directions *= sina
R += np.array(((0.0, -directions[2], directions[1]),
(directions[2], 0.0, -directions[0]),
(-directions[1], directions[0], 0.0)))
return R
Does either numpy or scipy have a compact vectorized function computing the appropriate rotation matrices in a way that avoids using for loops? The problem is that neither np.diag nor np.outer accept axis as an argument. My application will have N be very large, 1e7 or greater, so a vectorized function that keeps all the relevant axes aligned is necessary for performance reasons.
Dropping this here for now, will explain later. Using levi-cevita symbols from #jaime's answer here and the matrix form of the Rodrigues formula here and some algebra based on k = (a x b)/sin(theta)
def rotmatx(p, q):
eijk = np.zeros((3, 3, 3))
eijk[0, 1, 2] = eijk[1, 2, 0] = eijk[2, 0, 1] = 1
eijk[0, 2, 1] = eijk[2, 1, 0] = eijk[1, 0, 2] = -1
d = (p * q).sum(-1)[:, None, None]
c = (p.dot(eijk) # q[..., None]).squeeze() # cross product (optimized)
cx = c.dot(eijk)
return np.eye(3) + cx + cx # cx / (1 + d)
EDIT: dang. question changed.
def rotation_matrices(angles, directions):
eijk = np.zeros((3, 3, 3))
eijk[0, 1, 2] = eijk[1, 2, 0] = eijk[2, 0, 1] = 1
eijk[0, 2, 1] = eijk[2, 1, 0] = eijk[1, 0, 2] = -1
theta = angles[:, None, None]
K = directions.dot(eijk)
return np.eye(3) + K * np.sin(theta) + K # K * (1 - np.cos(theta))
Dropping another solution for bulk rotation of a Nx3x3 matrix. Where the 3x3 components represent vector components in
[[11, 12, 13],
[21, 22, 23],
[31, 32, 33]]
Now matrix rotation by np.einsum is:
data = np.random.uniform(size=(500, 3, 3))
rotmat = np.random.uniform(size=(3, 3))
data_rot = np.einsum('ij,...jk,lk->...il', rotmat, data, rotmat)
This is equivalent to
for data_mat in data:
np.dot(np.dot(rotmat, data_mat), rotmat.T)
Speedup over a np.dot-loop is around 250x.

Categories