# Matplotlib 繪圖技巧:在同一張圖上繪製兩個函數、兩張圖並列
> 作者:王一哲 日期:2018/11/20
我們在〈[冰與水蒸氣混合達熱平衡時溫度與質量比值關係圖](https://hackmd.io/s/B1oZPnpaX)〉中使用 Matplotlib 繪製單一的函數圖形,但如果我們想在同一張圖上繪製兩個函數,或是將兩張圖並列畫在同一張圖片中時要怎麼做呢?
我們以兩個點電荷之間的靜電力和電位能與距離的關係為例,假設點電荷的電量分別為 Q 和 q,兩者之間的距離為 r,則兩者之間的靜電力量值
$$F = \frac{kQq}{r^2}$$
電位能量值
$$U = \frac{kQq}{r}$$
由於使用 Matplotlib 繪圖時必須代入數值,我將數值設定為 $Q = 1 \times 10^{-4} ~\mathrm{C}$、$q = 1 \times 10^{-4} ~\mathrm{C}$、$0.01 \leq r \leq 10~\mathrm{m}$,r 不從 0 開始畫是為了避免靜電力和電位能量值變為無窮大。接著我們來繪製函數圖形。
<br></br>
## 在同一張圖上繪製兩個函數
我們希望圖片能有以下的特點:
1. 用不同的顏色繪製不同的函數
2. 加上圖例、格線、坐標軸標籤
3. 設定縱軸繪圖範圍
成果如下圖所示,使用的程式碼如下。
<img height="80%" width="80%" src="https://i.imgur.com/govT5Y1.png" style="display: block; margin-left: auto; margin-right: auto;"/>
<div style="text-align:center">在同一張圖上繪製靜電力、電位能與距離的關係圖</div>
<br></br>
```python=
"""
靜電力、電位能對距離的關係圖
日期: 2018/11/5
作者: 王一哲
"""
import numpy as np # 引入科學計算函式庫
import matplotlib.pyplot as plt # 引入繪圖函式庫
xmin, xmax, num = 0.01, 10, 100 # 設定繪圖範圍、取點數
x = np.linspace(xmin, xmax, num) # 產生x
Q = 1E-4
q = 1E-4
k = 8.988E9
F = k * Q * q / x**2 # 靜電力F
U = k * Q * q / x # 電位能U
plt.figure(figsize = (6, 4.5), dpi = 100) # 設定圖片尺寸
plt.xlabel('r (m)', fontsize = 16) # 設定坐標軸標籤
plt.xticks(fontsize = 12) # 設定坐標軸數字格式
plt.yticks(fontsize = 12)
plt.grid(color = 'red', linestyle = '--', linewidth = 1) # 設定格線顏色、種類、寬度
plt.ylim(0, 200) # 設定y軸繪圖範圍
# 繪圖並設定線條顏色、寬度、圖例
line1, = plt.plot(x, F, color = 'red', linewidth = 3, label = 'Electric Force (N)')
line2, = plt.plot(x, U, color = 'blue', linewidth = 3, label = 'Electric Potential Energy (J)')
plt.legend(handles = [line1, line2], loc='upper right')
plt.savefig('Fe_r_plot.svg') # 儲存圖片
plt.savefig('Fe_r_plot.png')
plt.show() # 顯示圖片
```
<br></br>
以下說明程式碼中較特別的部分
1. 使用 **plt.xlabel('r (m)', fontsize = 16)** 設定 x 軸標籤為 r (m),字型大小為 16。
2. 使用 **plt.grid(color = 'red', linestyle = '--', linewidth = 1)** 加上格線,格線為紅色虛線,線條寬度為 1。
3. 使用 **plt.ylim(0, 200)** 設定y軸繪圖範圍為 1 到 200。
4. 為了用不同的線條顏色繪製不同的函數,我們使用了以下的程式碼,括號中的選項有:**顏色** (**color**)、**線條寬度** (**linewidth**)、**標籤** (**label**)。由於 plt.plot 的回傳值不是一個單純的物件,如果我們要將繪製的線條物件指定給 line1 和 line2,**line1 和 line2 後方一定要加上逗號**。
```python
line1, = plt.plot(x, F, color = 'red', linewidth = 3, label = 'Electric Force (N)')
line2, = plt.plot(x, U, color = 'blue', linewidth = 3, label = 'Electric Potential Energy (J)')
```
5. 使用 **plt.legend(handles = [line1, line2], loc='upper right')** 加上圖例,其中 **handles** 是圖例的內容,在此設定為 line1 和 line2 的標籤;**loc**是圖例的位置,在此設定為右上方。如果想要知道更詳細的設定,請參考官方說明書 https://matplotlib.org/api/_as_gen/matplotlib.pyplot.legend.html
<br></br>
## 將兩張圖並列畫在同一張圖片中
我們希望圖片能有以下的特點:
1. 左、右兩張圖並列
2. 兩張圖共同相同格式的縱軸
3. 加坐標軸標籤
4. 設定縱軸繪圖範圍
成果如下圖所示,使用的程式碼如下。
<img height="100%" width="100%" src="https://i.imgur.com/uvscOWC.png" style="display: block; margin-left: auto; margin-right: auto;"/>
<div style="text-align:center">將靜電力、電位能與距離的關係圖並列於同一張圖中</div>
<br></br>
```python=
"""
靜電力、電位能對距離的關係圖, 兩圖並列
日期: 2018/11/18
作者: 王一哲
"""
import numpy as np # 引入科學計算函式庫
import matplotlib.pyplot as plt # 引入繪圖函式庫
xmin, xmax, num = 0.01, 10, 100 # 設定繪圖範圍、取點數
x = np.linspace(xmin, xmax, num) # 產生x
Q, q, k = 1E-4, 1E-4, 8.988E9 # 點電荷電量及靜電力常數
F = k * Q * q / x**2 # 靜電力F
U = k * Q * q / x # 電位能U
# 建立繪圖物件 fig, 大小為 12 * 4.5, 內有 1 列 2 欄的小圖, 兩圖共用 x 軸和 y 軸
fig, (ax1, ax2) = plt.subplots(1, 2, sharex = True, sharey = True, figsize = (12, 4.5))
# 設定小圖 ax1 的坐標軸標籤, 格線顏色、種類、寬度, y軸繪圖範圍, 最後用 plot 繪圖
ax1.set_xlabel('r (m)', fontsize = 16)
ax1.set_ylabel('F (N)', fontsize = 16)
ax1.grid(color = 'red', linestyle = '--', linewidth = 1)
ax1.set_ylim(0, 200)
ax1.plot(x, F, color = 'blue', linewidth = 3)
# 設定小圖 ax2 的坐標軸標籤, 格線顏色、種類、寬度, 最後用 plot 繪圖
ax2.set_xlabel('r (m)', fontsize = 16)
ax2.set_ylabel('U (J)', fontsize = 16)
ax2.grid(color = 'red', linestyle = '--', linewidth = 1)
ax2.plot(x, U, color = 'blue', linewidth = 3)
# 用 savefig 儲存圖片, 用 show 顯示圖片
fig.savefig('Fe_r_plot_2.svg')
fig.savefig('Fe_r_plot_2.png')
fig.show()
```
<br></br>
以下說明程式碼中較特別的部分
1. 使用 **fig, (ax1, ax2) = plt.subplots(1, 2, sharex = True, sharey = True, figsize = (12, 4.5))** 建立多張圖的繪圖物件,其中
a. **1, 2** 代表物件中有 1 列 2 欄的小圖
b. **sharex = True** 代表共用 x 軸坐標
c. **sharey = True** 代表共用 y 軸坐標
d. **figsize = (12, 4.5)** 將物件尺寸設定為 12 吋乘以 4.5 吋。
e. 整個繪圖物件指定給 fig
f. 兩張小圖分別指定給 ax1 和 ax2
2. 使用 **ax1.set_xlabel** 設定ax1 的 x 坐標軸標籤,使用 **ax1.set_ylabel** 設定ax1 的 y 坐標軸標籤 ,使用 **ax1.set_ylim(0, 200)** 設定y軸繪圖範圍為 1 到 200。
3. ax2 的設定方法與 ax1 相似,但是我們已經設定兩共用 y 軸格式,不需要再設定 ax2.set_ylim(0, 200)。
<br></br>
## 結語
這是一些使用 Matplotlib 繪圖的筆記,如果想要看更多的繪圖實例,請參考 https://python-graph-gallery.com/
<br></br>
---
###### tags:`Physics`、`Python`