0

I need to compute the components of a vector respect to another vector, in 3D. When displaying the results, while I am confident about the simple math under it, the visualization is plain wrong.

I wrote a little script to reproduce the problem. The plane is z = x + y, which is x + y - z = 0. A vector orthogonal to it is then (1, 1, -1). However, when plotting it with quiver, the visual result is wrong.

import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

X,Y = np.meshgrid(np.arange( -1,  1, 0.1), np.arange( -1, 1, 0.1))
XX = X.flatten()
YY = Y.flatten()
Z = X + Y 
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, alpha=0.2)

ax.scatter(1, 1, -1, c="orange", s=20, marker='o')

ax.quiver(0, 0, 0, 1, 1, -1, color="blue")
plt.show()

quiver probes to actually draw the vector pointing to the target point (1, 1, -1) and the plane is actually the correct one, but they are not orthogonal.

Am I missing something extremely obvious or is it simply a problem of perspective?

Bagnarol
  • 13
  • 6

2 Answers2

1

The orange point is correct, rigth? So the vector pointing to that point is correct as well, because it starts at the origin. So the only problem is that while the vector is correct and orthorgonal to the plane in data space, it is not in display space.

To make display space have an equal aspect ratio, there are pretty hacky solutions but the easiest is to

  1. Make a square figure
  2. Use equal margins on all sides
  3. Use equal limits for all axes.

This could look like this.

import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure(figsize=(6,6))
ax = fig.add_subplot(111, projection='3d')
fig.subplots_adjust(.1,.1,.9,.9)
ax.set(xlim=(-2,2), ylim=(-2,2), zlim=(-2,2))

X,Y = np.meshgrid(np.arange( -1,  1, 0.1), np.arange( -1, 1, 0.1))
Z = X + Y 
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, alpha=0.2)

ax.scatter(1, 1, -1, c="orange", s=20, marker='o')
ax.quiver(0, 0, 0, 1, 1, -1, color="blue")
plt.show()

enter image description here

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
0

I think it's a scaling issue. You can use ax.set_xlim3d to set the same range for all axis.

It looks fine like this:

import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')

X,Y = np.meshgrid(np.arange( -1,  1, 0.1), np.arange( -1, 1, 0.1))
XX = X.flatten()
YY = Y.flatten()
Z = X + Y 
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, alpha=0.2)

ax.scatter(1, 1, -1, c="orange", s=20, marker='o')

ax.quiver(0, 0, 0, 1, 1, -1, color="blue")

ax.set_xlim3d(-1,1) 
ax.set_ylim3d(-1,1) 
ax.set_zlim3d(-1,1) 

plt.show()
peer
  • 4,171
  • 8
  • 42
  • 73