转换为ipython Notebook格式
IPython Notebook自带一个叫做nbconvert
的工具,可以把笔记本导出成其他格式。但是我想知道怎么把文本转换成相反的方向?我之所以问这个,是因为我已经有了一些材料和一个不错的工作流程,都是用其他格式做的,但我想利用Notebook的互动环境。
一个可能的解决办法是:可以通过导入一个.py
文件来创建一个笔记本,文档中提到,当nbconvert
把笔记本导出为Python脚本时,会在注释中嵌入一些指令,这些指令可以用来重新创建笔记本。不过,这种方法有一些限制,文档中没有详细说明接受的格式在哪里可以找到。(奇怪的是,样本在描述笔记本的JSON格式的部分中有提到。)有没有人能提供更多的信息,或者更好的替代方案?
编辑(2016年3月1日): 之前的答案现在不再有效,因为某种原因,这种输入格式在Notebook API的第4版中不被支持。我添加了一个自我解答,展示了如何用当前(第4版)API导入一个笔记本。(我没有撤销当前答案,因为它当时解决了我的问题,并指引我找到了我在自我解答中使用的资源。)
10 个回答
希望我没有来得太晚。
我刚刚在PyPI上发布了一个叫p2j的Python包。这个包可以把Python源代码文件.py
转换成Jupyter笔记本文件.ipynb
。
pip install p2j
p2j script.py
下面是一个从.py
文件生成的Jupyter笔记本的例子:
PyPI链接: https://pypi.org/project/p2j/
下面是一个Python代码示例,教你如何构建IPython笔记本V4:
# -*- coding: utf-8 -*-
import os
from base64 import encodestring
from IPython.nbformat.v4.nbbase import (
new_code_cell, new_markdown_cell, new_notebook,
new_output, new_raw_cell
)
# some random base64-encoded *text*
png = encodestring(os.urandom(5)).decode('ascii')
jpeg = encodestring(os.urandom(6)).decode('ascii')
cells = []
cells.append(new_markdown_cell(
source='Some NumPy Examples',
))
cells.append(new_code_cell(
source='import numpy',
execution_count=1,
))
cells.append(new_markdown_cell(
source='A random array',
))
cells.append(new_raw_cell(
source='A random array',
))
cells.append(new_markdown_cell(
source=u'## My Heading',
))
cells.append(new_code_cell(
source='a = numpy.random.rand(100)',
execution_count=2,
))
cells.append(new_code_cell(
source='a = 10\nb = 5\n',
execution_count=3,
))
cells.append(new_code_cell(
source='a = 10\nb = 5',
execution_count=4,
))
cells.append(new_code_cell(
source=u'print "ünîcødé"',
execution_count=3,
outputs=[new_output(
output_type=u'execute_result',
data={
'text/plain': u'<array a>',
'text/html': u'The HTML rep',
'text/latex': u'$a$',
'image/png': png,
'image/jpeg': jpeg,
'image/svg+xml': u'<svg>',
'application/json': {
'key': 'value'
},
'application/javascript': u'var i=0;'
},
execution_count=3
),new_output(
output_type=u'display_data',
data={
'text/plain': u'<array a>',
'text/html': u'The HTML rep',
'text/latex': u'$a$',
'image/png': png,
'image/jpeg': jpeg,
'image/svg+xml': u'<svg>',
'application/json': {
'key': 'value'
},
'application/javascript': u'var i=0;'
},
),new_output(
output_type=u'error',
ename=u'NameError',
evalue=u'NameError was here',
traceback=[u'frame 0', u'frame 1', u'frame 2']
),new_output(
output_type=u'stream',
text='foo\rbar\r\n'
),new_output(
output_type=u'stream',
name='stderr',
text='\rfoo\rbar\n'
)]
))
nb0 = new_notebook(cells=cells,
metadata={
'language': 'python',
}
)
import IPython.nbformat as nbf
import codecs
f = codecs.open('test.ipynb', encoding='utf-8', mode='w')
nbf.write(nb0, f, 4)
f.close()
由于之前的答案中的代码现在已经不再有效,我添加了这个自答,展示如何使用当前的(v4
)API将内容导入到笔记本中。
输入格式
IPython Notebook API的版本2和3可以通过一些特殊的注释结构来导入Python脚本,并根据需要将其拆分成多个单元格。下面是一个示例输入文件(原始文档可以在这里找到)。文件的前两行会被忽略,而且是可选的。(实际上,读取器会忽略文件中任何地方的coding:
和<nbformat>
行。)
# -*- coding: utf-8 -*-
# <nbformat>3.0</nbformat>
# <markdowncell>
# The simplest notebook. Markdown cells are embedded in comments,
# so the file is a valid `python` script.
# Be sure to **leave a space** after the comment character!
# <codecell>
print("Hello, IPython")
# <rawcell>
# Raw cell contents are not formatted as markdown
(这个API还接受一些过时的指令,比如<htmlcell>
和<headingcell level=...>
,这些会被立即转换成其他类型。)
如何导入
出于某种原因,版本4的Notebook API不支持这种格式。不过,这种格式还是很不错的,所以值得花点时间通过导入到版本3并进行升级来支持它。原则上,这只需要两行代码,加上输入输出:
from IPython.nbformat import v3, v4
with open("input-file.py") as fpin:
text = fpin.read()
nbook = v3.reads_py(text)
nbook = v4.upgrade(nbook) # Upgrade v3 to v4
jsonform = v4.writes(nbook) + "\n"
with open("output-file.ipynb", "w") as fpout:
fpout.write(jsonform)
但别急!实际上,笔记本API有一个麻烦的bug:如果输入的最后一个单元格是一个markdown单元格,v3.reads_py()
会把它丢掉。最简单的解决方法是在最后加一个虚假的<markdown>
单元格:这个bug会把它删除,这样大家都能满意。所以在将text
传递给v3.reads_py()
之前,请执行以下操作:
text += """
# <markdowncell>
# If you can read this, reads_py() is no longer broken!
"""
下面的内容适用于 IPython 3,但不适用于 IPython 4。
IPython 提供了一些函数,可以用来读取和写入笔记本文件。你应该使用这些函数,而不是直接创建 JSON 文件。比如,下面这段代码可以把一个脚本 test.py
转换成一个笔记本 test.ipynb
。
import IPython.nbformat.current as nbf
nb = nbf.read(open('test.py', 'r'), 'py')
nbf.write(nb, open('test.ipynb', 'w'), 'ipynb')
关于 nbf.read 理解的 .py 文件格式,最好直接看看 IPython.nbformat.v3.nbpy.PyReader 这个解析器类。相关代码可以在这里找到(代码不多):
https://github.com/ipython/ipython/blob/master/jupyter_nbformat/v3/nbpy.py
补充:这个回答最初是为 IPython 3 写的。我不知道在 IPython 4 中该怎么正确操作。这里是上面链接的更新版本,指向 IPython 3.2.1 版本的 nbpy.py
:
https://github.com/ipython/ipython/blob/rel-3.2.1/IPython/nbformat/v3/nbpy.py
基本上,你可以使用一些特殊的注释,比如 # <codecell>
或 # <markdowncell>
来分隔不同的单元格。想要完整的列表,可以查看 PyReader.to_notebook
中的 line.startswith
语句。