Black Lives Matter. Please consider donating to Black Girls Code today.

Confusing behaviour of go.Cone in 3D Scatter - wrong vector direction

I constantly use Plotly to do a quick prototyping and check of my code as I write a lot of algorithms that handle 3D point geometry. I never got to understand how go.Cone behaves as the results can be somehow unexpected with vector scaling arbitrarily.
Here is an example, I have a set of 4 points that I use to best fit a plane. Using the obtained plane normal vector and plane center point I derive the plane equation, which I then use to build the 3D surface simply as

# x, y, z are cartesian coordinates, i, j, k the vector components
plane = plane_from_points(points)

d = - plane[i] * plane[x] - plane[j] * plane[y] - plane[k] * plane[z]
a, b, c = plane[i], plane[j], plane[k]

x_plane = np.linspace(points.x.min(), points.x.max()+100, 50)
y_plane = np.linspace(points.y.min(), points.y.max()+100, 50)

x2d, y2d = np.meshgrid(x_plane, y_plane)

z2d = (-a * x2d - b * y2d - d) / c

which I then plot as

surf = go.Surface(x=x2d, y=y2d, z=z2d)

This works pretty well and the surface looks like the best-fit plane that I’m lookin for. HOWEVER when I try to plot also the plane normal vector as

vector = go.Cone(x=[plane[x]], y=[plane[y]], z=[plane[z]],
                 u=[plane[i]], v=[plane[j]], w=[plane[k]])

I get a vector that is anything but normal to the plane (see pictures, points used for the plane fitting are blue)

If I put the same point positions, plane equation, vector components in Geogebra I get the correct plot

I’m really puzzled about what I could be doing wrong…Is this related to the perspective which is somewhat distorted? But I guess if the vector is by definition normal it should appear so regardless of the perspective…

Here are the values used to draw the points

# Plane equation 
0.963297 x + -0.268436 y + 0.000025 z + -17496.412266 = 0
# Plane center point
{18721.685261, 2004.602757, -1247.349811}
# Plane normal vector
(0.963297, -0.268436, 0.000025)
# Points used to best-fit the plane 
{18745.833058, 2091.337311, -942.977098}
{18697.525409, 1917.880742, -956.077473}
{18695.080808, 1909.148370, -1554.346526}
{18748.301769, 2100.044606, -1535.998146}

Here is the complete code (simplified and without the part where I create the surface posted before)

mycolorscale = [[0, 'Blue'], [1, 'Blue']]

surf = go.Surface(x=x2d, y=y2d, z=z2d,
                  showscale=False, colorscale=mycolorscale, opacity=0.6)

scatter = go.Scatter3d(x = points.x , y = points.y, z = points.z, mode = 'markers')

vector = go.Cone(x=[plane[x]], y=[plane[y]], z=[plane[z]],
                 u=[plane[i]], v=[plane[j]], w=[plane[k]], showscale=False,

fig = go.Figure(data=[scatter2, surf, vector], layout=layout)

Hi @guidocioni
To get the normal visualized as an orthogonal vector to the plane, the axes scales must be the same, as in the mathematical representation. As long as the axes have diferent scales the normal appears as a non-orthogonal vector. In such a case set aspectmode='data'.

In this notebook are illustrated a few examples:

Hi @empet , thanks for the reply! You’re absolutely right. The projection into a cubic space of axes with different ranges was indeed making everything appear distorted. I should had catch it before.
Thanks for the really useful examples!