Pitón;mapa consciente de excepciones ()
-
14-11-2019 - |
Pregunta
Estoy haciendo un pyploting de datos genéricos y convertirlo de un valor de potencia a un valor de dB.Debido al sistema del que provienen estos valores, 0 se utiliza como indicador de "los datos útiles terminan aquí" (la naturaleza de las matemáticas, no un valor definido).
Mi forma habitual de lidiar con esto es envolver la conversión en un intento/excepto y devolver un valor "bajo" predeterminado, por ejemplo
def f(value):
try:
return convert(value)
except ValueError:
return -140 #implementation specific, don't worry
Esto está muy bien para el 90% del uso dentro de mi marco, excepto cuando se trata de gráficos.
Soy vago así que lo que hago en este momento es:
pl.plot(xvals,map(f,yvals))
Esto extrae los datos correctamente y, cuando terminan, se precipita por un precipicio, que es el comportamiento esperado.Pero lo que me gustaría que sucediera es que el gráfico simplemente fin cuando se encuentra con una excepción ValueError y elimina f() por completo.
Aparte de dividir el mapa en un bucle, ¿alguien tuvo alguna idea brillante?
ACTUALIZACIONES:
Estoy usando pylab / matplotlib "Endpoint" es dependiente de la ejecución;A veces lo anterior no importa en absoluto ya que no existen valores "malos".Todo esto es en un esfuerzo por ser vago y usar la escala de gráficos matplotlibs en lugar de restablecer los ylim dinámicos en función del mínimo de ydata (lo cual no hago en cajeros automáticos, solo ylim (-140) en este caso).
Actualización vagamente importante sobre la respuesta:La respuesta de unutbu es lo que realmente usaré para mi implementación, debido a (no mencionado en las dependencias de la pregunta), ya que generar un StopIteration en esta función utilizada regularmente causa estragos en la lógica de control no relacionada con la pregunta, sin poner todo de esas otras instancias en try-excepts;A veces -inf tiene más sentido de lo que piensas.
Gracias a todos por ser increíblemente rápidos y le pido disculpas a unutbu por el QuestionFail.
Solución
Quizás haya algún truco en la biblioteca de trazado, pero, para empezar, parece que una opción mucho mejor no genera dichos datos.No es eso map
te ahorra treinta líneas de código...
Usar itertools.takewhile(lambda y: y != NO_VALUE, (f(y) for y in yvals))
(y envolverlo en una llamada a list
si la biblioteca de trazado requiere una lista en lugar de un iterable).
Editar:Tuve una idea aún mejor:En el envoltorio, agregue
except ValueError:
raise StopIteration
Esa es la excepción que indica "fin de iteración", y map
lo respeta.
Otros consejos
Si estas usando matplotlib
, entonces implica que tienes numpy
instalado.
Ya que estás convirtiendo a dB
, parece que podrías estar tomando un registro.En ese caso, np.log(0) = -inf
.
Puedes enmascarar nans e infs con la función numpy np.ma.masked_invalid, y matplotlib
puede trazar matrices enmascaradas.Por ejemplo,
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()
rendimientos
Observe que el gráfico termina con xval
igual a 89, ya que los últimos 10 valores de yval
están enmascarados.
Te estás limitando innecesariamente al negarte a utilizar una construcción en bucle.
En su situación, desea dejar de iterar sobre los datos cuando se alcanza un cierto valor, ese es exactamente el propósito de forloops
y breaks
yvals_ = []
for y in yvals:
y_ = f(y)
if y_ == -140:
break
else:
yvals_.append(y_)
p1.plot(xvals[:len(yvals_)],yvals_)
Parece que tienes datos y no quieres trazar el último punto.Entonces, ¿qué tal si no lo planeamos?
pl.plot(xvals[:-1], map(f, yvals)[:-1])