Python♪提出資料で使えるmatplotlibグラフ書式例2

複数のグラフを表示するサンプルコードです。私自身が提出資料として最低限必要と感じる書式を盛り込んだ例です。「あ~、これこれ」と思った方は、書式例のコードをコピペして自由に使ってください。matplotlib書式例シリーズの第2段です。

1.グラフの出力例

グラフの出力例を見てみましょう。右下にグラフがない部分があるのがポイントです。

この書式が気に入った人はサンプルコードをコピペして自分用にアレンジして使ってください。

複数のグラフの出力画像

なお、グラフが1つだけでよい場合は、以下の記事を参照してください。

なお、matlotlibのグラフを表示する上で混乱するのは「Matlabスタイル」と「オブジェクト指向スタイル」の2種類あることです。この2種類の差が全くわからない方も、以下の記事でざっとした違いは理解しておいてください。

Python♪提出資料で使えるmatplotlibグラフ書式例1

グラフ出力画像_グラフ1つだけ

2.私が必要と感じる書式

私が複数のグラフを表示するときに必要と考えた内容を箇条書きにしました。

  • 右下にはグラフを配置せず、その位置に凡例を配置
  • それぞれのグラフからは独立して、凡例の書式を設定可能
  • それぞれのグラフのタイトルをグラフ内に配置する
  • それぞれのグラフ内に配置したタイトルの背景色を白に設定(グラフ目盛り線との重なりを避ける)
  • それぞれのグラフの横間隔、縦間隔を指定
  • 軸ラベル、目盛の数値を外側だけに表示し、グラフ間の距離をできるだけ狭くする
  • 全てのグラフの下に、メインタイトルを表示する
  • グラフの縦と横の長さの比率を調整

なお、他にも基本的な書式設定として以下の内容を盛り込みました。

  • タイトル、X軸ラベル、Y軸ラベル、凡例で日本語を使用
  • マーカー、ラインの色、線幅、線種の設定
  • マーカーの中の色を透明に設定できる
  • 主目盛、補助目盛の色、線幅、線種の設定
  • タイトル、ラベルなどで上付文字、下付文字の使用
  • x軸y軸の値を10のN乗表記に設定
  • x軸y軸で表示する小数点の桁数を指定
  • 画像データ保存時の背景を透明に設定(貼付時に他との干渉を少なくする)
  • 画像データの解像度を指定

なお、x軸y軸の値を10のN乗で表記する方法については、以下の記事を参考にさせていただきました。わかりやすい記事で大変参考になります。

MatplotlibのY軸の目盛りを指数表記(10のN乗表記)に変更する

3.サンプルコード

コード01は最初に紹介したグラフのサンプルコードです。各コマンドの詳しい説明はしませんが、コードの中にコマンドの説明がありますので、すぐに自分用にアレンジできると思います。

なお、タイトルやラベルで日本語を表示するにはPCの中のフォントを指定する必要があります。自分のPCのどこにフォントがあるのかを探して位置とファイル名を指定してください。サンプルコードでは173、175行目でフォントを指定しています。MSゴシックはmsgothic.ttc、MS明朝はmsmincho.ttcです。

関数の引数にデータを渡せばブラックボックスのように使えるものではありませんので、フォントや凡例の位置など必要に応じてコードを変更してください。

#コード01 (2020.5.16) by Snow Tree in June

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties #日本語表示
import matplotlib.ticker as mtick #軸の値の書式設定
from matplotlib.ticker import ScalarFormatter #軸の値の10のN乗表記

class FixedOrderFormatter(ScalarFormatter):
    '''任意の桁数で軸の値の10のN乗表記するために必要なクラス

    (1) import必要
       from matplotlib.ticker import ScalarFormatter
    (2) 参照サイト
      http://villageofsound.hatenadiary.jp/entry/2014/11/06/155824
    '''
    def __init__(self, order_of_mag=0, useOffset=True, useMathText=True):
        self._order_of_mag = order_of_mag
        ScalarFormatter.__init__(self, useOffset=useOffset, 
                                 useMathText=useMathText)
    def _set_orderOfMagnitude(self, range):
        self.orderOfMagnitude = self._order_of_mag


