интерактивный график с двумя параметрами и взаимозависимыми данными с использованием ipywidget - PullRequest
1 голос
/ 19 сентября 2019

Я хотел бы создать ячейку 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 голосов
/ 20 сентября 2019

Во-первых, спасибо за очень понятный и работоспособный пример.

Как насчет извлечения линий, генерирующих сигналы и шумы, в кешированную функцию, используя lru_cache?Тогда эта часть всегда будет возвращать одно и то же значение для заданного входа signal и cnts, оставляя только сглаживание, которое нужно изменить при перемещении этого ползунка.

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