Matplotlib Object Model
Matplotlib を使ったコードを写経しようとしたが 10 行くらいで発狂しそうになる。この API, 眺めてるときからクソだと思ってたけれど自分で書くのは更に苦痛。耐えられませぬ...
しかし今回は high level な API に逃げないと決めているので、なんとかこの人たちの気持ちを理解しようと公式のドキュメントを読んでみる。と、一定程度理解が深まり殺意も和らいだのでみんな読むと良いよ、という話。
まず Introduction から。「表面的には Matlab インスパイヤな API だけれど中は割と object oriented だよ」という。かすかな希望を抱いて次に Introductory Tutorial を一通り眺める。それから Artist Tutorial を読む。
わかること:
- Matplotlib の API 呼び出しは、内部の DOM みたいなのを構築したり、オブジェクトのパラメタをセットしたりするものである。そうやって作ったオブジェクトモデルを最後に show() で描画する。
- オブジェクトモデルの中心は Artist と呼ばれるオブジェクト群。Artist は DOM の Node みたいなもの。Artist の中にはコンテナの役割を果たす Figure と Axes, 末端のプリミティブとして Line2D やらなんやらがある。
- 中でも主役は Axes オブジェクトで、Pyplot API call の大半はこのオブジェクトにリダイレクトされる。plot() などの API を呼ぶと、プリミティブである Line2D などが構築され、適当にプロパティをセットされ、そして Axes に追加される。Axes の API を使わず Line2D のオブジェクトを直接 instantiate することもできる(が、特に使いみちはなさげ。)Figure は Axes のコンテナ。
- Pyplot には "現在の Figure" や "現在の Axes" という概念があり、plt.* API の多くはショートカットとしてこの「現在のオブジェクト」たちにリダイレクトされる。
あのクソのような API たちもあくまでショートカットなのですよ・・・ちゃんとオブジェクトモデルあるよ・・・といわれると多少許してあげようという気になる。特にかっこいいデザインではないし Axes のモデルなんかは不必要に複雑だと思うけれども、理不尽というほどでもない。こんなもんだよなと諦めはついた。
まえに Coursera のクラスでさわった ggpot2 がかっこよすぎたせいでどうしても可視化 API への期待値があがってしまう。あそこまでかっこよくなくていいんだけど、せめでもうちょっとなんとかならなかったのか。でも Python は気の利いた API をつくるための文法が弱いよね。たとえば Ruby のようなブロック構文があったらだいぶ可愛くできるはずだけれど、Python に block はない。フル機能の lambda もない。R みたいに AST を quote/unparse することもできない。きびしい。
Plotnine のように ggplot を模倣するライブラリはあるから Python の言語機能が完全に力不足というわけでもないのだけれど (すくなくとも operator overloading はある)、一方で ORM みたいに多くのプログラマがよってたかって作りなおせるほど敷居の低いジャンルでもないから、Matplotlib のような kind of good enough なものが生き残ってしまうのだろうなあ。まあ Altair などを片目でひやかしつつしばらくは Matplotlib 修行します。はい。
追記
Effectively Using Matplotlib という記事を見かけた。この人は常に object oriented API を使えと言っているなあ。そして Pandas の plot と Matplotlib を混ぜて使っている。自分はこの二つを混ぜられないと勝手に思い込んでいたけれど、たしかに Pandas で書きつつ Matplotlib でカスタマイズするのは良い手に思える。