openfst quick tourをjupyterlab上で実行

openfst quick tourをjupyterlab上で実行

Open Fst Quick Tourをpython上からbinding経由で実行してみたりシェルコマンドを実行したりして試してみます。 若干内容が中途半端なので後日追記するかもしれません。

前提

下記を実行済の状態で実行しています。

$ pip install pybind11
$ git clone https://github.com/aldanor/ipybind.git && cd ipybind & python setup build && python setup.py install
$ conda install -c conda-forge openfst
$ apt install graphviz
$ pip install openfst-python

ビルド済のopenfstがcondaでインストールできるようになってて驚きました。

ipybindのロード

jupyter labではJavascript Error: require is not definedと表示されるが問題なく動作はする。

In [1]:
%load_ext ipybind

openfstがインストールされているかの確認

condaで入れた場合conda/binに格納されている模様

In [2]:
!which fstprint
/opt/conda/bin/fstprint

ipybind11での実行

  • -Wl="-lfst"でlibfst.soをリンクする必要がある
In [3]:
%%pybind11 -fv -Wl="-lfst"

#include <fst/fst-decl.h>
#include <fst/fstlib.h>

namespace fst {
    void openfst_basic_operation(void){
        // Vector FSTは一般的にmutableなFST 
        StdVectorFst fst;

        // 状態0を最初に空のFSTに追加しstart stateとする
        fst.AddState();   // 最初の状態は状態0となる(AddStateの返り値になる) 
        fst.SetStart(0);  // 引数は状態ID
        
        // 状態0から分岐する2つのarcを追加
        // arcのコンストラクタの引数は入力ラベル、出力ラベル、重み、宛先となる状態ID
        fst.AddArc(0, StdArc(1, 1, 0.5, 1));  // 最初の引数は分岐元の状態ID 
        fst.AddArc(0, StdArc(2, 2, 1.5, 1)); 
        
        // 状態1を追加し状態1から2に至るarcを追加 
        fst.AddState();
        fst.AddArc(1, StdArc(3, 3, 2.5, 2));

        // 状態2を追加し状態2を最終状態とする(最終状態の重みも追加) 
        fst.AddState();
        fst.SetFinal(2, 3.5);  // 最初の引数は状態IDであり、2番目の引数は重みである 
        
        // FSTをWriteでファイルに保存
        fst.Write("work/binary.fst");
    }
}

PYBIND11_MODULE(myadd, m){
    m.def("openfst_basic_operation", &fst::openfst_basic_operation, "Tutorial method.");
}
running build_ext
setting C++ standard: -std=c++14
building 'pybind11_41f0e60' extension
creating /home/jovyan/.cache/ipython/pybind11/pybind11_41f0e60/home
creating /home/jovyan/.cache/ipython/pybind11/pybind11_41f0e60/home/jovyan
creating /home/jovyan/.cache/ipython/pybind11/pybind11_41f0e60/home/jovyan/.cache
creating /home/jovyan/.cache/ipython/pybind11/pybind11_41f0e60/home/jovyan/.cache/ipython
creating /home/jovyan/.cache/ipython/pybind11/pybind11_41f0e60/home/jovyan/.cache/ipython/pybind11
/usr/bin/gcc -pthread -B /opt/conda/compiler_compat -Wl,--sysroot=/ -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -D_IPYBIND_MODULE_NAME=pybind11_41f0e60 -I/opt/conda/include/python3.7m -c /home/jovyan/.cache/ipython/pybind11/pybind11_41f0e60.cpp -o /home/jovyan/.cache/ipython/pybind11/pybind11_41f0e60/home/jovyan/.cache/ipython/pybind11/pybind11_41f0e60.o -std=c++14 -fvisibility=hidden -flto -isystem /opt/conda/lib/python3.7/site-packages/ipybind-0.1.0-py3.7.egg/ipybind/include -isystem /opt/conda/include -isystem /opt/conda/include -isystem /opt/conda/include
/usr/bin/g++ -pthread -shared -B /opt/conda/compiler_compat -L/opt/conda/lib -Wl,-rpath=/opt/conda/lib -Wl,--no-as-needed -Wl,--sysroot=/ /home/jovyan/.cache/ipython/pybind11/pybind11_41f0e60/home/jovyan/.cache/ipython/pybind11/pybind11_41f0e60.o -L/opt/conda/lib -o build/lib.linux-x86_64-3.7/pybind11_41f0e60.cpython-37m-x86_64-linux-gnu.so -flto -lfst
copying build/lib.linux-x86_64-3.7/pybind11_41f0e60.cpython-37m-x86_64-linux-gnu.so -> /home/jovyan/.cache/ipython/pybind11

ipybind経由で上記の関数をpythonから実行

In [4]:
openfst_basic_operation()

作成したbinary形式のfstはfstprintで表示が可能

In [5]:
!fstprint work/binary.fst
0	1	1	1	0.5
0	1	2	2	1.5
1	2	3	3	2.5
2	3.5

fstinfoコマンドでfstの情報を表示可能

In [6]:
!fstinfo work/binary.fst
fst type                                          vector
arc type                                          standard
input symbol table                                none
output symbol table                               none
# of states                                       3
# of arcs                                         3
initial state                                     0
# of final states                                 1
# of input/output epsilons                        0
# of input epsilons                               0
# of output epsilons                              0
input label multiplicity                          1
output label multiplicity                         1
# of accessible states                            3
# of coaccessible states                          3
# of connected states                             3
# of connected components                         1
# of strongly conn components                     3
input matcher                                     y
output matcher                                    y
input lookahead                                   n
output lookahead                                  n
expanded                                          y
mutable                                           y
error                                             n
acceptor                                          y
input deterministic                               y
output deterministic                              y
input/output epsilons                             n
input epsilons                                    n
output epsilons                                   n
input label sorted                                y
output label sorted                               y
weighted                                          y
cyclic                                            n
cyclic at initial state                           n
top sorted                                        y
accessible                                        y
coaccessible                                      y
string                                            n
weighted cycles                                   n

