समस्या यह है कि matplotlib कोई रे ट्रैसर नहीं है और यह वास्तव में एक 3 डी सक्षम साजिश पुस्तकालय होने के लिए डिज़ाइन नहीं किया गया है। जैसे कि यह 2 डी स्पेस में परतों की एक प्रणाली के साथ काम करता है, और ऑब्जेक्ट एक परत में पीछे या पीछे की ओर एक परत में हो सकते हैं। इसे अधिकांश प्लॉटिंग कार्यों के लिए zorder
कीवर्ड तर्क के साथ सेट किया जा सकता है। हालांकि matplotlib में कोई जागरूकता नहीं है कि कोई ऑब्जेक्ट 3 डी स्पेस में किसी अन्य ऑब्जेक्ट के सामने या पीछे है या नहीं। इसलिए आप या तो पूरी रेखा दिखाई दे सकते हैं (क्षेत्र के सामने) या छुपा हुआ (इसके पीछे)।
समाधान उन बिंदुओं की गणना करना होगा जो आपके द्वारा दिखाई देनी चाहिए। मैं यहां बिंदुओं के बारे में बात कर रहा हूं क्योंकि एक रेखा क्षेत्र के माध्यम से दृश्यमान बिंदुओं को जोड़ती है, जो अवांछित है। इसलिए मैं खुद को अंक प्लॉट करने के लिए प्रतिबंधित करता हूं - लेकिन यदि आपके पास पर्याप्त है, तो वे एक पंक्ति की तरह दिखते हैं :-)।
गणना जिनमें से अंक दिखाई देना चाहिए बहुत कठिन एक आदर्श क्षेत्र के लिए नहीं है, और विचार निम्नलिखित है:
- 3 डी साजिश
- कि से की देखने के कोण प्राप्त, की गणना दृश्य में दृष्टि के विमान के लिए सामान्य वेक्टर दृश्य की दिशा में निर्देशांक।
- इस सामान्य वेक्टर (नीचे दिए गए कोड में
X
कहा जाता है) के बीच स्केलर उत्पाद की गणना करें और इस स्केलर उत्पाद का उपयोग बिंदुओं को दिखाने के लिए या नहीं, इस शर्त के रूप में लाइन बिंदुओं के लिए करें। यदि स्केलर उत्पाद 0
से छोटा है तो संबंधित बिंदु पर्यवेक्षक से देखे गए देखने वाले विमान के दूसरी तरफ है और इसलिए इसे नहीं दिखाया जाना चाहिए।
- स्थिति के आधार पर अंक फ़िल्टर करें।
उपयोगकर्ता के दृश्य को घुमाने पर मामले के लिए दिखाए गए बिंदुओं को अनुकूलित करने के लिए एक और वैकल्पिक कार्य तब होता है। यह motion_notify_event
को उस फ़ंक्शन में कनेक्ट करके पूरा किया जाता है जो नए सेट देखने वाले कोण के आधार पर ऊपर से प्रक्रिया का उपयोग कर डेटा अपडेट करता है।
इसे लागू करने के तरीके पर नीचे दिए गए कोड को देखें।
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)
#Make colormap the fourth dimension
color_dimension = x_coord
minn, maxx = color_dimension.min(), color_dimension.max()
norm = matplotlib.colors.Normalize(minn, maxx)
m = plt.cm.ScalarMappable(norm=norm, cmap='jet')
m.set_array([])
fcolors = m.to_rgba(color_dimension)
theta2 = np.linspace(-np.pi, 0, 1000)
phi2 = np.linspace(0, 5 * 2*np.pi , 1000)
x_coord_2 = radius * np.sin(theta2) * np.cos(phi2)
y_coord_2 = radius * np.sin(theta2) * np.sin(phi2)
z_coord_2 = radius * np.cos(theta2)
# plot
fig = plt.figure()
ax = fig.gca(projection='3d')
# plot empty plot, with points (without a line)
points, = ax.plot([],[],[],'k.', markersize=5, alpha=0.9)
#set initial viewing angles
azimuth, elev = 75, 21
ax.view_init(elev, azimuth)
def plot_visible(azimuth, elev):
#transform viewing angle to normal vector in data coordinates
a = azimuth*np.pi/180. -np.pi
e = elev*np.pi/180. - np.pi/2.
X = [ np.sin(e) * np.cos(a),np.sin(e) * np.sin(a),np.cos(e)]
# concatenate coordinates
Z = np.c_[x_coord_2, y_coord_2, z_coord_2]
# calculate dot product
# the points where this is positive are to be shown
cond = (np.dot(Z,X) >= 0)
# filter points by the above condition
x_c = x_coord_2[cond]
y_c = y_coord_2[cond]
z_c = z_coord_2[cond]
# set the new data points
points.set_data(x_c, y_c)
points.set_3d_properties(z_c, zdir="z")
fig.canvas.draw_idle()
plot_visible(azimuth, elev)
ax.plot_surface(x_coord,y_coord,z_coord, rstride=1, cstride=1,
facecolors=fcolors, vmin=minn, vmax=maxx, shade=False)
# in order to always show the correct points on the sphere,
# the points to be shown must be recalculated one the viewing angle changes
# when the user rotates the plot
def rotate(event):
if event.inaxes == ax:
plot_visible(ax.azim, ax.elev)
c1 = fig.canvas.mpl_connect('motion_notify_event', rotate)
plt.show()
अंत एक आदेश में markersize
, alpha
और अंकों की संख्या के साथ एक सा खेलने के लिए हो सकता है पर इस का सबसे बाहर देखने में आकर्षक परिणाम प्राप्त करने के।
matplotlib में यह वास्तव में संभव नहीं है। [यह प्रश्न] देखें (http://stackoverflow.com/questions/14824893/how-to-draw-intersecting-planes/14825951#14825951) या टिप्पणियों में चर्चा [यहां] (http: // stackoverflow।कॉम/प्रश्न/16960126/पायथन-मैटलप्लिब-3 डी-लाइन-दिखने-के माध्यम से सतह), उदाहरण के लिए। – tom
@tom लिंक किए गए प्रश्नों और नीचे दिए गए मेरे समाधान को देखते हुए, मैं इस बयान से असहमत हूं कि "यह वास्तव में संभव नहीं है"। मैं कहूंगा "यह संभव है, लेकिन - वास्तविक मामले के आधार पर - बहुत काम हो सकता है"। – ImportanceOfBeingErnest