【问题标题】:How to use events in jupyterlab extensions?如何在 jupyterlab 扩展中使用事件?
【发布时间】:2021-10-21 07:07:44
【问题描述】:

我想在自定义扩展中收听 JupyterLab 笔记本(版本 3.2.0)的单元格事件。我该怎么做?

a) 搜索有关“事件”的文档并没有提供有用的信息:

https://jupyterlab.readthedocs.io/en/latest/search.html?q=events&check_keywords=yes&area=default

b) 这是我能找到的一些过时的例子:

Jupyter.events.on('execute.CodeCell', function(evt, data) {
    // data.cell is the cell object
});

https://github.com/jupyter/notebook/issues/2321

b) 这是另一个过时的代码被剪断:

require([
    "base/js/namespace",
    "base/js/events"
], 
    function(Jupyter, events){
        console.log("hello2");  
        events.on('notebook_loaded.Notebook', function(){
            console.log("hello3");
        });
        events.on('app_initialized.NotebookApp', function(){
            console.log("hello4");
        });
});

https://github.com/jupyter/notebook/issues/2499

我希望使用类似的东西

app.events

var { Events } = require('@jupyterlab/events');

但是,这些变体不起作用。

编辑

我找到了另一个代码sn-p:

panel.notebook.model.cells.changed.connect((list, changed) => {
            if (changed.type == 'add') {
                each(changed.newValues, cellmodel => {
                    let cell = panel.notebook.widgets.find(x => x.model.id === cellmodel.id);
                    // do something with cell widget.
                });
            }
        });

https://github.com/jupyterlab/jupyterlab/issues/4316

也许不再有全局“事件注册表”,但需要通过模型属性访问事件?

相关

Where is a docs for Jupyter front-end extensions JavaScript API?

【问题讨论】:

    标签: javascript jupyter-lab jupyter-extensions


    【解决方案1】:

    JupyterLab 扩展应使用基于 lumino Signal 实现的 signal pattern 侦听与应用程序相关的事件。

    您可以在参考 JupyterLab API Reference(也从文档中链接为最后一个条目)中识别感兴趣的信号,例如,单元格执行信号可用作 NotebookActions.executed

    扩展示例

    https://github.com/jupyterlab/extension-examples/tree/master/signals

    NotebookActions 的信号

    可观察列表的信号

    单个细胞的信号

    细胞模型提供信号

    使用示例:

    function __observeNotebook(app, dependencies){  
    
        let notebook = __tryToGetNotebook(app);
        if(notebook){       
            let cellModels = notebook.model.cells
            cellModels.changed.connect(__cellsChanged, this);   
    
            for(let cellIndex=0; cellIndex < cellModels.length; cellIndex++){
                let cellModel = cellModels.get(cellIndex);          
                __observeCell(cellModel, notebook);
            }
    
            let notebookActions = dependencies["NotebookActions"];
            notebookActions.executed.connect(__cellExecuted, this);  //selectionExecuted, exutionScheduled
        }        
    
    }
    
    function __observeCell(cellModel, notebook){   
        cellModel.contentChanged.connect(cellModel => __cellContentChanged(cellModel, notebook), this);   
        cellModel.stateChanged.connect(__cellStateChanged, this);   
    }
    
    function __cellsChanged(cellModels, change){
        console.log("Cells changed:")
        console.log("type: " + change.type);
        console.log("oldIndex: " + change.oldIndex);
        console.log("newIndex: " + change.newIndex);
        console.log("oldValues: " + change.oldValues); 
        console.log("newValues: " + change.newValues); 
    
        if(change.type == "add"){
            var newCellModel = cellModels.get(change.newIndex);
            __observeCell(newCellModel);
        }
    }
    
    function __cellContentChanged(cellModel, notebook){ 
        let id = cellModel.id
        console.log("Content of cell " + id + " changed");
    
        let currentText =  cellModel.value.text;
        console.log(currentText);
       
        let cellWidget = notebook.widgets.find(widget=>{
            return widget.model.id == id;
        });
    
        let outputArea = cellWidget.outputArea;
        let children = outputArea.node.children;
        if(children.length==1){
            let output = children[0];
            console.log(output);
        }
       
    }
    
    function __cellStateChanged(cellModel, change){
        let currentText =  cellModel.value.text;
        console.log("State of cell " + cellModel.id + " changed:");
        console.log("name: " + change.name);
        console.log("old value: " + change.oldValue);
        console.log("new value: " + change.newValue);
    }
    
    function __cellExecuted(any, context){
        let {cell, notebook, success, error} = context; 
        console.log("Executed cell " + cell.model.id);
    }
    
    
    function __tryToGetNotebookCell(app){   
        var notebook = __tryToGetNotebook(app);
        return notebook
            ?notebook.activeCell
            :null;      
    }
    
    function __tryToGetNotebook(app){
        var notebookPanel = __getFirstVisibleNotebookPanel(app);
        return notebookPanel
            ?notebookPanel.content
            :null;
    }
    
    
    function __getFirstVisibleNotebookPanel(app){
        var mainWidgets = app.shell.widgets('main');
        var widget = mainWidgets.next();
        while(widget){
            var type = widget.sessionContext.type;
            if(type == 'notebook'){  //other wigets might be of type DocumentWidget
                if (widget.isVisible){
                    return widget;
                }
            }
            widget = mainWidgets.next();
        }
        return null;
    }
    

    【讨论】:

    • 我为我的草稿答案添加了一些信息,因为您已经清楚地知道了。如果您愿意,请根据您的风格进行修改。
    • 这是一个关于如何访问单元格输出的后续问题:discourse.jupyter.org/t/…
    • 我遇到了完全相同的问题,非常感谢您的解决方案! signal tutorial 非常有帮助。
    猜你喜欢
    • 2021-02-13
    • 1970-01-01
    • 2020-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-10
    相关资源
    最近更新 更多