fstdrawコマンドでbinary形式のfstをgraphvizのdot形式へと変換が可能

In [7]:
!fstdraw work/binary.fst work/binary.dot

dot形式はテキストなのでcatで中身を表示

In [8]:
!cat work/binary.dot
digraph FST {
rankdir = LR;
size = "8.5,11";
center = 1;
orientation = Landscape;
ranksep = "0.4";
nodesep = "0.25";
0 [label = "0", shape = circle, style = bold, fontsize = 14]
	0 -> 1 [label = "1:1/0.5", fontsize = 14];
	0 -> 1 [label = "2:2/1.5", fontsize = 14];
1 [label = "1", shape = circle, style = solid, fontsize = 14]
	1 -> 2 [label = "3:3/2.5", fontsize = 14];
2 [label = "2/3.5", shape = doublecircle, style = solid, fontsize = 14]
}

上記のままだとorientationがLandscapeになっており縦に表示されるのでsedでPortraitに変換した上でgraphvizのdotコマンドでpngファイルに変換する。

In [9]:
!sed -e "s/Landscape/Portrait/g" work/binary.dot | dot -Tpng > work/binary.png
In [10]:
from IPython.display import Image
Image("work/binary.png")
Out[10]:

シェルからの実行

上記のfstはシェルからテキストで定義したFSTの構造ファイルと入力シンボル、出力シンボルを組み合わせることでも作成可能である。

fstのフォーマットは AT&T FSMフォーマットである。 fstの各行のフォーマットは 遷移元状態ID 遷移先状態ID 入力ラベル 出力ラベル [重み] 最終状態はのフォーマットは 状態ID [重み] である。 最初の状態が最初の行でなければならないことを除いて他の行についてはどんな順番で書いても良い。 重みが指定されない場合は0.0(ライブラリのデフォルトであるWeight型に対する値)となる。

In [11]:
%%writefile work/text.fst
0 1 a x .5
0 1 b y 1.5
1 2 c z 2.5
2 3.5
Overwriting work/text.fst

上記定義で入力ラベルに指定されていたa,b,cを1,2,3へと変換するためのファイルとしてisyms.txtを作成する。

については後述する。

In [12]:
%%writefile work/isyms.txt
<eps> 0
a 1
b 2
c 3
Overwriting work/isyms.txt

同様に上記定義で出力ラベルに指定されていたx,y,zを1,2,3へと変換するためのファイルとしてosyms.txtを作成する。

In [13]:
%%writefile work/osyms.txt
<eps> 0
x 1
y 2
z 3
Overwriting work/osyms.txt

これらのファイルを組み合わせることでfstcompileコマンドによってbinary形式のfstを作成可能である。

In [14]:
!fstcompile --isymbols=work/isyms.txt --osymbols=work/osyms.txt work/text.fst work/binary2.fst

念の為再度画像に変換して確認してみると同一のWFSTが作成できていることが分かる。

In [15]:
!fstdraw work/binary2.fst work/binary2.dot
In [16]:
!sed -e "s/Landscape/Portrait/g" work/binary2.dot | dot -Tpng > work/binary2.png
In [17]:
Image("work/binary2.png")
Out[17]:

ラベルにはどんな文字列を用いても良く、ラベルIDには非負整数であれば何を用いても良い。 ラベルID 0はepsilonラベルとして予約されている、これは空文字列を表す。 先の例ではテーブルに0を含めたがFSTの作成には用いていない。 後続するFSTの操作ではepsilonを追加するかもしれないので、シンボルファイルに含めておくのは良い心がけである。

このテキスト形式のFSTはOpenFstライブラリにで使用される前にbinary形式へとコンバートしなければならない。

FSTにシンボルテーブルを含める場合は--keep_isymbols--keep_osymbolsのオプションを付けて実行する。

In [36]:
!fstcompile --isymbols=work/isyms.txt --osymbols=work/osyms.txt --keep_isymbols --keep_osymbols work/text.fst work/binary2symkeep.fst
In [34]:
!fstinfo work/binary2.fst
fst type                                          vector
arc type                                          standard
input symbol table                                none
output symbol table                               none
# of states                                       3
# of arcs                                         3
initial state                                     0
# of final states                                 1
# of input/output epsilons                        0
# of input epsilons                               0
# of output epsilons                              0
input label multiplicity                          1
output label multiplicity                         1
# of accessible states                            3
# of coaccessible states                          3
# of connected states                             3
# of connected components                         1
# of strongly conn components                     3
input matcher                                     y
output matcher                                    y
input lookahead                                   n
output lookahead                                  n
expanded                                          y
mutable                                           y
error                                             n
acceptor                                          y
input deterministic                               y
output deterministic                              y
input/output epsilons                             n
input epsilons                                    n
output epsilons                                   n
input label sorted                                y
output label sorted                               y
weighted                                          y
cyclic                                            n
cyclic at initial state                           n
top sorted                                        y
accessible                                        y
coaccessible                                      y
string                                            n
weighted cycles                                   n
In [37]:
!fstinfo work/binary2symkeep.fst
fst type                                          vector
arc type                                          standard
input symbol table                                work/isyms.txt
output symbol table                               work/osyms.txt
# of states                                       3
# of arcs                                         3
initial state                                     0
# of final states                                 1
# of input/output epsilons                        0
# of input epsilons                               0
# of output epsilons                              0
input label multiplicity                          1
output label multiplicity                         1
# of accessible states                            3
# of coaccessible states                          3
# of connected states                             3
# of connected components                         1
# of strongly conn components                     3
input matcher                                     y
output matcher                                    y
input lookahead                                   n
output lookahead                                  n
expanded                                          y
mutable                                           y
error                                             n
acceptor                                          y
input deterministic                               y
output deterministic                              y
input/output epsilons                             n
input epsilons                                    n
output epsilons                                   n
input label sorted                                y
output label sorted                               y
weighted                                          y
cyclic                                            n
cyclic at initial state                           n
top sorted                                        y
accessible                                        y
coaccessible                                      y
string                                            n
weighted cycles                                   n

