【Python 筆記】Matplotlib Pyplot 套件應用(中)

感謝您點進本篇文章,我是 LukeTseng,該系列主要以筆記加上口語白話形式學習 Python,若文章某處有誤敬請告知,非常感謝。

解決中文顯示問題

要直接使用系統內建的中文字體,加入以下這一行即可:

1
plt.rcParams['font.sans-serif'] = ['Microsoft JhengHei']  # Windows 微軟正黑體

使用標楷體可將 Microsoft JhengHei 填入 DFKai-sb

在 colab 上執行可能會出錯,而在 Jupyter Notebook 就沒什麼問題,因為 Jupyter Notebook 是在電腦本機上執行的,可以隨時抓到字體庫。

透過以下範例可試試看顯示結果是否正確:

1
2
3
4
5
6
7
8
9
10
11
12
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['Microsoft JhengHei']
x = [0, 1, 2, 3, 4, 5]
y = [3, 4, 5, 6, 7, 8]
plt.plot(x, y)
plt.title("我的圖表")
plt.xlabel("月份(月)")
plt.ylabel("營收(十萬)")
plt.grid(True, linestyle="-", alpha=0.5)
plt.xticks(x)
plt.yticks(range(1, 11))
plt.show()

Output:

image

解決中文負號問題

中文字體的負號可能會產生錯誤,如下圖(X 軸要顯示 -3、-2、-1 就出現方框):

image

在程式中加上這行就不會產生這樣的錯誤了:plt.rcParams['axes.unicode_minus'] = False

完整範例程式碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['Microsoft JhengHei']
plt.rcParams['axes.unicode_minus'] = False
x = [-3, -2, -1, 0, 1, 2]
y = [3, 4, 5, 6, 7, 8]
plt.plot(x, y)
plt.title("我的圖表")
plt.xlabel("月份(月)")
plt.ylabel("營收(十萬)")
plt.grid(True, linestyle="-", alpha=0.5)
plt.xticks(x)
plt.yticks(range(1, 11))
plt.show()

Output:

image

設定圖表區

圖表區主要由 plt.figure() 這個函式所建立,以下是他的語法:

1
2
3
matplotlib.pyplot.figure(num=None, figsize=None, dpi=None, 
facecolor=None, edgecolor=None,
frameon=True, clear=False, **kwargs)
  • num:圖表區編號或名稱。可以給數字或字串,指定後如果已存在同編號的 figure 就會啟用它,不指定則自動產生新圖表區。
  • figsize:圖表區尺寸,tuple 格式 (寬, 高),單位為英吋。如 figsize=(8,4) 創建一張 8 吋寬、4 吋高的圖表區。
  • dpi:解析度,每英吋幾個像素。預設常見為 10080,dpi 越高圖越清晰但檔案也越大。
  • facecolor:圖表區的背景色,預設為白色。可用色名、16進位色碼等,例如 facecolor='yellow'
  • edgecolor:圖表區的邊框顏色。預設也是白色,可以設成你想要的顏色。
  • frameon:是否顯示圖表區的邊框和背景顏色。布林值,預設為 True(顯示);設成 False 可關掉背景框。
  • clear:若指定圖表區編號已存在,clear=True 會先清除其內容再使用(較少用,預設是 False)。
  • linewidth:邊框線條粗細,預設為 0(幾乎看不到)。設大一點可以明顯看到外框。

範例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import matplotlib.pyplot as plt
import numpy as np

plt.rcParams['font.sans-serif'] = ['DFKai-sb']
plt.rcParams['axes.unicode_minus'] = False

x = np.linspace(-np.pi, np.pi, 256)
y1 = np.sin(x)
y2 = np.cos(x)

# 創建第一個圖形
fig1 = plt.figure(num='first')
fig1.suptitle('第一個圖形')
plt.plot(x, y1)

# 創建第二個圖形
fig2 = plt.figure(num='second')
fig2.suptitle('第二個圖形')
plt.plot(x, y2)

# 切回第一個圖形繼續繪製
plt.figure(num='first') # 或用 plt.figure(num=1)
plt.plot(x, y2)

plt.show()

Output:

image

當中 numpy.linspace() 的語法如下:

1
numpy.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None)
  • start:序列起始值(包含)。
  • stop:序列結束值(預設包含,除非 endpoint 設為 False)。
  • num:產生的數字個數,預設為 50
  • endpoint:布林值,預設為 True,表示包含 stop 值;若 False 則不包含。
  • retstep:布林值,若為 True 會回傳(array, steps)。
  • dtype:指定輸出陣列的資料型態。

numpy 的 linspace() 函式用來在指定區間 [開始值, 結束值] 內,生成指定數量的等差數列,最後會回傳一個 NumPy 陣列。

而當中的 xx.suptitle() 可為這些圖表設定標題。

figsize

plt.figure() 的參數 figsize 可以調整圖的大小:

1
2
3
4
5
6
7
8
9
10
import matplotlib.pyplot as plt

# 創建較小的圖形(2英吋寬 x 1英吋高)
fig1 = plt.figure(figsize=(2, 1))
plt.plot([1, 2, 3, 4])

# 創建較大的圖形(8英吋寬 x 6英吋高)
fig2 = plt.figure(figsize=(8, 6))
plt.plot([1, 2, 3, 4])
plt.show()

Output:

image

facecolor

plt.figure()facecolor 參數可設定圖形的背景顏色,預設為白色。

1
2
3
4
5
6
7
8
import matplotlib.pyplot as plt

x = [1, 2, 3, 4, 5]

# 設定黃色背景
fig = plt.figure(facecolor='yellow')
plt.plot(x)
plt.show()

Output:

image

edgecolor

plt.figure()edgecolor 參數可設定圖形邊框的顏色。

1
2
3
4
5
6
import matplotlib.pyplot as plt

# 設定紅色邊框、黃色背景、邊框寬度 5
fig = plt.figure(edgecolor='#f00', facecolor='#ff0', linewidth=5, figsize=(8, 3))
plt.plot([1, 2, 3, 4, 5])
plt.show()

Output:

image

fig.savefig() 保存圖表

fig.savefig('my_figure.png') 可將先前用 plt.figure() 生成的 figure 物件像是 fig,將其圖表儲存。

小結

若有多個圖表的時候建議用 num 參數明確指定某個圖表,之後好方便去找、管理。

圖表區中加入多個圖表

首先介紹 plt.subplot(),這是拿來用在同一張圖表區(figure:或可以說是一個畫布)上創建多個子圖(subplot)的函數。

語法格式:

1
2
3
plt.subplot(nrows, ncols, index)
# 或簡寫成三位數
plt.subplot(nci) # n=nrows, c=ncols, i=index
  • nrows:子圖的列數(垂直方向有幾排)。
  • ncols:子圖的行數(水平方向有幾個)。
  • index:當前要操作的子圖位置編號,從 1 開始計數。

需特別注意同一張圖表區裡所有 subplot()nrowsncols 必須相同。

子圖編號規則

子圖的編號是由左到右、由上到下依序編號。以 2x2(2 列 2 行)的配置為例:

1
2
位置1 (1,1)  位置2 (1,2)
位置3 (2,1) 位置4 (2,2)

以下範例示範如何創建一個 1x2(1 列 2 行)子圖:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import matplotlib.pyplot as plt
import numpy as np

plt.rcParams['font.sans-serif'] = ['DFKai-sb']
plt.rcParams['axes.unicode_minus'] = False

# 創建圖表區
fig = plt.figure()

# 左邊的子圖
plt.subplot(1, 2, 1) # 1列2行,第1個位置
plt.plot([0, 6], [0, 100])
plt.title("plot 1")

# 右邊的子圖
plt.subplot(1, 2, 2) # 1列2行,第2個位置
x = [1, 2, 3, 4]
y = [1, 4, 9, 16]
plt.plot(x, y)
plt.title("plot 2")

plt.suptitle("我的圖表") # 整體標題
plt.show()

Output:

image

以下是 2x2(2 行 2 列)子圖的範例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import matplotlib.pyplot as plt
import numpy as np

plt.rcParams['font.sans-serif'] = ['DFKai-sb']
plt.rcParams['axes.unicode_minus'] = False

fig = plt.figure(figsize=(10, 8))

