[英]How can I programatically add cells to and IPython or Jupyter notebook?
这个问题之前已经被问过几次,但是接受的答案表明提问者想要做一些与我不同的事情。
我正在尝试创建一个创建和运行新单元格的 IPython 小部件。 这样做的目的是在小部件和 IPython 单元之间提供相似性。
例如:我想要一个 SelectorWidget,它用“cell magic”填充并运行下一个单元格。
但我面临的问题是(如果我错了,请纠正我)IPython 不保留单元的内部数据结构。
在我看来,修改新单元格的唯一方法是:
In [1]: get_ipython().set_next_input('1')
In [2]: 1
我只想能够自动运行该行。 但我认为set_next_input
不可能做到这一点,因为它只是readline
之上的一个hack。
我可以做我想做的事:
display(Javacript('''
var code = IPython.notebook.insert_cell_at_bottom('code'))
code.execute()
'''))
但是以这种方式驱动输入感觉非常错误,因为它依赖于网络浏览器来做一些非常简单的事情。 而且您依赖于外部事件循环。
在命令行上执行此操作的等价物是启动一个后台线程/进程/ stdin
,它可以访问 IPython 提示符的标准输入,并接受来自前台线程的任务以写入前台线程自己的标准输入。 可以这样做,但与 Jupyter 方法有相同的问题,因为它特定于 IPython 的输入机制。
看问题,我似乎也找不到没有 JavaScript 的完全同步方法。
我发现run_cell和run_cell_magic可以避免 JavaScript 示例,但无法生成具有输出的单元。
我最接近的是:
from IPython import get_ipython
def make_cell_run_code(code):
ipython = get_ipython()
ipython.set_next_input(code)
ipython.run_cell(code)
code = "print('test')"
make_cell_run_code(code)
这避免了 JavaScript 但仍然有单元不同步。
使用 JavaScript,我们可以使用负索引来确保执行相同的单元格。
from IPython.display import Javascript, display
def create_and_excecute_code_cell(code=''):
display(Javascript("""
var code = IPython.notebook.insert_cell_at_bottom('code');
code.set_text("{0}");
Jupyter.notebook.execute_cells([-1]);
""".format(code)))
create_and_excecute_code_cell("%time x=0")
我从这里抄来的。 您的 JavaScript 片段对我不起作用。
一种可能但不可移植的解决方案是对处理set_next_input
kernel 消息的 JavaScript 进行猴子补丁。
(function (){
IPython.CodeCell.prototype._handle_set_next_input = function (payload) {
var data = {
cell: this,
text: payload.text,
replace: payload.replace,
clear_output: payload.clear_output,
execute: payload.execute
};
this.events.trigger('set_next_input.Notebook', data);
};
var that = IPython.notebook;
// Out with the old, in with the new
that.events.unbind("set_next_input")
that.events.on('set_next_input.Notebook', function (event, data) {
if (data.replace) {
data.cell.set_text(data.text);
if (data.clear_output !== false) {
// default (undefined) is true to preserve prior behavior
data.cell.clear_output();
}
} else {
var index = that.find_cell_index(data.cell);
var new_cell = that.insert_cell_below('code',index);
new_cell.set_text(data.text);
}
if (data.execute && data.execute === true) {
new_cell.execute();
} else {
that.dirty = true;
}
});
})()
然后可以像这样在笔记本中调用它:
with open('run_next_cell_patch.js') as f:
# Monkey patch Jupyter with
# set_next_input(run=True) functionality
display(Javascript(f.read()))
from IPython import get_ipython
ip = get_ipython()
ip.payload_manager.write_payload(
dict(
source='set_next_input',
text='print(1)',
replace=False,
execute=True
)
)
这将在下面创建一个带有print(1)
的新单元格,并执行 output。 这比每次插入 JavaScript 来控制输入要好一点。
有问题的是,这只适用于 Jupyter notebook 。 仍在为 Jupyter Lab 寻找解决方案。 从好的方面来说,我认为这在普通终端中解决起来相当简单。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.