2014-10-01 92 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