我想在3D中绘制隐式方程F(x,y,z)= 0。在Matplotlib中有可能吗?
答案 0 :(得分:48)
您可以使用matplotlib绘制3D中的隐式方程。只需在所需限制内为每个z值制作等式的一级等高线图。您可以沿y轴和z轴重复该过程,以获得更加坚固的形状。
from mpl_toolkits.mplot3d import axes3d
import matplotlib.pyplot as plt
import numpy as np
def plot_implicit(fn, bbox=(-2.5,2.5)):
''' create a plot of an implicit function
fn ...implicit function (plot where fn==0)
bbox ..the x,y,and z limits of plotted interval'''
xmin, xmax, ymin, ymax, zmin, zmax = bbox*3
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
A = np.linspace(xmin, xmax, 100) # resolution of the contour
B = np.linspace(xmin, xmax, 15) # number of slices
A1,A2 = np.meshgrid(A,A) # grid on which the contour is plotted
for z in B: # plot contours in the XY plane
X,Y = A1,A2
Z = fn(X,Y,z)
cset = ax.contour(X, Y, Z+z, [z], zdir='z')
# [z] defines the only level to plot for this contour for this value of z
for y in B: # plot contours in the XZ plane
X,Z = A1,A2
Y = fn(X,y,Z)
cset = ax.contour(X, Y+y, Z, [y], zdir='y')
for x in B: # plot contours in the YZ plane
Y,Z = A1,A2
X = fn(x,Y,Z)
cset = ax.contour(X+x, Y, Z, [x], zdir='x')
# must set plot limits because the contour will likely extend
# way beyond the displayed level. Otherwise matplotlib extends the plot limits
# to encompass all values in the contour.
ax.set_zlim3d(zmin,zmax)
ax.set_xlim3d(xmin,xmax)
ax.set_ylim3d(ymin,ymax)
plt.show()
以下是Goursat Tangle的情节:
def goursat_tangle(x,y,z):
a,b,c = 0.0,-5.0,11.8
return x**4+y**4+z**4+a*(x**2+y**2+z**2)**2+b*(x**2+y**2+z**2)+c
plot_implicit(goursat_tangle)
通过使用创意色彩映射添加深度提示,您可以更轻松地进行可视化:
OP的情节如下:
def hyp_part1(x,y,z):
return -(x**2) - (y**2) + (z**2) - 1
plot_implicit(hyp_part1, bbox=(-100.,100.))
Bonus:您可以使用python在功能上组合这些隐式函数:
def sphere(x,y,z):
return x**2 + y**2 + z**2 - 2.0**2
def translate(fn,x,y,z):
return lambda a,b,c: fn(x-a,y-b,z-c)
def union(*fns):
return lambda x,y,z: np.min(
[fn(x,y,z) for fn in fns], 0)
def intersect(*fns):
return lambda x,y,z: np.max(
[fn(x,y,z) for fn in fns], 0)
def subtract(fn1, fn2):
return intersect(fn1, lambda *args:-fn2(*args))
plot_implicit(union(sphere,translate(sphere, 1.,1.,1.)), (-2.,3.))
答案 1 :(得分:2)
Matplotlib期待一系列观点;如果你能弄清楚如何渲染你的等式,它将进行绘图。
参考Is it possible to plot implicit equations using Matplotlib? Mike Graham的回答建议使用scipy.optimize以数字方式探索隐式函数。
在http://xrt.wikidot.com/gallery:implicit有一个有趣的画廊,展示了各种光线跟踪隐式函数 - 如果你的等式匹配其中一个,它可能会让你更好地了解你在看什么。
如果不这样做,如果你想分享实际的等式,也许有人可以提出一个更简单的方法。
答案 2 :(得分:2)
据我所知,这是不可能的。你必须自己用数字方法解决这个等式。使用scipy.optimize是个好主意。最简单的情况是你知道要绘制的曲面范围,并在x和y中制作一个规则网格,并尝试求解z的方程F(xi,yi,z)= 0,给出一个起点z点。以下是一个非常脏的代码,可能会帮助您
from scipy import *
from scipy import optimize
xrange = (0,1)
yrange = (0,1)
density = 100
startz = 1
def F(x,y,z):
return x**2+y**2+z**2-10
x = linspace(xrange[0],xrange[1],density)
y = linspace(yrange[0],yrange[1],density)
points = []
for xi in x:
for yi in y:
g = lambda z:F(xi,yi,z)
res = optimize.fsolve(g, startz, full_output=1)
if res[2] == 1:
zi = res[0]
points.append([xi,yi,zi])
points = array(points)
答案 3 :(得分:1)
你看过matplotlib上的mplot3d吗?
答案 4 :(得分:1)
最新答案,我只需要做同样的事情,在某种程度上我发现了另一种方法。所以我要分享另一个观点。
本文不回答:(1)如何绘制任何隐式函数F(x,y,z)=0
?但是答案是否正确:(2)如何使用带有matplotlib
的网格来绘制参数化曲面(不是所有隐式函数,而是其中一些)?
@Paul的方法具有非参数化的优点,因此我们可以在每个轴上绘制使用轮廓法绘制的几乎任何物体,它可以完全解决(1)的问题。但是matplotlib
无法轻松地通过此方法构建网格,因此我们无法直接从中获取曲面,而是获取所有方向的平面曲线。这就是促使我回答这个问题的原因,我想解决(2)。
如果我们能够参数化(这可能是困难的或不可能的),最多可以绘制两个要绘制的参数,然后可以使用matplotlib.plot_trisurf
方法对其进行绘制。
也就是说,根据隐式方程F(x,y,z)=0
,如果我们能够获得参数系统S={x=f(u,v), y=g(u,v), z=h(u,v)}
,则可以使用matplotlib
轻松绘制它,而不必求助于{{1 }}。
然后,渲染这样的3D表面归结为:
contour
其中# Render:
ax = plt.axes(projection='3d')
ax.plot_trisurf(x, y, z, triangles=tri.triangles, cmap='jet', antialiased=True)
是向量(不是meshgrid
,请参见ravel
),是根据参数(x, y, z)
计算得出的向量,而(u, v)
参数是从{{1 }}参数来承担网格的构建。
所需的进口是:
triangles
让某些表面参数化...
球(u,v)
锥体
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits import mplot3d
from matplotlib.tri import Triangulation
圆环面
# Parameters:
theta = np.linspace(0, 2*np.pi, 20)
phi = np.linspace(0, np.pi, 20)
theta, phi = np.meshgrid(theta, phi)
rho = 1
# Parametrization:
x = np.ravel(rho*np.cos(theta)*np.sin(phi))
y = np.ravel(rho*np.sin(theta)*np.sin(phi))
z = np.ravel(rho*np.cos(phi))
# Triangulation:
tri = Triangulation(np.ravel(theta), np.ravel(phi))
Möbius Strip
theta = np.linspace(0, 2*np.pi, 20)
rho = np.linspace(-2, 2, 20)
theta, rho = np.meshgrid(theta, rho)
x = np.ravel(rho*np.cos(theta))
y = np.ravel(rho*np.sin(theta))
z = np.ravel(rho)
tri = Triangulation(np.ravel(theta), np.ravel(rho))
大多数时候,Triangulation
是必需的,以便协调a, c = 1, 4
u = np.linspace(0, 2*np.pi, 20)
v = u.copy()
u, v = np.meshgrid(u, v)
x = np.ravel((c + a*np.cos(v))*np.cos(u))
y = np.ravel((c + a*np.cos(v))*np.sin(u))
z = np.ravel(a*np.sin(v))
tri = Triangulation(np.ravel(u), np.ravel(v))
方法的网格结构,并且该对象仅接受两个参数,因此我们仅限于2D参数化曲面。我们不可能用这种方法来表示古尔萨特缠结。
答案 5 :(得分:0)
最后,我做到了(我将matplotlib更新为1.0.1)。 这是代码:
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
def hyp_part1(x,y,z):
return -(x**2) - (y**2) + (z**2) - 1
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x_range = np.arange(-100,100,10)
y_range = np.arange(-100,100,10)
X,Y = np.meshgrid(x_range,y_range)
A = np.linspace(-100, 100, 15)
A1,A2 = np.meshgrid(A,A)
for z in A:
X,Y = A1, A2
Z = hyp_part1(X,Y,z)
ax.contour(X, Y, Z+z, [z], zdir='z')
for y in A:
X,Z= A1, A2
Y = hyp_part1(X,y,Z)
ax.contour(X, Y+y, Z, [y], zdir='y')
for x in A:
Y,Z = A1, A2
X = hyp_part1(x,Y,Z)
ax.contour(X+x, Y, Z, [x], zdir='x')
ax.set_zlim3d(-100,100)
ax.set_xlim3d(-100,100)
ax.set_ylim3d(-100,100)
结果如下:
谢谢你,保罗!
答案 6 :(得分:0)
答案 7 :(得分:0)
实际上,有一种简便的方法可以使用scikit-image
包绘制隐式3D表面。关键是marching_cubes
方法。
import numpy as np
from skimage import measure
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d
然后我们在3D网格上计算函数,在此示例中,我们使用其答案中定义的goursat_tangle
方法@Paul
:
xl = np.linspace(-3, 3, 50)
X, Y, Z = np.meshgrid(xl, xl, xl)
F = goursat_tangle(X, Y, Z)
神奇的事发生在marching_cubes
:
verts, faces, normals, values = measure.marching_cubes(F, 0, spacing=[np.diff(xl)[0]]*3)
verts -= 3
我们只需要校正以Voxel坐标表示的顶点坐标(因此使用spacing
开关进行缩放并随后进行原点平移)。
最后,它只是使用tri_surface
渲染等值面:
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_trisurf(verts[:, 0], verts[:, 1], faces, verts[:, 2], cmap='jet', lw=0)
哪个返回: