如何保存 Jupyter html 输出的图像快照?

Posted

技术标签:

【中文标题】如何保存 Jupyter html 输出的图像快照?【英文标题】:How to save image snapshot for Jupyter html output? 【发布时间】:2020-05-08 09:31:08 【问题描述】:

假设我在查看时使用itkwidgets,我看到:

但将其保存到 GitHub 会得到如下内容:

另一个直播example。所以我想知道应该实现什么来保持用户的 View 交互,同时在保存文件时(在 GitHub 上)保持 GitHub 可预览的 2d 图像快照?

所以,换句话说,假设我有一个函数,它有一个 return like so

    #...
    return html(Show("<inline url='./"+temp_file_name+"'> </inline> "))

并且我们希望为它提供静态图像数据以在笔记本不存在的情况下进行渲染。如何/通过什么可以做这样的事情?

【问题讨论】:

我想知道解决方案是否与在提交之前保存小部件状态('Widgets' -> 'Save Notebook Widget State')有关?这种策略帮助我应对了类似的挑战,尽管不是这个具体的。 【参考方案1】:

PhantomJS 可以帮你截屏。当你的 notebook 运行时,PhantomJS 浏览器会打开它并对指定的输出单元格进行截图:

PhantomJS 的 JS 文件:

// address of the notebook
var address = "http://localhost:8888/notebooks/Untitled.ipynb";
// auth token from Jupyter console
var authToken = "af6bc1d90688bb6c26aeb206b8690e4855d27ef8d265b1bc";
// cell number with a widget output
var cellNumber = 10;

// this function is used to verify that a page is fully loaded
// source: https://github.com/ariya/phantomjs/blob/master/examples/waitfor.js
function waitFor(testFx, onReady, timeOutMillis) 
    var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 3000,
        start = new Date().getTime(),
        condition = false,
        interval = setInterval(function() 
            if ( (new Date().getTime() - start < maxtimeOutMillis) && !condition ) 
                // If not time-out yet and condition not yet fulfilled
                condition = (typeof(testFx) === "string" ? eval(testFx) : testFx());
             else 
                if(!condition) 
                    // If condition still not fulfilled (timeout but condition is 'false')
                    console.log("'waitFor()' timeout");
                    phantom.exit(1);
                 else 
                    // Condition fulfilled (timeout and/or condition is 'true')
                    console.log("'waitFor()' finished in " + (new Date().getTime() - start) + "ms.");
                    typeof(onReady) === "string" ? eval(onReady) : onReady();
                    clearInterval(interval); //< Stop this interval
                
            
        , 250); //< repeat check every 250ms
;

// log in to a notebook using a token
function logIn() 
    console.log("Logging in");
    page.evaluate(function(token) 
        document.forms[0].password.value = token;
        document.forms[0].submit();
    , authToken);


// wait for a notebook to fully load, find the
// needed output cell and save it as a PNG file
function saveAsPNG() 
    console.log("Saving PNG")
    // Wait for 'notebook-container' to be visible
    waitFor(function() 
        // Check in the page if a specific element is now visible
        return page.evaluate(function() 
            return $("#notebook-container").is(":visible");
        );
    , function() 
        console.log("The notebook-container element should be visible now.");
        var clipRect = page.evaluate(function(cell)
            // we are selecting only the output cell
            var searchStr = 'div.input_prompt:contains("[' + cell + ']:")';
            var parentCell = $(searchStr).parents('div.cell')[0];
            // get only the data div
            var outputSubarea = $(parentCell).find('div.output_subarea')[0];
            // get the coordinates of the data div
            return outputSubarea.getBoundingClientRect()
        , cellNumber);

        page.clipRect = 
            top:    clipRect.top,
            left:   clipRect.left,
            width:  clipRect.width,
            height: clipRect.height
          ;
       page.render('example.png');
       phantom.exit();
    );


var page = require('webpage').create();
// it seems, viewportSize should fully cover the
// the rendered div position, or nothing will be saved.
page.viewportSize =  width: 5000, height: 5000 ;

page.open(address, function (status) 
    // Check for page load success
    if (status !== "success") 
        console.log("Unable to open a page");
     else 
        // Wait for 'password_input' to be visible
        waitFor(function() 
            // Check in the page if a specific element is now visible
            return page.evaluate(function() 
                return $("#password_input").is(":visible");
            );
        , function() 
           console.log("The password_input element should be visible now.");
           logIn();
           saveAsPNG();
        );
    
);

在脚本中指定你的 notebook 的地址、auth token 和 cell 号码,然后用 phantomjs 运行它:

phantomjs script.js

【讨论】:

以上是关于如何保存 Jupyter html 输出的图像快照?的主要内容,如果未能解决你的问题,请参考以下文章

如何拍摄由 Python-tkinter 创建的正在运行的 GUI 窗口的快照并保存为图像文件(.jpeg/.png)?

在 nbconvert 之前保存 Jupyter 笔记本

拍摄 div 的快照

拍摄快照并保存到相机胶卷时的 iOS 图像大小

如何在 Jupyter notebook (iPython) 中并排显示 2 张图像?

将 arkit 快照直接保存到照片库 swift 4