Как нарисовать случайные плоскости
Я использую следующий код для рисования случайных плоскостей в 3d, проходящих через начало координат.
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()
Но, глядя на картину, я не думаю, что они были единообразно выбраны. Что я делаю неправильно?
Ответы
Ответ 1
Ваш код генерирует плоскости со случайно распределенными нормалями. Они просто не выглядят так, потому что 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 pathpatch_2d_to_3d:
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]()
Ответ 2
Я предлагаю вам проверить свои топоры. Ваш расчет делает ось 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!]()
Ответ 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()
Это не идеально, но теперь кажется гораздо более случайным...
Ответ 4
Я попробовал это, возможно, это лучший способ создания однородных плоскостей. Я произвольно беру два разных угла для сферической системы координат и преобразовываю их в декартовы координаты, чтобы получить нормальный вектор плоскости. Также, когда вы строите график, вы должны знать, что средняя точка вашего самолета не находится в начале координат.
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)