【iOS】はじめてのPyto

# はじめに
iOSのPython環境で最も有名なのはPythonistaだと思います。個人的にPythonistaは、

* 更新が2年以上無い（2020/2/24現在）（2020/3/9追記：Pythonista v3.3がリリースされました）
* 対応ライブラリが少ない（Pandasが使えない）

という点が引っかかり、購入を見送っていました。ある日、日経ソフトウェアに「Pyto」というアプリが紹介されており、検索してみるとPythonistaと比較して、以下の点が魅力的だったので購入しました。

* 更新頻度が高い
* Pandasに加え、sklearn、skimage、OpenCVも使える
* Pythonistaと同様にiOS用のGUIアプリの作成が可能（iOS13以降）

この記事ではPytoの使い方や基本的な機能について説明します。

# 追記
2021/2/22
Pytoには3日間の無料トライアル版があります。
記事中の画像と内容の一部を最新のものに差し替えました。
 
# 環境
##### 初回投稿時
iPad pro11（2018）64GB (iOS13.3.1)
Pyto(11.4)

##### 2021/2/22投稿時
iPad pro11 (2018) 64GB (iOS14.3)
Pyto(16.0.1)
※おまけのmobilenetの画像は差し替えていませんが、動作は確認済みです。
 
# 使い方
## 起動画面・ファイル選択画面
![IMG_0343_edit.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549600/a2c7ce8f-db00-4176-5400-a807c79c59d0.png)
![IMG_0378.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549600/a7b29279-36c7-5306-9191-bac52ac54ab9.png)

 初回はアプリを起動すると、ファイルを選択する画面になります。任意の場所のファイルを開くか、新規作成を行います。画像1枚目の青矢印のボタンを押すことで、画像2枚目のようにアプリの各機能にアクセスできるようになります。アプリの設定は画像2枚目の歯車ボタンです。

 
### 対話モード（REPL）
![IMG_0353.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549600/1eaf784a-f6cc-9a8b-a7c6-f699c143a71e.png)

 対話モードです。コードは下のテキストボックスに入力します。対話モードでもmatplotlibのグラフ表示が可能です。
 
### Run module (python -m)
![IMG_0357.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549600/d1d1e7c2-79a0-3095-9599-0e4b6373a2f2.png)

 `.py`ファイルを実行できます。上の画面ではpipを実行していますが、`pip show`でパッケージの情報を表示することはできませんでした。また、インストール済みのパッケージを確認するために`pip list`を実行しましたが、後述するPyPiで後からインストールしたパッケージしか表示されませんでした。

### PyPI
![IMG_0379.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549600/da54dbce-c7ab-c7e9-e805-67e30b08cf3d.png)
![IMG_0355.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549600/041c43d0-42d2-4550-2924-7e666c6a41f4.png)
![IMG_0356.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549600/f14c4dd5-0d3f-74cc-7762-de6a56157ed9.png)


 PyPIを使ってインストールされているライブラリのバージョンを確認したり、新たにライブラリを追加することができます。ただし、追加できるのはpure pythonのものに限るそうです。seabornはインストールできましたが、tensorflow、pyaudioはインストールできませんでした。

 Pytoでサポートされているライブラリ（scikit-image, OpenCV等）は、初回実行時にダウンロード・インストールされます。よって、インターネット環境のない場所で使用する場合はあらかじめダウンロードしておく必要があります。すべてのライブラリをダウンロードする場合は「Settings」の「Download All」を実行します。

![IMG_0364.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549600/4be5a7e1-7b42-0c4c-296d-ab356f9116a5.png)

上の図ではインストールしたseabornを使ってpairplotを実行しています。Pytoでmatplotlibやseabornを使う際は、`plt.clf()`を最後に記述しないと複数回実行時にグラフが重なってしまいます。

### サンプルコード
![IMG_0359.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549600/a68a656a-e099-57f8-62ad-ca0994214e17.png)

