使用ipywidget具有两个参数和相互依赖的数据的交互式绘图

时间:2019-09-19 12:11:33

标签: python matplotlib jupyter-notebook ipywidgets

我想创建一个jupyter-notebook单元格,其中显示了一个带有matplotlib的交互式图,以说明噪声信号的平滑处理。在下面的示例中,我使用了scikit-image中的高斯滤波器。我希望可以通过滑块调整噪声水平和平滑程度。为此,我使用了ipywidgets

最初我尝试了以下方法

import ipywidgets as widgets
import matplotlib.pyplot as plt
import numpy as np
import skimage
%matplotlib inline

def plot_noise_filter(signal,cnts,sigma):
    s = signal/np.sum(signal)*cnts  #normalize the signal to have cnts counts
    noise = np.random.poisson(s)    #randomly generate poissonian noise
    filtered = skimage.filters.gaussian(noise,sigma)   #filter noisy signal with gauss filter
    f,ax = plt.subplots()                              #plot
    ax.plot(noise/np.max(noise))
    ax.plot(filtered/np.max(filtered))

c_slide = widgets.IntSlider(min=100,max=10000,step=10,description='counts')
s_slide = widgets.IntSlider(min=1,max=100,description='smoothing')

sig = np.heaviside(np.linspace(-1,1,100),1)+1
widgets.interact(plot_noise_filter,signal=widgets.fixed(sig),cnts=c_slide,sigma=s_slide)

原则上,这给了我想要的绘图,但是现在每次使用滑块s_slide时,都会调用该函数,并且即使计数没有更改,也会生成一个新的随机信号。我希望图中的噪声信号仅在相应的滑块移动时才改变。

我能想到的唯一解决方法是,事先将噪声信号计算并存储到一个数组中,然后根据滑块选择该数组中的元素,但这不是很优雅,并且可能会占用大量内存。

我当前的安装使用的是conda和python 3.7.3

ipywidgets                7.5.1
matplotlib                3.1.1
jupyter                   1.0.0
jupyter_client            5.3.1
jupyter_console           6.0.0
jupyter_core              4.4.0
notebook                  6.0.1
numpy                     1.17.2

欢迎任何帮助。预先感谢!

1 个答案:

答案 0 :(得分:0)

首先,感谢您提供了非常清晰且可运行的示例。

如何使用lru_cache将信号和噪声生成线提取到缓存的函数中?然后,对于给定的signalcnts输入,这部分将始终返回相同的值,仅留下平滑度即可随着移动该滑块而改变。

import ipywidgets as widgets
import matplotlib.pyplot as plt
import numpy as np
import skimage
%matplotlib inline
from functools import lru_cache

@lru_cache(32)
def make_sig_noise(signal, cnts):
    s = signal/np.sum(signal)*cnts  #normalize the signal to have cnts counts
    noise = np.random.poisson(s)    #randomly generate poissonian noise
    return s, noise

def plot_noise_filter(signal,cnts,sigma):
    s, noise = make_sig_noise(tuple(signal), cnts)
    filtered = skimage.filters.gaussian(noise,sigma)   #filter noisy signal with gauss filter
    f,ax = plt.subplots()                              #plot
    ax.plot(noise/np.max(noise))
    ax.plot(filtered/np.max(filtered))

c_slide = widgets.IntSlider(min=100,max=10000,step=10,description='counts')
s_slide = widgets.IntSlider(min=1,max=100,description='smoothing')

sig = np.heaviside(np.linspace(-1,1,100),1)+1
widgets.interact(plot_noise_filter,signal=widgets.fixed(sig),cnts=c_slide,sigma=s_slide)