Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

Matplotlib で 複数グラフを自由自在に配置する!

More than 3 years have passed since last update.

Matplotlib で複数のグラフを自由自在に配置する

今回、作成したは以下の図。
Screen Shot 2017-12-24 at 13.29.05.png

上記のような図をmatplotlibで作成するのは意外と難しい。
まず、思いつくのはsubplotを持ちいることである。しかしながら、subplot では同じアスペクトの図しか並べることができない。subplot2grid を利用すると多少は複雑な配置も可能にはなるが、アスペクトの制約はつきまとう。そこで今回は、 add_axesとbbox_inchesを駆使して、上記の図を作成した。

まずは、1パネル分のスクリプト

# coding: UTF-8
import sys
import numpy as np
import matplotlib 
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib import rcParams
rcParams['font.family'] = 'Arial'

if __name__ == "__main__":
    fig = plt.figure(figsize=(3,3)) 
    #add_axes([x軸の開始位置, y軸の開始位置, x軸の長さ(全体に対する比率), y軸の長さ(全体に対する比率)])
    ax1 = fig.add_axes([0.10,0.10,0.60,0.60]) 
    ax2 = fig.add_axes([0.71,0.10,0.20,0.60])#左のヒストグラム図
    ax3 = fig.add_axes([0.10,0.71,0.60,0.20])#上のヒストグラム図

    ax1.spines['top'].set_visible(False)
    ax1.spines['right'].set_visible(False)
    ax1.tick_params(top="off",right="off",direction="out",labelsize=10,pad=5)
    ax1.tick_params(right="off")

    ax2.spines['top'].set_visible(False)
    ax2.spines['right'].set_visible(False)
    ax2.spines['bottom'].set_visible(False)
    ax2.set_xticks([]) 
    ax2.set_yticks([])

    ax3.spines['top'].set_visible(False)
    ax3.spines['right'].set_visible(False)
    ax3.spines['left'].set_visible(False) 
    ax3.set_xticks([])
    ax3.set_yticks([])

    data = np.random.randn(2000,2000)
    ax1.scatter(data.T[0],data.T[1],s=5)
    ax2.hist(data.T[1],range=(-2,2),bins=100,orientation="horizontal") 
    ax3.hist(data.T[1],range=(-2,2),bins=100) 
    ax1.set_xlim(-2,2) 
    ax1.set_ylim(-2,2) 
    ax3.set_xlim(-2,2)

    fig.savefig("test.pdf",bbox_inches="tight")

Seabornをつかわなくても、こんな風にadd_axesを使えば散布図とヒストグラムを組み合わせた joint plot を作ることができる。ただし、最後にbbox_inches="tight"をつけないとlabel等が少しはみ出ることがある(左図)。つけるとはみ出た部分まで表示してくれる(右図)。
image.pngimage.png

厳密には bbox_inches=tight を指定すると、枠外にはみ出しているいないに関わらず、全てのobjectをきっちり表示してくれるようになる。枠外にはみ出しているいないに関わらず、全てのobjectをきっちり表示してくれるようになる。

つまり、add_axesにおいてobjectを 0≤x≤1、0≤y≤1 の枠の中に納める必要なんてものは実はどこにもない、ということで、先のパネルを複数枚並べたいのであれば、もうあとは簡単。add_axes で指定した x,y 座標の始点を並べたい方向に1.0 ずらしてしまえばいい。たとえば、5x5個ならべたいのであれば、以下のようにfor文で回して、、、

# coding: UTF-8
import sys
import numpy as np
import matplotlib 
matplotlib.use("Agg")
import matplotlib.pyplot as plt
from matplotlib import rcParams
rcParams['font.family'] = 'Arial'

if __name__ == "__main__":
    fig = plt.figure(figsize=(3,3)) 
    for i in range(5):
        for j in range(5):
            ax1 = fig.add_axes([j + 0.10, 5 - i + 0.10,0.60,0.60]) 
            ax2 = fig.add_axes([j + 0.71, 5 - i + 0.10,0.20,0.60])
            ax3 = fig.add_axes([j + 0.10, 5 - i + 0.71,0.60,0.20])

            ax1.spines['top'].set_visible(False)
            ax1.spines['right'].set_visible(False)
            ax1.tick_params(top="off",right="off",direction="out",labelsize=10,pad=5)
            ax1.tick_params(right="off")

            ax2.spines['top'].set_visible(False)
            ax2.spines['right'].set_visible(False)
            ax2.spines['bottom'].set_visible(False)
            ax2.set_xticks([]) 
            ax2.set_yticks([])

            ax3.spines['top'].set_visible(False)
            ax3.spines['right'].set_visible(False)
            ax3.spines['left'].set_visible(False) 
            ax3.set_xticks([])
            ax3.set_yticks([])

            data = np.random.randn(2000,2000)
            ax1.scatter(data.T[0],data.T[1],s=5)
            ax2.hist(data.T[1],range=(-2,2),bins=100,orientation="horizontal") 
            ax3.hist(data.T[1],range=(-2,2),bins=100) 
            ax1.set_xlim(-2,2) 
            ax1.set_ylim(-2,2) 
            ax3.set_xlim(-2,2)
            ax3.set_title(str(1+i*5+j),fontsize=10)

    fig.savefig("test.pdf",bbox_inches="tight")

とすればOK。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away