2014-10-01 95 views
15

我正在使用以下代碼繪製通過原點的三維隨機飛機。如何繪製隨機飛機

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

#Number of hyperplanes 
n = 20 
#Dimension of space 
d = 3 

plt3d = plt.figure().gca(projection='3d') 
for i in xrange(n): 
    #Create random point on unit sphere 
    v = np.random.normal(size = d) 
    v = v/np.sqrt(np.sum(v**2)) 
    # create x,y 
    xx, yy = np.meshgrid(range(-5,5), range(-5,5)) 
    z = (-v[0] * xx - v[1] * yy)/v[2] 
    # plot the surface 
    plt3d.plot_surface(xx, yy, z, alpha = 0.5) 
plt.show() 

但看着圖片我不相信他們一律選擇。我究竟做錯了什麼?

+5

熱該死!一個真正的最小工作示例。有一個upvote。 – Veedrac 2014-10-01 19:20:51

+3

@Veedrac你不能定義一個通過單個法線向量穿過原點的平面嗎?請參閱http://math.stackexchange.com/questions/952525/select-a-random-hyperplane。此外,我使用的方法是在http://mathworld.wolfram.com/SpherePointPicking.html – eleanora 2014-10-01 19:36:31

+0

中的「另一種輕鬆選取隨機點[..]的方法」中描述的方法啊,你說得對兩點。傻我。 – Veedrac 2014-10-01 19:47:58

回答

3

您的代碼生成與隨機分佈的法線的平面內。他們只是不這樣看,因爲z尺度比x尺度和y尺度大得多。

您可以通過生成平面上均勻分佈的點來生成更好看的圖像。爲此,按照 新座標(u,v)對平面進行參數化,然後在均勻間隔的網格 (u,v)點上對平面進行採樣。然後將這些(u,v)點轉換爲(x,y,z)空間中的點。

from __future__ import division 
import numpy as np 
import matplotlib.pyplot as plt 
from mpl_toolkits.mplot3d import Axes3D 
import math 
import itertools as IT 

def points_on_sphere(dim, N, norm=np.random.normal): 
    """ 
    http://en.wikipedia.org/wiki/N-sphere#Generating_random_points 
    """ 
    normal_deviates = norm(size=(N, dim)) 
    radius = np.sqrt((normal_deviates ** 2).sum(axis=0)) 
    points = normal_deviates/radius 
    return points 

# Number of hyperplanes 
n = 10 
# Dimension of space 
d = 3 

fig, ax = plt.subplots(subplot_kw=dict(projection='3d')) 
points = points_on_sphere(n, d).T 
uu, vv = np.meshgrid([-5, 5], [-5, 5], sparse=True) 
colors = np.linspace(0, 1, len(points)) 
cmap = plt.get_cmap('jet') 
for nhat, c in IT.izip(points, colors): 
    u = (0, 1, 0) if np.allclose(nhat, (1, 0, 0)) else np.cross(nhat, (1, 0, 0)) 
    u /= math.sqrt((u ** 2).sum()) 
    v = np.cross(nhat, u) 
    u = u[:, np.newaxis, np.newaxis] 
    v = v[:, np.newaxis, np.newaxis] 
    xx, yy, zz = u * uu + v * vv 
    ax.plot_surface(xx, yy, zz, alpha=0.5, color=cmap(c)) 
ax.set_xlim3d([-5,5]) 
ax.set_ylim3d([-5,5]) 
ax.set_zlim3d([-5,5])   
plt.show() 

enter image description here

或者,您也可以通過使用Till Hoffmann's pathpatch_2d_to_3d utility function避免毛毛數學:

for nhat, c in IT.izip(points, colors): 
    p = patches.Rectangle((-2.5, -2.5), 5, 5, color=cmap(c), alpha=0.5) 
    ax.add_patch(p) 
    pathpatch_2d_to_3d(p, z=0, normal=nhat) 

ax.set_xlim3d([-5,5]) 
ax.set_ylim3d([-5,5]) 
ax.set_zlim3d([-5,5])   
plt.show() 

enter image description here

+0

我真的很喜歡你鏈接到pathpatch_2d_to_3d,謝謝! – eleanora 2014-10-02 09:28:03

3

看起來並不是一切。你最好再測量一次: - ]。它似乎是非隨機分佈的,因爲你沒有固定軸。因此,你會看到一架主飛機,由於規模,看起來非常相似,而且沒有隨機分佈。

這個怎麼樣代碼:

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

#Number of hyperplanes 
n = 20 
#Dimension of space 
d = 3 

plt3d = plt.figure().gca(projection='3d') 
for i in xrange(n): 
    #Create random point on unit sphere 
    v = np.random.normal(size = d) 
    v = v/np.sqrt(np.sum(v**2)) 
    # create x,y 
    xx, yy = np.meshgrid(range(-1,1), range(-1,1)) 
    z = (-v[0] * xx - v[1] * yy)/v[2] 
    # plot the surface 
    plt3d.plot_surface(xx, yy, z, alpha = 0.5) 

plt3d.set_xlim3d([-1,1]) 
plt3d.set_ylim3d([-1,1]) 
plt3d.set_zlim3d([-1,1]) 
plt.show() 

