1. 程式人生 > >半小時學完視覺化利器Matplotlib

半小時學完視覺化利器Matplotlib

學ML那麼常用工具庫Numpy,Pandas,Matplotlib和Scipe等肯定是要用到的,磨刀不誤砍柴工,所以先學一些是有必要的,這裡先學習下Matplotlib,由於是程式碼+圖的學習,所以半小時是夠的。
Matplotlib是資料科學領域流行的Python底層繪相簿,主要做資料視覺化圖表,看名字感覺就很像Matlab,所以你用過Matlab畫圖的話那麼使用Matplotlib就會很熟練。

文章首先會介紹怎樣簡陋的折線圖,然後一步步完善。最後會畫直方圖,條形圖,散點圖。關於更多圖的畫法去看官方文件更多圖

1、首先來畫個一天的氣溫隨時間的變化圖,時間間隔是2小時。

from matplotlib import pyplot as plt  #導包
x = range(2,26,2) #橫座標,時間間隔兩小時
y = [15,13,14,17,20,25,26,26,24,22,19,15]  #溫度
plt.plot(x,y)  #畫折線圖,注意x和y的元素個數必須相同
plt.show()  #展示

效果如下

現在我們來完善這個圖。

  1. 圖片有點小
  2. 缺少描述資訊,比如橫縱座標,圖的意義
  3. 橫縱軸間距過大(圖中是系統給我們自動調整的)
  4. 線條的樣式,比如顏色和透明度
  5. 將圖片儲存
from matplotlib import pyplot as plt  #導包
#設定圖片寬高,畫素     注意:要放在開頭
plt.figure(figsize=(20,8),dpi=80)

x = range(2,26,2)#橫座標,時間間隔兩小時
y = [15,13,14,17,20,25,26,26,24,22,19,15]  #溫度
plt.plot(x,y)  #畫折線圖,注意x和y的元素個數必須相同 


_tick_lable = [i/2 for i in range(4,49)]
plt.xticks(_tick_lable)
# plt.xticks(x)
plt.yticks(range(min(y),max(y)+1))#max(y)是取不到的所以+1
  
plt.savefig("./t1.png") #儲存圖片
 
plt.show()  #展示

效果展示

在這裡插入圖片描述

上面的5個問題解決了3個。

再看一個例子:如果列表a表示10點到12點的每一分鐘的氣溫,如何繪製折線圖觀察每分鐘氣溫的變化情況?

from matplotlib import pyplot as plt
import random

#解決中文顯示問題,mat是不顯示中文的
plt.rcParams['font.sans-serif']=['SimHei'] #用來正常顯示中文標籤
plt.rcParams['axes.unicode_minus']=False #用來正常顯示負號

#1、準備資料
x = list(range(0,120))  #轉list是為了後面取步長
y = [random.randint(18,33) for i in range(120)]

#2、設定大小並繪圖
plt.figure(figsize=(20,8),dpi=80)
plt.plot(x,y)

#3、設定x刻度與表示    我們要顯示的是幾點幾分而不是數字
_x_labels = ["10點{}分".format(i) for i in range(0,60)]
_x_labels += ["11點{}分".format(i) for i in range(0,60)]
#前面兩個會一一對應,也就是原本的數字會被字串幾點幾分給替換掉,rotation表示旋轉度數,如果不旋轉那麼會擠壓到一起,可以自己嘗試下
plt.xticks(x[::3],_x_labels[::3],rotation = 270)

#4、設定描述資訊x,y軸,已經圖形
plt.xlabel("時間  min")
plt.ylabel("溫度  單位(攝氏度)")
plt.title("10點到12點溫度隨時間變化圖")

#5、繪製網格,設定透明度
plt.grid(alpha = 0.3)

#6、展示
plt.show()

在這裡插入圖片描述

在這裡插入圖片描述

到這裡一個散點圖也就繪製的有模有樣了。有時候需要將兩個或者多個折線圖繪在一起,這樣可以更直觀的進行比較,怎麼做呢,其實很簡單,看下面例子。

現在假設要繪製你和你室友,11到30這20年來交往的女友數量,看誰xxx。

from matplotlib import pyplot as plt

#解決中文顯示問題,mat是不顯示中文的
plt.rcParams['font.sans-serif']=['SimHei'] #用來正常顯示中文標籤
plt.rcParams['axes.unicode_minus']=False #用來正常顯示負號

#1、準備資料,y_1是你,y_2是你室友
x=range(11,31)
y_1 = [1,0,1,1,2,4,3,2,3,4,4,5,6,5,4,3,3,1,1,1]
y_2 = [1,0,3,1,2,2,3,3,2,1 ,2,1,1,1,1,1,1,1,1,1]

