如何使用pyplot在曲面图后面画一条线 [英] How to draw a line behind a surface plot using pyplot

查看:44
本文介绍了如何使用pyplot在曲面图后面画一条线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在我用曲面图绘制的圆环内画一条线.该线不应该在环面内可见 - 就像环面的内侧一样,只能在环面的末端"看到(我切断了环面的一半).然而,我绘制的线随处可见(如您在图中所见).

我使用了以下代码:

将 numpy 导入为 np导入matplotlib.pyplot作为plt从mpl_toolkits.mplot3d导入Axes3D# theta: 极向角 |phi:圆环角# 注意:只绘制半个圆环,因此 phi=0...pitheta = np.linspace(0,2. * np.pi,200)phi = np.linspace(0, 1.*np.pi, 200)theta,phi = np.meshgrid(theta,phi)#主要和次要半径R0,a = 3.,1.#环面参数化x_torus = (R0 + a*np.cos(theta)) * np.cos(phi)y_torus = (R0 + a*np.cos(theta)) * np.sin(phi)z_torus = a * np.sin(theta)#在theta = 0处对圆线进行参数化x_circle =(R0-a/2.+ a * np.cos(.0))* np.cos(phi)y_circle = (R0-a/2. + a*np.cos(.0)) * np.sin(phi)z_circle = a * np.sin(.0)无花果= plt.figure()ax1 = fig.add_subplot(111, 投影='3d')#绘制一半的圆线ax1.plot3D( x_circle, y_circle, z_circle )#绘制半个圆环ax1.plot_surface(x_torus,y_torus,z_torus)ax1.view_init(elev=15, azim=270)ax1.set_xlim(-3, 3)ax1.set_ylim(-3,3)ax1.set_zlim(-3,3)ax1.set_axis_off()plt.show()

我认为简单地绘制线条第一应该可以解决我的问题,但事实并非如此.非常感谢任何关于如何改变线路行为的建议或帮助.

numpy.__version__ : 1.12.1matplotlib .__ version__:2.0.0

解决方案

选项一 - 使用 Mayavi

更简单的方法是使用

选项二-使用matplotlib(有些不愉快的地方)

如果您不能使用 mayavi,则可以使用 matplotlib 来完成此操作,这只是……令人不快.该方法基于

注意在两种情况下,为了简化演示,我都更改了圆以匹配环形线圈的主半径,可以根据需要轻松地对其进行更改.

I want to draw a line inside a torus which I have drawn with a surface plot. The line should not be visible inside the torus - like the inner side of the torus, which can only be seen at the "ends" of the torus (I cut-off one half of the torus). The line I have drawn is however visible everywhere (as you can see in the plot).

I have used the following code:

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

# theta: poloidal angle | phi: toroidal angle
# note: only plot half a torus, thus phi=0...pi
theta = np.linspace(0, 2.*np.pi, 200)
phi   = np.linspace(0, 1.*np.pi, 200)
theta, phi = np.meshgrid(theta, phi)

# major and minor radius
R0, a = 3., 1.

# torus parametrization
x_torus = (R0 + a*np.cos(theta)) * np.cos(phi)
y_torus = (R0 + a*np.cos(theta)) * np.sin(phi)
z_torus = a * np.sin(theta)

# parametrization for a circular line at theta=0
x_circle = (R0-a/2. + a*np.cos(.0)) * np.cos(phi)
y_circle = (R0-a/2. + a*np.cos(.0)) * np.sin(phi)
z_circle = a * np.sin(.0)

fig = plt.figure()
ax1 = fig.add_subplot(111, projection='3d')

# plot half of a circular line
ax1.plot3D( x_circle, y_circle, z_circle )

# plot half of torus
ax1.plot_surface( x_torus, y_torus, z_torus )

ax1.view_init(elev=15, azim=270)
ax1.set_xlim( -3, 3)
ax1.set_ylim( -3, 3)
ax1.set_zlim( -3, 3)
ax1.set_axis_off()

plt.show()

I thought simply plotting the line first should solve my problem, but it doesn't. Any suggestion or help how to change the behaviour of the line is greatly appreciated.

