2010-03-20 9 views

risposta

18

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.

+0

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. –

6

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() 
1

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() 
+0

@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

14

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) 
+1

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). –

4

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 
+0

Sembra che sia stato rilasciato ora. :) –

+0

Da dove proviene 'the_matplotlib_axes_instance'? – theV0ID

+0

'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