ipywidgets: избегайте мерцания при использовании взаимодействия

Я сделал рисунок с четырьмя участками гистограммы на основе случайного нормального, гамма, экспоненциального и равномерного распределения соответственно. Я сделал это, используя блокнот matplotlib и Jupyter. Это интерактивная фигура через ipywidgets lib. В частности, есть четыре ползунка, которые управляют размером выборки на каждой гистограмме и соответствующим образом обновляют их. Однако при обновлении гистограмм он раздражающе мерцает. Есть ли способ избежать этого? Спасибо.

Теперь код для запуска на ноутбуке Jupyter:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib notebook
from ipywidgets import *

n = 1000
x1 = np.random.normal(-2.5, 1, n)
x2 = np.random.gamma(2, 1.5, n)
x3 = np.random.exponential(2, n)+7
x4 = np.random.uniform(14,20, n)
x = [x1, x2, x3, x4]

fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(10,7))
axs = [ax1,ax2,ax3,ax4]

titles = ['x1\nNormal', 'x2\nGamma', 'x3\nExponential', 'x4\nUniform']
subplots_axes = [[-7,2,0,250], [0,4.5,0,250], [7,25,0,250], [14,20,0,250]]

bins = [np.arange(-6, 6, 0.5),
np.arange(0, 10, 0.5),
np.arange(7, 17, 0.5),
np.arange(14, 24, 0.5)]

fig.subplots_adjust(hspace=0.5)

def plt_dist(s, sample):
    axs[s].hist(x[s][:sample], bins=bins[s], linewidth=0, color='#1F77B4')
    axs[s].axis(subplots_axes[s])
    axs[s].set_title('{}'.format(titles[s]))
    axs[s].set_ylabel('Frequency')
    axs[s].set_xlabel('Value')
    axs[s].annotate('n = {}'.format(sample), xycoords='axes fraction', xy = [0.8,0.9])
    display(fig)

for s in range(0,4):
    sld_bar = interact(plt_dist, s = fixed(s), sample = widgets.IntSlider(min=100,max=1000+45,step=1,value=100))

person Antonio Serrano    schedule 08.04.2017    source источник


Ответы (1)


Не совсем понятно, что будет делать display(fig) и для чего он нужен.

Для меня удаление этой строки и вместо этого очистка осей (axs[s].clear()) в начале функции plt_hist работает просто отлично, и «мерцания» больше нет.

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib notebook
from ipywidgets import *

n = 1000
x1 = np.random.normal(-2.5, 1, n)
x2 = np.random.gamma(2, 1.5, n)
x3 = np.random.exponential(2, n)+7
x4 = np.random.uniform(14,20, n)
x = [x1, x2, x3, x4]

fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(10,7))
axs = [ax1,ax2,ax3,ax4]

titles = ['x1\nNormal', 'x2\nGamma', 'x3\nExponential', 'x4\nUniform']
subplots_axes = [[-7,2,0,250], [0,4.5,0,250], [7,25,0,250], [14,20,0,250]]

bins = [np.arange(-6, 6, 0.5),
np.arange(0, 10, 0.5),
np.arange(7, 17, 0.5),
np.arange(14, 24, 0.5)]

fig.subplots_adjust(hspace=0.5)

def plt_dist(s, sample):
    axs[s].clear() # <-- clear axes
    axs[s].hist(x[s][:sample], bins=bins[s], linewidth=0, color='#1F77B4')
    axs[s].axis(subplots_axes[s])
    axs[s].set_title('{}'.format(titles[s]))
    axs[s].set_ylabel('Frequency')
    axs[s].set_xlabel('Value')
    axs[s].annotate('n = {}'.format(sample), xycoords='axes fraction', xy = [0.8,0.9])
    #display(fig)  <--- delete this

for s in range(0,4):
    sld_bar = interact(plt_dist, s = fixed(s), 
              sample = widgets.IntSlider(min=100,max=1000+45,step=1,value=100))
person ImportanceOfBeingErnest    schedule 08.04.2017
comment
Я должен использовать display(fig), потому что я хочу обновить фигуру с четырьмя подграфиками, используя цикл for, как в здесь. В противном случае рисунок не отображается. Я пытался использовать plt.cla() раньше, но это не сработало. - person Antonio Serrano; 08.04.2017
comment
Итак, вы можете запустить скрипт из моего ответа или нет? В зависимости от того, работает это или нет, мы можем найти решение для циклов for. - person ImportanceOfBeingErnest; 08.04.2017
comment
Да, я могу. Нет проблем с этим решением. - person Antonio Serrano; 08.04.2017
comment
Итак, я почти уверен, что при использовании display вы всегда будете получать мерцание. Поэтому было бы желательно не использовать его. На данный момент я не понимаю, как его неиспользование должно помешать вам обновить четыре подзаголовка вместо одного. Я думаю, вам следует создать минимально воспроизводимый пример с четырьмя подзаголовками; тогда у вас есть два варианта: (A) обновить этот вопрос новым примером, (B) принять этот ответ и задать новый вопрос о том, что пойдет не так при обновлении четырех подзаголовков. - person ImportanceOfBeingErnest; 08.04.2017
comment
Я собираюсь обновить его. Дайте мне несколько минут. Большое спасибо :) - person Antonio Serrano; 08.04.2017
comment
Сделанный. Посмотрите, пожалуйста. - person Antonio Serrano; 08.04.2017
comment
На самом деле это то же решение, что и для одного участка. Смотрите обновленный ответ. - person ImportanceOfBeingErnest; 08.04.2017
comment
Этот код должен работать до сих пор? Я работаю над той же проблемой, и это, похоже, вообще не обновляет сюжет. - person AturSams; 30.03.2021