【问题标题】:Plotting a solid cylinder centered on a plane in Matplotlib在 Matplotlib 中绘制以平面为中心的实心圆柱体
【发布时间】:2017-02-10 20:37:36
【问题描述】:

我将一个平面拟合到 3d 中的一堆点上,最初使用 np.meshgrid 给它一个任意大小,但现在我试图绘制一个以该平面为中心并以相同方式定向的圆柱体(这样平面fit 会将圆柱体的高度减半),但具有指定的半径和高度。我能找到的在 matplotlib 中绘制的唯一圆柱体示例是空心的,通常在顶部和底部打开。我希望我绘制的那个是实心的,这样我就可以清楚地看到它所包围的点。

这是一个随机生成平面的最小工作示例。由于我使用的平面总是由一个点和一个法线向量给出,因此圆柱体也应该基于这些东西(加上提供的半径和在平面上方和下方延伸的高度)。

from __future__ import division #Enables new-style division
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import seaborn as sns
import numpy as np

cen_x = 0
cen_y = 0
cen_z = 0

origin = np.array([cen_x,cen_y,cen_z])

normal = np.array([np.random.uniform(-1,1),np.random.uniform(-1,1),np.random.uniform(0,1)])

a = normal[0]
b = normal[1]
c = normal[2]

#equation for a plane is a*x+b*y+c*z+d=0 where [a,b,c] is the normal
#so calculate d from the normal
d = -origin.dot(normal)

# create x,y meshgrid
xx, yy = np.meshgrid(np.arange(cen_x-1,cen_x+1,0.01),np.arange(cen_y-1,cen_y+1,0.01))

# calculate corresponding z
zz = (-a * xx - b * yy - d) * 1./c

halo_x = [-0.3, -0.9, 0.8, 1.3, -0.1, 0.5]
halo_y = [0.8, 1.1, -0.5, -0.7, -1.2, 0.1]
halo_z = [1.0, -0.4, 0.3, -1.2, 0.9, 1.2]

fig = plt.figure(figsize=(9,9))
plt3d = fig.gca(projection='3d')
plt3d.plot_surface(xx, yy, zz, color='r', alpha=0.4)
plt3d.set_xlim3d(cen_x-3,cen_x+3)
plt3d.set_ylim3d(cen_y-3,cen_y+3)
plt3d.set_zlim3d(cen_z-3,cen_z+3)
plt3d.set_xlabel('X')
plt3d.set_ylabel('Y')
plt3d.set_zlabel('Z')
plt.show()

【问题讨论】:

    标签: python matplotlib plot 3d plane


    【解决方案1】:

    我已经修改了问题How to add colors to each individual face of a cylinder using matplotlib 的解决方案,删除了花哨的阴影并添加了端盖。如果要显示封闭的点,可以使用alpha=0.5之类的,使圆柱体半透明。

    圆柱体的方向由长度为 mag 的单位向量 v 定义,这可能是您表面的法线。

    #!/usr/bin/env python2
    # -*- coding: utf-8 -*-
    """
    Created on Sun Oct  2 18:33:10 2016
    
    Modified from https://stackoverflow.com/questions/38076682/how-to-add-colors-to-each-individual-face-of-a-cylinder-using-matplotlib
    to add "end caps" and to undo fancy coloring.
    
    @author: astrokeat
    """
    
    import numpy as np
    from matplotlib import pyplot as plt
    from scipy.linalg import norm
    
    #axis and radius
    p0 = np.array([1, 3, 2]) #point at one end
    p1 = np.array([8, 5, 9]) #point at other end
    R = 5
    
    #vector in direction of axis
    v = p1 - p0
    
    #find magnitude of vector
    mag = norm(v)
    
    #unit vector in direction of axis
    v = v / mag
    
    #make some vector not in the same direction as v
    not_v = np.array([1, 0, 0])
    if (v == not_v).all():
        not_v = np.array([0, 1, 0])
    
    #make vector perpendicular to v
    n1 = np.cross(v, not_v)
    #normalize n1
    n1 /= norm(n1)
    
    #make unit vector perpendicular to v and n1
    n2 = np.cross(v, n1)
    
    #surface ranges over t from 0 to length of axis and 0 to 2*pi
    t = np.linspace(0, mag, 2)
    theta = np.linspace(0, 2 * np.pi, 100)
    rsample = np.linspace(0, R, 2)
    
    #use meshgrid to make 2d arrays
    t, theta2 = np.meshgrid(t, theta)
    
    rsample,theta = np.meshgrid(rsample, theta)
    
    #generate coordinates for surface
    # "Tube"
    X, Y, Z = [p0[i] + v[i] * t + R * np.sin(theta2) * n1[i] + R * np.cos(theta2) *       n2[i] for i in [0, 1, 2]]
    # "Bottom"
    X2, Y2, Z2 = [p0[i] + rsample[i] * np.sin(theta) * n1[i] + rsample[i] * np.cos(theta) * n2[i] for i in [0, 1, 2]]
    # "Top"
    X3, Y3, Z3 = [p0[i] + v[i]*mag + rsample[i] * np.sin(theta) * n1[i] + rsample[i] * np.cos(theta) * n2[i] for i in [0, 1, 2]]
    
    
    ax=plt.subplot(111, projection='3d')
    ax.plot_surface(X, Y, Z, color='blue')
    ax.plot_surface(X2, Y2, Z2, color='blue')
    ax.plot_surface(X3, Y3, Z3, color='blue')
    
    plt.show()
    

    结果:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-01-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多