Python 三维隐式方程的绘制

Python 三维隐式方程的绘制,python,numpy,matplotlib,plot,Python,Numpy,Matplotlib,Plot,我想在3D中绘制隐式方程F(x,y,z)=0。在Matplotlib中是否可能?您看过Matplotlib吗?Matplotlib需要一系列点;如果你能弄清楚如何渲染你的方程,它将进行绘图 参考Mike Graham的回答,建议使用scipy.optimize对隐式函数进行数值探索 这里有一个有趣的画廊,展示各种光线跟踪隐式函数——如果你的方程与其中一个匹配,它可能会让你更好地了解你在看什么 如果你不愿意,如果你愿意分享实际的等式,也许有人可以建议一个更简单的方法。据我所知,这是不可能的。你必须

我想在3D中绘制隐式方程F(x,y,z)=0。在Matplotlib中是否可能?

您看过Matplotlib吗?

Matplotlib需要一系列点;如果你能弄清楚如何渲染你的方程,它将进行绘图

参考Mike Graham的回答,建议使用scipy.optimize对隐式函数进行数值探索

这里有一个有趣的画廊,展示各种光线跟踪隐式函数——如果你的方程与其中一个匹配,它可能会让你更好地了解你在看什么


如果你不愿意,如果你愿意分享实际的等式,也许有人可以建议一个更简单的方法。

据我所知,这是不可能的。你必须自己用数值解这个方程。使用scipy.optimize是个好主意。最简单的情况是,您知道要绘制的曲面的范围,只需在x和y上绘制规则网格,然后尝试求解方程F(xi,yi,z)=0表示z,给出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)

可以诱使matplotlib在三维中绘制隐式方程。只需在所需限值内为每个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.))

好处:您可以使用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.))

最后,我做到了(我将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)
结果如下:


谢谢你,保罗

(GPL绘图库)可以轻松绘图。只需使用函数值f[i,j,k]创建一个数据网格,并使用Surf3()函数在值f[i,j,k]=0时生成等值面。查看此图。

更新:我终于找到了一种使用
matplotlib
scikit image
渲染三维隐式曲面的简单方法,请参见我的。我把这个留给了对绘制参数化三维曲面感兴趣的人

动机 迟来的回答,我只是需要做同样的事情,我找到了另一种方法在某种程度上做到这一点。因此,我从另一个角度分享这一点

这篇文章没有回答:(1)如何绘制任何隐式函数
F(x,y,z)=0
?但问题的答案是:(2)如何使用带有
matplotlib
的网格绘制参数化曲面(不是所有隐式函数,而是其中一些函数)

@Paul的方法具有非参数化的优势,因此我们可以在每个轴上使用等高线方法绘制几乎任何我们想要的东西,它完全解决了(1)。但是,
matplotlib
无法通过此方法轻松构建网格,因此我们无法直接从中获取曲面,而是获取各个方向的平面曲线。这就是我的答案的动机,我想解决(2)

渲染网格 如果我们能够参数化(这可能很难或不可能),最多使用2个参数,我们要绘制的曲面,那么我们可以使用方法绘制它

也就是说,从一个隐式方程
F(x,y,z)=0
,如果我们能够得到一个参数系统
S={x=F(u,v),y=g(u,v),z=h(u,v)}
,那么我们可以用
matplotlib
轻松地绘制它,而不必求助于
contour

然后,渲染这样的3D曲面归结为:

# Render:
ax = plt.axes(projection='3d')
ax.plot_trisurf(x, y, z, triangles=tri.triangles, cmap='jet', antialiased=True) 
其中,
(x,y,z)
是从参数
(u,v)
功能性计算的向量(不,请参见),
三角形
参数是从
(u,v)
参数派生的三角剖分,以承载网格构造

进口 所需进口为:

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits import mplot3d
from matplotlib.tri import Triangulation
某些表面 让我们参数化一些曲面

球体

圆锥

环面

限度
大多数情况下,为了协调
plot_trisurf
方法的网格构造,需要使用,并且该对象仅接受两个参数,因此我们仅限于二维参数曲面。我们不太可能用这种方法来表示Goursat Tangle。

实际上,有一种简单的方法可以使用
scikit图像
包绘制隐式3D曲面。关键是方法

然后我们计算3D网格上的函数,在本例中,我们使用答案中定义的
goursat_tangle
方法
@Paul

xl = np.linspace(-3, 3, 50)
X, Y, Z = np.meshgrid(xl, xl, xl)
F = goursat_tangle(X, Y, Z)
奇迹就发生在这里:

我们只需要纠正顶点坐标,因为它们是用坐标表示的(因此使用
间距
开关和后续原点偏移进行缩放)

最后,只需使用以下方法渲染iso曲面:

返回:


您可以在以下位置找到一些示例:是否需要使用matplotlib执行此操作?如果没有,您可能想看一看。@Sven Marnach:谢谢,但不幸的是我必须用Matplotlib来做。它看起来不错,只是您没有按z的值移动z轮廓的位置。它们都被标为0.0!另外,您需要手动定义绘制的限制,因为z等高线解决方案将远远超出您所需的等高线间隔。我已经用更干净的代码更新了我的帖子,其中包括沿其他轴绘制的等高线间隔(切片)。是的,我已经更新了。主要问题是函数是隐式的。好了,Matplotlib不绘制方程,它绘制一系列点。我只是不知道如何计算所有符合我的隐式方程的点序列。我认为这不是一个好主意。尝试F(x,y,z)=x^2+y^2+z^2-1查看问题。它应该绘制一个球体,但是你的代码只绘制半个球体。哦,刚才注意到你已经使用了基本相同的函数:)这是真的。如果隐式函数是多值函数,则存在一个问题。正如我所说的,这只是一个肮脏的代码,使得最简单的事情成为可能。#@bpowah:根据matplotlib引用投影='3d'是无效的。也许投影='直线'?我记得
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))
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))
u = np.linspace(0, 2*np.pi, 20)
v = np.linspace(-1, 1, 20)
u, v = np.meshgrid(u, v)

x = np.ravel((2 + (v/2)*np.cos(u/2))*np.cos(u))
y = np.ravel((2 + (v/2)*np.cos(u/2))*np.sin(u))
z = np.ravel(v/2*np.sin(u/2))

tri = Triangulation(np.ravel(u), np.ravel(v))
import numpy as np
from skimage import measure
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import axes3d
xl = np.linspace(-3, 3, 50)
X, Y, Z = np.meshgrid(xl, xl, xl)
F = goursat_tangle(X, Y, Z)
verts, faces, normals, values = measure.marching_cubes(F, 0, spacing=[np.diff(xl)[0]]*3)
verts -= 3
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ax.plot_trisurf(verts[:, 0], verts[:, 1], faces, verts[:, 2], cmap='jet', lw=0)