9

我正在对通用数据进行一些 pyplotting并将其从功率值转换为 dB 值。由于这些值来自系统,0 被用作“有用数据到此结束”的指示符(数学的性质,不是定义的值)。

我通常的处理方法是将转换包装在 try/except 中并返回默认的“低”值,例如

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图形缩放而不是根据ydata的最小值重置动态ylim(在这种情况下我不做atm,只是ylim(-140)。)

关于答案的模糊重要更新:unutbu 的答案是我实际将用于我的实现的,因为(在问题依赖项中没有提到),因为在这个经常使用的函数中引发 StopIteration 会对与问题无关的问题造成严重破坏控制逻辑,而不将所有其他实例放在 try-excepts 中;有时 -inf 比你想象的更有意义。

感谢大家的速度非常快,我为 QuestionFail 向 unutbu 道歉。

4

4 回答 4

10

也许绘图库中有一些技巧,但是更好的选择似乎一开始就不会生成这样的数据。这不是为map您节省了三十行代码......

使用(如果绘图库需要列表而不是可迭代,则将其itertools.takewhile(lambda y: y != NO_VALUE, (f(y) for y in yvals))包装在调用中)。list

编辑:我有一个更好的主意:在包装器中,添加

except ValueError:
    raise StopIteration

这是异常信号“迭代结束”,并map尊重它。

于 2011-03-30T17:02:17.470 回答
2

如果您正在使用matplotlib,则表示您已numpy安装。

由于您正在转换为dB,因此听起来您可能正在记录日志。在这种情况下,np.log(0) = -inf

您可以使用 numpy 函数np.ma.masked_invalid屏蔽 nans 和 infs ,并且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()

产量 在此处输入图像描述

请注意,该图以xval等于 89 结尾,因为 的最后 10 个值yval被屏蔽了。

于 2011-03-30T17:04:53.830 回答
1

您通过拒绝使用循环构造来不必要地限制自己。

在您的情况下,您希望在达到某个值时停止迭代数据,这正是和的forloops目的breaks

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

p1.plot(xvals[:len(yvals_)],yvals_)
于 2011-03-30T17:07:38.420 回答
0

似乎您有数据,并且您不想绘制最后一点。那么不绘制呢?

pl.plot(xvals[:-1], map(f, yvals)[:-1])
于 2011-03-30T17:00:49.573 回答