2017-01-17 3 views
5

मैं एक क्षेत्र की सतह पर एक रंगरूप के माध्यम से Matplotlib का उपयोग कर डेटा प्लॉट करना चाहता हूँ। इसके अतिरिक्त, मैं एक 3 डी लाइन प्लॉट जोड़ना चाहता हूं। कोड मैं अब तक है यह है: this जो है मैं लगभग क्या चाहते हैं:matplotlib में सतह साजिश के पीछे एक रेखा को अस्पष्ट कैसे करें?

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


NPoints_Phi   = 30 
NPoints_Theta  = 30 

radius    = 1 
pi     = np.pi 
cos     = np.cos 
sin     = np.sin 

phi_array   = ((np.linspace(0, 1, NPoints_Phi))**1) * 2*pi 
theta_array   = (np.linspace(0, 1, NPoints_Theta) **1) * pi 


phi, theta   = np.meshgrid(phi_array, theta_array) 


x_coord    = radius*sin(theta)*cos(phi) 
y_coord    = radius*sin(theta)*sin(phi) 
z_coord    = radius*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') 
ax.plot(x_coord_2, y_coord_2, z_coord_2,'k|-', linewidth=1) 
ax.plot_surface(x_coord,y_coord,z_coord, rstride=1, cstride=1, facecolors=fcolors, vmin=minn, vmax=maxx, shade=False) 
fig.show() 

इस कोड को एक छवि है कि इस प्रकार लग रहा है पैदा करता है। हालांकि, जब पृष्ठभूमि में होता है और अग्रभूमि में दिखाई देता है तो काले रेखा को सतही साजिश से अस्पष्ट किया जाना चाहिए। दूसरे शब्दों में, काले रेखा को गोलाकार "चमक" नहीं करना चाहिए।

क्या यह मैटलप्लिब में और मायावी के उपयोग के बिना किया जा सकता है?

+0

matplotlib में यह वास्तव में संभव नहीं है। [यह प्रश्न] देखें (http://stackoverflow.com/questions/14824893/how-to-draw-intersecting-planes/14825951#14825951) या टिप्पणियों में चर्चा [यहां] (http: // stackoverflow।कॉम/प्रश्न/16960126/पायथन-मैटलप्लिब-3 डी-लाइन-दिखने-के माध्यम से सतह), उदाहरण के लिए। – tom

+0

@tom लिंक किए गए प्रश्नों और नीचे दिए गए मेरे समाधान को देखते हुए, मैं इस बयान से असहमत हूं कि "यह वास्तव में संभव नहीं है"। मैं कहूंगा "यह संभव है, लेकिन - वास्तविक मामले के आधार पर - बहुत काम हो सकता है"। – ImportanceOfBeingErnest

उत्तर

4

समस्या यह है कि matplotlib कोई रे ट्रैसर नहीं है और यह वास्तव में एक 3 डी सक्षम साजिश पुस्तकालय होने के लिए डिज़ाइन नहीं किया गया है। जैसे कि यह 2 डी स्पेस में परतों की एक प्रणाली के साथ काम करता है, और ऑब्जेक्ट एक परत में पीछे या पीछे की ओर एक परत में हो सकते हैं। इसे अधिकांश प्लॉटिंग कार्यों के लिए zorder कीवर्ड तर्क के साथ सेट किया जा सकता है। हालांकि matplotlib में कोई जागरूकता नहीं है कि कोई ऑब्जेक्ट 3 डी स्पेस में किसी अन्य ऑब्जेक्ट के सामने या पीछे है या नहीं। इसलिए आप या तो पूरी रेखा दिखाई दे सकते हैं (क्षेत्र के सामने) या छुपा हुआ (इसके पीछे)।

समाधान उन बिंदुओं की गणना करना होगा जो आपके द्वारा दिखाई देनी चाहिए। मैं यहां बिंदुओं के बारे में बात कर रहा हूं क्योंकि एक रेखा क्षेत्र के माध्यम से दृश्यमान बिंदुओं को जोड़ती है, जो अवांछित है। इसलिए मैं खुद को अंक प्लॉट करने के लिए प्रतिबंधित करता हूं - लेकिन यदि आपके पास पर्याप्त है, तो वे एक पंक्ति की तरह दिखते हैं :-)।

गणना जिनमें से अंक दिखाई देना चाहिए बहुत कठिन एक आदर्श क्षेत्र के लिए नहीं है, और विचार निम्नलिखित है:

  1. 3 डी साजिश
  2. कि से की देखने के कोण प्राप्त, की गणना दृश्य में दृष्टि के विमान के लिए सामान्य वेक्टर दृश्य की दिशा में निर्देशांक।
  3. इस सामान्य वेक्टर (नीचे दिए गए कोड में X कहा जाता है) के बीच स्केलर उत्पाद की गणना करें और इस स्केलर उत्पाद का उपयोग बिंदुओं को दिखाने के लिए या नहीं, इस शर्त के रूप में लाइन बिंदुओं के लिए करें। यदि स्केलर उत्पाद 0 से छोटा है तो संबंधित बिंदु पर्यवेक्षक से देखे गए देखने वाले विमान के दूसरी तरफ है और इसलिए इसे नहीं दिखाया जाना चाहिए।
  4. स्थिति के आधार पर अंक फ़िल्टर करें।

उपयोगकर्ता के दृश्य को घुमाने पर मामले के लिए दिखाए गए बिंदुओं को अनुकूलित करने के लिए एक और वैकल्पिक कार्य तब होता है। यह 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() 

enter image description here

अंत एक आदेश में markersize, alpha और अंकों की संख्या के साथ एक सा खेलने के लिए हो सकता है पर इस का सबसे बाहर देखने में आकर्षक परिणाम प्राप्त करने के।

+0

बहुत चालाक विचार, धन्यवाद! हालांकि, ऐसा लगता है कि किसी को सामान्य मामलों के लिए ऐसा करने में सक्षम होने के लिए मायावी पर स्विच करना पड़ता है (उदाहरण के लिए एक पूर्ण क्षेत्र नहीं)। क्या मुझे यह सही समझ रहा है? – Ethunxxx

+2

मुझे लगता है कि मैटलप्लिब में हमेशा समाधान होगा, यहां तक ​​कि अधिक जटिल मामलों के लिए भी। इसके बाद थोड़ा और शामिल गणित की आवश्यकता होगी। इस दिशा में जाना है या किसी अन्य लाइब्रेरी का उपयोग करना चाहे व्यक्तिगत स्वाद का सवाल हो। – ImportanceOfBeingErnest

संबंधित मुद्दे