Python 渲染球体中的矢量,具有更好的感知

Python 渲染球体中的矢量,具有更好的感知,python,matplotlib,data-visualization,Python,Matplotlib,Data Visualization,我需要渲染一些3D向量,从(0,0,0)开始,在球体上结束。目前,我使用python和matplotlib执行此操作: import matplotlib.pyplot as plt import numpy as np from mpl_toolkits.mplot3d import proj3d from matplotlib.patches import FancyArrowPatch fig = plt.figure() ax = fig.gca(projection='3d') ax

我需要渲染一些3D向量,从(0,0,0)开始,在球体上结束。目前,我使用python和matplotlib执行此操作:

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

fig = plt.figure()
ax = fig.gca(projection='3d')
ax.set_aspect("equal")

# render the sphere mesh
u, v = np.mgrid[0:2*np.pi:20j, 00:np.pi:10j]
x=np.cos(u)*np.sin(v)
y=np.sin(u)*np.sin(v)
z=np.cos(v)
ax.plot_wireframe(x, y, z, color="r")
plt.axis('off')

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)

gradients = [[ 0.57735027, -0.57735027,  0.57735027], [ 0.32103634, -0.15367924, -0.93451506], [ 0.41923004, -0.40336058,  0.81335509], [ 0.49175236, -0.7972576 , -0.35008559], [-0.77544582, -0.60942662,  0.16517574], [ 0.49080035, -0.37864643, -0.78469223], [-0.9688558 , -0.14921457, -0.19761968], [-0.55381966, -0.41340241, -0.72276008], [-0.51651138, -0.82581121,  0.22638878], [ 0.51285124, -0.09350922,  0.85336959], [-0.02404559, -0.99431705, -0.10370783], [-0.45752126, -0.15967038,  0.87474549], [-0.11906644, -0.66461051,  0.73764223], [-0.69553846, -0.26904184,  0.66621518], [ 0.84464198, -0.38759068,  0.3692607 ], [ 0.01218729, -0.86413401,  0.5031141 ], [-0.70542359, -0.10816363, -0.70048422], [-0.64579558, -0.75719821, -0.09797404], [ 0.22307518, -0.66173422,  0.715783  ], [ 0.35672677, -0.81123132,  0.46330312], [-0.64859039, -0.59819001,  0.47063699], [-0.9860335 , -0.04110239,  0.16139577], [ 0.78665483, -0.298026  , -0.54069835], [-0.22515292, -0.39356178,  0.89129978], [-0.03115982, -0.20828982, -0.97757065], [ 0.1714755 , -0.88971114, -0.42309603], [-0.1948448 , -0.48424336, -0.85296184], [-0.46394941, -0.51801461,  0.71861798], [-0.45273268, -0.81954175, -0.35126126], [-0.82887799, -0.29984823, -0.47228414], [ 0.21121763, -0.09845807,  0.97246754], [-0.11702234, -0.10076906,  0.98800373], [ 0.31119478, -0.68396461, -0.65981078], [ 0.65285712, -0.07680383, -0.75357729], [ 0.71209121, -0.26699486,  0.64933801], [ 0.97685069, -0.17835225,  0.11812361], [-0.34381351, -0.93718553, -0.05895334], [ 0.68615079, -0.67022949,  0.2828241 ], [-0.6588605 , -0.59295917, -0.46292791], [ 0.15754543, -0.46902952, -0.86901712], [ 0.89081973, -0.0551779 ,  0.45099396], [ 0.09939465, -0.40802586,  0.90754372], [ 0.93604255, -0.26702261, -0.22917943], [-0.93707269, -0.34256476,  0.06741077], [-0.19623031, -0.95031369,  0.24165596], [ 0.45153776, -0.87650371,  0.16689767], [-0.0195914 , -0.72917062, -0.68405145], [ 0.65216494, -0.75583613, -0.05824633], [ 0.13336134, -0.97014433,  0.20257032], [ 0.86954373, -0.49204889,  0.04220884], [ 0.60317737, -0.57162017, -0.55626202], [-0.34353963, -0.78447777,  0.51630914], [-0.35424244, -0.68266952, -0.63912022], [-0.84101379, -0.50332689, -0.19838808], [-0.85885382, -0.33475134,  0.38770047], [ 0.30507854, -0.94518369, -0.11642545], [ 0.7822451 , -0.55481136, -0.28333196], [-0.15034926, -0.90096235, -0.4070158 ], [-0.37529847, -0.20644124, -0.90362221], [-0.87414831, -0.01486413,  0.48543158]]