def format_common1(i, j, ax):
    '''グラフの共通の書式設定
    
    主目盛、補助目盛、グラフで表示する範囲の設定
    [入力]
    i: グラフの縦位置
    j: グラフの横位置
    ax: axesオブジェクト
    '''
    
    #主目盛の設定
    #xmin:x軸の主目盛の開始位置、xmax:x軸の主目盛の終了位置
    #つまり、主目盛はxminからスタートし、xmaxで終わる。
    #xstep:x軸の主目盛の間隔。
    #
    #なお、ax.set_xticks(np.linspace(xmin, xmax, n_x))とは
    #xmin~xmaxの範囲を(n_x - 1)分割した位置に主目盛を表示する。
    #したがって、(xmax - xmin)/xstep が整数になるような値を指定しなければ、
    #想定通りの目盛を表示できない。
    #
    #xmin~xmaxは実際にグラフで表示する範囲よりも大きめに設定しないと、
    #目盛が表示されない範囲ができてしまう。
    #
    #np.arange()は、stepが小数の場合、目盛の最後の数値が表示されないことが
    # あるため、np.linspace()で主目盛の位置を指定する。
    
    xmin = 0 #必ず主目盛を表示する値を指定
    xmax = 6 #必ず主目盛を表示する値を指定
    ymin = -1500 #必ず主目盛を表示する値を指定
    ymax = 1500 #必ず主目盛を表示する値を指定
    xstep = 1
    ystep = 500
    n_x = int((xmax - xmin) / xstep) + 1
    n_y = int((ymax - ymin) / ystep) + 1
    ax[i, j].set_xticks(np.linspace(xmin, xmax, n_x))
    ax[i, j].set_yticks(np.linspace(ymin, ymax, n_y))
    
    #補助目盛の設定
    xstep = 0.2  #x軸補助メモリのピッチ
    ystep = 100  #y軸補助メモリのピッチ
    n_x = int((xmax - xmin) / xstep) + 1
    n_y = int((ymax - ymin) / ystep) + 1
    ax[i, j].set_xticks(np.linspace(xmin, xmax, n_x),
                  minor = 'True')
    ax[i, j].set_yticks(np.linspace(ymin, ymax, n_y),
                  minor = 'True')
    
    #目盛の書式
    #which: 主目盛と補助目盛の選択('major', 'minor', 'both')
    #axis: 目盛を設定する軸('x', 'y', 'both')
    #direction: 目盛の方向 ('in', 'out', 'inout')
    #bottom, top, left, right 下、上、左、右のメモリ表示のon, off
    ax[i, j].tick_params(which='both', axis='both', direction='in',
               bottom='on', top='off', left='on', right='off')
    
    #主目盛線の書式
    ax[i, j].grid(which='major',color='black',
            linestyle='--', linewidth=0.5) 

    #補助目盛線の書式
    ax[i, j].grid(which='minor',color='black',
            linestyle='--', linewidth=0.3) 

    ax[i, j].grid(True)
    
    #グラフで表示する範囲を設定 ※目盛の設定の後に記述する必要あり
    ax[i, j].set_xlim(0, 6)
    ax[i, j].set_ylim(-1100, 1100)

def format_x_axis(i, j, ax):
    '''x軸目盛の数値の書式設定
    
    [入力]
    i: グラフの縦位置
    j: グラフの横位置
    ax: axesオブジェクト
    '''
    #x軸の数値のフォントサイズ  
    ax[i, j].tick_params(axis = 'x', labelsize = 12)
    
    #x軸の値を少数第1位まで表示する
    #  その他の書式指定
    #    例1: %表示にする場合は  '%.1f%%'
    #    例2: π表示  '%.0fπ'
    fmt = '%.1f'
    #「import matplotlib.ticker as mtick」が必要
    xticks = mtick.FormatStrFormatter(fmt)
    ax[i, j].xaxis.set_major_formatter(xticks)
    '''

    #(参考)x軸の値も10のN乗表記にしたい場合
    n10 = 1 #10のN乗のNを指定
    ax[i, j].xaxis.set_major_formatter(FixedOrderFormatter(n10,
                                    useMathText=True))
    ax[i, j].ticklabel_format(style='sci',  axis='x',scilimits=(0, 0))
    #指数表示部分のフォントサイズ
    ax[i, j].xaxis.offsetText.set_fontsize(12)
    '''
    
def format_y_axis(i, j, ax):
    '''y軸の値の書式設定
    
    [入力]
    i:グラフの縦位置
    j:グラフの横位置
    ax:axesオブジェクト
    '''
    #y軸の数値のフォントサイズ  
    ax[i, j].tick_params(axis = 'y', labelsize = 12)


    #y軸の値を10のN乗表記にする
    #「class FixedOrderFormatter」が必要
    n10 = 2 #10のN乗のNを指定
    ax[i, j].yaxis.set_major_formatter(FixedOrderFormatter(n10,
                                    useMathText=True))
    ax[i, j].ticklabel_format(style='sci',  axis='y',scilimits=(0, 0))
    #指数表示部分のフォントサイズ
    ax[i, j].yaxis.offsetText.set_fontsize(12)


