Я хотел бы построить неявное уравнение F (x, y, z) = 0 в 3D. Возможно ли это в Matplotlib?
Построение неявных уравнений в 3d
Ответ 1
Вы можете обмануть 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()
Здесь сюжет Гурса 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)
Вы можете упростить визуализацию, добавив подсказки глубины с помощью cololapapping:
Вот как выглядит график 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.))
Ответ 2
Matplotlib ожидает серию очков; он выполнит построение графика, если вы сможете выяснить, как сделать свое уравнение.
Ссылаясь на Можно ли построить неявные уравнения с использованием Matplotlib? Ответ Майка Грэма предполагает использование scipy.optimize для численного изучения неявной функции.
Есть интересная галерея на http://xrt.wikidot.com/gallery:implicit, показывающая множество явных функций raytraced - если ваше уравнение соответствует одному из них, оно может дать вам лучшее представление о том, что вы ищете.
В противном случае, если вы хотите поделиться фактическим уравнением, возможно, кто-то может предложить более простой подход.
Ответ 3
Насколько я знаю, это невозможно. Вы должны решить это уравнение численно самостоятельно. Использование 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)
Ответ 4
Вы посмотрели mplot3d на matplotlib?
Ответ 5
Наконец, я сделал это (я обновил свой 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
MathGL (GPL-графика) может легко построить график. Просто создайте сетку данных с значениями функций f [i, j, k] и используйте функцию Surf3(), чтобы сделать изоповерхность при значении f [i, j, k] = 0. Смотрите sample.
Ответ 7
мотивация
Поздний ответ, мне просто нужно было сделать то же самое, и я нашел другой способ сделать это в какой-то степени. Так что я разделяю эту другую точку зрения.
Этот пост не отвечает: (1) Как построить любую неявную функцию F(x,y,z)=0
? Но отвечает ли: (2) Как построить параметрические поверхности (не все неявные функции, но некоторые из них), используя меш с matplotlib
?
Преимущество метода @Paul в том, что он непараметрический, поэтому мы можем построить практически все, что захотим, используя контурный метод на каждом топоре, он полностью решает (1). Но matplotlib
не может легко построить меш из этого метода, поэтому мы не можем напрямую получить поверхность из него, вместо этого мы получаем плоские кривые во всех направлениях. Это то, что мотивировало мой ответ, я хотел обратиться (2).
Рендеринг сетки
Если мы можем параметризовать (это может быть сложно или невозможно), используя не более двух параметров, поверхность, которую мы хотим построить, то мы можем построить ее с matplotlib.plot_trisurf
метода matplotlib.plot_trisurf
.
То есть из неявного уравнения F(x,y,z)=0
, если мы можем получить параметрическую систему S={x=f(u,v), y=g(u,v), z=h(u,v)}
тогда мы можем легко построить его с помощью matplotlib
не прибегая к contour
.
Затем рендеринг такой трехмерной поверхности сводится к:
# Render:
ax = plt.axes(projection='3d')
ax.plot_trisurf(x, y, z, triangles=tri.triangles, cmap='jet', antialiased=True)
Где (x, y, z)
- векторы (не meshgrid
, см. ravel
), функционально вычисленные из параметров (u, v)
а параметр 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))
Конус 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))
ограничение
Большую часть времени Triangulation
необходима для координации построения plot_trisurf
метода plot_trisurf
, и этот объект принимает только два параметра, поэтому мы ограничены двумерными параметрическими поверхностями. Вряд ли мы могли бы представить Путаницу Гурса этим методом.