2010-03-29 5 views
21

Lors du tracé d'un graphique avec une discontinuité/asymptote/singularité/quoi que ce soit, existe-t-il un moyen automatique d'empêcher Matplotlib de «joindre les points» à travers le 'break'? (veuillez voir le code/image ci-dessous).
J'ai lu que Sage a une fonction [detect_poles] qui a l'air bien, mais je veux vraiment que cela fonctionne avec Matplotlib.comment gérer une asymptote/discontinuité avec 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

Merci pour cette question; bien que vous l'ayez marqué 'python', sachez qu'il s'agit plus généralement d'une question' matplotlib'; Je me suis servi l'une des réponses de Julia plutôt que de Python. Cordialement. –

Répondre

11

Cela peut ne pas être la solution élégante que vous recherchez, mais si vous voulez juste des résultats pour la plupart des cas, vous pouvez « clip » grand petites valeurs de vos données tracées à +∞ et -∞ respectivement. Matplotlib ne pas les tracer. Bien sûr, vous devez faire attention de ne pas faire votre résolution trop basse ou votre seuil d'écrêtage trop élevé.

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

Cela fonctionne très bien. Vous pouvez également utiliser 'np.nan' à la place de' np.inf' si vous aviez une autre raison d'éviter '∞' – MackM

5

Non, je pense qu'il n'y a aucun moyen intégré pour dire matplotlib d'ignorer ces points. Après tout, il suffit de connecter des points et ne sait rien sur les fonctions ou ce qui se passe entre les points.

Toutefois, vous pouvez utiliser sympy pour trouver les pôles, puis patcher les pièces continues de votre fonction ensemble. Voici un code certes laid qui fait exactement cela:

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

Ceci est très limité dans l'applicabilité: si la fonction était tan (x) au lieu de 1/(x-2), la commande solve ne trouverait aucune racine de 1/tan (x). Cela ne fonctionne que parce que 1/(1/(x-2)) est simplifié en x-2. –

20

En utilisant masked arrays vous pouvez éviter de tracer les régions sélectionnées d'une courbe.

Pour supprimer la singularité en 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) 

Cette courbe simple pourrait être un peu plus clair sur lequel les points sont exclus:

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

pourquoi est-ce que lorsque je lance votre code, j'obtiens toujours la droite verticale reliant les courbes rouges? –

Questions connexes