它不是完美的,但它似乎更隨意,現在...

+0

我用來挑選球體上的隨機點的方法在http://mathworld.wolfram.com/SpherePointPicking.html的末尾。這然後定義了飛機,如http://math.stackexchange.com/questions/952525/select-a-random-hyperplane然而,顯然我做錯了什麼。 – eleanora 2014-10-01 19:39:16

+0

好吧,這是有道理的,但說實話,我真的不知道它是如何變得均勻分佈... – Jendas 2014-10-01 19:44:53

+0

@Jendas哈哈!看起來你在一小時前得到了答案,而不是3分鐘!那麼,由此產生的輸出[有點亂。](http://imgur.com/G8JyArX)這是你得到的嗎? – Veedrac 2014-10-01 20:36:45

1

我想這一次,也許這是一個更好的方式來創建統一飛機。我隨機選取兩個不同的角度作爲球面座標系,並將其轉換爲笛卡爾座標以獲得平面的法向量。另外,當你繪製時,你應該知道你的飛機的中點不在原點上。

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

fig = plt.figure() 
ax = Axes3D(fig) 

for i in range(20): 
    theta = 2*np.pi*np.random.uniform(-1,1)  
    psi = 2*np.pi*np.random.uniform(-1,1) 
    normal = np.array([np.sin(theta)*np.cos(psi),np.sin(theta)*np.sin(psi), 
         np.cos(theta)]) 
    xx, yy = np.meshgrid(np.arange(-1,1), np.arange(-1,1)) 
    z = (-normal[0] * xx - normal[1] * yy)/normal[2] 
    ax.plot_surface(xx, yy, z, alpha=0.5)  
+0

非常感謝。 – eleanora 2014-10-02 09:28:55

4

我建議你檢查一下你的座標軸。你的計算使Z軸的方式太大,這意味着你有一個荒謬偏見的觀點。

首先檢查你的法線均勻地塗在圈分佈:

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

#Number of hyperplanes 
n = 1000 
#Dimension of space 
d = 3 

plt3d = plt.figure().gca(projection='3d') 
for i in xrange(n): 
    #Create random point on unit sphere 
    v = np.random.normal(size = d) 
    v = v/np.sqrt(np.sum(v**2)) 
    v *= 10 

    plt3d.scatter(v[0], v[1], v[2]) 

plt3d.set_aspect(1) 
plt3d.set_xlim(-10, 10) 
plt3d.set_ylim(-10, 10) 
plt3d.set_zlim(-10, 10) 

plt.show() 

A sphere of points around the normal

然後檢查是否被正確創建你的飛機:

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

#Number of hyperplanes 
n = 1 
#Dimension of space 
d = 3 

plt3d = plt.figure().gca(projection='3d') 
for i in xrange(n): 
    #Create random point on unit sphere 
    v = np.random.normal(size = d) 
    v = v/np.sqrt(np.sum(v**2)) 
    v *= 10 

    # create x,y 
    xx, yy = np.meshgrid(np.arange(-5,5,0.3), np.arange(-5,5,0.3)) 
    xx = xx.flatten() 
    yy = yy.flatten() 
    z = (-v[0] * xx - v[1] * yy)/v[2] 

    # Hack to keep the plane small 
    filter = xx**2 + yy**2 + z**2 < 5**2 
    xx = xx[filter] 
    yy = yy[filter] 
    z = z[filter] 

    # plot the surface 
    plt3d.scatter(xx, yy, z, alpha = 0.5) 

    for i in np.arange(0.1, 1, 0.1): 
     plt3d.scatter(i*v[0], i*v[1], i*v[2]) 

plt3d.set_aspect(1) 
plt3d.set_xlim(-10, 10) 
plt3d.set_ylim(-10, 10) 
plt3d.set_zlim(-10, 10) 

plt.show() 

A satellite dish... sort of.

然後你可以看到你實際上已經有了很好的結果!

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

#Number of hyperplanes 
n = 100 
#Dimension of space 
d = 3 

plt3d = plt.figure().gca(projection='3d') 
for i in xrange(n): 
    #Create random point on unit sphere 
    v = np.random.normal(size = d) 
    v = v/np.sqrt(np.sum(v**2)) 
    v *= 10 

    # create x,y 
    xx, yy = np.meshgrid(np.arange(-5,5,0.3), np.arange(-5,5,0.3)) 
    xx = xx.flatten() 
    yy = yy.flatten() 
    z = (-v[0] * xx - v[1] * yy)/v[2] 

    # Hack to keep the plane small 
    filter = xx**2 + yy**2 + z**2 < 5**2 
    xx = xx[filter] 
    yy = yy[filter] 
    z = z[filter] 

    # plot the surface 
    plt3d.scatter(xx, yy, z, alpha = 0.5) 

plt3d.set_aspect(1) 
plt3d.set_xlim(-10, 10) 
plt3d.set_ylim(-10, 10) 
plt3d.set_zlim(-10, 10) 

plt.show() 

It's a sphere made of spherically bound planes!

+0

這是一個可愛的答案,謝謝。 – eleanora 2014-10-02 06:58:47