Question: I have an array of coordinates in x and y, relative to the movement of an object in a constantly rotating circular environment (10 rpm). How can I disentangle between the movement of the object from that of the environment? I tried polar coordinates, speed and movement vectors, and I get results, but I'd like to know if someone knows the right way to go. Mainly, I derotate every point according to the distance from the center of rotation, converting to polar coordinates, creating an array of derotated positions. Then I calculate the movement vector between each original_points[idx] and derotated_points[idx+1]. Then, I take the first original point as the starting point for a new array, and to that I add the first vector, storing the new location. Which will be the starting point for adding the second vector, and so on... Seems reasonable but I'd like to know if there are other methods.

Answer: This is a really nice area and a good question about matrix transformations. If you wish to know about this, do read this course: https://graphics.stanford.edu/courses/cs248-01/ Now, Let's start by creating some sample data: import numpy as np import matplotlib.pyplot as plt import pandas as pd rpm = 10 omega = rpm * 2 * np.pi / 60 time = np.linspace(0, 60, 60) speed = 0.1 x_linear = speed * time y_linear = np.zeros_like(time) x_rotated = x_linear * np.cos(omega * time) - y_linear * np.sin(omega * time) y_rotated = x_linear * np.sin(omega * time) + y_linear * np.cos(omega * time) df = pd.DataFrame({ 'time': time, 'x': x_rotated, 'y': y_rotated }) print(df)  Here, I assume that rpm = 10, the angular velocity, in rad(s, is given as omega = rpm * 2 * np.pi / 60 and that the speed of the obejct is speed = 0.1 units/sec. This gives you  time x y 0 0.000000 0.000000 0.000000e+00 1 1.016949 0.049276 8.895896e-02 2 2.033898 -0.107882 1.724206e-01 3 3.050847 -0.304652 -1.623727e-02 4 4.067797 -0.177888 -3.658219e-01 5 5.084746 0.292265 -4.160862e-01 6 6.101695 0.606713 6.485704e-02 7 7.118644 0.276790 6.558492e-01 8 8.135593 -0.502393 6.399064e-01 9 9.152542 -0.903602 -1.455835e-01 10 10.169492 -0.344989 -9.566443e-01 11 11.186441 0.736640 -8.418588e-01 12 12.203390 1.192763 2.579585e-01 13 13.220339 0.381661 1.265744e+00 ... 56 56.949153 -5.686844 3.030958e-01 57 57.966102 -3.074643 -4.913986e+00 58 58.983051 2.858029 -5.159620e+00 59 60.000000 6.000000 -5.732833e-14  Now, to derotate (transform the above matrix); you need to define the following function (for your reference, Gilbert Strand's Linear Algebra and Its Applications is a perfect book. def derotate_coordinates(df, omega): df['x_derotated'] = df['x']*np.cos(-omega*df['time']) - df['y']*np.sin(-omega*df['time']) df['y_derotated'] = df['x']*np.sin(-omega*df['time']) + df['y']*np.cos(-omega*df['time']) return df  which applied df_derotated = derotate_coordinates(df.copy(), omega) print(df_derotated)  will give you  time x y x_derotated y_derotated 0 0.000000 0.000000 0.000000e+00 0.000000 0.000000e+00 1 1.016949 0.049276 8.895896e-02 0.101695 0.000000e+00 2 2.033898 -0.107882 1.724206e-01 0.203390 -1.387779e-17 3 3.050847 -0.304652 -1.623727e-02 0.305085 0.000000e+00 4 4.067797 -0.177888 -3.658219e-01 0.406780 0.000000e+00 5 5.084746 0.292265 -4.160862e-01 0.508475 0.000000e+00 6 6.101695 0.606713 6.485704e-02 0.610169 0.000000e+00 7 7.118644 0.276790 6.558492e-01 0.711864 0.000000e+00 8 8.135593 -0.502393 6.399064e-01 0.813559 0.000000e+00 9 9.152542 -0.903602 -1.455835e-01 0.915254 2.775558e-17 10 10.169492 -0.344989 -9.566443e-01 1.016949 -5.551115e-17 11 11.186441 0.736640 -8.418588e-01 1.118644 0.000000e+00 12 12.203390 1.192763 2.579585e-01 1.220339 0.000000e+00 13 13.220339 0.381661 1.265744e+00 1.322034 -5.551115e-17 ... 56 56.949153 -5.686844 3.030958e-01 5.694915 0.000000e+00 57 57.966102 -3.074643 -4.913986e+00 5.796610 0.000000e+00 58 58.983051 2.858029 -5.159620e+00 5.898305 -4.440892e-16 59 60.000000 6.000000 -5.732833e-14 6.000000 0.000000e+00  If you want to visualize this plt.figure(figsize=(12, 6)) plt.subplot(1, 2, 1) plt.plot(df['x'], df['y'], 'ro-') plt.title('Path in Rotating Frame') plt.xlabel('X') plt.ylabel('Y') plt.axis('equal') plt.subplot(1, 2, 2) plt.plot(df_derotated['x_derotated'], df_derotated['y_derotated'], 'bo-') plt.title('Path After Derotation') plt.xlabel('X') plt.ylabel('Y') plt.axis('equal') plt.show()  which gives  Update: In 3D, just because this is a fascinating topic In this case, let's define a rotating spiral and work in polar coordinates: import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D t = np.linspace(0, 4 * np.pi, 100) x = t * np.sin(t) y = t * np.cos(t) z = t original_points = np.vstack([x, y, z]) def rotation_matrix_y(theta): cos_theta, sin_theta = np.cos(theta), np.sin(theta) return np.array([ [cos_theta, 0, sin_theta], [0, 1, 0], [-sin_theta, 0, cos_theta] ]) def rotation_matrix_z(theta): cos_theta, sin_theta = np.cos(theta), np.sin(theta) return np.array([ [cos_theta, -sin_theta, 0], [sin_theta, cos_theta, 0], [0, 0, 1] ]) theta_z = np.radians(45) theta_y = np.radians(30) rot_matrix_z = rotation_matrix_z(theta_z) rot_matrix_y = rotation_matrix_y(theta_y) combined_rot_matrix = rot_matrix_y @ rot_matrix_z rotated_points = combined_rot_matrix @ original_points inverse_combined_rot_matrix = np.transpose(combined_rot_matrix) derotated_points = inverse_combined_rot_matrix @ rotated_points fig = plt.figure(figsize=(18, 6)) ax1 = fig.add_subplot(131, projection='3d') ax1.plot(*original_points, 'r') ax1.set_title('Original Spiral') ax1.set_xlim([-20, 20]) ax1.set_ylim([-20, 20]) ax1.set_zlim([0, 40]) ax2 = fig.add_subplot(132, projection='3d') ax2.plot(*rotated_points, 'b') ax2.set_title('Rotated Spiral') ax2.set_xlim([-20, 20]) ax2.set_ylim([-20, 20]) ax2.set_zlim([0, 40]) ax3 = fig.add_subplot(133, projection='3d') ax3.plot(*derotated_points, 'g') ax3.set_title('Derotated Spiral') ax3.set_xlim([-20, 20]) ax3.set_ylim([-20, 20]) ax3.set_zlim([0, 40]) plt.show()  which gives you