#2、設定圖片大小並繪圖
plt.figure(figsize=(20,8),dpi=80)
plt.plot(x,y_1)
plt.plot(x,y_2)  #注意這裡

#3、設定x,y軸刻度
_x_labels = ["{}歲".format(i) for i in range(11,31)]
_y_labels = range(0,9)
plt.xticks(x,_x_labels)
plt.yticks(_y_labels)

#4、設定描述資訊x,y軸,以及圖形
plt.xlabel("年齡")
plt.ylabel("女友數量")
plt.title("女友數量隨時間變化圖")

#5、繪製網格,設定透明度
plt.grid(alpha = 0.3)

#6、展示
plt.show()

看效果圖
在這裡插入圖片描述

在這裡插入圖片描述

注意上面的程式碼,除了多了個y_2資料外,也就多了個繪圖程式碼plt.plot(x,y_2)。

補充:線條顏色是mat自動幫我們決定的,但是我們也可以自己決定。另外別人根本不知道那條線是你的哪條是你室友的,所以需要標註,最後線條的形狀也可以自己決定。如何改,下面已經標註了。

在這裡插入圖片描述

在這裡插入圖片描述

到這裡,折線圖就完全繪製完了,那麼下面繪製的散點圖,直方圖,條形圖的例子就很簡單了。其他圖的繪製連結已經在上面給出了。

2、繪製散點圖,主要在於繪圖方法不同,使用plt.scatter(x,y),下面會將兩組資料繪製在一起。

先還是畫個簡陋的,然後來調整

from matplotlib import pyplot as plt
#解決中文顯示問題,mat是不顯示中文的
plt.rcParams['font.sans-serif']=['SimHei'] #用來正常顯示中文標籤
plt.rcParams['axes.unicode_minus']=False #用來正常顯示負號

x_3 = range(1,32)
x_10 = range(41,72) #給10間隔是為了不會連在一起
y_3 = [11,17,16,11,12,11,12,6,6,7,8,9,12,15,14,17,18,21,16,17,20,14,15,15,15,19,21,22,22,22,23]
y_10 = [26,26,28,19,21,17,16,19,18,20,20,19,22,23,17,20,21,20,22,15,11,15,5,13,17,10,11,13,12,13,6]

#注意:跟折線圖區別就是這裡
plt.scatter(x_3,y_3,label = "3月份",color = "r")
plt.scatter(x_10,y_10,label = "10月分",color = "y")

plt.legend(loc = "upper left")

plt.show()


來看效果圖

在這裡插入圖片描述

發現還是挺好看的,但是橫縱並不是我們想要的,下面進行調整並展示

from matplotlib import pyplot as plt
#解決中文顯示問題,mat是不顯示中文的
plt.rcParams['font.sans-serif']=['SimHei'] #用來正常顯示中文標籤
plt.rcParams['axes.unicode_minus']=False #用來正常顯示負號

x_3 = range(1,32)
x_10 = range(41,72) #給10間隔是為了不會連在一起
y_3 = [11,17,16,11,12,11,12,6,6,7,8,9,12,15,14,17,18,21,16,17,20,14,15,15,15,19,21,22,22,22,23]
y_10 = [26,26,28,19,21,17,16,19,18,20,20,19,22,23,17,20,21,20,22,15,11,15,5,13,17,10,11,13,12,13,6]

plt.figure(figsize=(20,8),dpi=100)

plt.scatter(x_3,y_3,label = "3月份",color = "r")
plt.scatter(x_10,y_10,label = "10月分",color = "y")

_x = list(x_3) + list(x_10)
_x_labels = ["3月{}日".format(i) for i in x_3]
_x_labels += ["10月{}日".format(i-40) for i in x_10]

plt.xticks(_x[::3],_x_labels[::3],rotation=45)


plt.xlabel("月份")
plt.ylabel("溫度  單位(攝氏度)")
plt.title("3,10月溫度隨時間變化圖")

plt.legend(loc = "upper left")

plt.show()


在這裡插入圖片描述

在這裡插入圖片描述

到這裡就畫完了散點圖了,以後聚類會用到的,接下來畫條形圖。

3、條形圖示例

假設你獲取到了2017年內地電影票房前20的電影(列表a)和電影票房資料(列表b),那麼如何更加直觀的展示該資料?

