I would like to plot implicit equations (of the form f(x, y)=g(x, y) eg. X^y=y^x) in Matplotlib. Is this possible?
问题:
回答1:
I don\'t believe there\'s very good support for this, but you could try something like
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()
See the API docs for contour
: if the fourth argument is a sequence then it specifies which contour lines to plot. But the plot will only be as good as the resolution of your ranges, and there are certain features it may never get right, often at self-intersection points.
回答2:
Since you\'ve tagged this question with sympy, I will give such an example.
From the documentation: 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)
回答3:
matplotlib does not plot equations; it plots serieses of points. You can use a tool like scipy.optimize
to numerically calculate y points from x values (or vice versa) of implicit equations numerically or any number of other tools as appropriate.
For example, here is an example where I plot the implicit equation x ** 2 + x * y + y ** 2 = 10
in a certain region.
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()
回答4:
There is an implicit equation (and inequality) plotter in sympy. It is created as a part of GSoC and it produces the plots as matplotlib figure instances.
Docs at http://docs.sympy.org/latest/modules/plotting.html#sympy.plotting.plot_implicit.plot_implicit
Since sympy version 0.7.2 it is available as:
>>> 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
回答5:
If you\'re willing to use something other than matplotlib (but still python), there\'s sage:
An example: http://sagenb.org/home/pub/1806
Documentation for implicit_plot
The Sage Homepage
回答6:
Many thanks Steve, Mike, Alex. I have gone along with Steve\'s solution (please see code below). My only remaining issue is that the contour plot appears behind my gridlines, as opposed to a regular plot, which I can force to the front with zorder. Any more halp greatly appreciated.
Cheers, Geddes
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()
回答7:
Examples (using the contour approach) for all conic sections are available at http://blog.mmast.net/conics-matplotlib