Pythonのmatplotlibで、複数の地図とデータを同時にプロット

地球惑星科学の研究などをやっていると、1つの図に複数の地図とデータを同時にプロットしたいという場面にしばしば遭遇する。
試しに今回は、Pythonのmatplotlibを用いて、

 - 1〜12月の1ヶ月毎の2次元データ(全球の海面水温データ)を地図とともに同時に1つの図にプロットする

ことを目標とする。

# 1. 複数の地図を同時にプロット
## コード

```py
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.basemap import Basemap

xlim = [100, 170]			# 図の範囲(x軸方向：経度)
ylim = [10, 60]				# 図の範囲(y軸方向：緯度)
column = 3					# 列の数
fsizex, fsizey= 16, 18		# 図の横・縦の長さ
line_interval = 15			# 地図上に描く緯線・経線の間隔
fontsize = 20				# 文字サイズ

if 12 % column != 0:
    raise ValueError('column must be a divisor of 12!')

row = 12 / column			# 行の数
months =  [ 'Jan',  'Feb',  'Mar',  'Apr',
            'May',  'Jun',  'Jul',  'Aug',
            'Sep',  'Oct',  'Nov',  'Dec' ]

fig = plt.figure(figsize = (fsizex, fsizey))
plt.rcParams['font.size'] = fontsize

ax = [0] * 12
for i in range(0, 12):
    ax[i] = fig.add_subplot(row, column, 1 + i)
    m = Basemap(projection = 'cyl', llcrnrlat = ylim[0], urcrnrlat = ylim[1], \
                llcrnrlon = xlim[0], urcrnrlon = xlim[1], resolution = 'c', lon_0 = 180)
    m.drawcoastlines(linewidth = 0.5)
    m.drawmapboundary()
    m.fillcontinents(color = '#eeeeee')
    if i == 12 - column:
        label = [1, 1]
    elif i > 12 - column:
        label = [1, 0]
    elif i % column == 0:
        label = [0, 1]
    else:
        label = [0, 0]

    m.drawmeridians(np.arange(0, 360, line_interval), labels = [0, 0, 0, label[0]], linewidth = 0.5)
    m.drawparallels(np.arange(-90, 90, line_interval), labels = [label[1], 0, 0, 0], linewidth = 0.5)
    ax[i].set_xlim(xlim)
    ax[i].set_ylim(ylim)
    ax[i].set_title(months[i])

fig.tight_layout()
plt.show()
```

## 図

![ダウンロード (12).png](https://qiita-image-store.s3.amazonaws.com/0/88804/5945006c-f5c6-3a8f-cea9-8234e1855e88.png)

# 2. 複数の地図とデータを同時にプロット
##下準備
各月でプロットするのが2次元データである場合、12ヶ月のそれぞれのデータを一つの3次元配列にまとめておく。

```py
xn = 360			# データのx軸(経度)方向のグリッド数
yn = 155            # データのy軸(緯度)方向のグリッド数
data = np.zeros((12, yn, xn))
for i in range(0, 12):
	data[i, :, :] = .....  # (i+1)月のデータを取得する処理
```

また、その2次元データのx軸(経度)とy軸(緯度)に対応する1次元配列を取得しておく。今回はそれぞれ、

 - xgrid
 - ygrid

とする(いずれも`numpy.ndarray`)。

## コード

```py
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.basemap import Basemap

xlim = [100, 170]			# 図の範囲(x軸方向：経度)
ylim = [10, 60]				# 図の範囲(y軸方向：緯度)
column = 3					# 列の数
fsizex, fsizey= 16, 18		# 図の横・縦の長さ
cb_min, cb_max = -2, 32     # カラーバーの最小値・最大値
cb_div = 17					# カラーバーで使う色の数
clabel = 'Sea Surface Temperature(deg)' # カラーバーにつけるラベル
line_interval = 15						# 地図上に描く緯線・経線の間隔
fontsize = 20							# 文字サイズ

if 12 % column != 0:
    raise ValueError('column must be a divisor of 12!')

row = 12 / column			# 行の数
months =  [ 'Jan',  'Feb',  'Mar',  'Apr',
            'May',  'Jun',  'Jul',  'Aug',
            'Sep',  'Oct',  'Nov',  'Dec' ]

fig = plt.figure(figsize = (fsizex, fsizey))
plt.rcParams['font.size'] = fontsize

delta = (cb_max - cb_min) / cb_div
interval_of_cf = np.arange(cb_min, abs(cb_max) * 2 + delta, delta)[0:int(cb_div) + 1]

ax = [0] * 12
for i in range(0, 12):
    ax[i] = fig.add_subplot(row, column, 1 + i)
    m = Basemap(projection = 'cyl', llcrnrlat = ylim[0], urcrnrlat = ylim[1], \
                llcrnrlon = xlim[0], urcrnrlon = xlim[1], resolution = 'c', lon_0 = 180)
    m.drawcoastlines(linewidth = 0.5)
    m.drawmapboundary()
    m.fillcontinents(color = '#eeeeee')
    if i == 12 - column:
        label = [1, 1]
    elif i > 12 - column:
        label = [1, 0]
    elif i % column == 0:
        label = [0, 1]
    else:
        label = [0, 0]

    m.drawmeridians(np.arange(0, 360, line_interval), labels = [0, 0, 0, label[0]], linewidth = 0.5)
    m.drawparallels(np.arange(-90, 90, line_interval), labels = [label[1], 0, 0, 0], linewidth = 0.5)

    # カラーコンターを描く
    x, y = np.meshgrid(xgrid, ygrid)
    X, Y = m(x, y)
    CF = ax[i].contourf(X, Y, data[i, :, :], interval_of_cf)

    ax[i].set_xlim(xlim)
    ax[i].set_ylim(ylim)
    ax[i].set_title(months[i])

# カラーバーを描く
cax = fig.add_axes([1.00, 0.15, 0.04, 0.7])
cb = fig.colorbar(CF, cax)
cb.set_label(clabel)

fig.tight_layout()
plt.show()
```

## 図
![ダウンロード (13).png](https://qiita-image-store.s3.amazonaws.com/0/88804/6f9baa92-3199-5b92-c2f1-d808b1ef3768.png)

無事作成することに成功。
縦×横の組み合わせは、columnの値を変えることで自由に変更することが出来る。

# **参考URL**
http://seesaawiki.jp/met-python/d/matplotlib/plot
http://bicycle1885.hatenablog.com/entry/2014/02/14/023734
http://nm-player.blogspot.jp/2012/09/matplotlibbasemap-1.html
http://qiita.com/AnchorBlues/items/0dd1499196670fdf1c46