for i in gradients:
    ax.add_artist( Arrow3D([0,-i[0]],[0,-i[1]],[0,-i[2]], mutation_scale=20, lw=1, arrowstyle="-|>", color="k") )
    ax.add_artist( Arrow3D([0,i[0]],[0,i[1]],[0,i[2]], mutation_scale=20, lw=1, arrowstyle="-|>", color="k") )
plt.show()
这会产生这样的图像:

然而,这是非常糟糕的,因为没有可见的空间深度。我如何改进结果

编辑
它们的结尾没有特殊意义,但是图像的读者应该看到,这些方向几乎是均匀分布的。

当前渲染中明显缺乏深度主要是由于缺少阴影

matplotlib
未设置为处理“真实”3D渲染(即遮挡、着色等),因此需要大量微妙的视觉提示才能获得深度印象

mayavi.mlab
对于一个简单的python API到一个功能非常全面的3D可视化包(VTK)来说是一个不错的选择

以您的为例:

import numpy as np
from mayavi import mlab

# render the sphere mesh
u, v = np.mgrid[0:2*np.pi:20j, 00:np.pi:10j]
x=np.cos(u)*np.sin(v)
y=np.sin(u)*np.sin(v)
z=np.cos(v)

for a,b,c in zip(x.T, y.T, z.T) + zip(x, y, z):
    mlab.plot3d(a, b, c, color=(1,0,0), tube_radius=0.01)

gradients = np.array([[ 0.57735027, -0.57735027,  0.57735027], [ 0.32103634, -0.15367924, -0.93451506], [ 0.41923004, -0.40336058,  0.81335509], [ 0.49175236, -0.7972576 , -0.35008559], [-0.77544582, -0.60942662,  0.16517574], [ 0.49080035, -0.37864643, -0.78469223], [-0.9688558 , -0.14921457, -0.19761968], [-0.55381966, -0.41340241, -0.72276008], [-0.51651138, -0.82581121,  0.22638878], [ 0.51285124, -0.09350922,  0.85336959], [-0.02404559, -0.99431705, -0.10370783], [-0.45752126, -0.15967038,  0.87474549], [-0.11906644, -0.66461051,  0.73764223], [-0.69553846, -0.26904184,  0.66621518], [ 0.84464198, -0.38759068,  0.3692607 ], [ 0.01218729, -0.86413401,  0.5031141 ], [-0.70542359, -0.10816363, -0.70048422], [-0.64579558, -0.75719821, -0.09797404], [ 0.22307518, -0.66173422,  0.715783  ], [ 0.35672677, -0.81123132,  0.46330312], [-0.64859039, -0.59819001,  0.47063699], [-0.9860335 , -0.04110239,  0.16139577], [ 0.78665483, -0.298026  , -0.54069835], [-0.22515292, -0.39356178,  0.89129978], [-0.03115982, -0.20828982, -0.97757065], [ 0.1714755 , -0.88971114, -0.42309603], [-0.1948448 , -0.48424336, -0.85296184], [-0.46394941, -0.51801461,  0.71861798], [-0.45273268, -0.81954175, -0.35126126], [-0.82887799, -0.29984823, -0.47228414], [ 0.21121763, -0.09845807,  0.97246754], [-0.11702234, -0.10076906,  0.98800373], [ 0.31119478, -0.68396461, -0.65981078], [ 0.65285712, -0.07680383, -0.75357729], [ 0.71209121, -0.26699486,  0.64933801], [ 0.97685069, -0.17835225,  0.11812361], [-0.34381351, -0.93718553, -0.05895334], [ 0.68615079, -0.67022949,  0.2828241 ], [-0.6588605 , -0.59295917, -0.46292791], [ 0.15754543, -0.46902952, -0.86901712], [ 0.89081973, -0.0551779 ,  0.45099396], [ 0.09939465, -0.40802586,  0.90754372], [ 0.93604255, -0.26702261, -0.22917943], [-0.93707269, -0.34256476,  0.06741077], [-0.19623031, -0.95031369,  0.24165596], [ 0.45153776, -0.87650371,  0.16689767], [-0.0195914 , -0.72917062, -0.68405145], [ 0.65216494, -0.75583613, -0.05824633], [ 0.13336134, -0.97014433,  0.20257032], [ 0.86954373, -0.49204889,  0.04220884], [ 0.60317737, -0.57162017, -0.55626202], [-0.34353963, -0.78447777,  0.51630914], [-0.35424244, -0.68266952, -0.63912022], [-0.84101379, -0.50332689, -0.19838808], [-0.85885382, -0.33475134,  0.38770047], [ 0.30507854, -0.94518369, -0.11642545], [ 0.7822451 , -0.55481136, -0.28333196], [-0.15034926, -0.90096235, -0.4070158 ], [-0.37529847, -0.20644124, -0.90362221], [-0.87414831, -0.01486413,  0.48543158]])
u, v, w = gradients.T
zero = np.zeros_like(u)

