pythondata-fittingplane

Scikit-Spatial Gives Weird Best-Fit Plane using Plane.best_fit


I am using scikit-spatial to find the best-fit plane for a list of 3D points. It usually works well for other lists, but this one is giving me a bit of trouble...

Code (py):

from skspatial.objects import Plane
from skspatial.objects import Points
from skspatial.objects import Point
from skspatial.plotting import plot_3d

points_list = [[2018.0, 3.0, -3.0], [2016.0, 3.0, -7.0], [2014.0, 27.0, 7.0], [2013.0, 3.0, -1.5], [2012.0, 4.5, 2.0], [2012.0, 16.5, 3.5], [2012.0, 18.0, 5.5], [2010.0, 13.5, 1.0], [2010.0, 21.0, -3.0], [2009.0, 30.0, 4.5]]

plot_3d(
    Points(points_list).plotter(c='k',s=15,depthshade=True),
    Plane.best_fit(points_list).plotter(alpha=0.2, lims_x=(-5, 5), lims_y=(-5, 5))
)[0].show()

For reference: Resulting Plot

Anyways, the list of data is very nearly flat, but scikit-spatial returns a plane which is absolutely unreasonable. Am I simply doing something wrong, or is something else happening? I have looked around online but was unable to find anything similar. Thanks!!


Solution

  • I'm the author of scikit-spatial (I wanted to start with "Hi" but StackOverflow seems to auto-delete that). I just happened to notice this question now, which is why I'm responding late. If you have another issue with the package, please create an issue on the GitHub repo and I should get back to you sooner.

    I agree that this plane of best fit looks wrong in your plot. But notice the ranges of the axes. The x-axis goes from 2008 to 2018, a range of 10. The y-axis goes from 5 to 30, a range of 25. But the z-axis goes from -1000 to 1000, a range of 2000.

    The range of the z-axis is so large that it makes your points appear to be flat, when in reality they aren't that flat at all.

    Try changing the z-axis limits to get a range more similar to the x and y axes:

    _, ax = plot_3d(
        Points(points_list).plotter(c='k',s=15, depthshade=True),
        Plane.best_fit(points_list).plotter(alpha=0.2, lims_x=(-10, 10), lims_y=(-10, 10), color='b'),
    )
    
    ax.set_zlim([-10, 10])
    

    enter image description here

    Now it looks a bit more believable that this is the plane of best fit.