Tex, python, illusrator, VPSの学生ノート

latotex-blog

Python

Pythonで複数の図をまたぐ境界線を描く(Axes.hlineのみ使用)

投稿日:





pythonで複数の図をまたぐ境界線を描く(ax.hlineのみ使用)

以前ax.hlineだけで複数の図をまたぐ境界線を引く図を作ることができたのですが、

やり方を忘れてしまったので、書き留めておきます。

かなり初歩的なことから書いているので、早く結論が知りたい方は、

目次から「複数の図をまたぐ境界線を引くには・・・?」にジャンプしてください。

スポンサーリンク

1つの図で境界線を引く

ax.hlineを使います。基本的に以下の4つの要素が入っていればOKです。

#!/usr/bin/env python3
Axes.hlines( y, xmin, xmax, colors='k')
#y:境界線にするY値
#xmin:境界線を引く始点X値
#xmax:境界線を引く終点X値
#colors:境界線の色
      

ただ境界線をひくだけでは面白くないので、世界の海溝の水深(m)を並べてみました。

地上を0とし、水深をマイナスの値でプロットしています。

#!/usr/bin/env python3

#必要なものを宣言
import numpy as np
import matplotlib.pyplot as plt

#解像度の指定
set_dpi = 100

#図のサイズ比を指定
#サムネイルに使うため、あえてXが長くしてある
fsize_x, fsize_y = 16, 9

#目盛りとそのラベルを削除
plt.rcParams['xtick.bottom'] = plt.rcParams['xtick.labelbottom'] = False
plt.rcParams['xtick.top'] = plt.rcParams['xtick.labeltop'] = False
plt.rcParams['ytick.left'] = plt.rcParams['ytick.labelleft'] = False


#世界の山の名称と標高
Trench_dict = {0: 'Mariana', 1: 'Tonga', 2:'Philippine',
            3:'Kamchatka', 4:'Japan', 5:'Kermadec',
            6:'Izu-Bonin', 7:'Puerto Rico', 8:'South Sandwich' ,
            9:'Peru–Chile'}

depth = [-10984, -10882, -10545, -10542, -10375,
                -10047, -9810, -8800, -8428, -8065]

#境界線を引くところ
zone_boundaries = [-8000, -9000, -10000, -10500]

#リスト・辞書の個数を定義
ndict, ndepth, nbound = len(Trench_dict),  len(depth), len(zone_boundaries)

#y軸の範囲
depth_lim = [-11500, -7500]

#重なり防止のため、ズレをつくる
x_diff = np.linspace(5, 50, 10, dtype = 'int')

#X軸の範囲
diff_lim = [0, 55]


#ここから作図
fig, ax = plt.subplots(figsize = (fsize_x, fsize_y))


for idep in range(ndepth):
	ax.plot(x_diff[idep], depth[idep], 'o', markersize=15)

	ax.set_xlim(diff_lim)
	ax.set_ylim(depth_lim)
	ax.set_ylabel('Depth (m)', fontsize=25)
	ax.set_xlabel('Oceanic Trench', fontsize=25)
	ax.set_yticks(depth_lim, 2000)
	ax.set_xticks(diff_lim, 5)

#海溝の名称を追加
#正の数にするため-1をかける
	meter = str(depth[idep]*-1)
	ax.text(x_diff[idep], depth[idep]-300,
                        Trench_dict[idep], horizontalalignment='left',
                        verticalalignment='bottom', zorder=1,
                        fontstyle='italic', fontsize=18)

#具体的な水深を追加
	ax.text(x_diff[idep]-2, depth[idep]+200,
                        meter, horizontalalignment='left',
                        verticalalignment='bottom', zorder=1,
                        fontstyle='italic', fontsize=10)


for izone in range(nbound):
    x0 =  diff_lim[0]
    x1 =  diff_lim[1]

#境界線の名称を追加
#正の数にするため-1をかける
	zone_name = str(zone_boundaries[izone]*-1) + ' ' + 'm'
	space = (x0 + x1)*0.05
	ax.text(space, zone_boundaries[izone],
                        zone_name, horizontalalignment='center',
                       verticalalignment='baseline', zorder=1,linespacing= 1, fontsize=15, rotation='horizontal')

#境界線を引く
	ax.hlines(zone_boundaries[izone], xmin=x0,
                        xmax=x1, colors='k', lw=0.2,
                        zorder=2, linestyles='-',alpha=1)


#自動調節
plt.tight_layout()


#pngで保存
fileo1 ='oceanic_trench' + '.png'
plt.savefig(fileo1, format='png', dpi=set_dpi)
#plt.show()

      

2つの図(複数の図)で境界線を引く

1つの図で作図するのとほとんど変わりません。

今回は世界の海溝の深さと山の高さを比べた図を作ってみました。

xmin, xmaxの指定には、numpy配列のスライスを利用しています。

具体的に説明すると・・・

 #!/usr/bin/env python3
diff_lim = np.array([[0, 40],
                     [0, 45]]) #54行目
ax[isubplot].set_xlim(diff_lim[isubplot, :]) #66行目
         

diff_lim[isubplot, :]はdiff_limから列を「isubplot」(図の数)、行を「:」(なんでもよい)

に抽出するという意味です。つまり、print(diff_lim[0,1])は40, print(diff_lim[1,0])は0

ということになります。

#!/usr/bin/env python3

#必要なものを宣言
import numpy as np
import matplotlib.pyplot as plt

#解像度の指定
set_dpi = 100