kwargs = dict(color=(.2,.2,.2), mode='arrow', resolution=20)
mlab.quiver3d(zero, zero, zero, u, v, w, **kwargs)
mlab.quiver3d(zero, zero, zero, -u, -v, -w, **kwargs)

mlab.show()

唯一的缺点是相对箭头是固定的(它们只是一个静态图示符)。可能会改变这一点(即使用自定义图示符),但我不知道如何立即改变

可以通过分别绘制箭头和主体来解决此问题。这将是缓慢的渲染,但它说明了这个想法:

import numpy as np
from mayavi import mlab

# render the sphere mesh
u, v = np.mgrid[0:2*np.pi:20j, 00:np.pi:10j]
x=np.cos(u)*np.sin(v)
y=np.sin(u)*np.sin(v)
z=np.cos(v)

# White background and turn on antialiasing
fig = mlab.figure(bgcolor=(1,1,1))
fig.scene.render_window.aa_frames = 8

# Plot the sphere's mesh
for a,b,c in zip(x.T, y.T, z.T) + zip(x, y, z):
    mlab.plot3d(a, b, c, color=(1,0,0), tube_radius=0.01)

gradients = np.array([[ 0.57735027, -0.57735027,  0.57735027], [ 0.32103634, -0.15367924, -0.93451506], [ 0.41923004, -0.40336058,  0.81335509], [ 0.49175236, -0.7972576 , -0.35008559], [-0.77544582, -0.60942662,  0.16517574], [ 0.49080035, -0.37864643, -0.78469223], [-0.9688558 , -0.14921457, -0.19761968], [-0.55381966, -0.41340241, -0.72276008], [-0.51651138, -0.82581121,  0.22638878], [ 0.51285124, -0.09350922,  0.85336959], [-0.02404559, -0.99431705, -0.10370783], [-0.45752126, -0.15967038,  0.87474549], [-0.11906644, -0.66461051,  0.73764223], [-0.69553846, -0.26904184,  0.66621518], [ 0.84464198, -0.38759068,  0.3692607 ], [ 0.01218729, -0.86413401,  0.5031141 ], [-0.70542359, -0.10816363, -0.70048422], [-0.64579558, -0.75719821, -0.09797404], [ 0.22307518, -0.66173422,  0.715783  ], [ 0.35672677, -0.81123132,  0.46330312], [-0.64859039, -0.59819001,  0.47063699], [-0.9860335 , -0.04110239,  0.16139577], [ 0.78665483, -0.298026  , -0.54069835], [-0.22515292, -0.39356178,  0.89129978], [-0.03115982, -0.20828982, -0.97757065], [ 0.1714755 , -0.88971114, -0.42309603], [-0.1948448 , -0.48424336, -0.85296184], [-0.46394941, -0.51801461,  0.71861798], [-0.45273268, -0.81954175, -0.35126126], [-0.82887799, -0.29984823, -0.47228414], [ 0.21121763, -0.09845807,  0.97246754], [-0.11702234, -0.10076906,  0.98800373], [ 0.31119478, -0.68396461, -0.65981078], [ 0.65285712, -0.07680383, -0.75357729], [ 0.71209121, -0.26699486,  0.64933801], [ 0.97685069, -0.17835225,  0.11812361], [-0.34381351, -0.93718553, -0.05895334], [ 0.68615079, -0.67022949,  0.2828241 ], [-0.6588605 , -0.59295917, -0.46292791], [ 0.15754543, -0.46902952, -0.86901712], [ 0.89081973, -0.0551779 ,  0.45099396], [ 0.09939465, -0.40802586,  0.90754372], [ 0.93604255, -0.26702261, -0.22917943], [-0.93707269, -0.34256476,  0.06741077], [-0.19623031, -0.95031369,  0.24165596], [ 0.45153776, -0.87650371,  0.16689767], [-0.0195914 , -0.72917062, -0.68405145], [ 0.65216494, -0.75583613, -0.05824633], [ 0.13336134, -0.97014433,  0.20257032], [ 0.86954373, -0.49204889,  0.04220884], [ 0.60317737, -0.57162017, -0.55626202], [-0.34353963, -0.78447777,  0.51630914], [-0.35424244, -0.68266952, -0.63912022], [-0.84101379, -0.50332689, -0.19838808], [-0.85885382, -0.33475134,  0.38770047], [ 0.30507854, -0.94518369, -0.11642545], [ 0.7822451 , -0.55481136, -0.28333196], [-0.15034926, -0.90096235, -0.4070158 ], [-0.37529847, -0.20644124, -0.90362221], [-0.87414831, -0.01486413,  0.48543158]])
u, v, w = gradients.T
zero = np.zeros_like(u)

