Python; карта с учетом исключений () - PullRequest
9 голосов
/ 30 марта 2011

Я делаю некоторые пиплоты общих данных и преобразовываю их из значения мощности в значение в дБ. Из-за системы, из которой берутся эти значения, 0 используется как индикатор «полезные данные заканчиваются здесь» (характер математики, а не определенное значение).

Мой обычный способ справиться с этим - заключить конвертацию в попытку / исключение и вернуть значение по умолчанию 'low', например

def f(value):
    try:
        return convert(value)
    except ValueError:
        return -140 #implementation specific, don't worry

Это нормально и прекрасно для 90% использования в моей среде, кроме случаев, когда речь идет о графике.

Я ленивый, так что я делаю в минуту:

pl.plot(xvals,map(f,yvals))

Это рисует данные правильно, а когда данные заканчиваются, падает с обрыва, что является ожидаемым поведением. Но я хотел бы, чтобы граф просто заканчивал , когда он встречает исключение ValueError и полностью исключает f ().

Кроме разрыва карты на части, у кого-нибудь есть какие-нибудь блестящие идеи?

ОБНОВЛЕНИЕ:

Я использую Pylab / MatplotLib «Конечная точка» зависит от исполнения; иногда все вышеперечисленное не имеет значения, поскольку нет «плохих» значений. Это все для меня, чтобы быть ленивым и использовать масштабирование графиков matplotlibs вместо того, чтобы сбрасывать динамические значения ylim на основе минимума ydata (который я не делаю atm, в данном случае просто ylim (-140).)

Неопределенно важное обновление при ответе: Ответ unutbu - это то, что я на самом деле буду использовать для своей реализации, потому что (не упомянутое в вопросных зависимостях), так как повышение StopIteration в этой регулярно используемой функции приводит к хаосу с несвязанной с вопросом логикой управления, не помещая все из этих других случаев в try-excepts; иногда -инф имеет больше смысла, чем вы думаете.

Спасибо всем за то, что вы были невероятно быстры, и я прошу прощения у unutbu за вопрос без ответа.

Ответы [ 4 ]

10 голосов
/ 30 марта 2011

Возможно, есть какая-то хитрость в библиотеке графиков, но гораздо лучшие варианты, кажется, не генерируют такие данные для начала.Дело не в том, что map экономит вам тридцать строк кода ...

Используйте itertools.takewhile(lambda y: y != NO_VALUE, (f(y) for y in yvals)) (и оберните его в вызов list, если для библиотеки черчения требуется список вместо итерируемого).

Редактировать: У меня была еще лучшая идея: в оболочку добавить

except ValueError:
    raise StopIteration

Это исключение, сигнализирующее "конец итерации", и map уважает его.

2 голосов
/ 30 марта 2011

Если вы используете matplotlib, то это означает, что у вас установлено numpy.

Поскольку вы конвертируете в dB, похоже, что вы ведете журнал. В этом случае np.log(0) = -inf.

Вы можете маскировать nans и infs с помощью функции numpy np.ma.masked_invalid , а matplotlib может отображать замаскированные массивы. Например,

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

дает enter image description here

Обратите внимание, что график заканчивается на xval, равном 89, поскольку последние 10 значений yval замаскированы.

1 голос
/ 30 марта 2011

Вы без необходимости ограничиваете себя, отказываясь использовать циклическую конструкцию.

В вашей ситуации вы хотите прекратить перебирать данные при достижении определенного значения, что и является целью forloops иbreaks

yvals_ = []
for y in yvals:
    y_ = f(y)
    if y_ == -140:
        break
    else:
        yvals_.append(y_)

p1.plot(xvals[:len(yvals_)],yvals_)
0 голосов
/ 30 марта 2011

Похоже, у вас есть данные, и вы не хотите строить последнюю точку. Так что насчет того, чтобы не строить его?

pl.plot(xvals[:-1], map(f, yvals)[:-1])
...