OpenCV、scikit-learn、GUIモジュール等を使ったサンプルコードが入っています。

 
### Loaded modules
![IMG_0358.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549600/abdcc62c-6ebc-d7af-c3bd-4b7bcd37e9c1.png)

 読み込んだことのあるモジュールが表示されます。そのモジュールのソースコードも表示できます。何に使うのかはよくわかりません。
  

### Settings
![IMG_0350.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549600/f06fa781-cf2d-d3eb-e2fd-a1698f3f7e3b.png)
![IMG_0351.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549600/9781d415-beca-cb6b-2c03-6ad016ab2346.png)

 エディタの設定画面です。ソフトタブ（スペースタブ）に対応しています。また、エディタの外観も数種類から選んだり、カスタマイズすることが可能です。サポートされているサードパーティ製ライブラリの一括ダウンロードもここで行います。

 
## エディタ画面
![IMG_0381.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549600/fa7efbab-1114-e0f9-f96d-a0cc6450835c.png)

 エディタ画面です。右下に歯車マークがありますが、これはアプリの設定ではありません。Siriに編集中のファイルを登録したり、カレントディレクトリを変更したりできます。左下のリストアイコンはエディタアクションで、ファイルに対して何か実行できるそうです。その隣のブックマークアイコンはPytoのドキュメントです。Pytoのパッケージ（GUIツールなど）の使い方が書いてあります。このドキュメントはインターネット上に公開されており、[こちら](https://pyto.readthedocs.io/en/latest/)から確認できます。

上部のボタンは左から順に「メニューサイドバーを開く」、「検索・置換」、「コードのアウトライン表示」、「デバッグ(pdb)」、「実行」です。

###  Arguments, Current Directory, Add to Siri,
![IMG_0365.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549600/9d753bdc-dd12-9582-0b5b-6291b36fef86.png)

add-to-siri, arguments, current directoryを設定できます。argumentsではプログラム実行時に渡す引数を設定できます。

 current directoryではカレントディレクトリを変更することができます。変更すると警告が出ますが、カレントディレクトリ変更後も問題なく実行できます。ここで選択したディレクトリには編集権限がつき、ファイルの参照・変更が可能となります。ローカルのファイルを読み込めない時はここでフォルダ選択すると読み込めるようになるかもしれません。

### Editor actions
![IMG_0369.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549600/949c5b9b-c9c9-8bf6-b789-a08debb7540f.png)

 Editor actionsです。デフォルトで2to3とblackが用意されています。

### アウトライン表示
![IMG_0367.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549600/ef00011b-49cb-07a0-ccc8-dc9c6f2505b3.png)

ソースコード内のモジュール、クラス、関数のアウトライン表示・検索が可能です。横に表示されている数字は行番号です。

### ドキュメント

![IMG_0361.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549600/5c5cbdb2-768a-d11b-af79-4a3745e8e74b.png)

ドキュメントです。公開されている[こちら](https://pyto.readthedocs.io/en/latest/)と同じものです。右上の「V」のようなボタンでスプリットビューになります。

![IMG_0362.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549600/906b272a-31bb-7250-e297-424252bae237.png)

ドキュメントをスプリットビューにしたところ。

### 補完
![IMG_0363.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549600/2c93eb7c-3891-ea8b-67d0-825f8d554ec8.png)

補完が可能です。タップで選択するか、Tabキーで候補から選んでEnterで確定します。

### フォルダロック
![IMG_0344_edit.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549600/5c786356-787a-d00e-18cb-946c9cd0a8a3.png)

 初めて使用するフォルダは初期状態では参照・変更できないようになっています。この場合は右下の鍵マークを押し、現在のディレクトリを選択することで参照・変更が可能となります。


## キーボード
![IMG_0373.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549600/5fa0be84-8953-ec9a-1764-38b896be1955.png)

 ソフトウェアキーボードはiOSのデフォルトです。PytoではTabキー以外の拡張キーは用意されていません。これはiPhoneでも同じなので、iPhoneでプログラムを書くのは少し厳しいです。

 外部キーボード（Bluetoothキーボード等）は難なく使えます。コメントアウト、逆インデント、実行等のショートカットキーも使用でき、そこそこ快適です。一括コメントアウトは複数行を選択した状態で[Cmd]+[Shift]+[C]を押すと可能です。
 
 
# おまけ
  OpenCVにはdnnモジュールが含まれているので、試しにMobilenetを動かしてみました。ソースコードはhttp://asukiaaa.blogspot.com/2018/03/opencvdnnpythonmobilenet.html からお借りし、Pyto用に少し書き直しました。カメラはiPadの外カメラです。
 動作は問題無く、フレームレートもカクツキを感じないレベルでした。正直、iOSアプリの上でMobilenetが動くとは思っていなかったので、驚きました。
![7F93B6F4-F29B-4BCC-A1E9-071D864BE627.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549600/9645e9d0-821e-a0bf-aba0-e5bdfd928cd1.png)

#### [2020/4/22追記] Mobilenetの使い方について


MobileNetの学習済みデータは、[こちら](https://github.com/shicai/MobileNet-Caffe)に含まれる

- mobilenet_v2.caffemodel
- mobilenet_v2_deploy.prototxt
- synset.txt

を使用させていただきました。iOS13以降であればzipの展開が可能なので、zip形式でダウンロードします。

次に上記ファイルを任意のフォルダに展開します。私は、  

```
python_code（適当なフォルダ）
├── MobileNet-Caffe-master
│   ├── mobilenet_v2.caffemodel
│   ├── mobilenet_v2_deploy.prototxt
│   └── synset.txt
├── mobilenet.py（実行ファイル）
```

としました。場所によってはアクセス許可が必要になるかもしれません。

使わせていただいたソースコードはコマンドライン引数でファイルを指定されています。pytoでは引数の指定が可能ですが、私は以下のようにプログラム内に直接書きました。

```python
import os
from cv2 import dnn

modelfolder = "./MobileNet-Caffe-master"  # 学習済みデータの入ったフォルダ
net = dnn.readNetFromCaffe(os.path.join(modelfolder, "mobilenet_v2_deploy.prototxt"), os.path.join(modelfolder, "mobilenet_v2.caffemodel"))
with open(os.path.join(modelfolder, "synset.txt"), "r") as f:
    classNames = f.readlines()
showPreview = True
```

あとは以下の点を書き換えると動くと思います。

- `cv2.autorotate`を使用する（デバイスの向きに合わせて画像を回転してくれる）
- `cv2.destroyAllWindows`および`cv2.waitKey`は書かない
- `print`関数は全てコメントアウトする

```python
# autorotateの書き方
import cv2

device = 0
cap = cv2.VideoCapture(device)
while cap.isOpened():
    ret, frame = cap.read()
    if not ret:
        continue
    frame = cv2.autorotate(frame, device)  # この部分を追加
    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
```

# その他
- ユニバーサルアプリ(iPhone, iPad両対応）である
- デバッガ(pdb)が使える
- csv、画像の読み込みはローカルでも問題なかった
- matplotlibのグラフ重なりは`plt.clf()`で解決できる（前述）
- PytoのGUIモジュールはpythonistaとほぼ同じ書き方ができる？
- ~~syntax highlightが少しおかしい（「おまけ」の18行目、20行目など）~~v11.5で修正されました
- 折り返された行は新しい行扱いになる（自動でインデントされなかったり、行の途中なのにコメントアウトできてしまう。バグ？）
- ~~閉じ括弧「）」を自動で付けてくれるが、自分で書くと2重になってしまう（vscodeみたいに括弧の外に出してくれない）~~（2020/8/16追記(v12.5)：改善されていました）
- pythonistaほどGUIに強くない（GUI作成ツールでパーツ配置できない）
- 動作が不安定でよく落ちる
- v16.0.1現在、skimageのioが使えない

GUIアプリ作成を重視するならPythonista、処理を重視するならPytoといった感じでしょうか。PythonistaにあってPytoに無いライブラリもあるので、ドキュメント等で内蔵ライブラリの比較を行うと良いと思います。

Pytoはこれからも発展していきそうなので、とても期待できるアプリだと感じました。

# リンク
Pyto公式サイト：https://pyto.app/
Pytoドキュメント：https://pyto.readthedocs.io/en/latest/