a = [“戰狼2”,“速度與激情8”,“功夫瑜伽”,“西遊伏妖篇”,“變形金剛5:最後的騎士”,“摔跤吧!爸爸”,“加勒比海盜5:死無對證”,“金剛:骷髏島”,“極限特工:終極迴歸”,“生化危機6:終章”,“乘風破浪”,“神偷奶爸3”,“智取威虎山”,“大鬧天竺”,“金剛狼3:殊死一戰”,“蜘蛛俠:英雄歸來”,“悟空傳”,“銀河護衛隊2”,“情聖”,“新木乃伊”,]

b=[56.01,26.94,17.53,16.49,15.45,12.96,11.8,11.61,11.28,11.12,10.49,10.3,8.75,7.55,7.32,6.99,6.88,6.86,6.58,6.23] 單位:億

照舊,先畫個簡陋的,跟折線圖比,同樣也只是畫圖方法不同plt.bar

from matplotlib import pyplot as plt
#解決中文顯示問題,mat是不顯示中文的
plt.rcParams['font.sans-serif']=['SimHei'] #用來正常顯示中文標籤
plt.rcParams['axes.unicode_minus']=False #用來正常顯示負號

a = ["戰狼2","速度與激情8","功夫瑜伽","西遊伏妖篇","變形金剛5:最後的騎士","摔跤吧!爸爸","加勒比海盜5:\n死無對證","金剛:骷髏島","極限特工:終極迴歸","生化危機6:終章","乘風破浪","神偷奶爸3","智取威虎山","大鬧天竺","金剛狼3:殊死一戰","蜘蛛俠:英雄歸來","悟空傳","銀河護衛隊2","情聖","新木乃伊"]
b=[56.01,26.94,17.53,16.49,15.45,12.96,11.8,11.61,11.28,11.12,10.49,10.3,8.75,7.55,7.32,6.99,6.88,6.86,6.58,6.23]
plt.figure(figsize=(20,8),dpi=100)

plt.bar(range(len(a)),b,width = 0.3)#可以直接寫成plt.bar(a,b),此時下面那句只需要旋轉90度即可。
#對應字元到x軸上,一定要旋轉90度,不然就擠到一起了
plt.xticks(range(len(a)),a,rotation = 90) 

plt.show()

來看效果圖
在這裡插入圖片描述

在這裡插入圖片描述

是不是看著有些彆扭,那麼橫過來吧,使用方法plt.barh()

在這裡插入圖片描述

在這裡插入圖片描述

實際上我們平常看到的都是多個條形圖放一起的,下面就來放到一起。

假設你知道了列表a中電影分別在2017-09-14(b_14), 2017-09-15(b_15), 2017-09-16(b_16)三天的票房,為了展示列表中電影本身的票房以及同其他電影的資料對比情況,應該如何更加直觀的呈現該資料?

a = [“猩球崛起3:終極之戰”,“敦刻爾克”,“蜘蛛俠:英雄歸來”,“戰狼2”]
b_16 = [15746,312,4497,319]
b_15 = [12357,156,2045,168]
b_14 = [2358,399,2358,362]

資料來源: http://www.cbooo.cn/movieday

from matplotlib import pyplot as plt
#解決中文顯示問題,mat是不顯示中文的
plt.rcParams['font.sans-serif']=['SimHei'] #用來正常顯示中文標籤
plt.rcParams['axes.unicode_minus']=False #用來正常顯示負號

a = ["猩球崛起3:終極之戰","敦刻爾克","蜘蛛俠:英雄歸來","戰狼2"]
b_14 = [2358,399,2358,362]
b_15 = [12357,156,2045,168]
b_16 = [15746,312,4497,319]

plt.figure(figsize=(20,8),dpi=100)

wid_bar = 0.2 #不要設定太大,否則就擠到一起了,甚至重疊
x_14 = range(len(a))
x_15 = [i + wid_bar for i in x_14]
x_16 = [i + wid_bar for i in x_15]

#注意:width必須為wid_bar,否則會發生重疊,上面的處理也正是為了解決這個問題
plt.bar(x_14,b_14,width=wid_bar,label = "9月14日") 
plt.bar(x_15,b_15,width=wid_bar,label = "9月15日")
plt.bar(x_16,b_16,width=wid_bar,label = "9月16日")

plt.xticks(x_15,a)

plt.legend(loc = "upper right")

plt.show()

來看效果圖

在這裡插入圖片描述

在這裡插入圖片描述

4、直方圖

直方圖通常來統計連續區間上的頻數或者頻率,這裡就只展示一個例子了。注意:直方圖的資料是未經處理的,組數=極差/組距離,要求能整除,否則會錯位。