def main_graph(t, a1, a2, a3):
    '''matplotlibによる散布図描画プログラム(グラフ数:3)
    
    t:時間(s)
    a1, a2, a3:加速度(m/s2)
    '''
    
    #figuree, axesオブジェクトの生成
    #figureオブジェクトの内側に複数のaxesオブジェクトを表示可能
    #nrows: 行数指定
    #ncols: 列数指定
    #figsize(x,y) アスペクト比を指定
    fig, ax = plt.subplots(nrows=2, ncols=2, figsize=(7, 6))
    
    #右下にはグラフなし
    ax[1,1].axis('off')

    #グラフとグラフの間隔を調整 
    #wspace=:左右の間隔
    #hspace=:上下の間隔
    plt.subplots_adjust(wspace=0.1, hspace=0.2)

    #日本語表示のためのフォント指定
    # 自分のPCの中でフォントファイルが保存されている場所を指定する必要がある
    #  msgothic.ttc: MSゴシック
    #  msmincho.ttc: MS明朝
    #MSゴシック、フォントサイズ14 (タイトル、軸ラベル等のフォントサイズは後で変更可能)
    fp1 = FontProperties(fname='C:/Windows/Fonts/msgothic.ttc',size=14)
    #MSゴシック、フォントサイズ12 (凡例のフォント)
    fp2 = FontProperties(fname='C:/Windows/Fonts/msgothic.ttc',size=12)

    #それぞれのグラフのタイトルの塗りつぶし、枠線の書式設定
    boxdic1 = {
    "facecolor" : "white",  #塗りつぶし色の指定
    "edgecolor" : "white",  #枠線の色
    "linewidth" : 1  #枠線の太さ
    }


    #それぞれのグラフのデータと基本設定
    
    #左上のグラフ
    #グラフ化したいデータの設定
    ax[0, 0].plot(t, a1, '-D',
            color='k', linestyle='-',
            markersize=5, markerfacecolor='None',
            markeredgecolor='k', markeredgewidth=1.0,
            label = '標準')
    ax[0, 0].plot(t, a2, '-^',
             color='k',linestyle='--', linewidth=1.0,
             markersize=5,
             markeredgecolor='k',
             label = '高速')
    #それぞれのグラフのタイトル
    # x = 1, y= 1  タイトルの位置を指定(タイトルの位置は割合で指定する)
    ax[0, 0].set_title('R$_1$', fontproperties = fp1,
                 fontsize=14 ,x = 0.9, y= 0.04, bbox = boxdic1)
    
    #右上のグラフ
    ax[0, 1].plot(t, a1, '-D',
            color='k', linestyle='-',
            markersize=5, markerfacecolor='None',
            markeredgecolor='k', markeredgewidth=1.0,
            label = '標準')
    ax[0, 1].plot(t, a3, '-o',
             color='r', linestyle='-', linewidth=1.0,
             markersize=5, markerfacecolor='None',
             markeredgecolor='r',
             label = '低速')
    ax[0, 1].set_title('R$_2$', fontproperties = fp1,
                 fontsize=14 ,x = 0.9, y= 0.04, bbox = boxdic1)
    
    #左下のグラフ
    ax[1, 0].plot(t, a2, '-^',
             color='k',linestyle='--', linewidth=1.0,
             markersize=5,
             markeredgecolor='k',
             label = '高速')
    ax[1, 0].plot(t, a3, '-o',
             color='r', linestyle='-', linewidth=1.0,
             markersize=5, markerfacecolor='None',
             markeredgecolor='r',
             label = '低速')
    ax[1, 0].set_title('R$_3$', fontproperties = fp1,
                 fontsize=14 ,x = 0.9, y= 0.04, bbox = boxdic1)

    #共通の凡例用のダミーのデータ。グラフ描画用のデータは省略できる
    ax[1, 1].plot('-D',
            color='k', linestyle='-',
            markersize=5, markerfacecolor='None',
            markeredgecolor='k', markeredgewidth=1.0,
            label = '標準')
    ax[1, 1].plot('-^',
             color='k',linestyle='--', linewidth=1.0,
             markersize=5,
             markeredgecolor='k',
             label = '高速')
    ax[1, 1].plot('-o',
             color='r', linestyle='-', linewidth=1.0,
             markersize=5, markerfacecolor='None',
             markeredgecolor='r',
             label = '低速')


    #共通の書式の設定を実行
    format_common1(0, 0, ax)
    format_common1(0, 1, ax)
    format_common1(1, 0, ax)

    
    #目盛の数値、軸ラベルを外側だけに表示する方法1(消す方向を直接指定)
    #x軸、y軸ラベル
    ax[0, 1].set_xlabel('時間(s)', fontProperties =fp1)
    ax[1, 0].set_xlabel('時間(s)', fontProperties =fp1)
    ax[0, 0].set_ylabel('加速度(m/s$^{2}$)', fontProperties =fp1)
    ax[1, 0].set_ylabel('加速度(m/s$^{2}$)', fontProperties =fp1)
    
    #軸目盛の数値の書式設定
    format_x_axis(0, 1, ax)
    format_x_axis(1, 0, ax)
    format_y_axis(0, 0, ax)
    format_y_axis(1, 0, ax)
    
    #x軸、y軸目盛の数値の非表示(軸ラベルは非表示にならない)
    ax[0, 0].tick_params(labelbottom='off')
    ax[0, 1].tick_params(labelleft='off')
    
    '''
    #目盛の数値、軸ラベルを外側だけに表示する方法2(消す方向を自動判定)
    # グラフが、全て埋まっている場合は、自動で目盛の数値、軸ラベルを消してくれるので
    # .label_outer()の方が楽。
    # ただし、グラフが配置されていない場所があるとうまくいかない。
    # 右下のグラフがないのに、右上のグラフのx軸ラベル、軸目盛の数値が消える
    for i in range(0, 2):
        for j in range(0, 2):
            ax[i, j].set_xlabel('時間(s)', fontProperties =fp1)
            ax[i, j].set_ylabel('加速度(m/s$^{2}$)', fontProperties =fp1)
            format_x_axis(i, j)
            format_y_axis(i, j)
            ax[i, j].label_outer()
    '''

    #凡例の表示(フォントのサイズはfp2の中で設定)
    # loc = 'center' 凡例の基準点からの位置
    #   'upper left', 'upper right', 'lower left',
    #   'lower right', 'center left', 'center right',
    #   'upper center', 'lower center', 'center',
    #   'best', 'right'
    # bbox_to_anchor=(0.5, 0.5) 凡例の基準位置(マイナスも可能)
    # prop 凡例の日本語フォント指定(このフォントの中でフォントサイズも指定)
    # ncol 凡例の列数
    # frameon=False  枠を中の塗りつぶしごとなくす
    # framealpha=0.5 凡例の透明度
    # facecolor=[0.,0.,0.] 凡例の色(0~1)で指定
    # edgecolor=[0.,0.,0.] 凡例の枠の色(0~1)で指定
    # markerscale = 1 凡例のマーカーの大きさ(同じ大きさなら1)
    # 以下、凡例の全体の大きさを調整する
    #   borderpad: 凡例の枠とラベルのスペース。
    #   labelspacing: ラベルの行間のスペース。
    #   columnspacing: 列が2列以上のとき、列の間のスペース。
    #   handlelength: ハンドル(ライン)の長さ。
    #   handletextpad: ハンドルとラベルのスペース。
    ax[1, 1].legend(loc = 'center', bbox_to_anchor=(0.5, 0.5),
              ncol = 1, prop = fp2, edgecolor=[0.,0.,0.])

    #全てのグラフの下に、メインタイトルを表示する
    #x = , y = :x,y方向の基準位置。割合で指定
    fig.suptitle('図-1 時間と加速度の関係', fontproperties = fp1,
                 fontsize=18 ,x = 0.5, y = 0.0)
    
    #画像ファイルの保存 ※plt.show()の前に記述
    # 第1引数:保存ファイル名
    # format = 'png' フォーマット形式
    # transparent = True 背景透明
    # dpi = 300 解像度
    # bbox_inches='tight' を入れると画像が切れない
    plt.savefig('グラフ2出力画像.png', format = 'png',
                 transparent = False, dpi = 300, bbox_inches='tight')
    
    plt.show()
    
    
