2014-04-04 15 views
15

Bazı 3D verilerinin özvektörlerini çizdim ve şu anda (zaten) ok uçlarını satırlara yerleştirmenin bir yolu olup olmadığını mı merak ettim? Birisi benim için bir ipucu varsa harika olurdu.Matplotlib'in 3d çiziminde vektörler üzerinde ok başları yerleştirme

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

#################################################### 
# This part is just for reference if 
# you are interested where the data is 
# coming from 
# The plot is at the bottom 
##################################################### 

# Generate some example data 
mu_vec1 = np.array([0,0,0]) 
cov_mat1 = np.array([[1,0,0],[0,1,0],[0,0,1]]) 
class1_sample = np.random.multivariate_normal(mu_vec1, cov_mat1, 20) 

mu_vec2 = np.array([1,1,1]) 
cov_mat2 = np.array([[1,0,0],[0,1,0],[0,0,1]]) 
class2_sample = np.random.multivariate_normal(mu_vec2, cov_mat2, 20) 

# concatenate data for PCA 
samples = np.concatenate((class1_sample, class2_sample), axis=0) 

# mean values 
mean_x = mean(samples[:,0]) 
mean_y = mean(samples[:,1]) 
mean_z = mean(samples[:,2]) 

#eigenvectors and eigenvalues 
eig_val, eig_vec = np.linalg.eig(cov_mat) 

################################ 
#plotting eigenvectors 
################################  

fig = plt.figure(figsize=(15,15)) 
ax = fig.add_subplot(111, projection='3d') 

ax.plot(samples[:,0], samples[:,1], samples[:,2], 'o', markersize=10, color='green', alpha=0.2) 
ax.plot([mean_x], [mean_y], [mean_z], 'o', markersize=10, color='red', alpha=0.5) 
for v in eig_vec: 
    ax.plot([mean_x, v[0]], [mean_y, v[1]], [mean_z, v[2]], color='red', alpha=0.8, lw=3) 
ax.set_xlabel('x_values') 
ax.set_ylabel('y_values') 
ax.set_zlabel('z_values') 

plt.title('Eigenvectors') 

plt.draw() 
plt.show() 

cevap

30

enter image description here 3D arsa için ok yamaları eklemek için basit bir çözüm /matplotlib/patches.py tanımlanan FancyArrowPatch sınıf kullanmaktır. Ancak, sadece onun posA ve posB olarak, (yazma anda) 2D arsa için çalışır,

nedenle yeni bir ok yama sınıf oluşturmak 2. uzunlukta tuples olmak devralır adını o Arrow3D, beklenen FancyArrowPatch. posA ve posB'u geçersiz kılmamız gereken tek şey. Bunu yapmak için Arrow3d'u posA ves ile başlatıyoruz. xs, ys, zs 3D koordinatları daha sonra proj3d.proj_transform() kullanılarak 3D'den 2D'ye yansıtıldı ve sonuç 2D koordinatları (0,0) s yerine .set_position() yöntemi kullanılarakve posB'a atanır. Bu sayede 3D oku çalışmaya başladık.

Yansıtma adımları, FancyArrowPatch nesnesinin .draw yöntemini geçersiz kılan .draw yöntemine gider.

Bu bir kesmek gibi görünebilir. Bununla birlikte, mplot3d, 3D-2D projeksiyonları sağlayarak, sadece 3D grafikleri (sadece 3D) sağlayarak, gerçekte 3D olarak değil, 2 boyutlu çizim yapabilmektedir.

import numpy as np 
from numpy import * 
from matplotlib import pyplot as plt 
from mpl_toolkits.mplot3d import Axes3D 
from matplotlib.patches import FancyArrowPatch 
from mpl_toolkits.mplot3d import proj3d 

class Arrow3D(FancyArrowPatch): 
    def __init__(self, xs, ys, zs, *args, **kwargs): 
     FancyArrowPatch.__init__(self, (0,0), (0,0), *args, **kwargs) 
     self._verts3d = xs, ys, zs 

    def draw(self, renderer): 
     xs3d, ys3d, zs3d = self._verts3d 
     xs, ys, zs = proj3d.proj_transform(xs3d, ys3d, zs3d, renderer.M) 
     self.set_positions((xs[0],ys[0]),(xs[1],ys[1])) 
     FancyArrowPatch.draw(self, renderer) 

#################################################### 
# This part is just for reference if 
# you are interested where the data is 
# coming from 
# The plot is at the bottom 
##################################################### 

# Generate some example data 
mu_vec1 = np.array([0,0,0]) 
cov_mat1 = np.array([[1,0,0],[0,1,0],[0,0,1]]) 
class1_sample = np.random.multivariate_normal(mu_vec1, cov_mat1, 20) 

mu_vec2 = np.array([1,1,1]) 
cov_mat2 = np.array([[1,0,0],[0,1,0],[0,0,1]]) 
class2_sample = np.random.multivariate_normal(mu_vec2, cov_mat2, 20) 

Gerçek çizim. Daha fazla detay için,

# concatenate data for PCA 
samples = np.concatenate((class1_sample, class2_sample), axis=0) 

# mean values 
mean_x = mean(samples[:,0]) 
mean_y = mean(samples[:,1]) 
mean_z = mean(samples[:,2]) 

#eigenvectors and eigenvalues 
eig_val, eig_vec = np.linalg.eig(cov_mat1) 

################################ 
#plotting eigenvectors 
################################  

fig = plt.figure(figsize=(15,15)) 
ax = fig.add_subplot(111, projection='3d') 

ax.plot(samples[:,0], samples[:,1], samples[:,2], 'o', markersize=10, color='g', alpha=0.2) 
ax.plot([mean_x], [mean_y], [mean_z], 'o', markersize=10, color='red', alpha=0.5) 
for v in eig_vec: 
    #ax.plot([mean_x,v[0]], [mean_y,v[1]], [mean_z,v[2]], color='red', alpha=0.8, lw=3) 
    #I will replace this line with: 
    a = Arrow3D([mean_x, v[0]], [mean_y, v[1]], 
       [mean_z, v[2]], mutation_scale=20, 
       lw=3, arrowstyle="-|>", color="r") 
    ax.add_artist(a) 
ax.set_xlabel('x_values') 
ax.set_ylabel('y_values') 
ax.set_zlabel('z_values') 

plt.title('Eigenvectors') 

plt.draw() 
plt.show() 

final_output

bu soruyu ilham this post, kontrol edin: biz sadece bir yeni ok sanatçı eklemek için kod satırı değiştirmek gerektiğini unutmayın.

+0

Bu kod, plt.draw() 'olmadan matplotlib 2.0'da çalışır. Bu kod satırı gerekli mi? – Seanny123

+0

@ Seanny123, isteğe bağlı, '.show()' kodu ayrıca ortamın nasıl kurulduğuna bağlı olarak isteğe bağlı olabilir. Sadece açıklık uğruna sanırım. –