input/output symbol tableに元のテーブルの情報が残っていることが分かる。この場合、fstprintで表示するとラベル文字列が表示される。

In [41]:
!fstprint work/binary2.fst
0	1	1	1	0.5
0	1	2	2	1.5
1	2	3	3	2.5
2	3.5
In [40]:
!fstprint work/binary2symkeep.fst
0	1	a	x	0.5
0	1	b	y	1.5
1	2	c	z	2.5
2	3.5

シンボルテーブルファイルを指定せずにFSTを作った場合を試してみる。

In [38]:
!fstcompile work/text.fst work/binary2wosym.fst
FATAL: FstCompiler: Bad arc ilabel integer = "a", source = work/text.fst, line = 1

このようにtext.fstで入出力ラベルに非負整数以外が使用されている場合は警告が出るようである。

一方でテキスト形式のFST内においてもしラベルが非負整数で表現されているのであればシンボルテーブルのファイルは不要となる。 この場合はのFSTの内部表現は先に描画した図と同じようになるはずである。 これを確かめるためにラベルを保持していない場合のバイナリ形式FSTであるbinary2.fstをfstprintし、その結果をfstcompileした上で再度fstprintしてみる。

In [44]:
!fstprint work/binary2.fst | fstcompile - | fstprint -
0	1	1	1	0.5
0	1	2	2	1.5
1	2	3	3	2.5
2	3.5

このようにラベルが非負整数の場合は問題なくfstcompileが可能であることが分かる。

なお、ラベルが非負整数の場合に先のと同じシンボルテーブルを与えてもシンボルテーブル内に非負整数のラベルに対応したエントリが存在していないためエラーが生じる。

In [47]:
!fstprint work/binary2.fst | fstcompile --isymbols=work/isyms.txt --osymbols=work/osyms.txt - | fstprint -
FATAL: FstCompiler: Symbol "1" is not mapped to any integer arc ilabel, symbol table = work/isyms.txt, source = standard input, line = 1
ERROR: FstHeader::Read: Bad FST header: standard input. Magic number not matched. Got: 0

一度バイナリ形式のFSTが作成されると、(同じアーキテクチャのマシン上であれば)他のシェルレベルのプログラムと組み合わせて使うことも可能である。 またC++コードでは下記コードでコード中でロードすることも可能である。

StdFst *fst = StdFst::Read("binary.fst");

pythonバインディングでの実行

openfstには公式に提供されているpywrapfstというラッパーがあるが、 openfst自体は別にインストールしておく必要があるため新規環境に導入しにくいため別途openfst本体を導入する必要を無くした openfst-pythonというライブラリが公開されている。 ここではこのopenfst-pythonを使って先程までと同様の内容を実施する。

In [18]:
!pip install openfst-python
Requirement already satisfied: openfst-python in /opt/conda/lib/python3.7/site-packages (1.7.3)
In [19]:
import openfst_python as fst

c++のStdVectorFSTfst.Fstという名前で生成できる模様である(要確認)。 またc++のStdArcfst.Arcで生成している。

fst.add_arcメソッドは"遷移元状態ID、Arcオブジェクト、遷移先状態ID"を取る模様であり 第2引数のArcオブジェクトは"入力ラベル、出力ラベル、Weightオブジェクト"を引数に取る。 このWeightオブジェクトは第一引数にFSTのweight_typeを取り、第2引数に重みの値を取る。 ここでは0->1への2つ目の遷移の重みだけはfst.Weight.Oneメソッドで与えているが、この第一引数もFSTのweight_typeである。

In [20]:
f = fst.Fst()
s0 = f.add_state()
s1 = f.add_state()
s2 = f.add_state()

f.set_start(s0)
f.add_arc(s0, fst.Arc(1, 2, fst.Weight(f.weight_type(), 0.5), s1))
f.add_arc(s0, fst.Arc(1, 3, fst.Weight.One(f.weight_type()),  s1))
f.add_arc(s1, fst.Arc(3, 3, fst.Weight(f.weight_type(), 2.5), s2))
f.set_final(s2, fst.Weight(f.weight_type(), 3.5))
Out[20]:
FST 0 01 10->1 1:2/0.50->1 1:32 2/3.51->2 3:3/2.5
In [21]:
f
Out[21]:
FST 0 01 10->1 1:2/0.50->1 1:32 2/3.51->2 3:3/2.5

上記のようにpythonラッパーはfstオブジェクトを評価すると自動的に画像に変換して描画してくれるようである。 使い方の詳細はドキュメント http://www.openfst.org/twiki/bin/view/FST/PythonExtension を確認すること。

(おまけ)自作pythonバインディングでの実行

この記事を書き始めた当初はpybind11でラッパーを作ろうかと思ったのですが分量が結構膨大なのと途中で公式でpythonラッパーを提供していることに気づいたので下記に微妙な痕跡を残しておきます。

In [22]:
%%pybind11 -fv -Wl="-lfst"

