我想在 Matplotlib 中绘制隐式方程(形式为 f(x, y)=g(x, y) 例如 X^y=y^x)。这可能吗?
6 回答
我不相信对此有很好的支持,但你可以尝试类似
import matplotlib.pyplot
from numpy import arange
from numpy import meshgrid
delta = 0.025
xrange = arange(-5.0, 20.0, delta)
yrange = arange(-5.0, 20.0, delta)
X, Y = meshgrid(xrange,yrange)
# F is one side of the equation, G is the other
F = Y**X
G = X**Y
matplotlib.pyplot.contour(X, Y, (F - G), [0])
matplotlib.pyplot.show()
请参阅API 文档:contour
如果第四个参数是一个序列,则它指定要绘制的轮廓线。但是情节只会与您的范围的分辨率一样好,并且某些功能可能永远不会正确,通常在自相交点处。
既然你已经用 sympy 标记了这个问题,我将举一个这样的例子。
来自文档:http ://docs.sympy.org/latest/modules/plotting.html 。
from sympy import var, plot_implicit
var('x y')
plot_implicit(x*y**3 - y*x**3)
matplotlib 不绘制方程;它绘制一系列点。您可以使用诸如scipy.optimize
从隐式方程的 x 值(或反之亦然)数值计算 y 点之类的工具或任何数量的其他工具(视情况而定)。
例如,这是一个示例,我x ** 2 + x * y + y ** 2 = 10
在某个区域中绘制了隐式方程。
from functools import partial
import numpy
import scipy.optimize
import matplotlib.pyplot as pp
def z(x, y):
return x ** 2 + x * y + y ** 2 - 10
x_window = 0, 5
y_window = 0, 5
xs = []
ys = []
for x in numpy.linspace(*x_window, num=200):
try:
# A more efficient technique would use the last-found-y-value as a
# starting point
y = scipy.optimize.brentq(partial(z, x), *y_window)
except ValueError:
# Should we not be able to find a solution in this window.
pass
else:
xs.append(x)
ys.append(y)
pp.plot(xs, ys)
pp.xlim(*x_window)
pp.ylim(*y_window)
pp.show()
sympy 中有一个隐式方程(和不等式)绘图仪。它是作为 GSoC 的一部分创建的,并将绘图生成为 matplotlib 图形实例。
http://docs.sympy.org/latest/modules/plotting.html#sympy.plotting.plot_implicit.plot_implicit上的文档
自 sympy 版本 0.7.2 起,它可用作:
>>> from sympy.plotting import plot_implicit
>>> p = plot_implicit(x < sin(x)) # also creates a window with the plot
>>> the_matplotlib_axes_instance = p._backend._ax
编辑:如果您使用 plt.plot() 绘制双曲线,那么您将获得不希望的分支效果。plt.scatter() 在它的位置应该仍然有效。那么就没有必要颠倒负值或正值的顺序了,但是如果你出于某种原因想使用这个代码(而不是使用 scipy 的等高线图),它无论如何都可以使用 plt.scatter()
二维的隐函数一般可以写成:
f(x,y)=0
因为我们不能把它写成 f(x) = y,所以我们不能从一个易于编程的离散 x 集合中计算 y。但是,可以查看从网格生成的点与真实函数的接近程度。
因此,将 x 和 y 的网格设置为自定义点密度,并查看每个点与满足方程的接近程度。
换句话说,如果我们不能得到 f(x,y) =0,也许我们可以接近 0。而不是寻找 f(x,y) =0 寻找 f(x,y) > -\ epsilon 和 f(x,y) < \epsilon。
\epsilon 是您的容差,如果此条件符合您的容差 0 并适当调整网格,您可以绘制函数。
下面的代码对半径为 1 的圆 (f(x,y)= x^2 + y^2 -1 = 0) 执行此操作。我使用符号 dr 表示 \epsilon。
此外,为了确保 plt.plot 函数以正确的顺序连接线,我将 x 值的反转版本用于负 y 值。这样,f(x,y) 的评估是在顺时针循环中完成的,因此最接近的值是一个接一个。如果没有这个,函数两侧的线会连接起来,并且看起来会稍微填充。
import numpy as np
import matplotlib.pyplot as plt
r = 1 #arbitrary radius to set up the span of points
points = 250
dr = r/points #epsilon window
x=list(np.linspace(-5*r,5*r,5*points+1)) #setting up the x,y grid
y=x
xreversed = reversed(x) #reversing the array
x_0=[] #placeholder arrays
y_0=[]
for i in x:
for j in y:
if i**2 + j**2 -1 < dr and i**2+j**2 -1 > -dr and j >= 0: #positive values of y
x_0.append(i)
y_0.append(j)
for i in xreversed:
for j in y:
if i**2+j**2 -1 < dr and i**2+j**2 -1 > -dr and j < 0: #negative values of y, using x reversed
x_0.append(i)
y_0.append(j)
plt.plot(x_0,y_0)
plt.show()
非常感谢史蒂夫、迈克、亚历克斯。我同意史蒂夫的解决方案(请参阅下面的代码)。我唯一剩下的问题是等高线图出现在我的网格线后面,而不是常规图,我可以用 zorder 将其强制到前面。任何更多的 halp 非常感谢。
干杯,格迪斯
import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator, FormatStrFormatter
import numpy as np
fig = plt.figure(1)
ax = fig.add_subplot(111)
# set up axis
ax.spines['left'].set_position('zero')
ax.spines['right'].set_color('none')
ax.spines['bottom'].set_position('zero')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
# setup x and y ranges and precision
x = np.arange(-0.5,5.5,0.01)
y = np.arange(-0.5,5.5,0.01)
# draw a curve
line, = ax.plot(x, x**2,zorder=100)
# draw a contour
X,Y=np.meshgrid(x,y)
F=X**Y
G=Y**X
ax.contour(X,Y,(F-G),[0],zorder=100)
#set bounds
ax.set_xbound(-1,7)
ax.set_ybound(-1,7)
#produce gridlines of different colors/widths
ax.xaxis.set_minor_locator(MultipleLocator(0.2))
ax.yaxis.set_minor_locator(MultipleLocator(0.2))
ax.xaxis.grid(True,'minor',linestyle='-')
ax.yaxis.grid(True,'minor',linestyle='-')
minor_grid_lines = [tick.gridline for tick in ax.xaxis.get_minor_ticks()]
for idx,loc in enumerate(ax.xaxis.get_minorticklocs()):
if loc % 2.0 == 0:
minor_grid_lines[idx].set_color('0.3')
minor_grid_lines[idx].set_linewidth(2)
elif loc % 1.0 == 0:
minor_grid_lines[idx].set_c('0.5')
minor_grid_lines[idx].set_linewidth(1)
else:
minor_grid_lines[idx].set_c('0.7')
minor_grid_lines[idx].set_linewidth(1)
minor_grid_lines = [tick.gridline for tick in ax.yaxis.get_minor_ticks()]
for idx,loc in enumerate(ax.yaxis.get_minorticklocs()):
if loc % 2.0 == 0:
minor_grid_lines[idx].set_color('0.3')
minor_grid_lines[idx].set_linewidth(2)
elif loc % 1.0 == 0:
minor_grid_lines[idx].set_c('0.5')
minor_grid_lines[idx].set_linewidth(1)
else:
minor_grid_lines[idx].set_c('0.7')
minor_grid_lines[idx].set_linewidth(1)
plt.show()