if __name__ == '__main__':

    #-----(グラフ化するデータ)------
    t = np.linspace(0, 2 * np.pi, 20)
    A = 1000
    w = 1
    a = 2
    a1 = -w ** 2 * A *np.cos(w * t - a)
    A = 1000
    w = 0.8
    a = 0
    a2 = -w ** 2 * A *np.cos(w * t - a)
    A = 500
    w = 1.4
    a = -1
    a3 = -w ** 2 * A *np.cos(w * t - a)
    #----------------------------
    
    #グラフ描画
    main_graph(t, a1, a2, a3)

私が実際に購入した教材のご紹介

以下、私が実際に購入したPythonの教材をまとめてみました。 Pythonを学習する上で、少しでもお役に立つことができればうれしいです。

Python♪私が購入したPythonの書籍のレビュー
UdemyのPythonの動画講座を書籍を買う感覚で購入してみた

その他

Twitterへのリンクです。SNSもはじめました♪

以下、私が光回線を導入した時の記事一覧です。
 (1) 2020年「光回線は値段で選ぶ」では後悔する ←宅内工事の状況も説明しています。
 (2) NURO光の開通までWiFiルーターを格安レンタルできる
 (3) NURO光の屋外工事の状況をご紹介。その日に開通!
 (4) 光回線開通!実測するとNURO光はやっぱり速かった
 (5) ネット上のNURO光紹介特典は個人情報がもれないの?