Jupytext を併用した Jupyter Notebook のカーネルを Spyder に接続する

# はじめに
Python IDE の [Spyder](https://github.com/spyder-ide/spyder) には [Spyder notebook](https://github.com/spyder-ide/spyder-notebook) というプラグインがあります．  
Spyder notebook は Spyder 内で Jupyter Notebook の編集が可能になるプラグインです．Notebook の編集に限らず，Spyder のコンソールと接続することで，Jupyter Notebook に記述したメソッドの実行，変数の確認・書き換え，また，変数エクスプローラーでの変数の確認などが可能になります．  
私は [Jupytext](https://jupytext.readthedocs.io/en/latest/index.html) を使用して，Jupyter Notebook を py ファイル形式で普段保存したい派なのですが，現時点（2020/7/19）では Spyder Notebook 上で Jupytext を有効にすると，エラーが発生し保存・更新がうまくできない状態です．Spyder notebook の [Issue には取り上げられており](https://github.com/spyder-ide/spyder-notebook/issues/272)，将来的には対応するのではないかと思います．

本記事では，現在の環境のまま上述のエラー回避をする方法を備忘録として掲載します．いずれは本体で対応されると思いますので，この記事は用無しになるかと思います．

# 本記事の目的
Jupytext を有効化した状態で Jupyter Notebook のカーネルを Spyder のコンソールに接続し，変数エクスプローラー等を有効にする．

# 確認した環境
- OS: Windows 10 Pro 64bit 2004
- Python: 3.7.3
- Spyder: 4.1.3, 4.1.4
- Spyder notebook: 0.1.4.dev1，0.2.3
- Jupyter: 1.0.0
- Jupytext: 1.5.1

※Spyder notebook 0.3.0 以降では動作しません．

# 手順
## 1. 編集したい Notebook を Spyder Notebook で開く
### 1) Notebook ペインを開きます．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43136/89ca2989-9872-03bb-b535-3a9f8102c5a3.png)
  
※通常は Spyder notebook をインストールすると，Spyder のエディタタブの隣に Notebook タブが自動で追加されます．タブが表示されていない場合，「ツールバー > 表示 > ペイン > Notebook」で表示できる可能性があります．ツールバーのメニューにも存在しない場合，インストールが正常にできていない可能性があります．

### 2a) 既存の Notebook を開いて編集を行う場合
以下の手順で Notebook を開きます．

1. Notebook の空白部分で右クリック → Open... を選択  
または，ペイン右上のハンバーガーメニューから Open... を選択
2. ファイル選択ダイアログで ipynb ファイルを選択して開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43136/696c4051-9064-390d-c800-c733bd08cd1c.png)


### 2b) 新規の Notebook で編集を行う場合
初期状態で開いている `Untitled0.ipynb` を以下の手順で任意の場所に保存します．

1. `Untitled0.ipynb` の空白部分で右クリック → Save as... を 選択  
または，ペイン右上のハンバーガーメニューから Save as... を選択
2. ファイル選択ダイアログでファイルの保存先を指定して保存

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43136/808eff89-f19d-36ad-0f49-fab71439d961.png)

## 2. Jupytext の設定
（初めてJupytextを使用する場合の設定，既に設定してある場合は不要）  

### 1) パーセントフォーマットでのファイル保存を有効化
Spyder Notebook の「File > Jupytext > Pair Notebook with percent Script」にチェックを入れ，パーセントフォーマットでのファイル保存を有効化します．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43136/d6da1024-2510-a8fe-ed62-b5d10944fbf2.png)

保存をすると，同一フォルダ内に .ipynb と同じファイル名の .py ファイルが作成されます．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43136/a8cdc4f5-53e8-7f56-ead7-5635730041a4.png)

- 例
    - `test_spyder_notebook.ipynb`
    - `test_spyder_notebook.py`

## 3. Spyder Notebook の URL の確認
### 1) 起動中の Jupyter Notebook サーバーの確認
`Anaconda prompt`を起動して以下のコマンドを入力し，現在起動している Jupyter Notebook サーバーを確認します．

```console:Anaconda-prompt
jupyter notebook list
```

コマンドを実行すると，以下のように出力されます．

```console:出力例
Currently running servers:
http://localhost:8888/?token=52a00d3ac13d903245ea6a85611667c45f19ea7d902d6e3d :: C:\Users\<user name>
http://localhost:8889/?token=d1e551f8c2627bccfd18f9e56a08035c800cd4ccb7f4097b :: C:\test
```

### 2) ブラウザで Notebook を開く
各URLの行末に表示されている初期ディレクトリと，Notebook の保存されているディレクトリが同一である URL（例では2行目）が，現在 Spyder notebook で開いている Notebook のサーバーの URL です．該当の URL を token まで全てコピーしてブラウザで開きます．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43136/1d068e26-1f78-deea-b643-c2bbab515948.png)


