IPython Notebook Javascript:从JavaScript变量中检索内容

问题描述 投票:6回答:3

有没有办法让函数(由IPython Notebook单元调用)检索JavaScript变量的内容(例如包含当前笔记本路径的IPython.notebook.notebook_path)?

直接在单元格中编写时(例如,基于this question及其注释),以下情况很有效:

from IPython.display import display,Javascript
Javascript('IPython.notebook.kernel.execute("mypath = " + "\'"+IPython.notebook.notebook_path+"\'");')

但是,如果我试图把它放在一个函数中,那就会崩溃:

# this doesn't work
from IPython.display import display,Javascript
def getname():
    my_js = """
    IPython.notebook.kernel.execute("mypath = " + "\'"+IPython.notebook.notebook_path+"\'");
    """
    Javascript(my_js)
    return mypath

(是的,我试图在global脚本和函数内部使mypath成为my_js变量。另请注意:不要被先前命令中变量中可能的剩余值所欺骗;为了确保使用mypath = None; del mypath在调用函数之前重置变量,或者重启内核。)

制定问题的另一种方法是:“IPython.notebook.kernel.execute()设定的变量的范围(时间和地点)是什么”?

我认为这不是一个无关紧要的问题,可能与IPython用来控制其内核及其变量的机制有关,而且我对此并不了解。以下实验说明了该机制的某些方面。以下工作在两个单独的单元格中完成,但如果两个单元格合并则不起作用:

细胞[1]:

my_out = None
del my_out
my_js = """
IPython.notebook.kernel.execute("my_out = 'hello world'");
"""
Javascript(my_js)

细胞[2]:

print(my_out)

这工作并产生预期的hello world。但如果你合并这两个单元格,它就不起作用(NameError: name 'my_out' is not defined)。

javascript python ipython-notebook
3个回答
4
投票

我认为这个问题与Javascript是asynchronus有关,而python则没有。通常,您会认为执行了Javascript(“”“python cmd”“”)命令,然后您的打印声明应该按预期正常工作。但是,Javascript命令被触发但未执行。最可能的是它在单元格1执行完全完成后执行。

我尝试了睡眠功能的例子。没有帮助。

通过在我的js中添加alert语句,但在kernel.execute行之前,可以很容易地看到异步问题。即使在尝试执行python命令之前,也应该触发警报。

但是在单元格1中存在print(my_out)语句时,您将再次收到相同的错误而没有任何警报。如果取出打印行,您将看到单元格1中弹出警报。但后来设置了变量my_out。

my_out = None
del my_out
my_js = """
**alert ("about to execute python comand");**
IPython.notebook.kernel.execute("my_out = 'hello world'");
"""
Javascript(my_js)

笔记本中还有其他javascript实用程序,如IPython.display.display_xxx,从显示视频到文本对象不等,但即使文本对象选项也不起作用。

有趣的是,我用我的webgl canvas应用程序对它进行了测试,该应用程序在HTML5画布上显示对象; display.display_javascript(javascript object)工作正常(这是一个looong html5文档),而输出的两个单词没有出现?!也许我应该将输出嵌入到某个地方的canvas应用程序中,所以它显示在画布上:)


2
投票

好吧,我找到了解决问题的方法:从Javascript调用Python函数并让它完成我需要的所有操作,而不是将名称返回到“above”并在那里使用该名称。

对于背景:我和我的同事有很多实验笔记本;我们试验了一段时间并尝试了各种各样的东西(在机器学习环境中)。在每个变体/运行结束时,我想保存笔记本,将其复制到反映时间的名称,将其上传到S3,从输出中删除它并将其推送到git,记录文件名,注释和结果分数到数据库等等。简而言之,我想自动跟踪我们的所有实验。

这就是我到目前为止所拥有的。在笔记本的底部,我说:

In [127]: import mymodule.utils.lognote as lognote
          lognote.snap()

In [128]: # not to be run in the same shot as above
          lognote.last
Out[128]: {'file': '/data/notebook-snapshots/2015/06/18/20150618-004408-save-note-exp.ipynb',
           'time': datetime.datetime(2015, 6, 18, 0, 44, 8, 419907)}

并在一个单独的文件中,例如mymodule/utils/lognote.py

# (...)

from datetime import datetime
from subprocess import call
from os.path import basename, join
from IPython.display import display, Javascript

# TODO: find out where the topdir really is instead of hardcoding it
_notebook_dir = '/data/notebook'
_snapshot_dir = '/data/notebook-snapshots'

def jss():
    return """
    IPython.notebook.save_notebook();
    IPython.notebook.kernel.execute("import mymodule.utils.lognote as lognote");
    IPython.notebook.kernel.execute("lognote._snap('" + IPython.notebook.notebook_path + "')");
    """
def js():
    return Javascript(jss())

def _snap(x):
    global last
    snaptime = datetime.now()
    src = join(_notebook_dir, x)
    dstdir = join(_snapshot_dir, '{}'.format(snaptime.strftime("%Y/%m/%d")))
    dstfile = join(dstdir, '{}-{}'.format(snaptime.strftime("%Y%m%d-%H%M%S"), basename(x)))
    call(["mkdir", "-p", dstdir])
    call(["cp", src, dstfile])
    last = {
        'time': snaptime,
        'file': dstfile
        }

def snap():
    display(js())

0
投票

为了增加其他很棒的答案,浏览器试图在nb load上运行jupyter nb javascript魔法有一个细微差别。

要演示:创建并运行以下单元格:

%%javascript 
IPython.notebook.kernel.execute('1')

现在保存笔记本,关闭它然后重新打开它。当你这样做时,突然在那个单元格下你会看到一个红色的错误:

Javascript error adding output!
TypeError: Cannot read property 'execute' of null
See your browser Javascript console for more details.

这意味着浏览器已经解析了一些js代码,并尝试运行它。这是chrome中的错误,它可能在不同的浏览器中有所不同。

我不知道为什么这个jupyter javascript魔术单元正在加载运行,为什么jupyter笔记本没有正确转义,但浏览器看到一些js代码,所以它运行它并失败,因为笔记本内核尚不存在!

因此,您必须添加对象存在的检查:

%%javascript 
if (IPython.notebook.kernel) {
    IPython.notebook.kernel.execute('1')
}

现在加载没问题。

在我的情况下,我需要保存笔记本并在其上运行外部脚本,所以我最终使用此代码:

from IPython.display import display, Javascript
def nb_auto_export():
    display(Javascript("if (IPython.notebook) { IPython.notebook.save_notebook() }; if (IPython.notebook.kernel) { IPython.notebook.kernel.execute('!./notebook2script.py  ' + IPython.notebook.notebook_name )}"))

在笔记本的最后一个单元格中:

nb_auto_export()
© www.soinside.com 2019 - 2024. All rights reserved.