Matplotlibで経済学の図を描く:需要と供給
一番はじめの図
Matplotlibでさくっと経済学の図が書けたら、楽なはずだ。
PowerPointで図を書いているときに、「ここが塗りたいのに、ずれた!」的なことはよくある。 根性で書いてもよいが、毎回根性が必要となると、萎えてくる。
実は僕自身はけっこう、PowerPointの扱いに慣れていて、図もかなりのスピードで作図できるようになっている。
けれども、出先などでマウスがないときに、タッチパッドで図を書くのは嫌だ。
似たような図なんだけど、ちょっとだけ平行移動したいときは、線の長さが変わるのでけっこうめんどうだ。
などなど、細かなストレスがある。
じゃあ、エクセルは?とも思うのだが、塗りつぶしの手間を考えるとあまり手を出す気はしない。
来年、一冊本を書くことになったので、この際、スクリプトで書けたらいいなあと感じはじめた。 論文の図もきれいなのが、書けるようになるだろうし、なにより推定結果から再現可能な図を作れるようになれば、かなり助かる。
というわけで、この際、作図をマスターすることにした。
作図環境
作図はPython+Matplotlibだ。 中期的にはPython+Plotnineに移行するが、今は標準環境をマスターする。
ちなみに、JavaScpriptを使って動く図を使うような環境も作れるが、僕はそちらにはあまり関心がない。 授業でも図を動かすときは、基本の図を作って、そこにペンで書きこんでいる。
(リアルなペンではなく、スタイラスでパワポ上に線を描画してるだけやけどね)
さて、まずは簡単な図
経済学の基本的な講義でほんとに毎回というぐらい使用するのが、需要と供給のごくシンプルな図。 僕は、どんな説明も最終的には、できるだけこの図に落としこむようにしているので、毎回使う。
https://blog.ecofirm.com/images/econfig001.png
この図は、抽象的な需要と供給なので、横軸と縦軸の目盛りがいらない。 単に右上がりの線と右下がりの線があればよい。
だが、これが意外と難しい。 抽象的に線がひければいいと思っているから、座標はいらないのかな?と感じてしまうと、もうそこから進まない。
Matplotlibのばあい、座標が必要だ。
なので、xを0から100の範囲と定義してその間で線をひくようにしてやる。
そのためには、x=np.linspace(0,100,101)とする。これは、xを0から100の間で定義して、その間を101個に区切るという命令だ。 100個ではなく101個なのは、0もカウントされるからだ。 この命令で、xには、0から100までの整数が格納される。 なお、0から100である必要もなくて、0から20とか0から10でもかまわない。
単純な直線を引くだけなら、ここは別に0と100だけでもいいし、整数でなくてもいいので30とかにしても問題ない。 曲線を書いたり、交点の座標を表示させたりすることを考えるなら、むしろ10000ぐらいにしておいたほうがいいが、まあ、今はどうでもいい。
この程度の作図なら、区切りが多くてもパフォーマンスにはほとんど影響しない。
この基本図でじゃまになるのが、目盛りだ。縦軸と横軸の数字は不要だ。 set_xticksとset_yticksを定義して、X軸の0として原点のみ表示させている。
また、あまり枠のなかに、きつきつに直線が入るのも好みではないので、右側と上に20ずつ余裕をもたせている。
もう一点、周囲の枠は不要で、X軸とY軸の線だけを表示させるために、右と上の線は消している。
ここまででようやく、枠の準備ができた。
次に需給曲線を引く。 これは、y=xとy=100-xを引くだけだ。
これで基本的な需要供給の図は完成だ。
こまごまとした装飾も可能だが、それは次回以降にとりくむ。
import numpy as np import matplotlib import matplotlib.pyplot as plt matplotlib.use('Agg') #matplotlib.use('tkagg') x = np.linspace(0,100,101) myfig = plt.figure() ax1 = myfig.add_subplot(111) ax1.set_xticks(ticks=[0]) ax1.set_yticks(ticks=[]) ax1.set_xlabel('X') ax1.set_ylabel('Y') ax1.set_xlim(0,120) ax1.set_ylim(0,120) ax1.spines['right'].set_visible(False) ax1.spines['top'].set_visible(False) ax1.plot(x,x) ax1.plot(x,100-x) myfig.savefig('images/econfig001.png') plt.close(myfig)