#include <fst/fst-decl.h>
#include <fst/fstlib.h>

namespace py = pybind11;

PYBIND11_MODULE(myadd, m){
    py::class_<fst::StdArc>(m, "StdArc")
    .def(py::init<int, int, double, int>());
    
    py::class_<fst::StdVectorFst>(m, "StdVectorFst")
    .def(py::init<>())
    .def("add_state", &fst::StdVectorFst::AddState)
    .def("add_arc"  , py::overload_cast<int, const fst::StdArc&>(&fst::StdVectorFst::AddArc))
    .def("set_start", &fst::StdVectorFst::SetStart)
    .def("set_final", [](fst::StdVectorFst& self, int state, double weight){ self.SetFinal(state, weight); })
    .def("write"    , [](fst::StdVectorFst& self, const char* filepath){ self.Write(filepath); });
    //.def("set_final", py::overload_cast<int, double>(&fst::StdVectorFst::SetFinal))
    //.def("write"    , py::overload_cast<const std::string&>(&fst::StdVectorFst::Write));
}
running build_ext
setting C++ standard: -std=c++14
building 'pybind11_32de930' extension
creating /home/jovyan/.cache/ipython/pybind11/pybind11_32de930/home
creating /home/jovyan/.cache/ipython/pybind11/pybind11_32de930/home/jovyan
creating /home/jovyan/.cache/ipython/pybind11/pybind11_32de930/home/jovyan/.cache
creating /home/jovyan/.cache/ipython/pybind11/pybind11_32de930/home/jovyan/.cache/ipython
creating /home/jovyan/.cache/ipython/pybind11/pybind11_32de930/home/jovyan/.cache/ipython/pybind11
/usr/bin/gcc -pthread -B /opt/conda/compiler_compat -Wl,--sysroot=/ -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -D_IPYBIND_MODULE_NAME=pybind11_32de930 -I/opt/conda/include/python3.7m -c /home/jovyan/.cache/ipython/pybind11/pybind11_32de930.cpp -o /home/jovyan/.cache/ipython/pybind11/pybind11_32de930/home/jovyan/.cache/ipython/pybind11/pybind11_32de930.o -std=c++14 -fvisibility=hidden -flto -isystem /opt/conda/lib/python3.7/site-packages/ipybind-0.1.0-py3.7.egg/ipybind/include -isystem /opt/conda/include -isystem /opt/conda/include -isystem /opt/conda/include
/usr/bin/g++ -pthread -shared -B /opt/conda/compiler_compat -L/opt/conda/lib -Wl,-rpath=/opt/conda/lib -Wl,--no-as-needed -Wl,--sysroot=/ /home/jovyan/.cache/ipython/pybind11/pybind11_32de930/home/jovyan/.cache/ipython/pybind11/pybind11_32de930.o -L/opt/conda/lib -o build/lib.linux-x86_64-3.7/pybind11_32de930.cpython-37m-x86_64-linux-gnu.so -flto -lfst
copying build/lib.linux-x86_64-3.7/pybind11_32de930.cpython-37m-x86_64-linux-gnu.so -> /home/jovyan/.cache/ipython/pybind11
In [23]:
# python binding test
fst = StdVectorFst()
fst.add_state()
fst.set_start(0)

fst.add_arc(0, StdArc(1, 1, 0.8, 1))
fst.add_arc(0, StdArc(2, 2, 1.3, 1))
fst.add_state()
fst.add_arc(1, StdArc(3, 3, 2.2, 2))
fst.add_state()
fst.set_final(2, 3.5)

fst.write("work/binary_py.fst");
In [24]:
!fstdraw work/binary_py.fst work/binary_py.dot
In [28]:
!cat work/binary_py.dot
digraph FST {
rankdir = LR;
size = "8.5,11";
center = 1;
orientation = Landscape;
ranksep = "0.4";
nodesep = "0.25";
0 [label = "0", shape = circle, style = bold, fontsize = 14]
	0 -> 1 [label = "1:1/0.8", fontsize = 14];
	0 -> 1 [label = "2:2/1.3", fontsize = 14];
1 [label = "1", shape = circle, style = solid, fontsize = 14]
	1 -> 2 [label = "3:3/2.2", fontsize = 14];
2 [label = "2/3.5", shape = doublecircle, style = solid, fontsize = 14]
}
In [29]:
!sed -e "s/Landscape/Portrait/g" work/binary_py.dot | dot -Tpng > work/binary_py.png
In [30]:
Image("work/binary_py.png")
Out[30]:

Jupyter LabおよびExtensionの紹介

Jupyter LabおよびExtensionの紹介

この記事はPyData Osaka Meetup #12の発表のために執筆しました。 ※2020/2/16 スライドへのリンクを追加

In [1]:
from IPython.display import IFrame
IFrame("https://www.hiromasa.info/slide/17.slides.html", "100%", "450px")
Out[1]:

自己紹介

  • 大橋(@wrist)
  • PyData Osakaオーガナイザーの一味
  • メーカー勤務(音響信号処理屋)
  • 近況: バタフライキーボードのbが壊れた

本日の実行環境

  • Docker上で動作
  • docker pull wrist/jupyterlab-custom:latest

本日の内容

  • Jupyter Labの簡単な歴史
  • Jupyter Lab単体機能の紹介
  • Extensionの紹介

Jupyter Labの簡単な歴史

Jupyter lab単体機能の紹介

個人的にJupyter Notebookに求めるもの

  • markdown/ipynbでのブログ執筆
  • ipynbのスライドへの変換
  • vimキーバインド

キーバインドの設定

  • デフォルトで用意
    • Settings -> Text Editor Key Map
    • Sublime Text, vim, emacs

