matplotlibを用いたグラフの書き方(備忘録)
色々とPythonを使ってデータ処理を行う機会が増える(かもしれない)ので、matplotlibを用いたグラフの書き方についていくつかメモします。個人的な備忘録の意味合いが強く、他記事と書き方が異なっており、説明なども少なめです。今後は予告なく内容を追加するかもしれません。
※環境はJupyter Notebookの想定です。
- 基本的なグラフ
- 凡例(legend)の調整
- axesを用いる方法
- グラフの表示範囲を変更する
- 複数のグラフを並べる(1)
- 複数のグラフを並べる(2)
- 複数のグラフを並べる(3)
- グラフを点線にする
- 散布図を描く
- 棒グラフを描く
- imshowによる2次元配列の描画
- 多次元配列を用いた、2変数関数のimshowによる描画
- 様々なカラーマップを用いてのimshowによる描画
- 3次元グラフ(サーフェス)を描く
- 3次元グラフ(ワイヤフレーム)を描く
- 3次元のバーを用いて、曲面を描く
- 【参考】公式による、様々なグラフの描画例
基本的なグラフ
%matplotlib inline import numpy as np import matplotlib.pyplot as plt x = np.linspace(-np.pi, np.pi, 100) y1 = np.sin(x) y2 = np.cos(x) plt.plot(x, y1, label="sin") plt.plot(x, y2, label="cos") plt.title("Graph") plt.xlabel("x", size=12) plt.ylabel("y", size=12) plt.legend() plt.show()
凡例(legend)の調整
legendは配置やフォントサイズを調整出来る。 bbox_to_anchorはアンカーポイントであり、左下が(0, 0)、右上が(1, 1)。 locでアンカーポイントに対する凡例の枠の位置を指定する。borderaxespadは凡例の枠に対して、余白をどの程度設けるかの設定。
locで可能な指定は以下の通りとなる。
‘best’, ‘upper right’, ‘upper left’, ‘lower left’, ‘lower right’, ‘right’,
‘center left’, ‘center right’, ‘lower center’, ‘upper center’, ‘center’
%matplotlib inline import numpy as np import matplotlib.pyplot as plt x = np.linspace(-np.pi, np.pi, 100) y1 = np.sin(x) y2 = np.cos(x) plt.title("Graph") plt.xlabel("x", size=12) plt.ylabel("y", size=12) plt.plot(x, y1, label="sin") plt.plot(x, y2, label="cos") plt.legend(bbox_to_anchor = (1.0, 1.0), loc = "upper right", borderaxespad=1, fontsize = 15) plt.show()
axesを用いる方法
%matplotlib inline import numpy as np import matplotlib.pyplot as plt x = np.linspace(-np.pi, np.pi, 100) y1 = np.sin(x) y2 = np.cos(x) fig = plt.figure(figsize=(5, 5)) ax = fig.add_subplot(111) ax.plot(x, y1, label="sin") ax.plot(x, y2, label="cos") ax.set_title("Graph") ax.set_xlabel("x", size=12) ax.set_ylabel("y", size=12) plt.legend(bbox_to_anchor = (0.0, 1.0), loc = "upper left", borderaxespad=1, fontsize = 12) plt.show()
グラフの表示範囲を変更する
plt.xlim(a, b), plt.ylim(a, b)を使用する(axesの場合はax.set_xlim(a, b)といった形にする)。
↓最初の「基本的なグラフ」に対して、plt.xlim(-1, 1), plt.ylim(-2, 2)を設定した場合。
複数のグラフを並べる(1)
%matplotlib inline import numpy as np import matplotlib.pyplot as plt fig, axes = plt.subplots(2, 2, figsize=(12, 6)) ax1, ax2, ax3, ax4 = axes.flatten() #以下のように1行で書くことも出来る #fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(12, 6)) #あるいは以下のように、1つ1つ追加することも出来る。subplotは(行数、列数、番号) #subplot(2, 2, 1)ではなくsubplot(221)のように書くことも可能 #fig = plt.figure(figsize=(12, 6)) #ax1 = fig.add_subplot(2, 2, 1) #ax2 = fig.add_subplot(2, 2, 2) #ax3 = fig.add_subplot(2, 2, 3) #ax4 = fig.add_subplot(2, 2, 4) x = np.linspace(-3*np.pi, 3*np.pi, 300) y0 = np.sin(x) y1 = np.cos(x) y2 = np.abs(np.sin(x)) y3 = np.abs(np.cos(x)) #凡例にLaTeXコマンドを使用する(raw文字列にする必要あり) ax1.plot(x, y0, color = "red", label = r"$\sin x$") ax2.plot(x, y1, color = "blue", label = r"$\cos x$") ax3.plot(x, y2, color = "green", label = r"$|\sin x$|") ax4.plot(x, y3, color = "yellow", label = r"$|\cos x$|") ax1.set_title("Graph 1") ax2.set_title("Graph 2") ax3.set_title("Graph 3") ax4.set_title("Graph 4") ax1.set_xlabel("x") ax2.set_xlabel("x") ax3.set_xlabel("x") ax4.set_xlabel("x") ax2.set_ylabel("y") ax2.set_ylabel("y") ax2.set_ylabel("y") ax2.set_ylabel("y") #locは指定しないと、各グラフで凡例の位置がバラける ax1.legend(loc = "upper right") ax2.legend(loc = "upper right") ax3.legend(loc = "upper right") ax4.legend(loc = "upper right") #並んだグラフのタイトルやラベルが、重なってしまうことを防ぐ fig.tight_layout() plt.show()
複数のグラフを並べる(2)
forループを用いて短く記述。出力されるグラフは(1)と同じ。
%matplotlib inline import numpy as np import matplotlib.pyplot as plt fig, axes = plt.subplots(2, 2, figsize=(12, 6)) faxes = axes.flatten() x = np.linspace(-3*np.pi, 3*np.pi, 300) y0 = np.sin(x) y1 = np.cos(x) y2 = np.abs(np.sin(x)) y3 = np.abs(np.cos(x)) y = [y0, y1, y2, y3] colorlist = ["red", "green", "blue", "yellow"] # 各プロットの色 labellist = [r"$\sin$",r"$\cos x$",r"$|\sin x|$",r"$|\cos x|$"] # 各ラベル for i, ax in enumerate(faxes): ax.plot(x, y[i], color=colorlist[i], label=labellist[i]) ax.set_title(f"Graph {i+1}") ax.set_xlabel("x") ax.set_ylabel("y") ax.legend(loc = "upper right") fig.tight_layout() plt.show()
複数のグラフを並べる(3)
グラフ1内に別のグラフ2を、任意の位置・サイズで描画する。left, bottomはグラフ2の左下位置、width, heightはグラフ2の幅、高さであり、それぞれグラフ1(figure)の範囲に対する相対値で指定する。
#グラフ1を上書きする形になるので、きちんと使うなら調整が必要。 %matplotlib inline import numpy as np import matplotlib.pyplot as plt x = np.linspace(-np.pi, np.pi, 100) y1 = np.sin(x) y2 = np.cos(x) plt.figure(figsize=(8, 5)) plt.plot(x, y1, label="sin") plt.legend(bbox_to_anchor = (0.0, 1.0), loc = "upper left", borderaxespad=1, fontsize = 12) ax2 = plt.axes([0.2, 0.2, 0.4, 0.4]) #[left, bottom, width, height] ax2.plot(x, y2, label="cos") plt.legend(bbox_to_anchor = (0.0, 1.0), loc = "upper left", borderaxespad=1, fontsize = 12) plt.show()
グラフを点線にする
plot()関数の、linestyle引数(lsと略記も可)で指定する。linewidth引数で線の太さも変更できる。 linestyleとして可能な指定は下表の通り。
※散布図(scatte)の場合、linewidthではマーカーの輪郭線の太さの指定となる。
":" | 点線 |
"-." | 一点鎖線 |
"--" | 破線 |
"-" | 実線 |
import numpy as np import matplotlib.pyplot as plt %matplotlib inline fig, axes = plt.subplots(2, 2, figsize=(10, 6)) faxes = axes.flatten() x = np.linspace(-np.pi, np.pi, 100) y = np.sin(x) stylelist = [":", "-.", "--", "-"] for i, ax in enumerate(faxes): ax.plot(x, y, color = "blue", ls = stylelist[i], linewidth = 2) ax.set_title(f"linstyle \"{stylelist[i]}\"") fig.tight_layout() plt.show()
散布図を描く
%matplotlib inline import numpy as np import matplotlib.pyplot as plt x = np.linspace(-np.pi, np.pi, 50) y = np.sin(x) plt.plot(x, y, color=(0.2, 0.8, 0.2)) #ノイズを加える y += 0.2 * np.random.randn(len(x)) plt.scatter(x, y) plt.show()
棒グラフを描く
%matplotlib inline import numpy as np import matplotlib.pyplot as plt np.random.seed(0) x = [0, 1, 2, 3, 4] y = np.random.rand(5) label = ["A", "B", "C", "D", "E"] plt.bar(x=x, height=y, tick_label=label) plt.xlabel("Sample") plt.ylabel("Value") plt.show()
imshowによる2次元配列の描画
cmap引数でカラーマップを指定する。カラーマップの一覧は以下の公式リファレンスを参照。
https://matplotlib.org/examples/color/colormaps_reference.htmlmatplotlib.org
%matplotlib inline import numpy as np import matplotlib.pyplot as plt plt.imshow(np.random.randn(50, 50), cmap = "magma") plt.title("50 x 50”)
多次元配列を用いた、2変数関数のimshowによる描画
Numpyの関数であるmgridを使用して、格子状の多次元配列を手軽に生成出来る。
mgrid[(x始点) : (x終点) : (x刻み幅), (y始点) : (y終点) : (y刻み幅)] または
mgrid[(x始点) : (x終点) : (x分割数)j, (y始点) : (y終点) : (y分割数)j] という形で使用する。
刻み幅の所に”j”を付けると、始点〜終点の区間を何分割するかという指定に変わる。
%matplotlib inline import numpy as np import matplotlib.pyplot as plt #それぞれ-2〜2の区間を400分割する y, x = np.mgrid[-2:2:400j, -2:2:400j] z = 10*np.sin(x**2 + y**2) plt.imshow(z)
様々なカラーマップを用いてのimshowによる描画
先述のカラーマップ一覧のうち、いくつかをピックアップして、適用したグラフを並べてみる。
%matplotlib inline import numpy as np import matplotlib.pyplot as plt y, x = np.mgrid[-np.pi:np.pi:300j, -np.pi:np.pi:300j] z = 10 * np.cos(x**2 + y**2) fig, axes = plt.subplots(6, 4, figsize=(12, 18)) faxes = axes.flatten() #公式リファレンスのカラーマップ一覧よりピックアップ cmaplist = ["viridis", "plasma", "inferno", "magma", "Greys", "Reds", "GnBu", "YlOrBr", "bone", "spring", "winter", "hot", "PiYG", "PuOr", "RdYlBu", "coolwarm", "Pastel1", "Paired", "Set1", "tab20", "flag", "prism", "terrain", "gist_rainbow"] for i, ax in enumerate(faxes): ax.imshow(z, cmap = cmaplist[i]) ax.set_title(f"{i+1} : {cmaplist[i]}") fig.tight_layout() plt.show()
3次元グラフ(サーフェス)を描く
Numpyの関数であるmeshgridを使用して、別の方法で格子状の多次元配列を生成する。そしてAxes3Dモジュールを用いて、add_subplot()の引数でprojection=‘3d’と指定することで、3次元グラフを扱うことが可能となる。
import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D %matplotlib inline x1 = np.linspace(0, 1, 100) x2 = np.linspace(0, 1, 100) x1, x2 = np.meshgrid(x1, x2) y = 0.3 * x1**2 + 0.7 * x2**2 fig = plt.figure(figsize=(10, 10)) ax = fig.add_subplot(111, projection="3d") #3次元版 ax.set_xlabel(r"$x_1$", fontsize=16) ax.set_ylabel(r"$x_2$", fontsize=16) ax.set_zlabel(r"$y$", fontsize=16) surf = ax.plot_surface(x1, x2, y, rstride=5, cstride=5, cmap="plasma", alpha=0.8) plt.colorbar(surf, ax=ax, shrink=0.75) plt.show()
3次元グラフ(ワイヤフレーム)を描く
import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D %matplotlib inline x1 = np.linspace(0, 1, 100) x2 = np.linspace(0, 1, 100) x1, x2 = np.meshgrid(x1, x2) y = 0.3 * x1**2 + 0.7 * x2**2 fig = plt.figure(figsize=(10, 10)) ax = fig.add_subplot(111, projection="3d") #3次元版 ax.set_xlabel(r"$x_1$", fontsize=16) ax.set_ylabel(r"$x_2$", fontsize=16) ax.set_zlabel(r"$y$", fontsize=16) ax.plot_wireframe(x1, x2, y, linewidth=0.5) plt.show()
3次元のバーを用いて、曲面を描く
bar3Dは本来、ヒストグラムや棒グラフを描くためのものであるが、これで強引に曲面を描いてみる。
bar3Dにおける各バーの座標は1次元配列で与える必要があるため、ravel関数で変換を行う。またバーの高さ(この場合はyの値)に応じて、カラーマップを割り当てるような仕組みは自前で実装する必要がある。
mport numpy as np import matplotlib.pyplot as plt import matplotlib.colors as colors import matplotlib.cm as cm %matplotlib inline x1 = np.linspace(0, 1, 20) x2 = np.linspace(0, 1, 20) x1, x2 = np.meshgrid(x1, x2) xr1 = x1.ravel() xr2 = x2.ravel() y = 0.3 * xr1**2 + 0.7 * xr2**2 def ColorMap(z, cmap): cmap = cm.get_cmap(cmap) norm = colors.Normalize(vmin = z.min(), vmax = z.max()) return cmap(norm(z)) fig = plt.figure(figsize=(10, 10)) ax = fig.add_subplot(111, projection='3d') ax.set_xlabel(r"$x_1$", fontsize=16) ax.set_ylabel(r"$x_2$", fontsize=16) ax.set_zlabel(r"$y$", fontsize=16) ax.bar3d(xr1, xr2, 0, 0.05, 0.05, y, color=ColorMap(y, 'plasma')) plt.show()