matplotlibで軸上にerrorbarをプロットする
環境
- python 3.6.2
- matplotlib 2.2.2
概要
matplotlibで軸上にerrorbarをプロットするとき、何も気にせずコードを書くと軸の上にerrorbarが乗らず微妙に上手くプロット出来ない。
これを回避するには、 set_on_clip
と zorder
を適切に使用すると良い。
詳細
いろいろグダグダ書いてますが、結論としては最後に貼ったコードのように set_on_clip
と zorder
を書けば良いです。
以下のようなコードを書いたとすると、
from matplotlib import pyplot as plt import numpy as np plt.style.use('ggplot') # Generate data num = 10 x = np.linspace(0, 1, num) y = np.exp(x) + 1.4 std_y = [1 for i in range(num)] # Plot fig, ax = plt.subplots(figsize=(8, 6)) ax.errorbar(x, y, std_y, fmt='-^', elinewidth=1.5, capsize=5, clip_on=False) ax.set_xlim([0, 1])
以下のようなグラフ(これは分かりやすいように拡大している)が得られる。
実際は軸の上にerrorbarの線なりマーカーをプロットしたいわけで、今のままだと上手くいっていない。
これを解決するためには現状、
- 枠の外に出ていないこと
- 軸の上にプロットできていないこと
の2つの問題がある。
まず1つ目の問題を解決する。
ax.errorbar()
の仕様( matplotlib.pyplot.errorbar — Matplotlib 3.1.2 documentation)を確認すると、この戻り値は ErrorbarContainer
というオブジェクトを返すようである。
Returns: container : ErrorbarContainer The container contains: plotline: Line2D instance of x, y plot markers and/or line. caplines: A tuple of Line2D instances of the error bar caps. barlinecols: A tuple of LineCollection with the horizontal and vertical error ranges.
ErrorbarContainer
は3つの要素
- plotline(マーカー・線)
- caplines(エラーバーのcaps(横線))
- barlinecols(エラーバーの縦線)
から構成されている。これらは全てmatplotlibの Artist
と呼ばれるオブジェクトから構成されており(というか殆ど全てそうなのでこれはちょっと良くない記述だが)、Artist
オブジェクトは set_on_clip
と呼ばれるメソッドを持つので(matplotlib.artist.Artist.set_clip_on — Matplotlib 3.1.2 documentation)、caplinesとbarlinecolsについて artist.set_on_clip(False)
とすれば枠の外に出ないという問題は解決する。
2つ目の軸の上にプロットされないという問題は、 ax.plot()
の zorder
オプションを適切に設定すれば良い。
zorderの仕様(Zorder Demo — Matplotlib 3.2.1 documentation)を確認すると、
Artist | Z-order |
---|---|
Images (AxesImage, FigureImage, BboxImage) | 0 |
Patch, PatchCollection | 1 |
Line2D, LineCollection (including minor ticks, grid lines) | 2 |
Major ticks | 2.01 |
Text (including axes labels and titles) | 3 |
Legend | 5 |
と書かれており、Z-orderの値が大きいほど上に表示される。軸(Major ticks)は2.01なのでこれより大きく値を設定すれば良い。
以上の2つの問題点を解決したコードは以下のようになる。
from matplotlib import pyplot as plt import numpy as np plt.style.use('ggplot') # Generate data num = 10 x = np.linspace(0, 1, num) y = np.exp(x) + 1.4 std_y = [1 for i in range(num)] # Plot fig, ax = plt.subplots(figsize=(8, 6)) plotline, caplines, barlinecols = ax.errorbar(x, y, std_y, fmt='-^', elinewidth=1.5, zorder=5, capsize=5, clip_on=False) for artist in caplines: artist.set_clip_on(False) for artist in barlinecols: artist.set_clip_on(False) ax.set_xlim([0, 1])