vimキーバインド

  • markdown編集などのみに適用
    • cell編集でvimキーバインドが使いたい場合はExtensionが必要
  • chrome/safariで使うのが無難?
    • firefoxだとescが効かない

ショートカット

  • ipynbではjupyter notebookのショートカットがそのまま使える
    • 移動 j,k
    • 選択 J,K
    • 挿入 a,b
    • コピペ c,x,v
    • セルタイプ変更 m, y
    • ドキュメント表示 shift+tab
In [1]:
# sumにカーソルをあてて`shift+tab`
y = sum([1, 2, 3])
y
Out[1]:
6
In [2]:
import scipy as sp
import scipy.signal as sg

labの機能のショートカット(一部)

  • コマンドパレット
    • shift+command+c
  • タブの移動
    • shift+ctrl+]
  • サイドバーの開閉
    • command+B

slide type変更のショートカットがないのが辛い

Drag&Dropによるセル編集

  • ipynb間でも可能

画像のペーストによる挿入

  • セルにはクリップボード上の画像をcommand+vで挿入可能
  • win+shift+sshift+ctrl+command+4で選択してキャプチャした矩形画像を挿入

image.png

プレビュー関連

Markdownのプレビュー
  • markdownファイルを右クリック
    • Show Markdown Previewを選択

リッチな補完

  • 補完が見やすい

image.png

ipynbのSlideへの変換

  • 各セルにサイドバー -> スパナアイコン -> Slide Typeを設定
  • File -> Export Notebook As... -> Reveal.jsでスライド生成
  • RISEはまだ使えない模様
    • リアルタイム修正ができない

image.png

ipynbへのメタデータの付与

  • スパナアイコン -> Advanced Tools -> Notebook Metadataで付与可能

Extensionの紹介

Extensionの種類

  • lab extension
    • フロントエンド側で動作するExtension
    • jupyter labextension install ...
  • server extension
    • サーバー側で動作するExtension
    • pip install jupyterlab_git
    • jupyter serverextension enable --py jupyterlab_git

Extension情報

Extension Manger

  • GUIでインストールが可能
  • コマンドパレットからEnable Extension Managerを実行
  • サイドバーからExtensionのインストールが可能に

@jupyter/toc

  • 目次をサイドバーに表示可能
  • アウトラインが分かりやすくなる

image.png

インストール方法

https://github.com/jupyterlab/jupyterlab-toc

jupyter labextension install @jupyter/toc

@jupyter/git

  • サイドバーからgit操作が可能
  • nbdimeによる差分表示
サイドバー
  • GUI操作でgit関連操作が可能

image.png

差分表示
  • 一番右の2つのアイコン
    • チェックポイントからの差分
    • HEADからの差分

image.png

インストール方法

https://github.com/jupyterlab/jupyterlab-git

pip install jupyterlab_git
jupyter serverextension enable --py jupyterlab_git
jupyter labextension install @jupyterlab/git
jupyter lab build

jupyterlab-vim

  • cellの中でもvimキーバインドが使える
    • 割と使い勝手が変わるので好みによる
  • セルからの脱出
    • shift+ctrl+esc
  • セルの確定
    • ctrl+enter(エクステンションに関係なく使用可能)
コロンをセルの中で押した場合の様子

image.png

インストール方法

https://github.com/jwkvam/jupyterlab-vim

jupyter labextension install jupyterlab_vim

@lckr/jupyterlab_variableinspector

  • 変数の一覧表示を実現
    • numpyなどにも対応
    • matrix表示可能
    • _に辞書を格納してるっぽい
      • 直前の出力が参照できなくなる

インストール方法

https://github.com/lckr/jupyterlab-variableInspector

jupyter labextension install @lckr/jupyterlab_variableinspector
In [6]:
1+1
Out[6]:
2
In [7]:
_
Out[7]:
'[{"varName": "a", "varType": "ndarray", "varSize": "1600", "varShape": "10 x 20", "varContent": "array([[-1.86952991e+00, -4.47590288e-01,  1.34226809e+00,\\n         3.89567167e-01,  2.11721934e-01, -1.11331027e-01,\\n        -1.58066888e+00,  4.8026 ...", "isMatrix": true}, {"varName": "x", "varType": "int", "varSize": "28", "varShape": "", "varContent": "1", "isMatrix": false}, {"varName": "y", "varType": "int", "varSize": "28", "varShape": "", "varContent": "6", "isMatrix": false}]'

使用方法

  • 右クリックメニュー
    • Open Variable Inspectorを選択

image.png

In [5]:
import numpy as np

x = 1
a = np.random.randn(10, 20)
変数一覧表示

image.png

ndarrayのmatrix表示

image.png

@ryantam626/jupyterlab_code_formatter

  • 各種コード整形ライブラリをセルに適用
    • コマンドパレットやipynb上部アイコンから使用
コマンドパレットから使用

image.png

アイコンから使用
  • 右から3番目のアイコン

image.png

インストール方法

https://github.com/ryantam626/jupyterlab_code_formatter

jupyter labextension install @lckr/jupyterlab_variableinspector

環境構築用のDockerfileの例

FROM jupyter/scipy-notebook
MAINTAINER Hiromasa OHASHI <stoicheia1986@gmail.com>

RUN pip install jupyterlab_git jupyterlab_code_formatter autopep8 black
RUN jupyter serverextension enable --py jupyterlab_git
RUN jupyter serverextension enable --py jupyterlab_code_formatter

RUN jupyter labextension install \
  @jupyterlab/toc @jupyterlab/git \
  @lckr/jupyterlab_variableinspector \
  @ryantam626/jupyterlab_code_formatter

RUN jupyter lab build

