The problem is that matplotlib is not rays and is not designed to create 3D graphics. As such, it works with a layer system in 2D space, and objects can be larger in the layer in front or behind. This can be set using the zorder
keyword argument for most zorder
functions. However, matplotlib lacks an understanding of whether the object is in front of or behind another object in three-dimensional space. Therefore, you can either have a full line visible (in front of the sphere) or hidden (behind it).
The solution is to calculate the points that should be visible by yourself. I am talking about points here because the line will connect the visible points "through" a sphere that is undesirable. Therefore, I limit myself to building points, but if you have enough of them, they look like a string :-).
Calculating which points should be visible is not too difficult for an ideal sphere, and the idea is this:
- Get the viewing angle of 3D graphics
- From this we calculate the normal vector to the plane of view in the data coordinates in the direction of the presentation.
- Compute the scalar product between this normal vector (called
X
in the code below) and the points of the line to use this scalar product as a condition for showing points or not. If the scalar product is less than 0
, then the corresponding point is on the other side of the viewing plane, as seen from the observer, and therefore should not be displayed. - Filter points by condition.
Another optional task is to adapt the points shown for the case when the user rotates the view. This is achieved by connecting motion_notify_event
to a function that updates the data using the procedure above, based on the newly set viewing angle.
See the code below for how to implement this.
import matplotlib import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D import numpy as np NPoints_Phi = 30 NPoints_Theta = 30 phi_array = ((np.linspace(0, 1, NPoints_Phi))**1) * 2*np.pi theta_array = (np.linspace(0, 1, NPoints_Theta) **1) * np.pi radius=1 phi, theta = np.meshgrid(phi_array, theta_array) x_coord = radius*np.sin(theta)*np.cos(phi) y_coord = radius*np.sin(theta)*np.sin(phi) z_coord = radius*np.cos(theta)

In the end, you need to play a little with markersize
, alpha
and the number of points to get the most attractive result from this.
source share