Vorrei tracciare equazioni implicite (della forma f (x, y) = g (x, y) ad esempio X^y = y^x) in Matplotlib. È possibile?E 'possibile tracciare equazioni implicite usando Matplotlib?
risposta
Non credo ci sia molto buon supporto per questo, ma si potrebbe provare qualcosa di simile
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()
Vedere la API docs per contour
: se il quarto argomento è una sequenza poi specifica che le curve di livello per tracciare . Ma la trama sarà valida solo come la risoluzione dei tuoi intervalli, e ci sono alcune caratteristiche che potrebbero non avere mai ragione, spesso nei punti di auto-intersezione.
matplotlib non calcola le equazioni; traccia delle serie di punti. È possibile utilizzare uno strumento come scipy.optimize
per calcolare numericamente i punti y dai valori x (o viceversa) delle equazioni implicite numericamente o un numero qualsiasi di altri strumenti, a seconda dei casi.
Ad esempio, ecco un esempio dove tracciare l'equazione implicita x ** 2 + x * y + y ** 2 = 10
in una certa regione.
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()
Se siete disposti a usare qualcosa di diverso matplotlib (ma ancora python), c'è la salvia:
Un esempio: http://sagenb.org/home/pub/1806
Molti grazie Steve, Mike, Alex. Ho seguito la soluzione di Steve (vedi il codice sotto). Il mio unico problema è che la trama del contorno appare dietro la mia griglia, al contrario di una trama regolare, che posso forzare in avanti con zorder. Ogni altra poppa è molto apprezzata.
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()
@Geddes, sembra che il supporto per il contorno rispetto allo zorder sia stato aggiunto solo di recente al sorgente matplotlib. Dal loro trunk SVN: http://matplotlib.svn.sourceforge.net/viewvc/matplotlib?view = rev & revision = 8098 – Mark
Dal momento che hai codificato a questa domanda con sympy, darò un esempio.
Dalla documentazione: http://docs.sympy.org/modules/plotting.html.
from sympy import var, Plot
var('x y')
Plot(x*y**3 - y*x**3)
Sembra che la nuova sintassi sia 'plot_implicit (Eq (x ** 5 + y ** 5, 1))', e il nuovo link doc [è qui] (http: //docs.sympy .org/ultima/modules/plotting.html). –
C'è un plotter implicito (e disequazione) in sympy. È creato come parte di GSoC e produce i grafici come istanze di figure matplotlib.
Documenti a http://docs.sympy.org/latest/modules/plotting.html#sympy.plotting.plot_implicit.plot_implicit
A partire dalla versione 0.7.2 sympy è disponibile come:
>>> 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
Sembra che sia stato rilasciato ora. :) –
Da dove proviene 'the_matplotlib_axes_instance'? – theV0ID
'p' è la trama che hai creato. 'p._backend._ax' sarebbe un'istanza di assi e, se lo desideri, puoi farne riferimento in una nuova variabile e usarlo per qualsiasi cosa tu voglia usare un'istanza di assi matplotlib. – Krastanov
Questa è una buona soluzione. La mia soluzione è un modo più manuale di ottenere lo stesso pezzo di informazione usando lo stesso concetto sottostante: impostare l'equazione implicita come f (x, y) tale che f (x, y) = 0 è equivalente all'equazione implicita originale e isolando il suo contorno zero. –