まとめ

  • Jupyter Labの基本的な機能とExtensionを紹介
  • 他にも色々便利な機能などあると思いますのでご意見ください

nikolaの記事をjupyter labで書く

nikolaの記事をjupyter labで書く

この記事はPython その2 Advent Calendarの22日目の記事です。 当日休日出勤になってしまっていたので遅刻してしまいました。すいません。

nikolaはipynbファイルでブログが書けるstatic site generatorの一種です。 nikolaについては過去に記事を書いていますのでご覧ください。 https://www.hiromasa.info/categories/nikola/

jupyter labの実行環境

ここではjupyter公式のscipy-notebookのdockerイメージを立ち上げてjupyter labを動かしています。ゆくゆくはこれにnikolaのブログ構築環境を追加したイメージを作成したいと思っています。 実行する場合は下記のような感じでブログ本体のあるディレクトリを/mnt/blogにマッピングしてローカルホストに対してポート8888でアクセスします。

docker run -ti -v /path/to/blog:/mnt/blog -p 8888:8888 jupyter/scipy-notebook /bin/bash

jupyter labでのMetadataの設定

Nikolaではこの記事に書いたように.ipynbファイルを公開する場合はblog用のメタデータを.ipynbファイルに付与する必要があります。 Metadataの設定はhttps://github.com/jupyterlab/jupyterlab/issues/1308 のissueで議論され、https://github.com/jupyterlab/jupyterlab/pull/5968 のプルリクエストで追加するためのUIが4月ごろに追加されています。

メタデータを付与するためには、一番左側のアイコンの並んでいるカラムからスパナアイコンを選択肢、Advanced Toolsの中のNotebook Metadataを編集すれば良いです。この記事では下記の様な感じにしています。

"nikola": {
        "tags": "python,docker,nikola,jupyterlab",
        "title": "nikolaの記事をjupyter labで書く",
        "date": "2019-12-22 23:00:00 UTC+09:00",
        "type": "text",
        "slug": "16",
        "category": "",
        "link": "",
        "description": ""
    }

image.png

画像のDrag & Dropおよびペースト

このプルリクエストによれば、

  • ファイルブラウザからセルへのドラッグアンドドロップによるファイルの保存
  • セルへの画像のペースト
  • セルのソースをattachmentを加えるように変更する
  • セルのattatchmentがセルの出力のどこからも参照されていない場合にはattachmentを削除する

が既に実現されているようです。 上記には記述がありませんが、そもそも(finderなどから)ファイルブラウザへのドラッグアンドドロップによる保存は可能ですので、そこから更にセルにドラッグアンドドロップすることも可能ですし、osxならshift+ctrl+command+4で範囲選択した内容をcommand+vで挿入できるので便利です。挿入した画像はbase64エンコードされてipynbに埋め込まれます。注意が必要なのは各セルに対してattachmentを複数埋め込むと後から貼り付けたもので上書きされてしまう点です。各セルにcommand+vで貼る画像は今の所一つにとどめておいた方が無難なようです。

extensionの導入

shift+command+cでコマンドパレットを表示し、Enable Extension Managerを選択・実行してEnableにすると左側のアイコンが並んでいるカラムにextention managerが表示されます。これによりjupyter lab上からextensionがインストールできるようになります。コマンドライン上でjupyter labextension installを実行するのと同等の操作が実行できるのだと思います。ここでは試しにtocと打ってみて目次を表示するextensionである@jupyterlab/tocをインストールしてみます。

image.png

インストールを実行したあとにブラウザのタブをリロードすると、ビルドするかを尋ねられるのでビルドを実行後、ビルドが完了するとreloadを求められました。reload後、左側のアイコンのカラムにTOCのアイコンが出現していました。

更にgitのextensionである@jupyter/gitをインストールしてみます。 インストールを実行すると、下記のようにこのextensionを使用する前に対応したserver extensionであるjupyter-gitをインストールしておく必要があると言われます。 image.png

自分はserver extensionを入れる前にOKを押してしまいましたが、先程と同じようにブラウザのタブをリロードするとextensionのビルドが求められました。しばらくするとBuildが完了した旨が表示されます。

server extensionを入れるにはpipでjupyterlab_gitを入れた後にjupyter serverextension enable --py jupyterlab_gitを実行すれば良いようです。

In [13]:
! pip install jupyterlab_git
Collecting jupyterlab_git
  Downloading https://files.pythonhosted.org/packages/24/9b/ce8a9166a0ed945aada0703d0ebae3e98b539b45db0188e571c1d384e68d/jupyterlab_git-0.9.0-py3-none-any.whl (144kB)
     |████████████████████████████████| 153kB 641kB/s eta 0:00:01
Requirement already satisfied: pexpect in /opt/conda/lib/python3.7/site-packages (from jupyterlab_git) (4.7.0)
Requirement already satisfied: notebook in /opt/conda/lib/python3.7/site-packages (from jupyterlab_git) (6.0.0)
Collecting nbdime>=1.1.0
  Downloading https://files.pythonhosted.org/packages/0f/3f/668922f04fa6848437d8486c495ceea2fbe2b011e1084cb49a792c4bec31/nbdime-1.1.0-py2.py3-none-any.whl (4.3MB)
     |████████████████████████████████| 4.3MB 294kB/s eta 0:00:01