# 第1個子圖(左上)
plt.subplot(2, 2, 1)
plt.plot([1, 2, 3, 4, 5])
plt.title("子圖 1")

# 第2個子圖(右上)
plt.subplot(2, 2, 2)
plt.plot([5, 4, 3, 2, 1])
plt.title("子圖 2")

# 第3個子圖(左下)
plt.subplot(2, 2, 3)
plt.plot([1, 3, 5, 7, 9])
plt.title("子圖 3")

# 第4個子圖(右下)
plt.subplot(2, 2, 4)
plt.plot([2, 4, 6, 8, 10])
plt.title("子圖 4")

plt.suptitle("2x2 子圖範例")
plt.tight_layout() # 自動調整間距
plt.show()

Output:

image

以下則是 2x1 的子圖,但使用簡寫方式撰寫:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import matplotlib.pyplot as plt

x = [1, 2, 3, 4, 5]
y = [5, 4, 3, 2, 1]

fig = plt.figure()

# 使用三位數簡寫
plt.subplot(221) # 等於 subplot(2, 2, 1)
plt.plot(x)

plt.subplot(224) # 等於 subplot(2, 2, 4)
plt.plot(y)

plt.show()

Output:

image

自動調整子圖間距

使用函式 plt.tight_layout(),可以自動調整子圖之間的間距,避免標題跟標籤重疊到,會很難看。

plt.axes()

plt.subplot() 後要介紹的是 plt.axes()plt.axes() 用來在當前的圖表區中新增並創建一個 Axes(座標系統),並把它設為當前操作的座標系統。可以把 Axes 想像成是在圖表區上實際可以繪圖的區域,包含 x 軸和 y 軸以及所有的圖形元素。

Figure 和 Axes - matplotlib 教學 ( Python ) | STEAM 教育學習網 有詳細圖文說明 Figure 跟 Axes 的關係,供參。

語法:

1
plt.axes(arg=None, **kwargs)

arg 參數有三種不同的用法:

  1. None(預設):創建一個填滿整個 Figure 的標準 Axes,相當於 subplot(111)
  2. 4-tuple 列表:[left, bottom, width, height]
    • 使用標準化坐標(範圍從 01)。
    • left:Axes 左邊界距離 Figure 左邊的比例。
    • bottom:Axes 下邊界距離 Figure 底部的比例。
    • width:Axes 的寬度比例。
    • height:Axes 的高度比例。
  3. Axes 物件:直接傳入一個已存在的 Axes 物件。

範例 1:創建預設的全尺寸 Axes。

1
2
3
4
5
6
7
8
9
10
11
12
import matplotlib.pyplot as plt
import numpy as np

plt.rcParams['font.sans-serif'] = ['DFKai-sb']
plt.rcParams['axes.unicode_minus'] = False

# 創建填滿整個 Figure 的 Axes
plt.figure()
plt.axes() # 等同於 plt.axes(None)
plt.plot([1, 2, 3, 4], [1, 4, 9, 16])
plt.title("我的圖表")
plt.show()

Output:

image

範例 2:使用 4-tuple 自訂 Axes 位置和大小。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import matplotlib.pyplot as plt
import numpy as np

plt.rcParams['font.sans-serif'] = ['DFKai-sb']
plt.rcParams['axes.unicode_minus'] = False

fig = plt.figure(figsize=(8, 6))

# 創建一個位於左下角的小 Axes
# [left=0.1, bottom=0.1, width=0.3, height=0.3]
ax1 = plt.axes([0.1, 0.1, 0.3, 0.3])
ax1.plot([1, 2, 3], [1, 4, 9])
ax1.set_title("小圖(左下)")

# 創建一個較大的 Axes 位於右上
# [left=0.5, bottom=0.5, width=0.4, height=0.4]
ax2 = plt.axes([0.5, 0.5, 0.4, 0.4])
ax2.plot([1, 2, 3], [9, 4, 1], 'r')
ax2.set_title("中圖(右上)")

plt.show()

Output:

image

範例 3:創建子圖中的圖(圖中圖)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import matplotlib.pyplot as plt
import numpy as np

plt.rcParams['font.sans-serif'] = ['DFKai-sb']
plt.rcParams['axes.unicode_minus'] = False

x = np.linspace(0, 10, 100)
y = np.sin(x)

