根据信号位置调整 xrange

Adjust xrange depending on where signal is

假设我有一个数据流,为简单起见,将其设为贝尔曲线,从大范围获取:

import numpy as np
import matplotlib.pyplot as plt


def pdf(x, mean, std):
    """Return a PDF."""
    y_out = 1/(std * np.sqrt(2 * np.pi)) * np.exp(-(x - mean)**2 / (2 * std**2))
    return y_out


x = np.linspace(-1000, 1000, 20000)
y = 100 * pdf(x, 0, 1) + np.random.normal(0, 1, 20000)

fig, ax = plt.subplots()
ax.plot(x, y)

由于 x 范围太大,绘图将只显示一条非常窄的线,无论如何我们不需要在绘图中包含所有噪声。

在这种情况下,通过仅显示范围 [-20, 20] 来绘制它可能是有意义的,例如:ax.set_xlim([-20, 20])。 但是,假设现在我们从另一次收购中得到了类似的东西:

y = 100 * pdf(x, -50, 1) + 100 * pdf(x, 0, 1) + 100 * pdf(x, 40, 1) + np.random.normal(0, 1, 20000)

有了这样的功能,我们可能想要绘制更宽的范围,例如ax.set_xlim([-70, 60]),可视化获取的所有信号。

有没有一种方法可以根据实际信号(即超过某个阈值,比如 10)以编程方式调整限制,而不必先绘制整个范围,然后再手动调整?

使用 argwhere 获取 y 高于特定阈值的索引,例如np.argwhere(y > 10)。在实践中,您可能希望在两侧添加一些边距,例如 200 点:

import numpy as np
import matplotlib.pyplot as plt

def pdf(x, mean, std):
    """Return a PDF."""
    y_out = 1/(std * np.sqrt(2 * np.pi)) * np.exp(-(x - mean)**2 / (2 * std**2))
    return y_out


x = np.linspace(-1000, 1000, 20000)
y = [100 * pdf(x, 0, 1) + np.random.normal(0, 1, 20000),
     100 * pdf(x, -50, 1) + 100 * pdf(x, 0, 1) + 100 * pdf(x, 40, 1) + np.random.normal(0, 1, 20000)]


def get_lims(y, threshold=10, margin=200):
    """Get indices +/- margin where y is above threshold."""
    signal = np.argwhere(y > threshold).flatten()
    return np.clip((signal[0] - margin, signal[-1] + margin), 0, len(y)-1)

fig, ax = plt.subplots(nrows=2)
for i in range(2):
    ax[i].plot(x, y[i])
    ax[i].set_xlim(x[get_lims(y[i])])

与 Stef 的答案非常相似,只是我提出了一个最小宽度和一个额外的百分比,因此边距将取决于您要显示的 x 的数量,而不是边距,因此您可以调整 window_excessmin_width。如果你有很多情节要制作,这样的东西可能会有用。用这个替换 Stef 的 get_lims 函数会得到结果:

def get_lims(y, threshold = 10, window_excess = 0.5, min_width = 100):
    minwidth = min_width / (1 + window_excess)

    a = np.argwhere(y > threshold)
    
    da = max(minwidth, x[a[-1]] - x[a[0]])
    ma = (x[a[-1]] + x[a[0]]) / 2
    minx = ma - da * (1 + window_excess) / 2
    maxx = ma + da * (1 + window_excess) / 2
    return([minx, maxx])

您只需添加一个检查,确保 xminxmax 在 x 的范围内。