Tkinterで「NSInvalidArgumentException」が出た

# はじめに
TkinterはPythonでGUIを組むことのできるツールキットです。これを使用してツールを作ろうとしたところ、MacではNSInvalidArgumentExceptionエラーが出て、動作しませんでした。これはbackendの指定に問題があったようです。

## backend
matplotlibをPythonシェルからインタラクティブに使用する人もいれば、Jupyterのノートブックを実行し、インラインプロットを描く人もいます。豊富なアプリケーションを構築するために、wxpythonやpygtkのようなグラフィカルユーザインタフェースにmatplotlibを組み込む人もいます。matplotlibはこれらの様々な出力先に対応できるようになっており、その設定がbackendと呼ばれます。今回はTkinter用のbackendを指定する必要がありました。

# 参考
- [Weird interaction with Tkinter #10239](https://github.com/matplotlib/matplotlib/issues/10239) > matplotlibのbackendの設定
- [OS X 10.6.8 - Tkinter crashing _GUI scripts #29](https://github.com/MTG/sms-tools/issues/29) > matplotlibのbackendの設定
- [Usage Guide](https://matplotlib.org/tutorials/introductory/usage.html) > backendに関する解説
- [Crash on Mac OS when importing Tkinter #110](https://github.com/ninia/jep/issues/110) > MacOS特有の問題に関する解決策

# 環境

- macOS Mojave 10.14.2
- python 3.6.7


# 手順
エラーが起きるとターミナルに次のようなメッセージが出力されます。

```
2018-12-18 00:22:20.180 python[37108:1011614] -[NSApplication _setup:]: unrecognized selector sent to instance 0x7ff8acdfaa40
2018-12-18 00:22:20.183 python[37108:1011614] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSApplication _setup:]: unrecognized selector sent to instance 0x7ff8acdfaa40'
*** First throw call stack:
(
        0   CoreFoundation                      0x00007fff4c4f5ecd __exceptionPreprocess + 256
        1   libobjc.A.dylib                     0x00007fff785ad720 objc_exception_throw + 48
        2   CoreFoundation                      0x00007fff4c573275 -[NSObject(NSObject) __retain_OA] + 0
        3   CoreFoundation                      0x00007fff4c497b40 ___forwarding___ + 1486
        4   CoreFoundation                      0x00007fff4c4974e8 _CF_forwarding_prep_0 + 120
        5   libtk8.6.dylib                      0x0000001c17e6c31d TkpInit + 413
        6   libtk8.6.dylib                      0x0000001c17dc417e Initialize + 2622
        7   _tkinter.cpython-36m-darwin.so      0x0000001c14fe8a16 _tkinter_create + 1174
        8   python                              0x0000000100cec088 _PyCFunction_FastCallDict + 200
        9   python                              0x0000000100dc2f4f call_function + 143
        10  python                              0x0000000100dc0abf _PyEval_EvalFrameDefault + 46847
        11  python                              0x0000000100db4209 _PyEval_EvalCodeWithName + 425
        12  python                              0x0000000100dc3b1c _PyFunction_FastCallDict + 364
        13  python                              0x0000000100c6a8b0 _PyObject_FastCallDict + 320
        14  python                              0x0000000100c91fe8 method_call + 136
        15  python                              0x0000000100c71efe PyObject_Call + 62
        16  python                              0x0000000100d13385 slot_tp_init + 117
        17  python                              0x0000000100d178c1 type_call + 241
        18  python                              0x0000000100c6a821 _PyObject_FastCallDict + 177
        19  python                              0x0000000100dc3048 call_function + 392
        20  python                              0x0000000100dc0abf _PyEval_EvalFrameDefault + 46847
        21  python                              0x0000000100db4209 _PyEval_EvalCodeWithName + 425
        22  python                              0x0000000100daea79 builtin_exec + 345
        23  python                              0x0000000100cec088 _PyCFunction_FastCallDict + 200
        24  python                              0x0000000100dc2f4f call_function + 143
        25  python                              0x0000000100dc0abf _PyEval_EvalFrameDefault + 46847
        26  python                              0x0000000100db4209 _PyEval_EvalCodeWithName + 425
        27  python                              0x0000000100dc33ba fast_function + 362
        28  python                              0x0000000100dc2fac call_function + 236
        29  python                              0x0000000100dc0abf _PyEval_EvalFrameDefault + 46847
        30  python                              0x0000000100dc330c fast_function + 188
        31  python                              0x0000000100dc2fac call_function + 236
        32  python                              0x0000000100dc0abf _PyEval_EvalFrameDefault + 46847
        33  python                              0x0000000100db4209 _PyEval_EvalCodeWithName + 425
        34  python                              0x0000000100dc33ba fast_function + 362
        35  python                              0x0000000100dc2fac call_function + 236
        36  python                              0x0000000100dc0abf _PyEval_EvalFrameDefault + 46847
        37  python                              0x0000000100dc330c fast_function + 188
        38  python                              0x0000000100dc2fac call_function + 236
        39  python                              0x0000000100dc0abf _PyEval_EvalFrameDefault + 46847
        40  python                              0x0000000100db4209 _PyEval_EvalCodeWithName + 425
        41  python                              0x0000000100cb55bd function_call + 125
        42  python                              0x0000000100c71efe PyObject_Call + 62
        43  python                              0x0000000100dc0cc0 _PyEval_EvalFrameDefault + 47360
        44  python                              0x0000000100db4209 _PyEval_EvalCodeWithName + 425
        45  python                              0x0000000100cb55bd function_call + 125
        46  python                              0x0000000100c71efe PyObject_Call + 62
        47  python                              0x0000000100dc0cc0 _PyEval_EvalFrameDefault + 47360
        48  python                              0x0000000100db4209 _PyEval_EvalCodeWithName + 425
        49  python                              0x0000000100cb55bd function_call + 125
        50  python                              0x0000000100c71efe PyObject_Call + 62
        51  python                              0x0000000100dc0cc0 _PyEval_EvalFrameDefault + 47360
        52  python                              0x0000000100db4209 _PyEval_EvalCodeWithName + 425
        53  python                              0x0000000100dc33ba fast_function + 362
        54  python                              0x0000000100dc2fac call_function + 236
        55  python                              0x0000000100dc0b6f _PyEval_EvalFrameDefault + 47023
        56  python                              0x0000000100db4209 _PyEval_EvalCodeWithName + 425
        57  python                              0x0000000100dc33ba fast_function + 362
        58  python                              0x0000000100dc2fac call_function + 236
        59  python                              0x0000000100dc0abf _PyEval_EvalFrameDefault + 46847
        60  python                              0x0000000100db4209 _PyEval_EvalCodeWithName + 425
        61  python                              0x0000000100e0cd4c PyRun_FileExFlags + 252
        62  python                              0x0000000100e0c224 PyRun_SimpleFileExFlags + 372
        63  python                              0x0000000100e32d66 Py_Main + 3734
        64  python                              0x0000000100c62929 main + 313
        65  libdyld.dylib                       0x00007fff7967bed9 start + 1
        66  ???                                 0x0000000000000009 0x0 + 9
)
libc++abi.dylib: terminating wi
```

これを解決するにはスクリプトの最初にbackendの設定を記述します。

```python
import matplotlib 
matplotlib.use('tkagg') 
```
ここで、[サイト](https://github.com/MTG/sms-tools/issues/29)によっては引数を`'TkAgg'`としている場合があります。精査していませんが、python2.7の場合は`'TkAgg'`と思われます。私の環境（python 3.6.7）では`'tkagg'`で動作しました。


# おわりに
`'TkAgg'`と書いたばかりに3時間ほど浪費しました。
[ちなみに他にもいくつかbackendがあります。](https://matplotlib.org/tutorials/introductory/usage.html)

| Backend | Description |
|:--|:--|
| Qt5Agg | Agg rendering in a Qt5 canvas (requires PyQt5). This backend can be activated in IPython with %matplotlib qt5. |
| ipympl | Agg rendering embedded in a Jupyter widget. (requires ipympl). This backend can be enabled in a Jupyter notebook with %matplotlib ipympl. |
| GTK3Agg | Agg rendering to a GTK 3.x canvas (requires PyGObject, and pycairo or cairocffi). This backend can be activated in IPython with %matplotlib gtk3. |
| macosx | Agg rendering into a Cocoa canvas in OSX. This backend can be activated in IPython with %matplotlib osx. |
| TkAgg | Agg rendering to a Tk canvas (requires TkInter). This backend can be activated in IPython with %matplotlib tk. |
| nbAgg | Embed an interactive figure in a Jupyter classic notebook. This backend can be enabled in Jupyter notebooks via %matplotlib notebook. |
| WebAgg | On show() will start a tornado server with an interactive figure. |
| GTK3Cairo | Cairo rendering to a GTK 3.x canvas (requires PyGObject, and pycairo or cairocffi). |
| Qt4Agg | Agg rendering to a Qt4 canvas (requires PyQt4 or pyside). This backend can be activated in IPython with %matplotlib qt4. |
| WXAgg | Agg rendering to a wxWidgets canvas (requires wxPython 4). This backend can be activated in IPython with %matplotlib wx. |


動かないときはすべて小文字にして試してみるとよいのかもしれません。
また、Macの場合はTcl/Tkにバグが有る場合があり、[環境を再構築する必要がある場合もあります。](https://github.com/ninia/jep/issues/110)