【问题标题】:ipywidgets: avoid flickering when using interactipywidgets:使用交互时避免闪烁
【发布时间】:2017-09-03 16:46:03
【问题描述】:

我分别根据随机正态分布、伽马分布、指数分布和均匀分布制作了一个直方图的四个子图。我使用 matplotlib 和 Jupyter notebook 制作了它。它是一个通过 ipywidgets lib 的交互式图形。特别是,有四个滑动条控制每个直方图上的样本大小并相应地更新它们。但是,在更新直方图时,它会令人讨厌地闪烁。有没有办法避免这种情况?谢谢。

现在要在 jupyter notebook 上运行的代码:

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

【问题讨论】:

    标签: python matplotlib jupyter-notebook ipywidgets


    【解决方案1】:

    目前还不清楚display(fig) 会做什么或需要什么。

    对我来说,删除那条线并在 plt_hist 函数的开头清除轴 (axs[s].clear()) 工作正常,“闪烁”不再存在。

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

    【讨论】:

    • 我必须使用 display(fig),因为我想使用 for 循环来更新具有四个子图的图形,就像在 here 中一样。否则图不显示。我之前尝试使用plt.cla(),但它不起作用。
    • 那么,您能否根据我的回答运行脚本?根据这是否有效,我们可以找到 for 循环的解决方案。
    • 是的,我可以。该解决方案没问题。
    • 好的,所以我很确定您在使用display 时总会得到一些闪烁。因此最好不要使用它。目前,我看不出不使用它会如何阻止您更新四个子图,而不仅仅是一个。我认为你应该用四个子图创建一个minimal reproducible example;然后您有两个选择:(A) 使用新示例更新此问题,(B) 接受此答案并询问有关更新四个子图时出了什么问题的新问题。
    • 我要更新它。给我几分钟。很多谢谢 :)
    【解决方案2】:

    如果其他人遇到此问题,在您的交互功能中使用打印语句也会导致闪烁。

    fig, ax = plt.subplots()
    @widgets.interact
    def run(
        a = 1.2,
    ):
        ax.clear()
        print(1) # Comment this line to stop flickering
        ax.plot([1,2,3])
        display(fig)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-07-14
      • 2023-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-12
      • 1970-01-01
      相关资源
      最近更新 更多