# 【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)