Requirement already satisfied: ptyprocess>=0.5 in /opt/conda/lib/python3.7/site-packages (from pexpect->jupyterlab_git) (0.6.0)
Requirement already satisfied: jupyter-client>=5.3.1 in /opt/conda/lib/python3.7/site-packages (from notebook->jupyterlab_git) (5.3.3)
Requirement already satisfied: ipykernel in /opt/conda/lib/python3.7/site-packages (from notebook->jupyterlab_git) (5.1.3)
Requirement already satisfied: prometheus-client in /opt/conda/lib/python3.7/site-packages (from notebook->jupyterlab_git) (0.7.1)
Requirement already satisfied: traitlets>=4.2.1 in /opt/conda/lib/python3.7/site-packages (from notebook->jupyterlab_git) (4.3.3)
Requirement already satisfied: tornado>=5.0 in /opt/conda/lib/python3.7/site-packages (from notebook->jupyterlab_git) (6.0.3)
Requirement already satisfied: Send2Trash in /opt/conda/lib/python3.7/site-packages (from notebook->jupyterlab_git) (1.5.0)
Requirement already satisfied: terminado>=0.8.1 in /opt/conda/lib/python3.7/site-packages (from notebook->jupyterlab_git) (0.8.3)
Requirement already satisfied: jinja2 in /opt/conda/lib/python3.7/site-packages (from notebook->jupyterlab_git) (2.10.3)
Requirement already satisfied: pyzmq>=17 in /opt/conda/lib/python3.7/site-packages (from notebook->jupyterlab_git) (18.1.1)
Requirement already satisfied: nbformat in /opt/conda/lib/python3.7/site-packages (from notebook->jupyterlab_git) (4.4.0)
Requirement already satisfied: jupyter-core>=4.4.0 in /opt/conda/lib/python3.7/site-packages (from notebook->jupyterlab_git) (4.6.1)
Requirement already satisfied: nbconvert in /opt/conda/lib/python3.7/site-packages (from notebook->jupyterlab_git) (5.6.1)
Requirement already satisfied: ipython-genutils in /opt/conda/lib/python3.7/site-packages (from notebook->jupyterlab_git) (0.2.0)
Requirement already satisfied: six in /opt/conda/lib/python3.7/site-packages (from nbdime>=1.1.0->jupyterlab_git) (1.13.0)
Requirement already satisfied: pygments in /opt/conda/lib/python3.7/site-packages (from nbdime>=1.1.0->jupyterlab_git) (2.5.2)
Requirement already satisfied: requests in /opt/conda/lib/python3.7/site-packages (from nbdime>=1.1.0->jupyterlab_git) (2.22.0)
Collecting colorama
  Downloading https://files.pythonhosted.org/packages/c9/dc/45cdef1b4d119eb96316b3117e6d5708a08029992b2fee2c143c7a0a5cc5/colorama-0.4.3-py2.py3-none-any.whl
Collecting GitPython!=2.1.4,!=2.1.5,!=2.1.6
  Downloading https://files.pythonhosted.org/packages/20/8c/4543981439d23c4ff65b2e62dddd767ebc84a8e664a9b67e840d1e2730d3/GitPython-3.0.5-py3-none-any.whl (455kB)
     |████████████████████████████████| 460kB 801kB/s eta 0:00:01
Requirement already satisfied: python-dateutil>=2.1 in /opt/conda/lib/python3.7/site-packages (from jupyter-client>=5.3.1->notebook->jupyterlab_git) (2.8.1)
Requirement already satisfied: ipython>=5.0.0 in /opt/conda/lib/python3.7/site-packages (from ipykernel->notebook->jupyterlab_git) (7.10.1)
Requirement already satisfied: decorator in /opt/conda/lib/python3.7/site-packages (from traitlets>=4.2.1->notebook->jupyterlab_git) (4.4.1)
Requirement already satisfied: MarkupSafe>=0.23 in /opt/conda/lib/python3.7/site-packages (from jinja2->notebook->jupyterlab_git) (1.1.1)
Requirement already satisfied: jsonschema!=2.5.0,>=2.4 in /opt/conda/lib/python3.7/site-packages (from nbformat->notebook->jupyterlab_git) (3.2.0)
Requirement already satisfied: bleach in /opt/conda/lib/python3.7/site-packages (from nbconvert->notebook->jupyterlab_git) (3.1.0)
Requirement already satisfied: entrypoints>=0.2.2 in /opt/conda/lib/python3.7/site-packages (from nbconvert->notebook->jupyterlab_git) (0.3)
Requirement already satisfied: defusedxml in /opt/conda/lib/python3.7/site-packages (from nbconvert->notebook->jupyterlab_git) (0.6.0)
Requirement already satisfied: pandocfilters>=1.4.1 in /opt/conda/lib/python3.7/site-packages (from nbconvert->notebook->jupyterlab_git) (1.4.2)
Requirement already satisfied: mistune<2,>=0.8.1 in /opt/conda/lib/python3.7/site-packages (from nbconvert->notebook->jupyterlab_git) (0.8.4)
Requirement already satisfied: testpath in /opt/conda/lib/python3.7/site-packages (from nbconvert->notebook->jupyterlab_git) (0.4.4)
Requirement already satisfied: idna<2.9,>=2.5 in /opt/conda/lib/python3.7/site-packages (from requests->nbdime>=1.1.0->jupyterlab_git) (2.8)
Requirement already satisfied: certifi>=2017.4.17 in /opt/conda/lib/python3.7/site-packages (from requests->nbdime>=1.1.0->jupyterlab_git) (2019.11.28)
Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in /opt/conda/lib/python3.7/site-packages (from requests->nbdime>=1.1.0->jupyterlab_git) (1.25.7)
Requirement already satisfied: chardet<3.1.0,>=3.0.2 in /opt/conda/lib/python3.7/site-packages (from requests->nbdime>=1.1.0->jupyterlab_git) (3.0.4)
Collecting gitdb2>=2.0.0
  Downloading https://files.pythonhosted.org/packages/03/6c/99296f89bad2ef85626e1df9f677acbee8885bb043ad82ad3ed4746d2325/gitdb2-2.0.6-py2.py3-none-any.whl (63kB)
     |████████████████████████████████| 71kB 1.7MB/s eta 0:00:01