### 3) Notebook の確認
ブラウザ上の Jupyter Notebook のリストに対象の Notebook （例:  `test_spyder_notebook.ipynb`）が存在するか確認します．対象の Notebook が確認できない場合，URL が誤っている可能性があります．その場合は先程コンソールで確認した URL リストから別の URL を選択し，再度ブラウザで確認します．

### 4) Spyder Notebook 上の Notebook を閉じる
対象の Notebook が確認できたら，Spyder Notebook 上の Notebook は**閉じます**．
（Spyder Notebook のデフォルト画面が表示されているだけの状態になります）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43136/e331f70d-9c6e-da69-a698-872a96f37164.png)

## 4. パーセントフォーマット py ファイルを Jupyter Notebook で開く
### 1) .pyファイルをブラウザ上の Jupyter Notebook で開く  

- 補足
    - .py ファイルを開くと，ステータスが `Running` となり，ファイル名が緑色になります．
    - .ipynbファイルは先程 spyder 上で閉じたので，グレーの文字になっているはずです．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43136/8da46da8-033a-9803-47af-86c1b72f81b5.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43136/a774faa9-968c-1625-76d4-8106ec352a2d.png)

## 5. Jupyter Notebook のカーネルを Spyder のコンソールへ接続
### 1) 既存のカーネルに接続
Spyder コンソールのハンバーガーメニューから，「既存のカーネルに接続」を選択します．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43136/f95b1798-bcf5-b58f-1c22-9bd75dbc8d35.png)

ダイアログが開いたら，接続情報ファイルの「表示」ボタンを押します．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43136/0769e744-d638-5935-29bb-a0a4729c8048.png)

ファイル選択ダイアログが開くので，更新日順でファイルを並び替え，最も更新日の新しいJSONファイルを選択します．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43136/3cfe94bf-bfe4-61a3-a14d-a35393fa2b87.png)

- 補足
    - このJSONファイルが先程 Jupyter Notebook で開いた `test_spyder_notebook.py` ファイルのカーネル接続情報です
    - 規定の接続情報ファイル（jsonファイル）の保存先は `C:\Users\<user name>\AppData\Roaming\jupyter\runtime` です

```json:jsonファイルの中身（例）
{
  "shell_port": 49552,
  "iopub_port": 49553,
  "stdin_port": 49554,
  "control_port": 49555,
  "hb_port": 49556,
  "ip": "127.0.0.1",
  "key": "591c2e22-fc725f42989c69108b68f974",
  "transport": "tcp",
  "signature_scheme": "hmac-sha256",
  "kernel_name": ""
}
```

ほかは変更せず，OKを押し，ダイアログを閉じます．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43136/80c1c6c8-ce9b-bed9-78b9-b19b921b1631.png)

### 2) 接続後の状態
コンソールが追加されていることが確認出来ます．
（ここではコンソール名は「コンソール 2/A」）
コンソールへの接続前に Notebook を編集していた場合，変数エクスプローラには変数が表示されます．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43136/e2ae4821-19c1-22df-997b-3351a1eb1a67.png)

## 6. 実行例
### 1) Jupyter Notebook への入力
普段通りに使用できます．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43136/cec5665d-627c-0138-239f-c30461844dd3.png)

### 2) 変数エクスプローラーの確認
Jupyter Notebook の内容がリアルタイムでは反映されないため，
初期状態では変数エクスプローラーには変数が何も表示されていません．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43136/90053b00-ce16-7e61-959e-3ada2495fe9c.png)

この状態で Spyder のコンソールで空行のまま Enter キーを押し実行すると，変更が反映されます．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43136/e5c0673d-c96f-54ad-1d1e-ae082657eaec.png)

変更が反映されると，普段 Spyder で使用している際と同様に，変数エクスプローラーで変数の確認ができるようになります．  

例: df_iris
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43136/7b3521d3-ee05-d566-f7ba-f624aa28fea0.png)

### 3) Spyder上での py ファイルの編集
Jupytext を利用しているため，Jupyter Notebook 上での実行内容は随時 py ファイルに保存されていきます．py ファイルはスクリプトファイルなので Spyder のエディタでも開くことが可能であり，編集も可能です．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43136/8a6de19a-8b0f-8527-ac0f-12cabed17d22.png)

#### 注意点
Jupyter Notebook 上で変更があると，Spyder のエディタが自動で py ファイルを再読み込みしますが，Spyder のエディタ上でpyファイルを変更しても Jupyter Notebook は自動で再読み込みしてくれません．Spyder のエディタ上で変更した内容を Jupyter Notebook に反映させる場合は，Jupyter Notebook のページを F5 キーなどで再読込する必要があります．
（設定で対応できそうですが私は判っていません．）