NuitkaでPlotlyをアプリケーション化する

# NuitkaでPlotlyをアプリケーション化する
NuitkaにはいくつかPluginが用意されているが、Plotlyは用意されておらず、
かなり悩んだので、ここにメモしておきます。

### 0. 前提、使用環境など
* Windows10 64bit
* Anaconda使用
* Python 3.8.13
* Nuitka用にAnaconda内に仮想環境を新しく作って、そこで作業しました。
>NumpyとPandasはバージョンを少し下げています。最初の思考錯誤でエラー回避のため下げましたが
結果的に下げる必要があったかは定かではありません。
あとは、Plotlyもconda-forgeでinstallして、最新版にすればエラー回避？？と期待してやったのですが、
たぶん結果的には関係なかったと思います。
```shell:仮想環境nuitka内のlist
# Name                    Version                   Build  Channel
blas                      1.0                         mkl
bottleneck                1.3.5            py38h080aedc_0
brotli                    1.0.9                h2bbff1b_7
brotli-bin                1.0.9                h2bbff1b_7
ca-certificates           2022.9.14            h5b45459_0    conda-forge
certifi                   2022.9.14          pyhd8ed1ab_0    conda-forge
cffi                      1.15.1           py38h2bbff1b_0
cycler                    0.11.0             pyhd3eb1b0_0
fonttools                 4.25.0             pyhd3eb1b0_0
freetype                  2.10.4               hd328e21_0
glib                      2.69.1               h5dc1a3c_1
gst-plugins-base          1.18.5               h9e645db_0
gstreamer                 1.18.5               hd78058f_0
icu                       58.2                 ha925a31_3
intel-openmp              2021.4.0          haa95532_3556
jpeg                      9e                   h2bbff1b_0
kiwisolver                1.4.2            py38hd77b12b_0
lerc                      3.0                  hd77b12b_0
libbrotlicommon           1.0.9                h2bbff1b_7
libbrotlidec              1.0.9                h2bbff1b_7
libbrotlienc              1.0.9                h2bbff1b_7
libclang                  12.0.0          default_h627e005_2
libdeflate                1.8                  h2bbff1b_5
libffi                    3.4.2                hd77b12b_4
libiconv                  1.16                 h2bbff1b_2
libogg                    1.3.5                h2bbff1b_1
libpng                    1.6.37               h2a8f88b_0
libtiff                   4.4.0                h8a3f274_0
libvorbis                 1.3.7                he774522_0
libwebp                   1.2.2                h2bbff1b_0
libxml2                   2.9.14               h0ad7f3c_0
libxslt                   1.1.35               h2bbff1b_0
lz4-c                     1.9.3                h2bbff1b_1
matplotlib                3.5.2            py38haa95532_0
matplotlib-base           3.5.2            py38hd77b12b_0
mkl                       2021.4.0           haa95532_640
mkl-service               2.4.0            py38h2bbff1b_0
mkl_fft                   1.3.1            py38h277e83a_0
mkl_random                1.2.2            py38hf11a4ad_0
munkres                   1.1.4                      py_0
nuitka                    0.6.16             pyhd3eb1b0_1
numexpr                   2.8.3            py38hb80d3ca_0
numpy                     1.21.5           py38h7a0a035_3
numpy-base                1.21.5           py38hca35cd5_3
openssl                   1.1.1q               h8ffe710_0    conda-forge
packaging                 21.3               pyhd3eb1b0_0
pandas                    1.3.5            py38h6214cd6_0
pcre                      8.45                 hd77b12b_0
pillow                    9.2.0            py38hdc2b20a_1
pip                       22.1.2           py38haa95532_0
plotly                    5.10.0             pyhd8ed1ab_0    conda-forge
ply                       3.11                     py38_0
pycparser                 2.21               pyhd3eb1b0_0
pyparsing                 3.0.9            py38haa95532_0
pyqt                      5.15.7           py38hd77b12b_0
pyqt5-sip                 12.11.0          py38hd77b12b_0
pysimplegui               4.60.3             pyhd8ed1ab_0    conda-forge
python                    3.8.13               h6244533_0
python-dateutil           2.8.2              pyhd3eb1b0_0
pytz                      2022.1           py38haa95532_0
qt-main                   5.15.2               he8e5bd7_7
qt-webengine              5.15.9               hb9a9bb5_4
qtwebkit                  5.212                h3ad3cdb_4
setuptools                61.2.0           py38haa95532_0
sip                       6.6.2            py38hd77b12b_0
six                       1.16.0             pyhd3eb1b0_1
sqlite                    3.39.2               h2bbff1b_0
tenacity                  8.0.1            py38haa95532_1
tk                        8.6.12               h2bbff1b_0
toml                      0.10.2             pyhd3eb1b0_0
tornado                   6.2              py38h2bbff1b_0
vc                        14.2                 h21ff451_1
vs2015_runtime            14.27.29016          h5e58377_2
wheel                     0.37.1             pyhd3eb1b0_0
wincertstore              0.2              py38haa95532_2
xz                        5.2.5                h8cc25b3_1
zlib                      1.2.12               h8cc25b3_3
zstandard                 0.15.2           py38h2bbff1b_0
zstd                      1.5.2                h19a0ad4_0
```
### 1. Nuitkaのインストールなど
以下のページを参考にさせて頂きました。
* [簡単にPythonスクリプトから実行ファイルを作れるNUITKA-Utilities hinted-compilationの使い方](https://qiita.com/Miyabi1456/items/e44864d307e6d253cd30)
* [PyInstaller より圧倒的に優れている Nuitka の使い方とハマったポイント](https://blog.tsukumijima.net/article/python-nuitka-usage/)
* [Kivyで作ったアプリをNuitkaでexeファイル化した時の試行錯誤のメモの巻](https://vucavucalife.com/generate-exefile-from-kivy-app-with-nuitka/)

Nuitka公式の[Github](https://github.com/Nuitka/Nuitka)も参考に作業しました。
数年前に１度、exe化したことがあるのですが、今回はうまくいきませんでした。

### 2. Nuitka Utilitiesを使う
上記の公式Githubを参考にexe化する方法があります。
が、PlotlyのnotFoundModuleエラーが改善せず、いろいろオプションをつけていくと、
コンパイルが全く終わりそうにない状態に陥りました。
※自分のやり方の問題だと思います（涙）。

そこで[NUITKA-Utilities](https://github.com/Nuitka/NUITKA-Utilities)にも説明がある通り、
コンパイル時間の短縮にもつながるこちらのUyilitiesを使うことにしました。
Utilities一式をダウンロードして、ローカルに保存。
但し、そのままでは使えなかったため、、[こちら](https://stackoverflow.com/questions/68354474/why-does-nuitka-hinted-compilation-return-error)にある通り、hinted-compilationフォルダのhinted-mods.pyの中身を修正してから使用します。

### 3. get-hints.py
* Anacondaプロンプトを起動し、仮想環境Nuitkaをアクティベイト。
```shell
$ conda activate Nuitka
```
* Utilitiesを保存した場所にcdで移動し、hinted-compliactionフォルダに入る。

* exe化したいPlotlyが含まれるPythonプログラムをMyScript.pyとすると、
```shell
$ python get-hints.py MyScript.py
```
　実行すると、MyScript.pyが実行され、正常に動作すれば、MyScript-38-win32-64.jsonファイルが生成されます。
　新規に仮想環境作っているので、インストールし忘れているものがあるともちろんエラーが出ます（思いっきりでました）。

>とりあえず、ここまでは問題なく作業できると思います。

### 4. nuitka-hints.py
__むちゃくちゃ悩まされたplotly.validators.layout.xaxis__
![NotFound.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/571035/fee212d3-a040-b13d-8678-2f09826438c3.jpeg)
ちなみに、xaxisだけ追加すると、次はyaxisのModuleNotFoundErrorがでます（涙）、、、次はannotation、、、

公式のUse Case 1に倣うと
```shell
$ python -m nuitka --follow-imports --include-module=plotly.validators.layout.xaxis MyScript.py
```
とかで行けそうなんですが、こちらでやると時間がかかるのと、別のPandasのエラーなどが出て、
なんともならず（私のやり方の問題でしょうけど）。
どうやって、オプション追加するのか、、、、と探してやっと見つけました（涙）。

```python:nuitka-hints.py 56行目
my_opts = [
    "--standalone",  # the purpose of this script
    "--nofollow-imports",  # exclude everything
]
```
誰も困っていないのか、、、自分だけなのか、、、
ここにオプションの記載がありました。というわけで、上にもある[こちら](https://vucavucalife.com/generate-exefile-from-kivy-app-with-nuitka/)の方のオプションをnuitka-hints.pyに追記しました。
```python:nuitka-hints.py 56行目
my_opts = [
    "--standalone",  # the purpose of this script
    "--nofollow-imports",  # exclude everything
    "--include-module=plotly.io",
    "--include-module=plotly.graph_objs",
    "--include-module=plotly.validators",
    "--include-package-data=plotly",
    "--onefile" 
]
```
plotly関連の追加モジュール3つと、Plotlyパッケージデータが1つ。
最後の--onefileは、公式の説明ではhinted-compilationフォルダの１つ上の階層の
onefile-maker-windows.pyで１つのファイルにすることができるとあるのですが、うまくいかなったので、
ついでにこちらで１つのファイルにして出力しました。

### 5. まとめ
調べたんですが、出てこないということは、皆さんさほど悩んでいないということかもしれませんが、
私のように、できそうで、できない、、、おしいところまできているのに、なんで？？？と
思ってる方がもし、他にもいれば、お役に立てれば幸いです（笑）