Requirement already satisfied: backcall in /opt/conda/lib/python3.7/site-packages (from ipython>=5.0.0->ipykernel->notebook->jupyterlab_git) (0.1.0)
Requirement already satisfied: prompt-toolkit!=3.0.0,!=3.0.1,<3.1.0,>=2.0.0 in /opt/conda/lib/python3.7/site-packages (from ipython>=5.0.0->ipykernel->notebook->jupyterlab_git) (3.0.2)
Requirement already satisfied: pickleshare in /opt/conda/lib/python3.7/site-packages (from ipython>=5.0.0->ipykernel->notebook->jupyterlab_git) (0.7.5)
Requirement already satisfied: setuptools>=18.5 in /opt/conda/lib/python3.7/site-packages (from ipython>=5.0.0->ipykernel->notebook->jupyterlab_git) (42.0.2.post20191201)
Requirement already satisfied: jedi>=0.10 in /opt/conda/lib/python3.7/site-packages (from ipython>=5.0.0->ipykernel->notebook->jupyterlab_git) (0.15.1)
Requirement already satisfied: pyrsistent>=0.14.0 in /opt/conda/lib/python3.7/site-packages (from jsonschema!=2.5.0,>=2.4->nbformat->notebook->jupyterlab_git) (0.15.6)
Requirement already satisfied: attrs>=17.4.0 in /opt/conda/lib/python3.7/site-packages (from jsonschema!=2.5.0,>=2.4->nbformat->notebook->jupyterlab_git) (19.3.0)
Requirement already satisfied: importlib-metadata; python_version < "3.8" in /opt/conda/lib/python3.7/site-packages (from jsonschema!=2.5.0,>=2.4->nbformat->notebook->jupyterlab_git) (1.1.0)
Requirement already satisfied: webencodings in /opt/conda/lib/python3.7/site-packages (from bleach->nbconvert->notebook->jupyterlab_git) (0.5.1)
Collecting smmap2>=2.0.0
  Downloading https://files.pythonhosted.org/packages/55/d2/866d45e3a121ee15a1dc013824d58072fd5c7799c9c34d01378eb262ca8f/smmap2-2.0.5-py2.py3-none-any.whl
Requirement already satisfied: wcwidth in /opt/conda/lib/python3.7/site-packages (from prompt-toolkit!=3.0.0,!=3.0.1,<3.1.0,>=2.0.0->ipython>=5.0.0->ipykernel->notebook->jupyterlab_git) (0.1.7)
Requirement already satisfied: parso>=0.5.0 in /opt/conda/lib/python3.7/site-packages (from jedi>=0.10->ipython>=5.0.0->ipykernel->notebook->jupyterlab_git) (0.5.1)
Requirement already satisfied: zipp>=0.5 in /opt/conda/lib/python3.7/site-packages (from importlib-metadata; python_version < "3.8"->jsonschema!=2.5.0,>=2.4->nbformat->notebook->jupyterlab_git) (0.6.0)
Requirement already satisfied: more-itertools in /opt/conda/lib/python3.7/site-packages (from zipp>=0.5->importlib-metadata; python_version < "3.8"->jsonschema!=2.5.0,>=2.4->nbformat->notebook->jupyterlab_git) (7.2.0)
Installing collected packages: colorama, smmap2, gitdb2, GitPython, nbdime, jupyterlab-git
Successfully installed GitPython-3.0.5 colorama-0.4.3 gitdb2-2.0.6 jupyterlab-git-0.9.0 nbdime-1.1.0 smmap2-2.0.5
In [14]:
! jupyter serverextension enable --py jupyterlab_git
Enabling: jupyterlab_git
- Writing config: /home/jovyan/.jupyter
    - Validating...
      jupyterlab_git  OK

上記を実行した後にブラウザのタブを再実行したところnbdime-jupyterlabのビルドがダイアログが表示され要求されたため実行しました。 しかしここまでを実行したところ、左側のアイコンが並んでいるカラムにgitのアイコンが表示されるようにはなりましたが、ローカルのリポジトリを読み込んでくれる気配がありませんのでこのあたりについては要調査の上で追記したいと思います。

2020/1/13追記

  • 後日確認したところjupyter lab上でgitのextensionをインストールする前にjupyter serverextension enable --py jupyterlab_gitを実行しておくと、自動的にjupyter labのextensionもインストールされていました
  • 事前にコマンドラインからビルドを実行しておく場合はjupyter lab buildで行けるようです
  • ローカルのリポジトリを読み込まない問題はリポジトリのページを確認したところTroubleShootingの欄のIssue: the Git panel does not recognize that you are in a Git repository.として記載がありましたが原因はjupyter serverextension enable --py jupyterlab_gitを実行した後に、コマンドラインまたはjupyter lab上の表示からビルドを行った上でjupyter labを立ち上げていないことでした。つまり稼働中にserverextensionをenableしてからビルドを行うのではなく、稼働前にビルドを実行しておく必要がありました。上記を踏まえた上でjupyter labを再起動したら下記のような感じのインタフェースが使えるようになりました。

image.png

ブログのビルド

ここではブログのビルド自体はローカル環境(docker上ではない)で実行しています。

$ nikola build
$ nikola serve -b

上記を実行するとビルドを実行した上でローカルサーバを立ち上げてくれ、-bオプションによって自動的にブラウザのタブが開きます。内容に問題ないことを確認したら、あとはサーバーにプッシュしておしまいです。

まとめ

jupyter lab上でブログを執筆する環境構築について記しました。