30
16

More than 5 years have passed since last update.

Jupyter Notebookの内部構造

Last updated at Posted at 2017-12-12

Jupyter Advent Calendar 2017 12日目です。
Jupyter Notebookの内部構造を解説します。

Jupyter Notebookを輸出する

Jupyter は、科学技術文書を作成する環境として大変便利ですね。Download as のメニューから、Notebook以外の形式でも保存できます。現時点で保存可能な形式は、HTML、markdown、PDF、LaTeX、reST (restructured text)、使用中言語ソース (下では Julia) です。

スクリーンショット 2017-12-10 11.43.20.png

Jupyterから直接保存できない形式で使う場合には、Notebookファイルから直接変換するのがよいかもしれません。Notebook形式 (.ipynb) は JSONファイルですから、読み書きするのも簡単です。 

Notebookの内部構造

Notebook形式(.ipynb)の内部構造は、The Notebook file format に説明がありますが、構文規則のみです。実務家としては、実際の Notebook の中身をみるのが分かりやすいでしょう。

以下のような、Juliaプログラムの Notebookの中身を見てみます。gist に貼っておきます → https://gist.github.com/anonymous/8d51c367d5cee2828f3da30390033010

https://gyazo.com/6b88dbbadac14fe8d9d9eb61ce2b43e4

using PyPlot
ts=linspace(0,2pi)
plot( ts .* cos.(ts), ts .* sin.(ts))

NotebookのJSONの中身は、gist のraw形式で表示できます。そのまま貼り付けるのも芸がないので、Rubyを使ってYAMLで表示してみます。参考 → YAML <-> JSON 変換 (Rubyで実装)

require "JSON"
json=JSON.parse( File.read("Untitled10.ipynb"));
require "YAML"
YAML.dump(json)
---
cells:
- cell_type: markdown
  metadata: {}
  source:
  - "# アルキメデスの渦"
- cell_type: markdown
  metadata: {}
  source:
  - "$$r = \\theta\\quad\\text{極座標}$$"
- cell_type: code
  execution_count: 1
  metadata: {}
  outputs: []
  source:
  - using PyPlot
- cell_type: code
  execution_count: 2
  metadata: {}
  outputs:
  - data:
      text/plain:
      - 0.0:0.1282282715750936:6.283185307179586
    execution_count: 2
    metadata: {}
    output_type: execute_result
  source:
  - ts=linspace(0,2pi)
- cell_type: code
  execution_count: 3
  metadata: {}
  outputs:
  - data:
      image/png:
      iVBORw0KGgoAAAANSUhE ..(途中省略).. 64AAAAASUVORK5CYII=
      text/plain:
      - PyPlot.Figure(PyObject <matplotlib.figure.Figure object at 0x11e764eb8>)
    metadata: {}
    output_type: display_data
  - data:
      text/plain:
      - '1-element Array{PyCall.PyObject,1}:

'
      - " PyObject <matplotlib.lines.Line2D object at 0x1248e2eb8>"
    execution_count: 3
    metadata: {}
    output_type: execute_result
  source:
  - plot( ts .* cos.(ts), ts .* sin.(ts))
- cell_type: code
  execution_count:
  metadata: {}
  outputs: []
  source: []
metadata:
  kernelspec:
    display_name: Julia 0.6.1
    language: julia
    name: julia-0.6
  language_info:
    file_extension: ".jl"
    mimetype: application/julia
    name: julia
    version: 0.6.1
nbformat: 4
nbformat_minor: 2

以下のような内部構造が読み取れます。

  1. 最上位の要素は metadata, cells, nbformat, nbformat_minor です。前2つは配列で、最後の二つは整数です。
  2. metadataには、Jupyterのカーネルと、言語の情報が入ります。
  3. cellsには、Notebookの各セルが入ります。
    1. 各セルで重要な要素は、cell_type, metadata, sources です。
    2. cell_typeは、セルの型です。 markdownセルでは markdown、codeセルではcodeという値が入ります。 Raw NBConvert セル(=表示の際に変換されたくないデータを入れる)では rawという値が入ります。
      1. sourceには、入力文字列の各行が配列で入ります
      2. codeセルには、execution_countoutputの要素があります。
        1. execution_count は、入力セルの通し番号です。 In[n] の n に相当する整数またはnullが入ります。
        2. outputには、出力結果が配列で入ります。
          1. 出力結果の重要な要素は output_typedataです。
          2. outout_typeは、出力の形式です。
          3. data には、データ本体が入ります。 以上です。

