2010-03-29 12 views
21

Quando si traccia un grafico con discontinuità/asintoto/singolarità/altro, esiste un modo automatico per impedire a Matplotlib di "unire i punti" attraverso l'interruzione? (vedi codice/immagine sotto).
Ho letto che Sage ha una funzione [detect_poles] che sembra buona, ma voglio davvero che funzioni con Matplotlib.come gestire un asintoto/discontinuità con Matplotlib

import matplotlib.pyplot as plt 
import numpy as np 
from sympy import sympify, lambdify 
from sympy.abc import x 

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 
xx = np.arange(-0.5,5.5,0.01) 

# draw my curve 
myfunction=sympify(1/(x-2)) 
mylambdifiedfunction=lambdify(x,myfunction,'numpy') 
ax.plot(xx, mylambdifiedfunction(xx),zorder=100,linewidth=3,color='red') 

#set bounds 
ax.set_xbound(-1,6) 
ax.set_ybound(-4,4) 

plt.show() 

Discontinuity

+1

Grazie per questo domanda; sebbene tu l'abbia etichettato 'python', sii consapevole che è più generalmente una domanda' matplotlib'; Ho usato me stesso una delle risposte di Julia piuttosto che Python. Saluti. –

risposta

11

Questo non può essere la soluzione elegante che si sta cercando, ma se vogliono solo risultato per la maggior parte dei casi, è possibile "clip" grande e piccoli valori dei dati tracciati rispettivamente a +∞ e -∞. Matplotlib non traccia questi. Ovviamente devi stare attento a non rendere la tua risoluzione troppo bassa o la soglia di clipping troppo alta.

utol = 100. 
ltol = -100. 
yy = 1/(xx-2) 
yy[yy>utol] = np.inf 
yy[yy<ltol] = -np.inf 

ax.plot(xx, yy, zorder=100, linewidth=3, color='red') 
+0

Funziona molto bene. Si potrebbe anche usare 'np.nan' invece di' np.inf' se si avesse un altro motivo per evitare '∞' – MackM

5

No, penso che non c'è modo built-in per dire matplotlib di ignorare questi punti. Dopo tutto, collega solo i punti e non sa nulla delle funzioni o di ciò che accade tra i punti.

Tuttavia, è possibile utilizzare sympy per trovare i poli, quindi applicare i pezzi continui della funzione. Ecco alcuni certamente brutto codice che fa esattamente questo:

from pylab import * 
from sympy import solve 
from sympy.abc import x 
from sympy.functions.elementary.complexes import im 

xmin = -0.5 
xmax = 5.5 
xstep = 0.01 

# solve for 1/f(x)=0 -- we will have poles there 
discontinuities = sort(solve(1/(1/(x-2)),x)) 

# pieces from xmin to last discontinuity 
last_b = xmin 
for b in discontinuities: 
    # check that this discontinuity is inside our range, also make sure it's real 
    if b<last_b or b>xmax or im(b): 
     continue 
    xi = np.arange(last_b, b, xstep) 
    plot(xi, 1./(xi-2),'r-') 
    last_b = b 

# from last discontinuity to xmax 
xi = np.arange(last_b, xmax, xstep) 
plot(xi, 1./(xi-2),'r-') 

xlim(xmin, xmax) 
ylim(-4,4) 
show() 

example http://i43.tinypic.com/30mvbzb.jpg

+0

Questo è molto limitato nell'applicabilità: se la funzione era tan (x) invece di 1/(x-2), il comando solve non troverebbe radici di 1/tan (x). Funziona solo qui perché 1/(1/(x-2)) è semplificato in x-2. –

20

Utilizzando masked arrays si può evitare di tracciare regioni selezionate di una curva.

Per rimuovere la singolarità in x = 2:

import matplotlib.numerix.ma as M # for older versions, prior to .98 
#import numpy.ma as M    # for newer versions of matplotlib 
from pylab import * 

figure() 

xx = np.arange(-0.5,5.5,0.01) 
vals = 1/(xx-2)   
vals = M.array(vals) 
mvals = M.masked_where(xx==2, vals) 

subplot(121) 
plot(xx, mvals, linewidth=3, color='red') 
xlim(-1,6) 
ylim(-5,5) 

Questo semplice curva potrebbe essere un po 'più chiara su cui sono esclusi i punti:

xx = np.arange(0,6,.2) 
vals = M.array(xx) 
mvals = M.masked_where(vals%2==0, vals) 
subplot(122) 
plot(xx, mvals, color='b', linewidth=3) 
plot(xx, vals, 'rx') 
show() 

enter image description here

+0

perché quando eseguo il codice ottengo ancora la linea verticale diritta che collega le curve rosse? –

Problemi correlati