天天看點

Matplotlib繪制子圖多個子圖的合成

多個子圖的合成

有時,我們希望檢查資料的多個方面。例如,檢視一個地區的天氣狀況,我們不僅希望得到時間與溫度的關系,同時我們也需要關注時間與風力、PM2.5 等方面之間的關系,此時我們希望同時展現時間-溫度、時間-風力、時間-PM2.5三個不同的圖形,Matplotlib 提供了将多個圖形組合在一起的方法。

import numpy as np
from matplotlib import pyplot as plt
t = np.linspace(-np.pi, np.pi, 1024)
grid_size = (4, 2)
plt.subplot2grid(grid_size, (0, 0), rowspan = 3, colspan = 1)
plt.plot(np.sin(2 * t), np.cos(0.5 * t), c = 'm')
plt.subplot2grid(grid_size, (0, 1), rowspan = 3, colspan = 1)
plt.plot(np.cos(3 * t), np.sin(t), c = 'c')
plt.subplot2grid(grid_size, (3, 0), rowspan=1, colspan=3)
plt.plot(np.cos(5 * t), np.sin(7 * t), c= 'y')
plt.tight_layout()
plt.show()      
Matplotlib繪制子圖多個子圖的合成

Tips:使用 plt.subplot2grid() 可以定義一個 R 行、C 列的網格。然後,我們可以将一個圖形渲染到所定義的網格中。

plt.subplot2grid() 函數有四個常用參數:

1. 第一個參數是網格的行數和列數,作為元組傳遞,例如我們想要一個 R 行、C 列的網格,則需要傳遞(R,C)。

2. 第二個參數用于确定圖形在網格中的坐标,也作為元組傳遞。

3. 可選參數 rowspan 定義圖形将占據多少行。

4. 可選參數 colspan 定義圖形将占據多少列。

調用 plt.subplot2grid() 後,對 plt 繪圖的下一次調用将在指定的矩形區域内繪制圖形,同理,要在網格的另一個區域中繪制下一個圖形,需要再次調用 plt.subplot2grid()。

在示例中,定義了一個 2x4 的網格。前兩個圖形占據了 1 列、3 行,第三個圖形占據了兩列、一行。一旦繪制了所有的圖形,就需要調用 pyplot.tight_layout() 按照定義自動排列所有圖形,確定它們彼此不重疊。

為每個子圖添加标題

我們已經可以将多個子圖合成在一個圖形中,但是每個子圖可能還需要有自己的标題,可以使用 plt.title() 為每個子圖添加标題:

import numpy as np
from matplotlib import pyplot as plt
def get_radius(t, params):
    m, n_1, n_2, n_3 = params
    u = (m * t) / 4
    return (np.fabs(np.cos(u)) ** n_2 + np.fabs(np.sin(u)) ** n_3) ** (-1. / n_1)
grid_size = (3, 4)
t = np.linspace(0, 2 * np.pi, 1024)
for i in range(grid_size[0]):
    for j in range(grid_size[1]):
        params = np.random.randint(1, 20+1, size = 4)
        r = get_radius(t, params)
        plt.subplot2grid(grid_size, (i, j), rowspan=1, colspan=1)
        plt.plot(r * np.cos(t), r * np.sin(t), c = 'c')
        plt.title('%d, %d, %d, %d' % tuple(params), fontsize = 'small')
plt.suptitle("Example of plt.suptitle")
plt.tight_layout()
plt.show()      
Matplotlib繪制子圖多個子圖的合成

Tips:plt.title() 函數可以為每一個圖形提供一個标題,但此時,如果我們需要為整個圖形提供一個标題,則應該使用 plt.suptitle() 函數。

子圖合成的另一種方法

上述的子圖合成方法具有通用性,可以使用它建立複雜的布局,但如果我們隻需要在同一行或同一列中繪制多個子圖,則可以使用更簡潔的代碼:

import numpy as np
from matplotlib import pyplot as plt
t = np.linspace(-np.pi, np.pi, 1024)
fig, (ax0, ax1, ax2) = plt.subplots(ncols =3)
ax0.plot(np.sin(2 * t), np.cos(0.5 * t), c = 'c')
ax1.plot(np.cos(3 * t), np.sin(t), c = 'c')
ax2.plot(np.cos(3 * t), np.sin(2 * t), c = 'c')
plt.tight_layout()
plt.show()      
Matplotlib繪制子圖多個子圖的合成

Tips:plt.subplots() 函數接受兩個可選參數 ncols 和 nrows,并傳回一個帶有 ncols*nrows 軸執行個體的 Figure 對象。軸執行個體按 nrows 行、ncols 列排列在網格中。

更簡潔的方法

雖然上述兩種方法都可以實作合成子圖的應用需求,但是我們需要的遠不止此,我們可能想要更簡潔的方法,而 plt.subplot() 函數就是我們所需要的。

import numpy as np
from matplotlib import pyplot as plt
def get_radius(t, params):
    m, n_1, n_2, n_3 = params
    u = (m * t) / 4
    return (np.fabs(np.cos(u)) ** n_2 + np.fabs(np.sin(u)) ** n_3) ** (-1. / n_1)
grid_size = (3, 4)
t = np.linspace(0, 2 * np.pi, 1024)
for i in range(grid_size[0] * grid_size[1]):
    params = np.random.random_integers(1, 20, size = 4)
    r = get_radius(t, params)
    plt.subplot(grid_size[0], grid_size[1], i+1)
    plt.plot(r * np.cos(t), r * np.sin(t), c = 'c')
    plt.title('%d, %d, %d, %d' % tuple(params), fontsize = 'small')
plt.suptitle("Example of plt.suptitle")
plt.tight_layout()
plt.show()      
Matplotlib繪制子圖多個子圖的合成

Tips:plt.subplot() 函數接收三個參數,分别為行數,列數,以及子圖的位序,直接指定劃分網格的方式和需要繪圖的位置索引。