#図のサイズ比を指定
#サムネイルに使うため、あえてXが長くしてある
fsize_x, fsize_y = 16, 9

#目盛りとそのラベルを削除
plt.rcParams['xtick.bottom'] = plt.rcParams['xtick.labelbottom'] = False
plt.rcParams['xtick.top'] = plt.rcParams['xtick.labeltop'] = False
plt.rcParams['ytick.left'] = plt.rcParams['ytick.labelleft'] = False


#世界の山の名称と標高
Mt_dict = {0:'Mt. Everest', 1:'K2', 2:'Kangchenjunga', 3:'Lhotse',  4:'Makalu',
            5:'Cho Oyu',  6:'Dhaulagiri I',7:'Manaslu', 8:'Nanga Parbat',
            9:'Annapurna I', 10:'Gasherbrum I'}

height = [-8848, -8611, -8586, -8516, -8485,
                -8188, -8167, -8163, -8126, -8091, -8080]

#世界の海溝と水深
Trench_dict = {0:'Mariana', 1: 'Tonga', 2:'Philippine',
             3:'Kamchatka', 4:'Japan', 5:'Kermadec',
             6:'Izu-Bonin', 7:'Puerto Rico', 8:'South Sandwich' ,
             9:'Peru–Chile'}

depth = [-10984, -10882, -10545, -10542, -10375,
                -10047, -9810, -8800, -8428, -8065]

#境界線を引くところ
zone_boundaries = [-8000, -9000, -10000, -10500]

#リスト・辞書の個数を定義
ntdict, ndepth, nbound = len(Trench_dict),  len(depth), len(zone_boundaries)
nmdict, nheight = len(Mt_dict), len(height)


#1行2列、計2つの図
nsubplot = 2
nrowsubplot = 1
ncolsubplot = 2

#y軸の範囲
depth_lim = [-11500, -7500]

#X軸の範囲(スライスを使いたいので、numpy配列にしている)
diff_lim = np.array([[0, 40], [0, 45]])


#ここから作図
fig = plt.figure(figsize = (fsize_x, fsize_y))
plt.subplots_adjust(left=20/297, right=(297-20)/297, \
                       top=(210-20)/210, bottom=20/210, \
                       wspace=0.3, hspace=3.0)

for isubplot in range(nsubplot):
	ax = [0]*nsubplot
	ax[isubplot] = plt.subplot(nrowsubplot,ncolsubplot+1, isubplot +1)
	ax[isubplot].set_xlim(diff_lim[isubplot, :])
	ax[isubplot].set_ylim(depth_lim)
	ax[isubplot].set_yticks(depth_lim, 2000)

    #海溝
	if isubplot == 0:
		for idep in range(ndepth):

			x_diff = np.linspace(5, 30, ndepth, dtype = 'int')
			ax[isubplot].plot(x_diff[idep], depth[idep],
								'o', markersize=15, label=Trench_dict[idep], zorder=idep+1)

			ax[isubplot].set_xlabel('Oceanic Trench', fontsize=25)

            #境界線の名称を追加
			for izone in range(nbound):
				x0 =  diff_lim[1,0]
				x1 =  diff_lim[0,1]
				zone_name = str(zone_boundaries[izone]*-1) + ' ' + 'm'

				space = x1 + x1*0.15
				ax[isubplot].text(space, zone_boundaries[izone]-50,
                                    zone_name, horizontalalignment='center',
                                    verticalalignment='baseline', zorder=izone+1,linespacing= 1, fontsize=15, rotation='horizontal')

    #山
	else:
		for iheight in range(nheight):

			x_diff = np.linspace(5, 30, nheight, dtype = 'int')
            ax[isubplot].plot(x_diff[iheight], height[iheight],
								'o', markersize=15, label=Mt_dict[iheight], zorder=iheight+1)
			ax[isubplot].set_xlabel('Mountains', fontsize=25)



    #境界線を引く
	ax[isubplot].hlines(zone_boundaries, xmin=diff_lim[0,0],
                            xmax=diff_lim[1,1], colors='k', lw=0.2,
                            zorder=2, linestyles='-',alpha=1)
    #汎例の追加
	ax[isubplot].legend(loc='lower right')



#plt.tight_layout()

#pngで保存
fileo1 ='test' + '.png'
plt.savefig(fileo1, format='png', dpi=set_dpi)
#plt.show()


         

スポンサーリンク

複数の図をまたぐ境界線を引くには・・・?

一番簡単な方法はax.hlineのあと、plt.tight_layout()するだけです。

XY軸・目盛り、タイトルだけしか追加しないよ!という場合は問題ないですが、

axesの中にテキストなどを入れる場合、plt.tight_layout()では無視されるので注意してください。

(ax.hline()の中にclip_on=Falseをいれても無駄です)

*ただしplotするもの(plt,plot() または ax.plot()に入るX,Y)がnp.squeeze()したものであり、

かつsqueezeの中でsubplotと同じ数だけループをする変数があれば、

plt.tight_layout()をしなくても、zorderの変更で境界線を引くことができる場合があります!!

参考にしたサイト様

legendのところ、深さ・高さが低い順に表示するようにすればよかったかなあ・・・

海溝の深さのデータ

https://en.wikipedia.org/wiki/Oceanic_trench

山の高さのデータ

https://en.wikipedia.org/wiki/List_of_highest_mountains_on_Earth



-Python

Copyright© latotex-blog , 2020 All Rights Reserved Powered by STINGER.