首页 文章

转换为(不是)ipython Notebook格式

提问于
浏览
41

IPython Notebook附带nbconvert,可以将笔记本导出为其他格式 . 但是如何以相反的方向转换文本?我问,因为我已经拥有不同格式的材料和良好的工作流程,但我想利用Notebook的交互式环境 .

可能的解决方案:可以通过导入 .py 文件来创建笔记本,并且文档指出当 nbconvert 将笔记本导出为python脚本时,它会在可用于重新创建笔记本的注释中嵌入指令 . 但是有关此方法的局限性的信息附带a disclaimer,并且我所能找到的任何地方都没有记录可接受的格式 . (奇怪的是,在描述笔记本的JSON format的部分中显示了一个示例) . 任何人都可以提供更多信息,或更好的选择吗?

Edit (1 March 2016): 已接受的答案不再有效,因为由于某种原因,Notebook API的第4版不支持此输入格式 . I have added a self-answer 显示如何使用当前(v4)API导入笔记本 . (我不是不接受当前的答案,因为它解决了我当时的问题并指出了我在自我回答中使用的资源 . )

8 回答

  • 28

    以下适用于IPython 3,但不适用于IPython 4 .

    IPython API具有读写笔记本文件的功能 . 您应该使用此API而不是直接创建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

    Edit: 这个答案最初是为IPyhton 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 语句以获取完整列表 .

  • 8

    由于接受的答案中的代码不再起作用,我添加了这个自我答案,显示如何使用当前( v4 )API导入到笔记本中 .

    输入格式

    IPython Notebook API的第2版和第3版可以导入带有特殊结构注释的python脚本,并根据需要将其分解为单元格 . 这是一个示例输入文件(原始文档here) . 前两行被忽略,并且是可选的 . (事实上,读者将忽略文件中任何位置的 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=...> ,它们会立即转换为其他类型 . )

    如何导入它

    出于某种原因,Notebook API的第4版不支持此格式 . 它通过导入版本3和升级来支持它是值得的 . 原则上它只是两行代码,加上i / o:

    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有一个令人讨厌的错误:如果输入中的最后一个单元格是降价单元格, v3.reads_py() 将丢失它 . 最简单的解决方法是在最后添加一个伪造的单元格:错误将删除它,每个人都很高兴 . 在将 text 传递给 v3.reads_py() 之前,请执行以下操作:

    text += """
    # <markdowncell>
    
    # If you can read this, reads_py() is no longer broken! 
    """
    
  • 2

    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()
    
  • 3

    考虑到Volodimir Kopey的例子,我整理了一个简单的脚本,将.ipynb导出的.py转换回V4 .ipynb .

    当我编辑(在适当的IDE中)我从笔记本导出的.py时,我一起攻击了这个脚本,我想回到Notebook,逐个单元地运行它 .

    该脚本仅处理代码单元格 . 无论如何,导出的.py不包含太多其他内容 .

    import nbformat
    from nbformat.v4 import new_code_cell,new_notebook
    
    import codecs
    
    sourceFile = "changeMe.py"     # <<<< change
    destFile = "changeMe.ipynb"    # <<<< change
    
    
    def parsePy(fn):
        """ Generator that parses a .py file exported from a IPython notebook and
    extracts code cells (whatever is between occurrences of "In[*]:").
    Returns a string containing one or more lines
    """
        with open(fn,"r") as f:
            lines = []
            for l in f:
                l1 = l.strip()
                if l1.startswith('# In[') and l1.endswith(']:') and lines:
                    yield "".join(lines)
                    lines = []
                    continue
                lines.append(l)
            if lines:
                yield "".join(lines)
    
    # Create the code cells by parsing the file in input
    cells = []
    for c in parsePy(sourceFile):
        cells.append(new_code_cell(source=c))
    
    # This creates a V4 Notebook with the code cells extracted above
    nb0 = new_notebook(cells=cells,
                       metadata={'language': 'python',})
    
    with codecs.open(destFile, encoding='utf-8', mode='w') as f:
        nbformat.write(nb0, f, 4)
    

    没有保证,但它对我有用

  • 2

    采取和修改P.Toccateli和alexis的代码的自由,以便它也可以与pycharm和spyder一样使用细胞标记并在github上发布它 .

  • 5

    我为vscode写了一个可能有帮助的扩展 . 它将python文件转换为ipython笔记本 . 它处于早期阶段,因此如果发生任何错误,请随时提交问题 .

    Jupyter Notebook Converter

  • 28

    很老的问题,我知道 . 但jupytext(也可在pypi上使用)可以从 ipynb 转换为多种格式并返回 .

    安装 jupytext 时,您可以使用

    $ jupytext --to notebook test.py
    

    为了生成 test.ipynb .

    jupytext 有许多有趣的功能,在使用笔记本电脑时可以派上用场 .

  • -1

    您可以使用https://github.com/sklam/py2nb中的脚本py2nb

    您将不得不为* .py使用某种语法,但使用起来相当简单(查看'samples'文件夹中的示例)

相关问题