numpy.__version__     : 1.12.1
matplotlib.__version__: 2.0.0

解决方案

Option one - use Mayavi

The easier way to do this would be with the Mayavi library. This is pretty similar to matplotlib, the only meaningful differences for this script are that the x, y, and z arrays passed to plot3d to plot the line should be 1d and the view is set a bit differently (depending on whether it is set before or after plotting, and the alt/az are measured from different reference).

import numpy as np
import mayavi.mlab as mlab
from mayavi.api import OffScreenEngine
mlab.options.offscreen = True

# theta: poloidal angle | phi: toroidal angle
# note: only plot half a torus, thus phi=0...pi
theta = np.linspace(0, 2.*np.pi, 200)
phi   = np.linspace(0, 1.*np.pi, 200)

# major and minor radius
R0, a = 3., 1.

x_circle = R0 * np.cos(phi)
y_circle = R0 * np.sin(phi)
z_circle = np.zeros_like(x_circle)

# Delay meshgrid until after circle construction
theta, phi = np.meshgrid(theta, phi)
x_torus = (R0 + a*np.cos(theta)) * np.cos(phi)
y_torus = (R0 + a*np.cos(theta)) * np.sin(phi)
z_torus = a * np.sin(theta)

mlab.figure(bgcolor=(1.0, 1.0, 1.0), size=(1000,1000))
mlab.view(azimuth=90, elevation=105)

mlab.plot3d(x_circle, y_circle, z_circle)
mlab.mesh(x_torus, y_torus, z_torus, color=(0.0, 0.5, 1.0))
mlab.savefig("./example.png")
# mlab.show() has issues with rendering for some setups

Option two - use matplotlib (with some added unpleasantness)

If you can't use mayavi it is possible to accomplish this with matplotlib, it's just... unpleasant. The approach is based on the idea of creating transparent 'bridges' between surfaces and then plotting them together as one surface. This is not trivial for more complex combinations, but here is an example for the toroid with a line which is fairly straightforward

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

theta = np.linspace(0, 2.*np.pi, 200)
phi   = np.linspace(0, 1.*np.pi, 200)
theta, phi = np.meshgrid(theta, phi)

# major and minor radius
R0, a = 3., 1.
lw = 0.05 # Width of line

# Cue the unpleasantness - the circle must also be drawn as a toroid
x_circle = (R0 + lw*np.cos(theta)) * np.cos(phi)
y_circle = (R0 + lw*np.cos(theta)) * np.sin(phi)
z_circle = lw * np.sin(theta)
c_circle = np.full_like(x_circle, (1.0, 1.0, 1.0, 1.0), dtype=(float,4))

# Delay meshgrid until after circle construction
x_torus = (R0 + a*np.cos(theta)) * np.cos(phi)
y_torus = (R0 + a*np.cos(theta)) * np.sin(phi)
z_torus = a * np.sin(theta)
c_torus = np.full_like(x_torus, (0.0, 0.5, 1.0, 1.0), dtype=(float, 4))

# Create the bridge, filled with transparency
x_bridge = np.vstack([x_circle[-1,:],x_torus[0,:]])
y_bridge = np.vstack([y_circle[-1,:],y_torus[0,:]])
z_bridge = np.vstack([z_circle[-1,:],z_torus[0,:]])
c_bridge = np.full_like(z_bridge, (0.0, 0.0, 0.0, 0.0), dtype=(float, 4))

# Join the circle and torus with the transparent bridge
X = np.vstack([x_circle, x_bridge, x_torus])
Y = np.vstack([y_circle, y_bridge, y_torus])
Z = np.vstack([z_circle, z_bridge, z_torus])
C = np.vstack([c_circle, c_bridge, c_torus])

fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot_surface(X, Y, Z, rstride=1, cstride=1, facecolors=C, linewidth=0)
ax.view_init(elev=15, azim=270)
ax.set_xlim( -3, 3)
ax.set_ylim( -3, 3)
ax.set_zlim( -3, 3)
ax.set_axis_off()

plt.show()

Note in both cases I changed the circle to match the major radius of the toroid for demonstration simplicity, it can easily be altered as needed.

这篇关于如何使用pyplot在曲面图后面画一条线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