Python;EXCEPTION CADITION CARTE ()
-
14-11-2019 - |
Question
Je fais du pyplotting des données génériques et de la convertir d'une valeur de puissance en une valeur de dB. En raison du système, ces valeurs proviennent, 0 est utilisée comme indicateur "Les données utiles ici" (la nature des mathématiques, pas une valeur définie).
Ma façon habituelle de traiter avec celles-ci est en train d'envelopper la conversion en essayant / sauf et de retourner une valeur «basse» par défaut, par exemple
def f(value):
try:
return convert(value)
except ValueError:
return -140 #implementation specific, don't worry
C'est bon et dandy pour 90% d'une utilisation dans mon cadre, sauf en ce qui concerne le graphique.
Je suis paresseux alors ce que je fais à la minute est:
pl.plot(xvals,map(f,yvals))
Ceci dessine correctement les données et lorsque les données se termine, plongeant une falaise, qui est le comportement attendu. Mais ce que j'aimerais arriver, c'est que le graphique soit juste finalement quand il rencontre une exception de ValueError et élimine complètement avec F ().
Autre que briser la carte dans une boucle, tout le monde a obtenu des idées brillantes?
mises à jour:
J'utilise pylab / matplotlib "Terminal" est dépendant de l'exécution; Parfois, ce qui précède n'a pas d'importance, car il n'y a pas de valeurs «mauvaises». C'est tout dans un effort pour moi d'être paresseux et d'utiliser Matplotlibs graphique à la mise à l'échelle au lieu de réinitialiser les YLIM dynamiques basé sur la minute de l'ydata (que je ne fais pas ATM, juste Ylim (-140) dans ce cas.)
Mise à jour vaguement importante sur la réponse: La réponse de tsutbu est ce que j'aurai réellement utiliser pour ma mise en œuvre, en raison de (non mentionné dans les dépendances de la question), comme élever une stariterie dans cette fonction régulièrement utilisée gagne des ravages avec une logique de contrôle non liée à la question, sans mettre tout de ces autres cas en essayant-sauf; parfois -inf a plus de sens que vous ne le pensez.
Merci à tout le monde pour être rapide, et je m'excuse à Outbu pour le questionnaire.
La solution
Perhaps there's some trick in the plotting library, but a much better options seems not generating such data to begin with. It's not that map
saves you thirty lines of code...
Use itertools.takewhile(lambda y: y != NO_VALUE, (f(y) for y in yvals))
(and wrap it in a call to list
if the plotting library requires a list instead of an iterable).
Edit: I had an even better idea: In the wrapper, add
except ValueError:
raise StopIteration
That's the exception signaling "end of iterale", and map
respects it.
Autres conseils
If you are using matplotlib
, then it implies you have numpy
installed.
Since you are converting to dB
, it sounds like you might be taking a log. In that case, np.log(0) = -inf
.
You can mask nans and infs with the numpy function np.ma.masked_invalid, and matplotlib
can plot masked arrays. For example,
import matplotlib.pyplot as plt
import numpy as np
xvals=np.arange(100)
yvals=np.cumsum(np.random.random(100))
yvals[-10:]=0
yvals=np.log(yvals)
print(yvals[-10:])
# [-Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf -Inf]
yvals=np.ma.masked_invalid(yvals)
plt.plot(xvals,yvals)
plt.show()
yields
Notice that the graph ends with xval
equal to 89, since the last 10 values of yval
are masked.
You're needlessly limiting yourself by refusing to use a looping construct.
In your situation you want to stop iterating over data when a certain value is reached, that is exactly the purpose of forloops
and breaks
yvals_ = []
for y in yvals:
y_ = f(y)
if y_ == -140:
break
else:
yvals_.append(y_)
p1.plot(xvals[:len(yvals_)],yvals_)
It seems like you have data, and you don't want to plot the last point. So what about not plotting it?
pl.plot(xvals[:-1], map(f, yvals)[:-1])