matplotlib / matplotlib/ipympl

Closed Figure's state is silently changed in HTML export when plotting asynchronously

未关闭
#584 6 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

bug
主要语言
Jupyter Notebook
星标
1.7k
派生
234
PR 合并指标
30 天内没有已合并 PR

描述

Describe the issue

I know, this is a seemingly contrived example, but it's a real-world problem for me.

See attached Notebook and according HTML export
issue.zip

I'm running the notebook cell by cell, where I only start the next cell when the previous animation has been finished. The animation stops automatically. The code for animation is:

def runPlot(duration):
    plt.close('all')
    fig = plt.figure(1)
    t = np.linspace(0, 1, 100)
    data_line = plt.plot(t, np.sin(6.28*2*t))[0]
    
    def _impl():
        start = time.time()
        it = 0
        while time.time() - start < duration:
            freq = time.time() - start
            if it == 0:
                data_line.set_ydata(t)
            else:
                data_line.set_ydata(np.sin(6.28*t*freq))
            it = it + 1
                
            fig.canvas.draw()   
            time.sleep(0.03)
        
        
    T = threading.Thread(target=_impl)
    T.start()

Within this code, a thread is started which shows a figure and continuously updates the ydata of the plotted line. The cell immediately returns, but the thread runs for the given amount of seconds. This leads to an animation in the notebook. Note that in the first iteration, a linear line is plotted instead of the sine wave. After running all cells, the notebook looks like this:
image

Upon pressing save and exporting to HTML, the exported HTML looks like this:
image

Apparently, for the HTML export, the state of the first plot widget has been replaced by the data that was first set by set_ydata. Adding more calls to runPlot only keeps the last figure in the correct shape for export, whereas the other figures contain the data initially set by set_ydata.

The problem does not happen when I create a new figure without a number all the time, i.e. replace this

    plt.close('all')
    fig = plt.figure(1)

with

fig = plt.figure()

However, as all figures are closed by close('all'), no data should be changed in previously open figures anymore.

Versions

$ python -c "import sys; print('\n',sys.version); import ipympl; print('ipympl version:', ipympl.__version__)" && jupyter --version && jupyter nbextension list && jupyter labextension list

 3.13.1 (main, Dec 19 2024, 10:35:14) [GCC 11.1.0]
ipympl version: 0.9.5
Selected Jupyter core packages...
IPython          : 8.30.0
ipykernel        : 6.29.5
ipywidgets       : 8.1.5
jupyter_client   : 8.6.3
jupyter_core     : 5.7.2
jupyter_server   : 2.14.2
jupyterlab       : 4.3.4
nbclient         : 0.10.2
nbconvert        : 7.16.4
nbformat         : 5.10.4
notebook         : 7.3.1
qtconsole        : not installed
traitlets        : 5.14.3

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

调研方向

从随附的 notebook 和 HTML 导出文件开始,使用所报告的 Python、ipympl、Jupyter 和 ipywidgets 版本。使用编号的 figure 重现异步动画,并将其与每次创建新 figure 的情况进行比较。当导出的 HTML 保留每个先前已关闭 figure 的最终状态,而不是显示第一个 set_ydata 值时,即表示完成。

由索引模型根据 Issue 内容生成。

评估

技术栈
jupyter-notebook, python
领域
frontend
Issue 类型
缺陷
难度
4/5
预计耗时
3-5 天
活跃度
停滞
描述清晰度
基本清楚
新手友好度
35/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。