color = (0.2, 0.2, 0.2)
head_length = 0.2
for direct in [-1, 1]:
    h, b = direct * 0.2, direct * (1 - head_length)
    mlab.quiver3d(b*u, b*v, b*w, h*u, h*v, h*w, 
                  mode='cone', scale_factor=1, color=color, resolution=20)
    for i, j, k in zip(u, v, w):
        mlab.plot3d([0, b*i], [0, b*j], [0, b*k], color=color, tube_radius=0.01)

mlab.show()

您还可以更改内容,使圆锥体位于球体的外部:

更进一步,您可以通过执行以下操作来提高渲染速度,并获得更清晰的图形:

import numpy as np
from mayavi import mlab

# White background and turn on antialiasing
fig = mlab.figure(bgcolor=(1,1,1))
fig.scene.render_window.aa_frames = 8

# Sphere at origin with a diameter of 2 (radius of 1)
ltgray = (0.9, 0.9, 0.9)
mlab.points3d([0], [0], [0], [2], resolution=20, scale_factor=1, color=ltgray)

gradients = np.array([[ 0.57735027, -0.57735027,  0.57735027], [ 0.32103634, -0.15367924, -0.93451506], [ 0.41923004, -0.40336058,  0.81335509], [ 0.49175236, -0.7972576 , -0.35008559], [-0.77544582, -0.60942662,  0.16517574], [ 0.49080035, -0.37864643, -0.78469223], [-0.9688558 , -0.14921457, -0.19761968], [-0.55381966, -0.41340241, -0.72276008], [-0.51651138, -0.82581121,  0.22638878], [ 0.51285124, -0.09350922,  0.85336959], [-0.02404559, -0.99431705, -0.10370783], [-0.45752126, -0.15967038,  0.87474549], [-0.11906644, -0.66461051,  0.73764223], [-0.69553846, -0.26904184,  0.66621518], [ 0.84464198, -0.38759068,  0.3692607 ], [ 0.01218729, -0.86413401,  0.5031141 ], [-0.70542359, -0.10816363, -0.70048422], [-0.64579558, -0.75719821, -0.09797404], [ 0.22307518, -0.66173422,  0.715783  ], [ 0.35672677, -0.81123132,  0.46330312], [-0.64859039, -0.59819001,  0.47063699], [-0.9860335 , -0.04110239,  0.16139577], [ 0.78665483, -0.298026  , -0.54069835], [-0.22515292, -0.39356178,  0.89129978], [-0.03115982, -0.20828982, -0.97757065], [ 0.1714755 , -0.88971114, -0.42309603], [-0.1948448 , -0.48424336, -0.85296184], [-0.46394941, -0.51801461,  0.71861798], [-0.45273268, -0.81954175, -0.35126126], [-0.82887799, -0.29984823, -0.47228414], [ 0.21121763, -0.09845807,  0.97246754], [-0.11702234, -0.10076906,  0.98800373], [ 0.31119478, -0.68396461, -0.65981078], [ 0.65285712, -0.07680383, -0.75357729], [ 0.71209121, -0.26699486,  0.64933801], [ 0.97685069, -0.17835225,  0.11812361], [-0.34381351, -0.93718553, -0.05895334], [ 0.68615079, -0.67022949,  0.2828241 ], [-0.6588605 , -0.59295917, -0.46292791], [ 0.15754543, -0.46902952, -0.86901712], [ 0.89081973, -0.0551779 ,  0.45099396], [ 0.09939465, -0.40802586,  0.90754372], [ 0.93604255, -0.26702261, -0.22917943], [-0.93707269, -0.34256476,  0.06741077], [-0.19623031, -0.95031369,  0.24165596], [ 0.45153776, -0.87650371,  0.16689767], [-0.0195914 , -0.72917062, -0.68405145], [ 0.65216494, -0.75583613, -0.05824633], [ 0.13336134, -0.97014433,  0.20257032], [ 0.86954373, -0.49204889,  0.04220884], [ 0.60317737, -0.57162017, -0.55626202], [-0.34353963, -0.78447777,  0.51630914], [-0.35424244, -0.68266952, -0.63912022], [-0.84101379, -0.50332689, -0.19838808], [-0.85885382, -0.33475134,  0.38770047], [ 0.30507854, -0.94518369, -0.11642545], [ 0.7822451 , -0.55481136, -0.28333196], [-0.15034926, -0.90096235, -0.4070158 ], [-0.37529847, -0.20644124, -0.90362221], [-0.87414831, -0.01486413,  0.48543158]])
u, v, w = gradients.T

