Python之Matplotlib數據可視化(四):多子圖問題(超級詳細,爆肝推薦)

有時候需要從多個角度對數據進行對比。Matplotlib 爲此提出了子圖(subplot)的概念:在較大的圖形中同時放置一組較小的座標軸。這些子圖可能是畫中畫(inset)網格圖(grid of plots),或者是其他更復雜的佈局形式。在這裏將介紹四種用 Matplotlib 創建子圖的方法。

首先,導入畫圖需要的程序庫:

import matplotlib.pyplot as plt
plt.style.use('seaborn-white')
import numpy as np

1  plt.axes :手動創建子圖

1.1 圖中圖的座標軸

創建座標軸最基本的方法就是使用 plt.axes 函數。可見我上幾篇博客,這個函數的默認配置是創建一個標準的座標軸,填滿整張圖。它還有一個可選參數,由圖形座標系統的四個值構成。這四個值分別表示圖形座標系統的 [bottom, left, width, height] (底座標、左座標、寬度、高度),數值的取值範圍是左下角(原點)爲 0,右上角爲 1

如果想要在右上角創建一個畫中畫,那麼可以首先將 x 與 y 設置爲0.65(就是座標軸原點位於圖形高度 65% 和寬度 65% 的位置),然後將 x 與 y 擴展到 0.2(也就是將座標軸的寬度與高度設置爲圖形的 20%)。 顯示了代碼的結果:

ax1 = plt.axes() # 默認座標軸
ax2 = plt.axes([0.65, 0.65, 0.2, 0.2])
import matplotlib.pyplot as plt
plt.style.use('seaborn-white')
import numpy as np
ax1 = plt.axes() # 默認座標軸
ax2 = plt.axes([0.65, 0.65, 0.2, 0.2])
plt.show()

在這裏插入圖片描述

1.2 豎直排列的座標軸

面向對象畫圖接口中類似的命令有 fig.add_axes() 。用這個命令創建兩個豎直排列的座標軸:

fig = plt.figure()
ax1 = fig.add_axes([0.1, 0.5, 0.8, 0.4],
xticklabels=[], ylim=(-1.2, 1.2))
ax2 = fig.add_axes([0.1, 0.1, 0.8, 0.4],
ylim=(-1.2, 1.2))
x = np.linspace(0, 10)
ax1.plot(np.sin(x))
ax2.plot(np.cos(x));
import matplotlib.pyplot as plt
plt.style.use('seaborn-white')
import numpy as np
fig = plt.figure()
ax1 = fig.add_axes([0.1, 0.5, 0.8, 0.4],
xticklabels=[], ylim=(-1.2, 1.2))
ax2 = fig.add_axes([0.1, 0.1, 0.8, 0.4],
ylim=(-1.2, 1.2))
x = np.linspace(0, 10)
ax1.plot(np.sin(x))
ax2.plot(np.cos(x));
plt.show()

在這裏插入圖片描述
現在就可以看到兩個緊挨着的座標軸(上面的座標軸沒有刻度):上子圖(起點 y 座標爲0.5 位置)與下子圖的 x 軸刻度是對應的(起點 y 座標爲 0.1,高度爲 0.4)。

2  plt.subplot :簡易網格子圖

2.1 plt.subplot()

若干彼此對齊的行列子圖是常見的可視化任務,Matplotlib 擁有一些可以輕鬆創建它們的簡便方法。最底層的方法是用 plt.subplot() 在一個網格中創建一個子圖。這個命令有三個整型參數——將要創建的網格子圖行數、列數和索引值,索引值從 1 開始,從左上角到右下角依次增大:

for i in range(1, 7):
	plt.subplot(2, 3, i)
	plt.text(0.5, 0.5, str((2, 3, i)),fontsize=18, ha='center')
import matplotlib.pyplot as plt
plt.style.use('seaborn-white')
import numpy as np
for i in range(1, 7):
	plt.subplot(2, 3, i)
	plt.text(0.5, 0.5, str((2, 3, i)),fontsize=18, ha='center')
plt.show()

在這裏插入圖片描述

2.2 帶邊距調整功能的 plt.subplot()

plt.subplots_adjust 命令可以調整子圖之間的間隔。用面向對象接口的命令 fig.add_subplot() 可以取得同樣的效果:

fig = plt.figure()
fig.subplots_adjust(hspace=0.4, wspace=0.4)
for i in range(1, 7):
	ax = fig.add_subplot(2, 3, i)
	ax.text(0.5, 0.5, str((2, 3, i)),fontsize=18, ha='center')
import matplotlib.pyplot as plt
plt.style.use('seaborn-white')
import numpy as np
fig = plt.figure()
fig.subplots_adjust(hspace=0.4, wspace=0.4)
for i in range(1, 7):
	ax = fig.add_subplot(2, 3, i)
	ax.text(0.5, 0.5, str((2, 3, i)),fontsize=18, ha='center')
plt.show()

在這裏插入圖片描述
我們通過 plt.subplots_adjust 的 hspace 與 wspace 參數設置與圖形高度與寬度一致的子圖間距,數值以子圖的尺寸爲單位(在本例中,間距是子圖寬度與高度的 40%)。

3  plt.subplots :用一行代碼創建網格

當你打算創建一個大型網格子圖時,就沒辦法使用前面那種亦步亦趨的方法了,尤其是當你想隱藏內部子圖的 x 軸與 y 軸標題時。出於這一需求, plt.subplots() 實現了你想要的功能(需要注意此處 subplots 結尾多了個 s )。這個函數不是用來創建單個子圖的, 而是用一行代碼創建多個子圖,並返回一個包含子圖的 NumPy 數組。關鍵參數是行數與列數,以及可選參數 sharex 與 sharey ,通過它們可以設置不同子圖之間的關聯關係。

