# Python 學習筆記 : Matplotlib 資料視覺化 (一) 基本篇
更多 Python 筆記參考 :
# Python 學習筆記索引
pyplot 子套件除 plot() 外之統計圖繪製函數如下表 :
pyplot 統計圖函數 | 說明 |
bar(x, y, [options]) | 依據 x, y 軸資料繪製長條圖或柱狀圖 (bar chart) |
hist(data, [options]) | 依據 data 資料繪製直方圖 (histogram) |
pie(data, [options]) | 依據 data 資料繪製圓餅圖 (pie chart) |
scatter(x, y, [options] | 依據 x, y 軸資料繪製散佈圖 (scatter chart) |
boxplot(data, [options]) | 依據 data 資料繪製箱型圖或盒鬚圖 (box chart) |
Matplotlib 還可以繪製更多統計圖, 參考 :
# https://matplotlib.org/stable/gallery/ (Matplotlib 畫廊)
長條圖 (bar chart) 主要用來呈現定性資料 (qualitative) 之分布情形 (亦即其統計變數為類別變數 categorical), 有垂直與水平兩種型態.
1. 垂直長條圖 (bar chart) :
垂直長條圖函數 bar() 介面如下 :
bar(x, height [kwargs]*)
其中 x 是代表長條圖 X 軸座標位置的序列物件 (例如 tuple, list, 或 ndarray 陣列等), kwargs 為選擇性參數, 常用的參數如下表 :
bar() 常用參數 | 說明 |
color | 顏色 ('blue', '#0000ff', 或 0~1 數值), 預設藍色 'blue' |
edgecolor | 長條邊框顏色 |
width | 長條寬度 (0~1 數值), 預設 0.8 |
align | X 軸對齊方式 ('center', 'edge'), 預設 'center' |
label | 圖例文字 (字串), 預設 None |
tick_label | 刻度標籤 (序列物件), 預設 None |
bottom | Y 軸基底座標, 預設 0 |
log | Y 軸是否為對數刻度 (True/False), 預設 False |
linewidth | 長條邊框寬度 (px), 預設 0 (無邊框) |
參考 :
# https://matplotlib.org/3.2.1/api/_as_gen/matplotlib.pyplot.bar.html
下面範例以直條圖顯示 2020 總統大選得票數統計結果, X 軸變數為類別變數而非數值變數 :
範例 1-1 : 2020 總統大選得票數長條圖 (1) [原始碼]
import numpy as np
import matplotlib.pyplot as plt
votes=[608590, 5522119, 8170231] #2020總統大選得票數
candidates=['James Soong', 'Korea Fish', 'Tsai Ing-Wen'] #X軸刻度
x=np.arange(len(candidates)) #產生X軸座標序列
plt.bar(x, votes, tick_label=candidates) #繪製長條圖
plt.title('2020 Presidential Election') #設定圖形標題
plt.xlabel('Candidates') #設定X軸標籤
plt.ylabel('Votes(million)') #設定Y軸標籤
plt.show()
此例以 np.arange() 動態產生 [0, 1, 2, 3 ... N-1] 序列傳入 bar() 當作 X 軸座標, 雖然 X 軸是 [0,1, 2]的序列數值, 但那其實是代表候選人的類別變數而已, 此處用 tick_label 參數將 X 軸座標刻度設定為候選人, 否則預設會顯示序列數值 0, 1, 2 ... 等, 結果如下 :
由於數字最大為百萬, 所以 Y 軸刻度自動以百萬 (1e6) 為單位, 但刻度標籤 1, 2, 3, 4, ... 似乎無法直接感受到那是百萬票, 應該改標成 100, 200, 300,.... 較好. 事實上用 pyplot 的 xticks() 與 yticks() 來設定刻度標籤更有彈性, 例如下面的範例 :
範例 1-2 : 2020 總統大選得票數長條圖 (2) [原始碼]
import numpy as np
import matplotlib.pyplot as plt
votes=[608590, 5522119, 8170231] #2020總統大選得票數
candidates=['James Soong', 'Korean Fish', 'Tsai Ing-Wen'] #X 軸刻度
x=np.arange(len(candidates)) #產生 X 軸座標序列
y=np.arange(0, 9000000, 1000000) #產生 Y 軸座標序列
plt.bar(x, votes) #繪製長條圖
plt.xticks(x, candidates) #設定 X 軸刻度標籤
y_ticks=np.arange(0,900,100) #Y軸刻度陣列
plt.yticks(y, y_ticks) #設定 Y 軸刻度標籤
plt.title('2020 Presidential Election') #設定圖形標題
plt.xlabel('Candidates') #設定 X 軸標籤
plt.ylabel('Votes(million)') #設定 Y 軸標籤
plt.show()
此例以 np.arange(0, 9000000, 1000000) 產生間隔為 100 百萬的數字陣列當做 Y 軸座標之刻度序列, 以 np.arange(0, 900, 100) 產生間隔為 100 的數字陣列當作 Y 軸座標之刻度標籤, 呼叫 plt.yticks(y, y_ticks) 就可以將其對應起來, 結果如下 :
Y 軸刻度標籤經過這樣調整後就比較容易了解了. 下面範例測試選擇性參數 :
範例 1-3 : 2020 總統大選得票數長條圖 (3) [原始碼]
import numpy as np
import matplotlib.pyplot as plt
votes=[608590, 5522119, 8170231] #2020總統大選得票數
candidates=['James Soong', 'Korean Fish', 'Tsai Ing-Wen'] #X 軸刻度
x=np.arange(len(candidates)) #產生 X 軸座標序列
y=np.arange(0, 9000000, 1000000) #產生 Y 軸座標序列
plt.bar(x, votes,
color='cyan',
edgecolor='#0000ff',
width=0.5,
linewidth=2
) #繪製長條圖
plt.xticks(x, candidates) #設定 X 軸刻度標籤
y_ticks=np.arange(0,900,100) #Y軸刻度陣列
plt.yticks(y, y_ticks) #設定 Y 軸刻度標籤
plt.title('2020 Presidential Election') #設定圖形標題
plt.xlabel('Candidates') #設定 X 軸標籤
plt.ylabel('Votes(million)') #設定 Y 軸標籤
plt.show()
此例將長條寬度減為 0.5, 長條顏色設為青色, 框邊寬度設為 2px, 框邊顏色設為藍色, 結果如下 :
長條圖也可以顯示多組資料 (group bar chart), 不過需要將每個長條的寬度變小才能容納多組數據, 例如改為 0.25, 還要將第二組以後的 X 軸座標位置以及 X 軸刻度位置往後移位, 確保刻度是標在各組長條的中間位置, 參考 :
# Group Bar Plot In MatPlotLib
# https://python-graph-gallery.com/11-grouped-barplot/
下面是繪製兩組資料的長條圖範例 :
範例 1-4 : 兩組資料之長條圖 : ETF 殖利率比較 [原始碼]
import numpy as np
import matplotlib.pyplot as plt
width=0.25
x1=[2015, 2016, 2017, 2018, 2019] #X 軸 (第一組)
y1=(4.33, 5.67, 3.78, 5.62, 6.7) #Y 軸1=0056殖利率
x2=[p + width for p in x1] #X 軸 (第二組)
y2=(3.01, 1.28, 6.1, 7.1, 7.22) #Y 軸2=0050殖利率
plt.bar(x1, y1, label='0056', width=0.25) #繪製長條圖
plt.bar(x2, y2, label='0050', width=0.25) #繪製長條圖
plt.xticks([p + width/2 for p in x1], x1) #設定 X 軸刻度標籤
plt.legend() #顯示圖例
plt.title('ETF Dividend Yield') #設定圖形標題
plt.xlabel('Year') #設定 X 軸標籤
plt.ylabel('Dividend yield(NT$)') #設定 Y 軸標籤
plt.show()
此例將每個常條寬度縮小為 0.25 (預設寬度的 1/4), 第二組資料的 X 軸座標位置 x2 需全部往右移一個長條的寬度, 此處用串列生成式產生. 另外 X 軸刻度也必須往右移, 由於刻度在一組資料時是標在長條的中央, 因此顯示兩組資料的話, 刻度要標在兩個長條中間, 因此刻度應該右移半個長條寬度 (即加上 width/2), 結果如下 :
可見 Matplotlib 會自動幫各組資料指定長條的顏色, 若要自訂可以透過 color 參數去設定.
如果要顯示三組資料, 則需 X 軸座標刻度位置需右移一個長條寬度, 如下範例所示 :
範例 1-5 : 三組資料之長條圖 : ETF 殖利率比較 [原始碼]
import numpy as np
import matplotlib.pyplot as plt
width=0.25
x1=[2015, 2016, 2017, 2018, 2019] #X 軸 (第一組)
y1=(4.33, 5.67, 3.78, 5.62, 6.7) #Y 軸1=0056殖利率
x2=[p + width for p in x1] #X 軸 (第二組)
y2=(3.01, 1.28, 6.1, 7.1, 7.22) #Y 軸2=0050殖利率
x3=[p + 2*width for p in x1] #X 軸 (第三組)
y3=(0, 2.44, 1.41, 1.72, 1.05) #Y 軸3=0052殖利率
plt.bar(x1, y1, label='0056', width=0.25) #繪製長條圖
plt.bar(x2, y2, label='0050', width=0.25) #繪製長條圖
plt.bar(x3, y3, label='0052', width=0.25) #繪製長條圖
plt.xticks([p + width for p in x1], x1) #設定 X 軸刻度標籤
plt.legend() #顯示圖例
plt.title('ETF Dividend Yield') #設定圖形標題
plt.xlabel('Year') #設定 X 軸標籤
plt.ylabel('Dividend yield(NT$)') #設定 Y 軸標籤
plt.show()
此例加入第三組資料 (0052 富邦科技 ETF), x3 座標位置要往右移兩個長條寬度 (width*2), 而 X 軸座標刻度則是右移一個長條寬度 (width), 結果如下 :
可見預設圖形在長條寬度為 0.25 情況下只能同時繪製 4 組資料, 如果要繪製 5 組資料, 長條寬度需設為 1/5=0.2 才裝得下. 不管要顯示幾組資料, X 軸座標刻度可依照下列通式計算要右移多少 :
xn=p + (n-1)*width/2
資料來源 :
# https://goodinfo.tw/StockInfo/StockDetail.asp?STOCK_ID=0052
2. 水平長條圖 (horizontal bar chart) :
水平長條圖函數介面如下 :
barh(y, width [kwargs]*)
水平長條圖與垂直長條圖的 x, y 與 width, height 互相對調, 此外參數用法都相同 :
barh() 常用參數 | 說明 |
color | 顏色 ('blue', '#0000ff', 或 0~1 數值), 預設藍色 'blue' |
edgecolor | 長條邊框顏色 |
height | 長條高度 (0~1 數值), 預設 0.8 |
align | X 軸對齊方式 ('center', 'edge'), 預設 'center' |
label | 圖例文字 (字串), 預設 None |
tick_label | 刻度標籤 (序列物件), 預設 None |
bottom | Y 軸基底座標, 預設 0 |
log | Y 軸是否為對數刻度 (True/False), 預設 False |
linewidth | 長條邊框寬度 (px), 預設 0 (無邊框) |
範例 2-1 : 一組資料之水平長條圖 : 2020 總統大選得票數 [原始碼]
import numpy as np
import matplotlib.pyplot as plt
votes=[608590, 5522119, 8170231] #2020總統大選得票數
candidates=['James Soong', 'Korean Fish', 'Tsai Ing-Wen'] #Y 軸刻度
y=np.arange(len(candidates)) #產生 Y 軸座標序列
x=np.arange(0, 9000000, 1000000) #產生 X 軸座標序列
plt.barh(y, votes) #繪製長條圖
plt.yticks(y, candidates) #設定 Y 軸刻度標籤
x_ticks=np.arange(0,900,100) #X 軸刻度陣列
plt.xticks(x, x_ticks) #設定 X 軸刻度標籤
plt.title('2020 Presidential Election') #設定圖形標題
plt.xlabel('Votes(million)') #設定 X 軸標籤
plt.ylabel('Candidates') #設定 Y 軸標籤
plt.show()
水平長條圖同樣可繪製多組資料, 但第二組後的 Y 軸座標位置, 以及 Y 軸座標刻度都必須往下移, 其位移通式如下 :
yn=p + (n-1)*height/2
範例 2-2 : 兩組資料之水平長條圖 : ETF 殖利率比較 [原始碼]
import numpy as np
import matplotlib.pyplot as plt
height=0.25
y1=[2015, 2016, 2017, 2018, 2019] #Y 軸 (第一組)
x1=(4.33, 5.67, 3.78, 5.62, 6.7) #X 軸1=0056殖利率
y2=[p + height for p in y1] #Y 軸 (第二組)
x2=(3.01, 1.28, 6.1, 7.1, 7.22) #X 軸2=0050殖利率
plt.barh(y1, x1, label='0056', height=0.25) #繪製長條圖
plt.barh(y2, x2, label='0050', height=0.25) #繪製長條圖
plt.yticks([p + height/2 for p in y1], y1) #設定 Y 軸刻度標籤
plt.legend() #顯示圖例
plt.title('ETF Dividend Yield') #設定圖形標題
plt.ylabel('Year') #設定 Y 軸標籤
plt.xlabel('Dividend yield(NT$)') #設定 X 軸標籤
plt.show()
此例事實上是將上面範例 1-4 中的 X, Y 軸變數對調, 並將 width 改成 height 兒得, 結果如下 :
三組資料的水平長條圖如下例所示 :
範例 2-3 : 兩組資料之水平長條圖 : ETF 殖利率比較 [原始碼]
import numpy as np
import matplotlib.pyplot as plt
height=0.25
y1=[2015, 2016, 2017, 2018, 2019] #Y 軸 (第一組)
x1=(4.33, 5.67, 3.78, 5.62, 6.7) #X 軸1=0056殖利率
y2=[p + height for p in y1] #Y 軸 (第二組)
x2=(3.01, 1.28, 6.1, 7.1, 7.22) #X 軸2=0050殖利率
y3=[p + 2*height for p in y1] #Y 軸 (第三組)
x3=(0, 2.44, 1.41, 1.72, 1.05) #X 軸3=0052殖利率
plt.barh(y1, x1, label='0056', height=0.25) #繪製長條圖
plt.barh(y2, x2, label='0050', height=0.25) #繪製長條圖
plt.barh(y3, x3, label='0052', height=0.25) #繪製長條圖
plt.yticks([p + height for p in y1], y1) #設定 Y 軸刻度標籤
plt.legend() #顯示圖例
plt.title('ETF Dividend Yield') #設定圖形標題
plt.ylabel('Year') #設定 Y 軸標籤
plt.xlabel('Dividend yield(NT$)') #設定 X 軸標籤
plt.show()
結果如下 :
可見經過 Y 軸刻度位移後, 刻度線都剛好位於各組資料的中間.
此外 barh() 也常被用來畫專案進度之甘特圖 (Gantt chart), 參考 :
# 實用程式碼Python(五)用Matplotlib畫甘特圖
# matplotlib 之甘特图
# Gantt Charts in Matplotlib
3. 直方圖 (histogram chart) :
直方圖會對資料進行次數分配統計, 通常用來呈現定量資料 (quantitative) 的分布情形, 可藉此觀察資料之偏態與峰度, 其函數介面如下 :
n, bins, patches=plt.hist(data [, bins=10] [, kwargs]*)
傳回值為一組 tuple, 第一個元素 n 為資料的次數分配表 (串列), 第二個元素 bins 為分布區間 (串列), 第三個參數 patches 是一個 Patch 物件 (串列), 其元素為 Rectangle 物件, 用來描繪直方圖中的每一個矩形長條. 參數 data 為序列資料 (串列/元組) 或陣列, bins 為資料分布區間數目 (或稱為組距, 預設為 10 個區間), kwargs 為關鍵字參數, 常用的參數如下表 :
hist() 常用參數 | 說明 |
bins | 分布區間數目 (整數), 預設 10 |
range | 分布區間數目範圍 (元組) : (min, max) |
color | 直方圖長條顏色, 例如 'blue' 或 '#0000ff' 等 |
edgecolor | 直方圖長條邊緣顏色, 例如 'blue' 或 '#0000ff' 等 |
histtype | 直方圖類型 : 'bar' (預設), 'barstacked', 'step', 'stepfilled' |
rwidth | 直方圖長條相對於區間之寬度 (0~1) |
linewidth | 長條邊框寬度 (px) |
edgecolor | 長條邊框顏色, 例如 'blue' 或 '#0000ff' 等 |
orientation | 方向, 'vertical' (預設) 或 'horizontal' |
align | 對齊方式, 'left', 'mid' (預設), 'right' |
label | 直方圖之圖例標籤 |
stacked | 多組資料時後一組是否疊到前一組織上 : True, False (預設) |
cumulative | 每個分布區間是否由小到大累計, True, False (預設) |
其實, 大部分的 plot() 的選擇性參數都可以用在 hist() 上, 參考 :
# https://matplotlib.org/3.2.1/api/_as_gen/matplotlib.pyplot.hist.html
範例 3-1 : 學生成績分布之直方圖 (1) [原始碼]
import numpy as np
import matplotlib.pyplot as plt
scores=[20, 75, 45, 68, 92, 34, 65, 29, 88, 31,
66, 94, 72, 55, 49, 59, 11, 85, 79, 84,
69, 83, 96, 45, 73, 85, 69, 86, 100, 9] #成績
bins_list=[0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100] #分布區域 (組距)
n, bins, patches=plt.hist(scores, bins=bins_list) #繪製直方圖
print(n) #輸出次數分配
print(bins) #輸出分布區間
for p in patches: #輸出 Patch 物件內容
print(p)
plt.title('Score Distribution') #設定圖形標題
plt.ylabel('Scores') #設定 Y 軸標籤
plt.xlabel('Students') #設定 X 軸標籤
plt.show()
此例之 scores 列舉了學生某科目成績, bins 則以串列列舉了各個組距, 結果如下 :
print() 輸出結果 :
[1. 1. 2. 2. 3. 2. 5. 4. 6. 4.]
[ 0 10 20 30 40 50 60 70 80 90 100]
Rectangle(xy=(0, 0), width=10, height=1, angle=0)
Rectangle(xy=(10, 0), width=10, height=1, angle=0)
Rectangle(xy=(20, 0), width=10, height=2, angle=0)
Rectangle(xy=(30, 0), width=10, height=2, angle=0)
Rectangle(xy=(40, 0), width=10, height=3, angle=0)
Rectangle(xy=(50, 0), width=10, height=2, angle=0)
Rectangle(xy=(60, 0), width=10, height=5, angle=0)
Rectangle(xy=(70, 0), width=10, height=4, angle=0)
Rectangle(xy=(80, 0), width=10, height=6, angle=0)
Rectangle(xy=(90, 0), width=10, height=4, angle=0)
可見分數在 80~90 這個組距人數為 6 人最多, 而分數在 0~20 分這組距有 2 人最少, 每個分布區間都是由個別的 Rectangle 物件所描繪, 例如次數分配由 height 屬性控制.
由上面範例可知, 直方圖預設為藍色. 長條無邊框, 這些都可以用選擇性參數設定, 例如 :
範例 3-2 : 學生成績分布之直方圖 (2) : 使用選擇性參數 [原始碼]
import numpy as np
import matplotlib.pyplot as plt
scores=[20, 75, 45, 68, 92, 34, 65, 29, 88, 31,
66, 94, 72, 55, 49, 59, 11, 85, 79, 84,
69, 83, 96, 45, 73, 85, 69, 86, 100, 9] #成績
bins_list=[0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100] #分布區域 (組距)
plt.hist(scores, bins=bins_list,
color='cyan',
linewidth=1,
edgecolor='black',
label='Students') #繪製直方圖
plt.legend() #加上圖例
plt.title('Score Distribution') #設定圖形標題
plt.xlabel('Scores') #設定 X 軸標籤
plt.ylabel('Students') #設定 Y 軸標籤
plt.xticks(bins_list) #設定 X 軸刻度
plt.show()
此例在呼叫 hist() 時傳入更多參數來調整直方圖, 其中 color 用來改變直條顏色, linewidth 用來設定直條的邊框寬度, 而 edgecolor 則用來設定邊框顏色, 最後用 xticks() 來調整刻度, 參考 :
# Python histogram outline
結果如下 :
可見 X 軸刻度顯示所有組距,比預設的每 20 一格更清楚了.
在上面我們已知 hist() 的傳回值是一個三元素的 tuple, 其中第三個傳回值 patches 是由代表直方圖中每個長條的 Rectangle 物件組成之串列, 這些 Rectangle 物件可搭配 plot.setp() 函數來設定特定直條的樣式, 例如顏色或邊框等以凸顯該組距, 參考 :
# What are n bins and patches in matplotlib?
pyplot.setp() 函數介面如下 :
pyplot.setp(obj, args [, kwargs]*)
其中 obj 為要設定屬性之物件, args 為參數, kwargs 為關鍵字參數, 參考 :
# https://matplotlib.org/3.2.1/api/_as_gen/matplotlib.pyplot.setp.html
要凸顯某些組距只要將 facecolor 屬性指定為特定顏色即可, 例如若要凸顯上面範例中人數最多 (80~90) 與最少 (0~20) 的組距可以這麼做 :
範例 3-3 : 學生成績分布之直方圖 (3) : 用 Rectangle 物件凸顯特定區間 [原始碼]
import numpy as np
import matplotlib.pyplot as plt
scores=[20, 75, 45, 68, 92, 34, 65, 29, 88, 31,
66, 94, 72, 55, 49, 59, 11, 85, 79, 84,
69, 83, 96, 45, 73, 85, 69, 86, 100, 9] #成績
bins_list=[0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100] #分布區域 (組距)
n, bins, patches=plt.hist(scores, bins=bins_list,
color='cyan',
linewidth=1,
edgecolor='black',
label='Students') #繪製直方圖
plt.setp(patches[0:2], facecolor='red') #設定物件屬性
plt.setp(patches[8], facecolor='yellow') #設定物件屬性
plt.legend() #加上圖例
plt.title('Score Distribution') #設定圖形標題
plt.xlabel('Scores') #設定 Y 軸標籤
plt.ylabel('Students') #設定 X 軸標籤
plt.xticks(bins_list) #設定 X 軸刻度
plt.show()
此例利用 setp() 函數將 hist() 傳回的 tuple 第三個元素 patches 中之 Rectangle 物件 [0], [1], 以及 [8] 的 facecolor 屬性改變, 這樣便能凸顯這三個直條的顏色. facecolor 屬性只改變直條內部的顏色, 不包括直條外框顏色. 如果改用 color 屬性則包含直條邊框顏色也會一起改變. 結果如下 :
可見透過設定 Rectangle 物件的 facecolor 屬性凸顯高標與低標區間使圖表可讀性更高.
4. 圓餅圖 (pie chart) :
圓餅圖是一種描述類別 (categorical) 資料的統計圖, 它將圓形分割成幾個扇形或切片 (slice), 以切片的面積大小來描述資料中各類別數據的相對比例, pyplot 的 pie() 函數可用來繪製圓餅圖, 其介面如下 :
pitches, texts, autotexts=plt.pie(data [, kwargs]*)
參數群包括一個必要參數 data 以及若干選擇性的關鍵字參數, 其中 data 為要繪製之序列資料 (元組, 串列, 或陣列), 每個元素在圓餅中所佔之比例為該元素值除以所有元素值總和. 此函數會會傳回三個串列 : patches 為每個扇形之物件, texts 為 Texts 物件; autotexts 為代表比例值之 Texts 物件. 常用的選擇性參數 kwargs 如下表 :
pie() 常用參數 | 說明 |
explode | 對應資料之 0~1 數值串列, 表示該扇形與圓形分離之程度. |
colors | 對應資料之顏色字串串列, 表示該扇形之顏色, 例如 'blue' |
labels | 對應資料之標籤字串串列, 表示該扇形之說明. |
autopct | 扇形所佔比例之顯示格式字串或可傳回格式字串之函數, 例如 '%1.1f%' |
pctdistance | 比例值距離圓心之顯示位置 (0~1 浮點數), 預設 0.6 |
shadow | 是否顯示扇形之陰影 (True/False), 預設 False |
startangle | 扇形繪圖起始度數 (浮點數), 預設 None 為自 X 軸起逆時鐘繪製 |
radius | 圓形半徑 (0~1 浮點數), 預設 1 |
counterclock | 是否為逆時鐘繪製 (True/False), 預設 True |
center | 設定圓心座標 (tuple), 預設 (0,0) |
frame | 是否在圓形四周顯示座標軸 (True/False), 預設 False |
rotatelabels | 是否旋轉扇形之標籤使其與扇形同角度 (True/False), 預設 False |
autopct 為以 % 字元開頭之顯示格式字串或是能傳回格式字串的函數, 格式主要是以小數點 '.' 與 'f' 字元規範浮點數的小數位數, 例如 '%.2f' 表示要顯示到小數點後兩位, 若要顯示 '%' 本身則要再用一個 '%' 跳脫, 例如 '%.2f%%' 會顯示例如 '28.45%'.
參考 :
# https://matplotlib.org/3.2.1/api/_as_gen/matplotlib.pyplot.pie.html
範例 4-1 : 資產配置 (1) : 預設圓餅圖 [原始碼]
import numpy as np
import matplotlib.pyplot as plt
data=[60, 20, 10, 5, 5] #資產配置比率 (%)
plt.pie(data) #繪製圓餅圖
plt.title('Asset Allocation') #設定圖形標題
plt.show()
此例的 data 以串列表示五類資產 (股票, 債券, 現金, 黃金, 不動產) 佔總資產之百分比, 不傳入任何選擇性參數時 matplotlib 會自動為各項資產配色, 結果如下 :
可見 pie(data) 會用自動以不同顏色顯示資料中各類別, 但預設的圓餅圖缺乏說明資訊, 例如切片的類別標籤與比例等, 事實上繪製一個基本的圓餅圖至少要有 data, labels, 與 autopct 這三個參數才算資訊充分, 例如 :
範例 4-2 : 資產配置 (2) : 圓餅圖設定 autopct 顯示比例值 [原始碼]
import numpy as np
import matplotlib.pyplot as plt
data=[600, 200, 100, 50, 50] #資產配置 (百萬元)
labels=['Stock', 'Bond', 'Cash', 'Gold', 'Real estate'] #資產標籤
plt.pie(data, labels=labels, autopct='%.2f%%') #繪製圓餅圖
plt.title('Asset Allocation') #設定圖形標題
plt.show()
此例傳入了與資料 data 對應的參數 labels 與 autopct, 這樣就會顯示每一個扇形切片的說明標籤以及所佔的百分比. 另外與上例不同的是此處 data 串列的元素不是百分比, 而是百萬元為單位的資產金額, pie() 函數會將所有元素加總後計算百分比再以 autopct 指定格式顯示 (預設是於距圓心 0.6 處), 結果如下 :
這樣圖表的描述功能就很充分了, 這是畫圓餅圖最基本的要求.
參數 autopct 也可以是一個可傳回格式字串的函數, 這樣就能自行控制要顯示的格式, 例如 :
範例 4-3 : 資產配置 (3) : 圓餅圖 autopct 呼叫閉包函數 [原始碼]
import numpy as np
import matplotlib.pyplot as plt
def myautopct(data):
def inner_myautopct(pct):
total=sum(data)
val=int(round(pct*total/100.0))
return '{p:.0f}% ({v:d})'.format(p=pct,v=val)
return inner_myautopct
data=[600, 200, 100, 50, 50] #資產配置 (百萬元)
labels=['Stock', 'Bond', 'Cash', 'Gold', 'Real estate'] #資產標籤
colors=['#1f77b4', 'yellow', 'green', 'red', 'cyan'] #資產顏色
plt.pie(data, labels=labels, autopct=myautopct(data),
colors=colors) #繪製圓餅圖
plt.title('Asset Allocation') #設定圖形標題
plt.show()
此例利用自訂函數 myautopct(), 它會傳回一個閉包 (closure) 函數 inner_myautopct(), 在此閉包中, 對每一個扇形, matplotlib 會傳入其百分比做為參數 pct, 從而可由總和與 pct 反推其值 val, 再用 format() 產生所要的特定字串, 參考 :
# How do I use matplotlib autopct?
# 如何使用 matplotlib autopct?
與上面範例另一個不同處是傳入 colors 串列來自定每個扇形切片的顏色, 結果如下 :
可見百分比後面多出了括弧中的金額 (百萬元).
參數 autopct 也可以傳入匿名函數 (lambda) 以便像上面範例一樣在函數中自訂輸出格式, 例如 :
範例 4-4 : 資產配置 (4) : 圓餅圖 autopct 呼叫 Lambda 函數 [原始碼]
import numpy as np
import matplotlib.pyplot as plt
data=[600, 200, 100, 50, 50] #資產配置 (百萬元)
labels=['Stock', 'Bond', 'Cash', 'Gold', 'Real estate'] #資產標籤
colors=['#1f77b4', 'yellow', 'green', 'red', 'cyan'] #資產顏色
plt.pie(data, labels=labels,
autopct=lambda p:f'{p:.0f}% ({p*sum(data)/100 :.0f})', #匿名]函數
colors=colors) #繪製圓餅圖
plt.title('Asset Allocation') #設定圖形標題
plt.show()
結果與上面範例完全一樣 :
接下來的範例測試 pie() 的其他常用參數, 例如想要特別凸顯某些類別時可傳入 explode 參數將這些類別從圓形中分離, 這參數是一個相對於 data 資料類別的 0~1 數值串列, 用來表示與圓形的分離程度, 0 表示不分離 (不凸顯), 而 1 表示分離程度最大. 其次 shadow 可設定是否要有陰影, 例如 :
範例 4-5 : 資產配置 (5) : 圓餅圖其它常用參數測試 [原始碼]
import numpy as np
import matplotlib.pyplot as plt
data=[600, 200, 100, 50, 50] #資產配置 (百萬元)
labels=['Stock', 'Bond', 'Cash', 'Gold', 'Real estate'] #資產標籤
colors=['#1f77b4', 'yellow', 'green', 'red', 'cyan'] #資產顏色
explode=[0, 0, 0.2, 0, 0] #凸顯 Cash (扇形分離 0.2)
plt.pie(data, labels=labels, #資料與標籤
autopct='%.0f%%', #百分比格式
colors=colors, #扇形顏色
startangle=180, #起始角度
shadow=True, #顯示陰影
explode=explode) #扇形分離設定
plt.title('Asset Allocation') #設定圖形標題
plt.show()
此例添加了三個常用參數 : startangle 用來指定 data 資料第一個類別 (此處為 Stock) 扇形之起始角度; shadow=True 開啟陰影顯示; explode 則設定將 Cash 類別以 0.2 比例從圓餅中分離以凸顯其重要性, 結果如下 :
可見整個圓餅圖有陰影效果, Cash 類別被分離出來, 且扇形從 180 度 (左方) 開始繪製.
5. 散佈圖 :
散佈圖在統計學中用來描述兩個量變數的相關性, 以自變數為 X 軸, 應變數為 Y 軸, 從散佈圖可看出這兩個變數是呈現正相關, 負相關, 或零相關. pyplot 的 scatter() 函數可用來繪製散佈圖, 其介面如下 :
plt.scatter(x, y [, kwargs]*)
其中 x 為應變數 (X 軸), y 為自變數 (Y 軸), 常用關鍵字參數如下表 :
scatter() 常用參數 | 說明 |
marker | 資料點標記符號字元, 例如 'o' 為圓點, 's' 為方點 |
c 或 color | 資料點的顏色 (字串, 元組或陣列), 例如 'blue', '#0000ff' 或 (0, 1, 0) 等 |
s | 資料點的大小 (浮點數, 預設 20) |
alpha | 資料點的透明度, 0 (透明)~1 (不透明) |
cmap | 當 c 參數為陣列時所使用之顏色映射表名稱 (字串), 例如 'hsv' |
linewidths | 資料點邊框寬度 (預設 1.5) |
edgecolors | 資料點邊框顏色 (字串或序列), 預設 'face', 無顏色用 'none' |
參考 :
# https://matplotlib.org/3.2.1/api/_as_gen/matplotlib.pyplot.scatter.html
其中 cmap 參數是顏色映射表名稱, 用於搭配顏色參數 c 為陣列時顯示顏色變遷方式Matplotlib 定義了 7 種顏色映射表 :
顏色映射表分類 | 映射表名稱 |
Perceptually Uniform Sequential | 'viridis', 'plasma', 'inferno', 'magma', 'cividis' |
Sequential | 'Greys', 'Purples', 'Blues', 'Greens', 'Oranges', 'Reds', 'YlOrBr', 'YlOrRd', 'OrRd', 'PuRd', 'RdPu', 'BuPu', 'GnBu', 'PuBu', 'YlGnBu', 'PuBuGn', 'BuGn', 'YlGn' |
Sequential (2) | 'binary', 'gist_yarg', 'gist_gray', 'gray', 'bone', 'pink', 'spring', 'summer', 'autumn', 'winter', 'cool', 'Wistia', 'hot', 'afmhot', 'gist_heat', 'copper' |
Diverging | 'PiYG', 'PRGn', 'BrBG', 'PuOr', 'RdGy', 'RdBu', 'RdYlBu', 'RdYlGn', 'Spectral', 'coolwarm', 'bwr', 'seismic' |
Cyclic | 'twilight', 'twilight_shifted', 'hsv' |
Qualitative | 'Pastel1', 'Pastel2', 'Paired', 'Accent', 'Dark2', 'Set1', 'Set2', 'Set3', 'tab10', 'tab20', 'tab20b', 'tab20c' |
Miscellaneous | 'flag', 'prism', 'ocean', 'gist_earth', 'terrain', 'gist_stern', 'gnuplot', 'gnuplot2', 'CMRmap', 'cubehelix', 'brg', 'gist_rainbow', 'rainbow', 'jet', 'nipy_spectral', 'gist_ncar' |
參考 :
# https://matplotlib.org/3.2.1/gallery/color/colormap_reference.html
範例 5-1 : 體重與身高關聯性散佈圖 [原始碼]
import numpy as np
import matplotlib.pyplot as plt
weight=[49, 65, 53, 45, 56, 47, 52, 61] #X軸:體重
height=[159, 177, 156, 163, 164, 158, 166, 171] #Y軸:身高
plt.scatter(weight, height) #繪製散佈圖
plt.title('Relationship of Weight vs Height') #設定圖形標題
plt.xlabel('Weight(Kg)') #設定X軸標籤
plt.ylabel('Height(Cm)') #設定Y軸標籤
plt.show()
此例以體重 weight 為 X 軸, 以身高 height 為 Y 軸, 繪製散佈圖觀察兩個變數的關係, 結果如下 :
此有限的資料顯示體重與身高似乎呈現正相關, 即身高越高的人也越重. 其實 plot() 函數也可以繪製散佈圖, 只要資料點標記符號傳入 'o' 即可, 例如 :
範例 5-2 : 使用 plot() 繪製散佈圖 [原始碼]
import numpy as np
import matplotlib.pyplot as plt
weight=[49, 65, 53, 45, 56, 47, 52, 61] #X軸:體重
height=[159, 177, 156, 163, 164, 158, 166, 171] #Y軸:身高
plt.plot(weight, height, 'o') #繪製散佈圖
plt.title('Relationship of Weight vs Height') #設定圖形標題
plt.xlabel('Weight(Kg)') #設定X軸標籤
plt.ylabel('Height(Cm)') #設定Y軸標籤
plt.show()
此例使用 plot() 繪製散佈圖, 傳入 'o' 表示以圓點作為資料點符號, 結果與上面 5-1 的完全一樣 :
雖然 plot() 與 scatter() 都能繪製散佈圖, 但在數據量很多時使用 plot() 繪圖效率會比 scatter() 好, 這是因為 scatter() 對於每個資料點的大小與顏色都是單獨繪製的 (所以可控制各別資料點之顏色與大小), 需要花較多時間處理; 反觀 plot() 的資料點的外觀處理只要做一次, 其他資料點的外觀屬性都是複製而來的, 因此繪製速度較快.
如果要在同一張圖上繪製多組散佈圖, 可以呼叫多次 scatter(), 下面範例以線性與平方函數產生的點繪製散佈圖, 主要是測試 color 與 marker 參數 :
範例 5-3 : 繪製函數散佈圖 (10 個資料點) [原始碼]
import numpy as np
import matplotlib.pyplot as plt
x=np.linspace(0, 100, 10) #X軸:體重
y1=[100*x for x in x] #Y軸1:y1=2x
y2=[x**2 for x in x] #Y軸2:y2=2x
plt.scatter(x, y1,
color='red',
marker='s',
label='100*x') #繪製散佈圖1
plt.scatter(x, y2,
color='blue',
marker='o',
label='x**2') #繪製散佈圖2
plt.legend() #顯示圖例
plt.title('Linear & Square functions') #設定圖形標題
plt.xlabel('X') #設定X軸標籤
plt.ylabel('Y') #設定Y軸標籤
plt.show()
此例用 Numpy 的 linspace() 函數產生X 軸自變數串列, 在 0~100 區間中每 10 個取一點即得串列 [1, 10, 20, ... 100]; 而 Y 軸則有兩個函數, 一是線性函數 y=100*x, 另一個是平方函數 y=x**2, 結果如下 :
可見線性與平方函數分別用紅藍色散佈圖繪製, 各有 10 個資料點. 當資料點增加時, 這些點會連成一線變成類似折線圖效果, 例如將上面範例的 10 個資料點改成 100 個資料點如下 :
範例 5-4 : 繪製函數散佈圖 (100 個資料點) [原始碼]
import numpy as np
import matplotlib.pyplot as plt
x=np.linspace(0, 100, 100) #X軸
y1=[100*x for x in x] #Y軸1:y1=100*x
y2=[x**2 for x in x] #Y軸1:y2=x**2
plt.scatter(x, y1,
color='red',
marker='s',
label='100*x') #繪製散佈圖1
plt.scatter(x, y2,
color='blue',
marker='o',
label='x**2') #繪製散佈圖2
plt.legend() #顯示圖例
plt.title('Linear & Square functions') #設定圖形標題
plt.xlabel('X') #設定X軸標籤
plt.ylabel('Y') #設定Y軸標籤
plt.show()
此例僅僅是將 linspace() 的資料點改為 100 而已, 結果如下 :
下面的範例使用亂數來繪製散佈圖, 主要是測試參數 s, cmap, 以及 alpha :
範例 5-5 : 繪製函數散佈圖 (隨機函數) [原始碼]
import numpy as np
import matplotlib.pyplot as plt
rng=np.random.RandomState(0) #偽隨機數生成器
x=rng.randn(100) #X軸:100個隨機數
y=rng.randn(100) #Y軸:100個隨機數
colors=rng.rand(100) #顏色:100個隨機數
sizes=1000*rng.rand(100) #資料點大小
plt.scatter(x, y,
c=colors,
s=sizes,
alpha=0.3,
cmap='hsv') #繪製散佈圖
plt.colorbar() #顯示顏色刻度
plt.show()
此例呼叫 Numpy 的隨機數生成器函數 random.RandomState(0) 傳回一個 RandomState 物件 rng, 再呼叫 randn() 與 rand() 產生隨機數, randn(100) 會傳回 100 個平均 (高斯) 分布的隨機數, 可正可負; 而方法 rand(100) 則是傳回 100 個 [0, 1) 之間的常態分佈隨機數. 呼叫 colorbar() 會在 Y 軸右邊顯示顏色刻度, 參考 :
# numpy.random.RandomState
# https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.pyplot.colorbar.html
結果如下 :
範例 5-6 : 繪製函數散佈圖 (隨機函數) [原始碼]
import numpy as np
import matplotlib.pyplot as plt
x=np.linspace(0, 10, 100) #X軸
y=[x**2 for x in x] #Y軸1:y=x**2
line_width=(1+x)**2 #資料點寬度
plt.scatter(x, y,
s=line_width, #資料點寬度
color='blue',
marker='o',
label='x**2') #繪製散佈圖
plt.legend() #顯示圖例
plt.title('Square Fuction Line Width Test') #設定圖形標題
plt.xlabel('X') #設定X軸標籤
plt.ylabel('Y') #設定Y軸標籤
plt.show()
此例設定了一個隨 x 變大的資料點寬度 line_width 傳給參數 s, 結果如下 :
可見隨著 x 變大, 資料點大小也變粗了. 下面範例測試顏色映射表 cmap 用法 :
範例 5-7 : 繪製函數散佈圖 (顏色映射表) [原始碼]
import numpy as np
import matplotlib.pyplot as plt
x=np.linspace(0, 100, 500) #X軸
y1=x #Y軸1:y=x
y2=x+10 #Y軸2:y=x+10
y3=x+20 #Y軸3:y=x+20
y4=x-10 #Y軸4:y=x-10
y5=x-20 #Y軸5:y=x-20
plt.scatter(x, y1, c=x, cmap='rainbow') #繪製散佈圖
plt.scatter(x, y2, c=x, cmap='twilight') #繪製散佈圖
plt.scatter(x, y3, c=x, cmap='hsv') #繪製散佈圖
plt.scatter(x, y4, c=x, cmap='seismic') #繪製散佈圖
plt.scatter(x, y5, c=x, cmap='ocean') #繪製散佈圖
plt.title('Cmap Test') #設定圖形標題
plt.xlabel('X') #設定X軸標籤
plt.ylabel('Y') #設定Y軸標籤
plt.show()
此例指定顏色參數 c (color) 隨 x 而變, 對不同函數指定不同之 cmap 之結果如下 :
注意, cmap 需與變動的 color 參數一起使用才會顯現顏色變遷的效果.
6. 箱型圖 :
箱型圖 (box plot) 又稱為盒鬚圖 (notched box), 用來呈現數據的四分位距統計資訊, 可看出一個統計變數的集中趨勢, 最大與最小值, 變異與偏態等分布特徵.
pyplot 的 boxplot() 函數可用來繪製箱型圖, 其介面如下 :
plt.boxplot(x, notch=False, labels=None [, kwargs]*)
其中 x 為要繪製之資料, 可以是陣列或序列等. 參數 notch 用來指定要繪製箱型圖 (box) 或盒鬚圖 (notched box), 預設是箱型圖, 參數 labels 為字串序列, 用來指定每個箱型的標籤.
範例 6-1 : 繪製箱型圖 [原始碼]
# Creating boxplots with Matplotlib
~進行中~
# Creating boxplots with Matplotlib
參考 :
# [Day20]Matplotlib資料視覺化進階!
# Better visualization of Pie charts by MatPlotLib
# Matplotlib可视化最有价值的50个图表
# [Day17]Numpy的數學&統計方法!
沒有留言 :
張貼留言