# Put cones on the outside of the sphere
for direct in [-1, 1]:
    h = direct * 0.2 # Head length
    mlab.quiver3d(direct*u, direct*v, direct*w, h*u, h*v, h*w, color=(.2,.2,.2),
                  mode='cone', scale_factor=1, resolution=20)

mlab.show()

您还可以将球体稍微增大一点作为模糊因子,以绕过与某些圆锥体底部不完全相交的平面(例如,
点3d([0],[0],[0],[2.05],…)
):

另一种方法是立体网。立体网有点晦涩难懂,但它们是使用2D绘图在3D中显示方向分布的一种非常好的方法

import numpy as np
import matplotlib.pyplot as plt
import mplstereonet

gradients = np.array([[ 0.57735027, -0.57735027,  0.57735027], [ 0.32103634, -0.15367924, -0.93451506], [ 0.41923004, -0.40336058,  0.81335509], [ 0.49175236, -0.7972576 , -0.35008559], [-0.77544582, -0.60942662,  0.16517574], [ 0.49080035, -0.37864643, -0.78469223], [-0.9688558 , -0.14921457, -0.19761968], [-0.55381966, -0.41340241, -0.72276008], [-0.51651138, -0.82581121,  0.22638878], [ 0.51285124, -0.09350922,  0.85336959], [-0.02404559, -0.99431705, -0.10370783], [-0.45752126, -0.15967038,  0.87474549], [-0.11906644, -0.66461051,  0.73764223], [-0.69553846, -0.26904184,  0.66621518], [ 0.84464198, -0.38759068,  0.3692607 ], [ 0.01218729, -0.86413401,  0.5031141 ], [-0.70542359, -0.10816363, -0.70048422], [-0.64579558, -0.75719821, -0.09797404], [ 0.22307518, -0.66173422,  0.715783  ], [ 0.35672677, -0.81123132,  0.46330312], [-0.64859039, -0.59819001,  0.47063699], [-0.9860335 , -0.04110239,  0.16139577], [ 0.78665483, -0.298026  , -0.54069835], [-0.22515292, -0.39356178,  0.89129978], [-0.03115982, -0.20828982, -0.97757065], [ 0.1714755 , -0.88971114, -0.42309603], [-0.1948448 , -0.48424336, -0.85296184], [-0.46394941, -0.51801461,  0.71861798], [-0.45273268, -0.81954175, -0.35126126], [-0.82887799, -0.29984823, -0.47228414], [ 0.21121763, -0.09845807,  0.97246754], [-0.11702234, -0.10076906,  0.98800373], [ 0.31119478, -0.68396461, -0.65981078], [ 0.65285712, -0.07680383, -0.75357729], [ 0.71209121, -0.26699486,  0.64933801], [ 0.97685069, -0.17835225,  0.11812361], [-0.34381351, -0.93718553, -0.05895334], [ 0.68615079, -0.67022949,  0.2828241 ], [-0.6588605 , -0.59295917, -0.46292791], [ 0.15754543, -0.46902952, -0.86901712], [ 0.89081973, -0.0551779 ,  0.45099396], [ 0.09939465, -0.40802586,  0.90754372], [ 0.93604255, -0.26702261, -0.22917943], [-0.93707269, -0.34256476,  0.06741077], [-0.19623031, -0.95031369,  0.24165596], [ 0.45153776, -0.87650371,  0.16689767], [-0.0195914 , -0.72917062, -0.68405145], [ 0.65216494, -0.75583613, -0.05824633], [ 0.13336134, -0.97014433,  0.20257032], [ 0.86954373, -0.49204889,  0.04220884], [ 0.60317737, -0.57162017, -0.55626202], [-0.34353963, -0.78447777,  0.51630914], [-0.35424244, -0.68266952, -0.63912022], [-0.84101379, -0.50332689, -0.19838808], [-0.85885382, -0.33475134,  0.38770047], [ 0.30507854, -0.94518369, -0.11642545], [ 0.7822451 , -0.55481136, -0.28333196], [-0.15034926, -0.90096235, -0.4070158 ], [-0.37529847, -0.20644124, -0.90362221], [-0.87414831, -0.01486413,  0.48543158]])
x, y, z = gradients.T