3.1 plt.subplots() 方法共享 x 軸與 y 軸座標

我們將創建一個 2×3 網格子圖,每行的 3 個子圖使用相同的 y 軸座標,每列的 2 個子圖使用相同的 x 軸座標:

fig, ax = plt.subplots(2, 3, sharex='col', sharey='row')
import matplotlib.pyplot as plt
plt.style.use('seaborn-white')
import numpy as np
fig, ax = plt.subplots(2, 3, sharex='col', sharey='row')
plt.show()

在這裏插入圖片描述

3.2 確定網格中的子圖

設置 sharex 與 sharey 參數之後,我們就可以自動去掉網格內部子圖的標籤,讓圖形看起來更整潔。座標軸實例網格的返回結果是一個 NumPy 數組,這樣就可以通過標準的數組取值方式輕鬆獲取想要的座標軸了:

# 座標軸存放在一個NumPy數組中,按照[row, col]取值
for i in range(2):
	for j in range(3):
		ax[i, j].text(0.5, 0.5, str((i, j)),fontsize=18, ha='center')
fig
import matplotlib.pyplot as plt
plt.style.use('seaborn-white')
import numpy as np
fig, ax = plt.subplots(2, 3, sharex='col', sharey='row')
# 座標軸存放在一個NumPy數組中,按照[row, col]取值
for i in range(2):
    for j in range(3):
        ax[i, j].text(0.5, 0.5, str((i, j)),fontsize=18, ha='center')
fig
plt.show()

在這裏插入圖片描述
與 plt.subplot() 1 相比, plt.subplots() 與 Python 索引從 0 開始的習慣保持一致。

4  plt.GridSpec :實現更復雜的排列方式

如果想實現不規則的多行多列子圖網格, plt.GridSpec() 是最好的工具。 plt.GridSpec()對象本身不能直接創建一個圖形,它只是 plt.subplot() 命令可以識別的簡易接口。

4.1 用 plt.GridSpec 生成不規則子圖

例如,一個帶行列間距的 2×3 網格的配置代碼如下所示:

grid = plt.GridSpec(2, 3, wspace=0.4, hspace=0.3)

可以通過類似 Python 切片的語法設置子圖的位置和擴展尺寸

plt.subplot(grid[0, 0])
plt.subplot(grid[0, 1:])
plt.subplot(grid[1, :2])
plt.subplot(grid[1, 2]);
import matplotlib.pyplot as plt
plt.style.use('seaborn-white')
import numpy as np
grid = plt.GridSpec(2, 3, wspace=0.4, hspace=0.3)
plt.subplot(grid[0, 0])
plt.subplot(grid[0, 1:])
plt.subplot(grid[1, :2])
plt.subplot(grid[1, 2]);
plt.show()

在這裏插入圖片描述

4.2 用 plt.GridSpec 可視化多維分佈數據

這種靈活的網格排列方式用途十分廣泛,我經常會用它來創建 所示的多軸頻次直方圖(multi-axes histogram)

# 創建一些正態分佈數據
mean = [0, 0]
cov = [[1, 1], [1, 2]]
x, y = np.random.multivariate_normal(mean, cov, 3000).T
# 設置座標軸和網格配置方式
fig = plt.figure(figsize=(6, 6))
grid = plt.GridSpec(4, 4, hspace=0.2, wspace=0.2)
main_ax = fig.add_subplot(grid[:-1, 1:])
y_hist = fig.add_subplot(grid[:-1, 0], xticklabels=[], sharey=main_ax)
x_hist = fig.add_subplot(grid[-1, 1:], yticklabels=[], sharex=main_ax)
# 主座標軸畫散點圖
main_ax.plot(x, y, 'ok', markersize=3, alpha=0.2)
# 次座標軸畫頻次直方圖
x_hist.hist(x, 40, histtype='stepfilled',orientation='vertical', color='gray')
x_hist.invert_yaxis()
y_hist.hist(y, 40, histtype='stepfilled',orientation='horizontal', color='gray')
y_hist.invert_xaxis()
import matplotlib.pyplot as plt
plt.style.use('seaborn-white')
import numpy as np
# 創建一些正態分佈數據
mean = [0, 0]
cov = [[1, 1], [1, 2]]
x, y = np.random.multivariate_normal(mean, cov, 3000).T
# 設置座標軸和網格配置方式
fig = plt.figure(figsize=(6, 6))
grid = plt.GridSpec(4, 4, hspace=0.2, wspace=0.2)
main_ax = fig.add_subplot(grid[:-1, 1:])
y_hist = fig.add_subplot(grid[:-1, 0], xticklabels=[], sharey=main_ax)
x_hist = fig.add_subplot(grid[-1, 1:], yticklabels=[], sharex=main_ax)
# 主座標軸畫散點圖
main_ax.plot(x, y, 'ok', markersize=3, alpha=0.2)
# 次座標軸畫頻次直方圖
x_hist.hist(x, 40, histtype='stepfilled',orientation='vertical', color='gray')
x_hist.invert_yaxis()
y_hist.hist(y, 40, histtype='stepfilled',orientation='horizontal', color='gray')
y_hist.invert_xaxis()
plt.show()

在這裏插入圖片描述
這種類型的分佈圖十分常見,Seaborn 程序包提供了專門的 API 來實現它們,可以自己查看。

備註

各位老鐵來個“關注”、“點贊”、“評論”三連擊哦
各位老鐵來個“關注”、“點贊”、“評論”三連擊哦
各位老鐵來個“關注”、“點贊”、“評論”三連擊哦

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章