fig = plt.figure(figsize=(10, 6))

# 主圖(填滿整個 Figure)
ax_main = plt.axes()
ax_main.plot(x, y, 'b-', linewidth=2)
ax_main.set_title("主圖:sin(x)")
ax_main.set_xlabel("x")
ax_main.set_ylabel("sin(x)")

# 嵌入的小圖(右上角)
ax_inset = plt.axes([0.6, 0.59, 0.25, 0.25])
ax_inset.plot(x, y**2, 'r-')
ax_inset.set_title("小圖:sin²(x)", fontsize=10)

plt.show()

Output:

image

範例 4:創建多個不規則排列的 Axes。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import matplotlib.pyplot as plt

plt.rcParams['font.sans-serif'] = ['DFKai-sb']
plt.rcParams['axes.unicode_minus'] = False

fig = plt.figure(figsize=(10, 8))

# 左側大圖
ax1 = plt.axes([0.1, 0.1, 0.4, 0.8])
ax1.plot([1, 2, 3, 4], [1, 4, 2, 3])
ax1.set_title("左側主圖")

# 右上小圖
ax2 = plt.axes([0.6, 0.55, 0.3, 0.35])
ax2.plot([1, 2, 3], [3, 1, 2], 'g')
ax2.set_title("右上圖")

# 右下小圖
ax3 = plt.axes([0.6, 0.1, 0.3, 0.35])
ax3.plot([1, 2, 3], [2, 3, 1], 'r')
ax3.set_title("右下圖")

plt.show()

Output:

image

plt.axes() vs plt.subplot()

plt.axes()

  • 可以自由指定位置和大小(使用標準化坐標)。
  • 適合創建不規則排列或重疊的圖。
  • Axes 可以位於任意位置,不限於網格內。

plt.subplot()

  • 將 Figure 劃分為規則的網格(m×n)。
  • 適合創建整齊排列的多子圖。
  • 所有子圖大小統一、不重疊。

總結

中文字體設定

使用系統字體讓 Matplotlib 正確顯示中文:

1
plt.rcParams['font.sans-serif'] = ['Microsoft JhengHei']  # Windows 微軟正黑體

標楷體(DFKai-sb)。

中文負號錯誤修正程式碼:

1
plt.rcParams['axes.unicode_minus'] = False

圖表區設定

語法:

1
2
3
plt.figure(num=None, figsize=None, dpi=None, 
facecolor=None, edgecolor=None,
frameon=True, clear=False, **kwargs)
參數說明
num圖表區編號或名稱(便於管理多圖)
figsize圖尺寸(單位:英吋),如 (8, 4)
dpi解析度,數值越高圖越清晰
facecolor圖表區背景色
edgecolor邊框顏色
frameon是否顯示背景邊框
clear若圖表區已存在是否清除內容
linewidth邊框粗細

圖表區內建立多子圖

1
plt.subplot(nrows, ncols, index)

或簡寫為三位數:plt.subplot(221)

子圖排列規則:

由上到下、由左到右編號。

例如 2×2 共有四張子圖:

1
2
(1,1) (1,2)
(2,1) (2,2)

建立自由座標區

  • 用來在圖表區上手動指定繪圖區位置與大小。
  • 可創建重疊、不規則或嵌入式(圖中圖)的小圖。
1
plt.axes([left, bottom, width, height])

各參數範圍為 0–1,代表相對於整張圖表區的比例。

plt.axes() vs plt.subplot()

plt.subplot()plt.axes()
配置方式規則網格(m×n)自由指定位置大小
適用情境整齊排列的多子圖不規則或重疊圖形
彈性固定尺寸、等間距高度客製化
編號方式由上到下、左到右用座標指定

參考資料

Figure 參數設定 - matplotlib 教學 ( Python ) | STEAM 教育學習網

matplotlib.pyplot.figure() in Python - GeeksforGeeks\

建立多個子圖表 ( subplot、subplots ) - matplotlib 教學 ( Python ) | STEAM 教育學習網

Matplotlib Subplot | W3Schools

Matplotlib.pyplot.axes() in Python - GeeksforGeeks

Figure 和 Axes - matplotlib 教學 ( Python ) | STEAM 教育學習網