---
# System prepended metadata

title: 【Python 筆記】Matplotlib Pyplot 套件應用（中）
tags: [python, 程式設計, 數據分析, Python, 程式語言]

---

# 【Python 筆記】Matplotlib Pyplot 套件應用（中）

[TOC]

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

## 解決中文顯示問題

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

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

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

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

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

```python=
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](https://hackmd.io/_uploads/SkhwpKPRlx.png)

### 解決中文負號問題

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

![image](https://hackmd.io/_uploads/BJMhpKvAxg.png)

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

完整範例程式碼：

```python=
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](https://hackmd.io/_uploads/rJeg0tDCxx.png)

## 設定圖表區

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

```python
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`：解析度，每英吋幾個像素。預設常見為 `100` 或 `80`，dpi 越高圖越清晰但檔案也越大。
* `facecolor`：圖表區的背景色，預設為白色。可用色名、16進位色碼等，例如 `facecolor='yellow'`。
* `edgecolor`：圖表區的邊框顏色。預設也是白色，可以設成你想要的顏色。
* `frameon`：是否顯示圖表區的邊框和背景顏色。布林值，預設為 `True`（顯示）；設成 `False` 可關掉背景框。
* `clear`：若指定圖表區編號已存在，`clear=True` 會先清除其內容再使用（較少用，預設是 `False`）。
* `linewidth`：邊框線條粗細，預設為 0（幾乎看不到）。設大一點可以明顯看到外框。

範例：

```python=
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](https://hackmd.io/_uploads/rJYT8qDRlg.png)

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

```python
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` 可以調整圖的大小：

```python=
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](https://hackmd.io/_uploads/SkmOccw0ge.png)

### facecolor

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

```python=
import matplotlib.pyplot as plt

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

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

Output：

![image](https://hackmd.io/_uploads/S17JjcvAel.png)

### edgecolor

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

```python=
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](https://hackmd.io/_uploads/Hy5Mo5v0gl.png)

### fig.savefig() 保存圖表

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

### 小結

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

## 圖表區中加入多個圖表

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

語法格式：

```python
plt.subplot(nrows, ncols, index)
# 或簡寫成三位數
plt.subplot(nci)  # n=nrows, c=ncols, i=index
```

* `nrows`：子圖的列數（垂直方向有幾排）。
* `ncols`：子圖的行數（水平方向有幾個）。
* `index`：當前要操作的子圖位置編號，從 1 開始計數。

需特別注意同一張圖表區裡所有 `subplot()` 的 `nrows` 和 `ncols` 必須相同。

### 子圖編號規則

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

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

以下範例示範如何創建一個 1x2（1 列 2 行）子圖：

```python=
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](https://hackmd.io/_uploads/S1OOUow0xg.png)

以下是 2x2（2 行 2 列）子圖的範例：

```python=
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](https://hackmd.io/_uploads/SJc-PiPRll.png)

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

```python=
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](https://hackmd.io/_uploads/HyPw6ovClx.png)

### 自動調整子圖間距

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

### plt.axes()

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

[Figure 和 Axes - matplotlib 教學 ( Python ) | STEAM 教育學習網](https://steam.oxxostudio.tw/category/python/example/matplotlib-figure-axes.html) 有詳細圖文說明 Figure 跟 Axes 的關係，供參。

語法：

```python
plt.axes(arg=None, **kwargs)
```

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

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

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

```python=
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](https://hackmd.io/_uploads/By27i_OAlx.png)

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

```python=
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](https://hackmd.io/_uploads/r1mSs_ORge.png)

範例 3：創建子圖中的圖（圖中圖）。

```python=
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](https://hackmd.io/_uploads/S18ToO_Cxe.png)

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

```python=
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](https://hackmd.io/_uploads/B17l3O_Ale.png)

### plt.axes() vs plt.subplot()

`plt.axes()`：

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

`plt.subplot()`：

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

## 總結

### 中文字體設定

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

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

標楷體（DFKai-sb）。

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

```python
plt.rcParams['axes.unicode_minus'] = False
```

### 圖表區設定

語法：

```python
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` | 邊框粗細                  |

### 圖表區內建立多子圖

```python
plt.subplot(nrows, ncols, index)
```

或簡寫為三位數：`plt.subplot(221)`。

子圖排列規則：

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

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

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

### 建立自由座標區

- 用來在圖表區上手動指定繪圖區位置與大小。
- 可創建重疊、不規則或嵌入式（圖中圖）的小圖。

```python
plt.axes([left, bottom, width, height])
```

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

### plt.axes() vs plt.subplot()

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

## 參考資料

[Figure 參數設定 - matplotlib 教學 ( Python ) | STEAM 教育學習網](https://steam.oxxostudio.tw/category/python/example/matplotlib-figure.html)

[matplotlib.pyplot.figure() in Python - GeeksforGeeks](https://www.geeksforgeeks.org/python/matplotlib-pyplot-figure-in-python/)\

[建立多個子圖表 ( subplot、subplots ) - matplotlib 教學 ( Python ) | STEAM 教育學習網](https://steam.oxxostudio.tw/category/python/example/matplotlib-subplot.html)

[Matplotlib Subplot | W3Schools](https://www.w3schools.com/python/matplotlib_subplot.asp)

[Matplotlib.pyplot.axes() in Python - GeeksforGeeks](https://www.geeksforgeeks.org/python/matplotlib-pyplot-axes-in-python/)

[Figure 和 Axes - matplotlib 教學 ( Python ) | STEAM 教育學習網](https://steam.oxxostudio.tw/category/python/example/matplotlib-figure-axes.html)