fig, ax = mplstereonet.subplots(projection='equal_area')
ax.grid(True)
ax.pole(*mplstereonet.vector2pole(x,y,z))

plt.show()

说不出话来。精彩的。我会投票一千次!(等等,这几乎超过了我的一半。)你帮了我这么多。我真的更喜欢不渲染内部,而是着色灰色表面的想法!我只是稍微修改了一下,让箭头加上一点管子留在表面的顶部。再次:太好了+谢谢!我正在做类似的事情(至少使用了quiver3d)。是否有一种简单的方法来固定箭头的大小和轴的直径,但允许轴的长度按比例缩放。。我猜这是按照你的“自定义字形”建议。(我已经开始读一些关于mayavi/tvtk管道/来源等的细节,但是为了这么一个小请求而沿着这条路线走似乎有点过头了。)@dan man——这就是我回答中的第二个例子所做的。不幸的是,据我所知,没有比这更好的方法了。我提到的“自定义图示符”仍然是静态的。箭头的头部和轴必须有一个固定的比率,不能随数据而改变。在VTK中,你可以按标量缩放一个字形,但整个字形必须缩放,所以箭头的轴不能独立,除非它们是两个独立的对象。@JoeKington-谢谢。很明显,我对你的文章的第一次阅读不是很透彻……但令人惊讶的是,没有一种简单的方法可以画出你在最基本的2d设置中找到的那种“常规”箭头……matplotlib/MSword等。