假設你獲取了250部電影的時長(列表a中),希望統計出這些電影時長的分佈狀態(比如時長為100分鐘到120分鐘電影的數量,出現的頻率)等資訊,你應該如何呈現這些資料?

a=[131, 98, 125, 131, 124, 139, 131, 117, 128, 108, 135, 138, 131, 102, 107, 114, 119, 128, 121, 142, 127, 130, 124, 101, 110, 116, 117, 110, 128, 128, 115, 99, 136, 126, 134, 95, 138, 117, 111,78, 132, 124, 113, 150, 110, 117, 86, 95, 144, 105, 126, 130,126, 130, 126, 116, 123, 106, 112, 138, 123, 86, 101, 99, 136,123, 117, 119, 105, 137, 123, 128, 125, 104, 109, 134, 125, 127,105, 120, 107, 129, 116, 108, 132, 103, 136, 118, 102, 120, 114,105, 115, 132, 145, 119, 121, 112, 139, 125, 138, 109, 132, 134,156, 106, 117, 127, 144, 139, 139, 119, 140, 83, 110, 102,123,107, 143, 115, 136, 118, 139, 123, 112, 118, 125, 109, 119, 133,112, 114, 122, 109, 106, 123, 116, 131, 127, 115, 118, 112, 135,115, 146, 137, 116, 103, 144, 83, 123, 111, 110, 111, 100, 154,136, 100, 118, 119, 133, 134, 106, 129, 126, 110, 111, 109, 141,120, 117, 106, 149, 122, 122, 110, 118, 127, 121, 114, 125, 126,114, 140, 103, 130, 141, 117, 106, 114, 121, 114, 133, 137, 92,121, 112, 146, 97, 137, 105, 98, 117, 112, 81, 97, 139, 113,134, 106, 144, 110, 137, 137, 111, 104, 117, 100, 111, 101, 110,105, 129, 137, 112, 120, 113, 133, 112, 83, 94, 146, 133, 101,131, 116, 111, 84, 137, 115, 122, 106, 144, 109, 123, 116, 111,111, 133, 150]

from matplotlib import pyplot as plt
#解決中文顯示問題,mat是不顯示中文的
plt.rcParams['font.sans-serif']=['SimHei'] #用來正常顯示中文標籤
plt.rcParams['axes.unicode_minus']=False #用來正常顯示負號

a=[131,  98, 125, 131, 124, 139, 131, 117, 128, 108, 135, 138, 131, 102, 107,
   114, 119, 128, 121, 142, 127, 130, 124, 101, 110, 116, 117, 110, 128, 128,
   115,  99, 136, 126, 134,  95, 138, 117, 111,78, 132, 124, 113, 150, 110,
   117,  86,  95, 144, 105, 126, 130,126, 130, 126, 116, 123, 106, 112, 138,
   123,  86, 101,  99, 136,123, 117, 119, 105, 137, 123, 128, 125, 104, 109,
   134, 125, 127,105, 120, 107, 129, 116, 108, 132, 103, 136, 118, 102, 120,
   114,105, 115, 132, 145, 119, 121, 112, 139, 125, 138, 109, 132, 134,156, 106,
   117, 127, 144, 139, 139, 119, 140,  83, 110, 102,123,107, 143, 115, 136,
   118, 139, 123, 112, 118, 125, 109, 119, 133,112, 114, 122, 109, 106, 123,
   116, 131, 127, 115, 118, 112, 135,115, 146, 137, 116, 103, 144,  83, 123,
   111, 110, 111, 100, 154,136, 100, 118, 119, 133, 134, 106, 129, 126, 110,
   111, 109, 141,120, 117, 106, 149, 122, 122, 110, 118, 127, 121, 114, 125, 126,114, 140, 103, 130, 141,
   117, 106, 114, 121, 114, 133, 137,  92,121, 112, 146,  97, 137, 105,  98, 117, 112,  81,  97, 139, 113,134,
   106, 144, 110, 137, 137, 111, 104, 117, 100, 111, 101, 110,105, 129, 137, 112, 120, 113, 133, 112,  83,
   94, 146, 133, 101,131, 116, 111,  84, 137, 115, 122, 106, 144, 109, 123, 116, 111,111, 133, 150]

d = 3
bins = (max(a)-min(a))//d

plt.figure(figsize=(20,8),dpi=100)
plt.hist(a,bins)
#設定x的刻度
plt.xticks(range(min(a),max(a)+d,d))
plt.yticks(range(0,26,2))


plt.grid(alpha=0.4)

plt.show()


來看效果圖
在這裡插入圖片描述

在這裡插入圖片描述