You are using np.lstsq very poorly since you feed it with a precomputed 3x3 matrix instead of letting it do the job. I would do it like this:
import numpy as np def calc_plane(x, y, z): a = np.column_stack((x, y, np.ones_like(x))) return np.linalg.lstsq(a, z)[0] >>> x = np.random.rand(1000) >>> y = np.random.rand(1000) >>> z = 4*x + 5*y + 7 + np.random.rand(1000)*.1 >>> calc_plane(x, y, z) array([ 3.99795126, 5.00233364, 7.05007326])
In fact, it is more convenient to use a formula for your plane, which does not depend on the coefficient, when z not equal to zero, i.e. uses a*x + b*y + c*z = 1 . You can also calculate a , b and c :
def calc_plane_bis(x, y, z): a = np.column_stack((x, y, z)) return np.linalg.lstsq(a, np.ones_like(x))[0] >>> calc_plane_bis(x, y, z) array([-0.56732299, -0.70949543, 0.14185393])
To project points onto a plane using my alternative equation, the vector (a, b, c) perpendicular to the plane. It is easy to verify that the point (a, b, c) / (a**2+b**2+c**2) is on the plane, so the projection can be done by referencing all the points on this point on the plane, projecting points to a normal vector, subtracting the projection from the points, then referring to them back to the beginning. You can do it as follows:
def project_points(x, y, z, a, b, c): """ Projects the points with coordinates x, y, z onto the plane defined by a*x + b*y + c*z = 1 """ vector_norm = a*a + b*b + c*c normal_vector = np.array([a, b, c]) / np.sqrt(vector_norm) point_in_plane = np.array([a, b, c]) / vector_norm points = np.column_stack((x, y, z)) points_from_point_in_plane = points - point_in_plane proj_onto_normal_vector = np.dot(points_from_point_in_plane, normal_vector) proj_onto_plane = (points_from_point_in_plane - proj_onto_normal_vector[:, None]*normal_vector) return point_in_plane + proj_onto_plane
So now you can do something like:
>>> project_points(x, y, z, *calc_plane_bis(x, y, z)) array([[ 0.13138012, 0.76009389, 11.37555123], [ 0.71096929, 0.68711773, 13.32843506], [ 0.14889398, 0.74404116, 11.36534936], ..., [ 0.85975642, 0.4827624 , 12.90197969], [ 0.48364383, 0.2963717 , 10.46636903], [ 0.81596472, 0.45273681, 12.57679188]])