本例では、画像を一つ含んでいます。 画像に対応する出力セルは output_type=display_data という値となり、dataにはimage/pngの行に引き続き、BASE64形式で png画像が格納されていました。
ちなみに昨年のAdvent Calendarでは、Mayavi という3DオブジェクトをNotebookに埋め込む試みを紹介しました。 → [Python, Julia] Jupyter で 3D 表示 - Mayavi ライブラリ
Mayaviオブジェクトに対応する出力セルは、output_type = execute_result となり、dataにはtext/html に続き、xml形式のデータが含まれていました。

Scrapboxに輸出したい

Nota Inc. が提供するScrapboxは、複数人でリアルタイムに編集できるWikiです。各ページ中のタグやリンクを使うと、関連する複数のページが整理されて表示されます、Markdownと比べて記法が簡単です。 → Scrapboxヘルプ: 記法

https://gyazo.com/092e74b612f8d212b24dcfc4b80a6f8b

私は、Jupyter NotebookをScrapboxに輸出したくなりました。始めは手作業で、以下のようにすれば、scrapboxのページと親和性が高いことが分かりました。
- markdownセルは、Scrapboxの地のテキストに入れる。
- codeセルは、source(= プログラム)と出力テキストを、別々のコードブロックに格納する。

JupyterToScrapboxの紹介

Notebook形式からScrapbox形式への変換を支援するツールJupyterToScrapboxを紹介します。 Rubyで書かれていて gemでインストールできます。 bundler を使っていますが、その辺の環境設定は割愛します。

gem install jupyter_to_scrapbox

簡単な使い方は、以下の通りです。 Scrapboxで輸入できる形式のJSONファイルが scrapbox.json に格納されます。

bundle exec jupyter_to_scrapbox convert notebook1.ipynb notebook2.ipynb > scrapbox.json

さらに、Notebook内の画像を取り込む機能もつけました。Scrapboxの画像は、Nota Inc. の画像キャプチャサービス Gyazoへの各リンクになっています。Gyazo APIへのuser access tokenを環境変数GYAZO_TOKENに指定しておき、--imageオプションをつけて jupyter_to_scrapboxを起動します。

export GYAZO_TOKEN="(gyazo user access token)"
bundle exec jupyter_to_scrapbox convert Untitled10.ipynb --image > scrapbox.json

冒頭の Notebookから生成したScrapbox形式JSONを、YAMLで表示しましょう。

- title: '2017-12-10 01:15:04 +0900'
  lines:
  - '2017-12-10 01:15:04 +0900'
  - "Untitled10.ipynb"
  - ''
  - "[*** アルキメデスの渦]"
  - "[$ r = \\theta\\quad\\text{極座標} ]"
  - code:source.jl
  - "\t# In[1]"
  - "\tusing PyPlot"
  - ''
  - code:source.jl
  - "\t# In[2]"
  - "\tts=linspace(0,2pi)"
  - ''
  - code:output.txt
  - "\t0.0:0.1282282715750936:6.283185307179586"
  - ''
  - code:source.jl
  - "\t# In[3]"
  - "\tplot( ts .* cos.(ts), ts .* sin.(ts))"
  - ''
  - code:output.txt
  - "\timage/png"
  - "[https://i.gyazo.com/f720e453a77bd42bfe666fb5f8a2d914.png]"
  - ''
  - code:output.txt
  - "\tPyPlot.Figure(PyObject <matplotlib.figure.Figure object at 0x11e764eb8>)"
  - ''
  - code:output.txt
  - "\t1-element Array{PyCall.PyObject,1}:"
  - "\t PyObject <matplotlib.lines.Line2D object at 0x1248e2eb8>"
  - ''
  - code:source.jl
  - "\t# In[]"
  - ''

codeブロックは、code:(ファイル名) で始まり、空行''で終わる範囲です。
プログラム列はsource.jlブロックに、出力テキストはoutput.txtブロックに格納することにしました。

これをScrapboxに取り込むと、以下のようになります。画像も含めて取り込まれています。

https://gyazo.com/f6336483e04cc3d97097b731c4599c59

なお、上のURLに source.jlを付与すると、プログラム列のみが取り出せます。
https://scrapbox.io/api/code/JuliaExamples/2017-12-10_01:15:04_+0900/source.jl

source.jl
# In[1]
using PyPlot
# In[2]
ts=linspace(0,2pi)
# In[3]
plot( ts .* cos.(ts), ts .* sin.(ts))
# In[]

終わりに

Jupyter Notebookの内部構造と、Scrapboxへの変換ツールを紹介しました。 たくさんのNotebookをScrapboxに輸出して実例集を作ってみたいと考えています。詳細は Julia Advent Calendarとして書きます。

30
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
30
16