ended up looking like this: @classmethod def fromaxisangle(cls, axis, angle): # from https://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_... cos_theta = np.cos(angle) sin_theta = np.sin(angle) axis = axis[:3] axis = axis / np.linalg.norm(axis) mat = np.identity(4) I = mat[:3,:3] mat[:3, :3] = ( cos_theta * I + sin_theta * np.cross(axis, -I) + (1 - cos_theta) * np.outer(axis, axis) ) return cls(mat) $ python3 test.py [[ 0.98006658 0. 0.19866933 0. ] [ 0. 1. 0. 0. ] [-0.19866933 0. 0.98006658 0. ] [ 0. 0. 0. 1. ]] This is a reasonable rotation matrix about the second axis. Since it's rotating about the second axis, it changes only the first and third, and the values are perpendicular sines and cosines.