Matplotlib 可視化系列一

Python中的可視化庫包括:Pandas、Matplotlib、Seaborn,其中最核心的是Matplotlib。

Matplotlib 的基本圖包含以下類型:

  • boxplot
  • violinplot
  • polarplot
  • hexbin
  • histogram

風格設置的切換:可以設置成ggplot的風格,也可以設置成黑底背景的風格,還可以設置成一般財務公司常用的風格,如excel風格。

Python可視化系列將分塊講解 matplotlib 庫里的繪圖方法。

本期講解第一部分:箱線圖、直方圖、小提琴圖、雷達圖在Python中的實現。

1 基本圖 part 1 —— boxplot、violinplot、histogram、polar

import matplotlib.pyplot as pltimport numpy as np

如果你使用 jupyter notebook 環境,想要使圖形內嵌地顯示在 jupyter notebook 中,而不是彈出一個繪圖窗口,需要使用一些 magic,如下:

%matplotlib inline

但這樣設置後,也存在一個缺陷:除非將所有繪圖代碼一次全部執行,否則,無法疊加繪圖。

1.1 boxplot

1.1.1 生成隨機數

在這裡我們利用 numpy 庫生成三組正態分布隨機數,為了使結果可重現,我們還需要播撒隨機種子,不妨設定隨機種子編碼為 123:

np.random.seed(123)all_data=[np.random.normal(0,std,100) for std in range(1,4)].1.

1.1.2 畫板 + 軸 + 描點上色 = 圖

早有《黑客與畫家》一書論述過編程與繪畫的相似之處,在用 Python 的 matplotlib 作圖時,和真實繪圖方式一致,我們先要有:

  • 畫板(figure)

然後確定:

  • 繪圖框架結構(axis)

最後再基於框架結構:

  • 描點上色(輸入data,指定上色參數patch_artist=True)

非常容易上手!以上三個步驟只需要用三條命令即可完成,下面我們就來試試:

figure,axes=plt.subplots() #得到畫板、軸axes.boxplot(all_data,patch_artist=True) #描點上色plt.show() #展示

plt.subplots 顧名思義是子圖集合(用過 matlab 的童鞋想必已經想起來些什麼了),當不指定 plt.subplots() 的 nrows 和 ncols 參數值時,默認只生成一張圖。

Note:默認 patch_artist=False,所以我們需要指定其參數值為 True,即可自動填充顏色。

1.1.3 多圖輸出

有時我們會有把多張圖放在同一行輸出的對比需求,這時只需指定 plt.subplots() 函數的 nrows,ncols 參數值,舉個例子,我想生成一個 2x3 的面板,即每一行放三張圖,只需設定 nrows=2,ncols=3。

當然,你還可以通過參數 figsize 指定圖形大小。

下面我們將兩張圖放在一行輸出試試:

fig,axes=plt.subplots(nrows=1,ncols=2,figsize=(9,4))#首先有圖(fig),然後有軸(ax)bplot1=axes[0].boxplot(all_data, vert=True, patch_artist=True)#axes[0]表示在第一張圖的軸上描點畫圖#vert=True表示boxplot圖是豎著放的#patch_artist=True 表示填充顏色bplot2 = axes[1].boxplot(all_data, notch=True, # notch shape vert=True, # vertical box aligmnent patch_artist=True) # fill with colorplt.show()

第一張圖是矩形箱線圖,第二張圖是 notch 形狀的箱線圖,顯然,把兩張圖放在同一行輸出非常有利於對比觀察圖形差異。

1.1.4 美化圖形

基本圖形畫得差不多了,接下來就只需要讓她美美美了!

我們先來查看一下我們之前作出的箱線圖對象的類型:

type(bplot1) #返回字典#dict

噢!它是字典類型呀!

  • 顏色填充

顏值即正義!要選個好的配色不容易呢…

填充顏色基本遵循以下步驟:

  1. 指定箱線圖中每個箱子的填充顏色,如:red、green、blue、pink 等
  2. 構造字典存放箱子配色 —— {箱線圖中每個箱子patch:對應的配色color}
  3. 重新上色 —— patch.set_facecolor(color)

好啦,把代碼擺出來,一目了然!

#顏色填充colors = [pink, lightblue, lightgreen]for bplot in (bplot1, bplot2): for patch, color in zip(bplot[boxes], colors): patch.set_facecolor(color)

  • 添加網格線

    你可以:
  1. 指定在x軸上添加網格線(ax.xaxis.grid(True)),或者在y軸上添加網格線(ax.yaxis.grid(True))
  2. 指定 x 軸和 y 軸上的刻度個數(ax.set_xticks([1,2,3]),ax.set_yticks([1,2,3,4,5,6,7,8]))
  3. 設置 x 軸名稱(ax.set_xlabel("xlabel"))
  4. 設置 y 軸名稱(ax.set_xlabel("ylabel"))

# 加水平網格線for ax in axes: ax.yaxis.grid(True) #在y軸上添加網格線 ax.set_xticks([y+1 for y in range(len(all_data))] ) #指定x軸的軸刻度個數 ## [y+1 for y in range(len(all_data))]運行結果是[1,2,3] ax.set_xlabel(xlabel) #設置x軸名稱 ax.set_ylabel(ylabel) #設置y軸名稱

  • 添加刻度

添加刻度名稱,我們需要使用 plt.setp() 函數:

# 加刻度名稱plt.setp(axes, xticks=[1,2,3], xticklabels=[x1, x2, x3])

我們需要告訴 plt.setp,我們的刻度數是哪些,以及我們想要它添加的刻度標籤是什麼。

講解完代碼,讓我們把代碼匯總,畫個圖看看:

fig,axes=plt.subplots(nrows=1,ncols=2,figsize=(9,4))bplot1=axes[0].boxplot(all_data, vert=True, patch_artist=True)bplot2=axes[1].boxplot(all_data, notch=True, vert=True, patch_artist=True)colors = [pink, lightblue, lightgreen]for bplot in (bplot1, bplot2): for patch, color in zip(bplot[boxes], colors): patch.set_facecolor(color)for ax in axes: ax.yaxis.grid(True) ax.set_xticks([y+1 for y in range(len(all_data))]) ax.set_xlabel(xlabel) ax.set_ylabel(ylabel)plt.setp(axes, xticks=[1,2,3], xticklabels=[x1, x2, x3])plt.show()

  • 添加標題

使用 ax.set_title 來設置單個圖形主標題,用 fig.suptitle 來設置整張畫板的標題:

np.random.seed(1221)data=np.random.binomial(n=10,p=0.76,size=(10,3))labels=list("ABC")fig,ax=plt.subplots(figsize=(9,6))ax.boxplot(data,labels=labels,patch_artist=True)plt.rcParams[font.sans-serif]=[SimHei] #正確顯示中文plt.rcParams[axes.unicode_minus]=False #用來正確顯示負號ax.set_title("設置 fontsize=15 的標題",fontsize=15) #設置字體大小為18號字體fig.suptitle("Boxplot Examples",fontsize=24)plt.show()

想必細心的朋友已經發現了我在代碼里偷偷加了兩行設置字體的代碼,這兩行代碼專為防止出現中文亂碼而生!

plt.rcParams[『font.sans-serif』]=[『SimHei』] -> 用來正確顯示中文

plt.rcParams[『axes.unicode_minus』]=False -> 用來正確顯示負號

  • 其他參數

在圖上標記出均值線

fig,axes=plt.subplots(1,2,figsize=(9,5))axes[0].boxplot(data,labels=labels,showmeans=True,meanline=False)axes[0].set_title("默認 meanline=False",fontsize=15)axes[1].boxplot(data,labels=labels,showmeans=True,meanline=True)axes[1].set_title("meanline=True",fontsize=15)plt.show()

Note:

meanline=False,那麼均值位置會在圖中用小三角表示出來

meanline=True,那麼均值位置會在圖中用虛線表示出來

在圖上去除離群值

fig,axes=plt.subplots(1,2,figsize=(9,5))axes[0].boxplot(data,labels=labels,patch_artist=True)axes[0].set_title("默認 showfliers=True",fontsize=15)axes[1].boxplot(data,labels=labels,patch_artist=True,showfliers=False)axes[1].set_title("showfliers=False",fontsize=15)plt.show()

默認 showfliers=True,那麼圖中會顯示出離群值

showfliers=False,那麼圖中會去除離群值

1.2 violinplot

  • 小提琴圖

小提琴圖其實是箱線圖與核密度圖的結合。箱線圖展示了分位數的位置,小提琴圖還展示了任意位置的密度,通過小提琴圖可以知道哪些位置的密度較高。

import randomimport numpy as npimport matplotlib.pyplot as pltfs=10pos = [2,4,6]data=[np.random.normal(0,std,size=150) for std in pos]fig,axes = plt.subplots(nrows=1,ncols=2,figsize=(9,6))axes[0].violinplot(data,pos,points=20,widths=0.7, showmeans=False,showextrema=True,showmedians=True)axes[1].violinplot(data, pos, points=80, vert=False, widths=0.7, showmeans=True, showextrema=True, showmedians=True)plt.show()

在左上圖中,每個小提琴圖中間那條橫線是中位數,小提琴上下兩條橫線分別表示最大值、最小值。外部擴張的區域即為核密度估計(在概率論中用來估計未知的密度函數,屬於非參數檢驗方法之一),表現了這些位置的數據密度。

Note:標題、字體、顏色的設置同 boxplot 部分。

1.3 histogram

1.3.1 等距直方圖

想必大家已經很熟悉直方圖了,下面我們來實現一下直方圖的繪製:

  • 生成隨機數

生成一組服從 mu=100,sigma=15 的正態分布隨機數:

import matplotlib.mlab as mlabnp.random.seed(1)mu = 100 # mean of distributionsigma = 15 # standard deviation of distributionx = mu + sigma * np.random.randn(437)

  • 指定分組個數

num_bins = 10

上面的代碼指定了直方圖的組數為 10

  • 畫出直方圖

通過調用 as.hist 函數,來生成組數為 10 的直方圖:

fig, ax = plt.subplots()n, bins_limits, patches = ax.hist(x, num_bins, normed=1)print("n 是分組區間對應的頻率:",n,end="

")print("bins_limits 是分組時的分隔值:",bins_limits,end="

")print("patches 指的是是直方圖中那10個矩形對象",end="

")#n 是分組區間對應的頻率: [ 0.00157167 0.00419112 0.00890613 #0.01807421 0.02802812 0.02462284# 0.01833616 0.00602474 0.00392918 0.00078584]#bins_limits 是分組時的分隔值: [ 58.103725 66.83963817 #75.57555134 84.3114645 93.04737767# 101.78329084 110.51920401 119.25511718 127.99103035 #136.72694352# 145.46285669]#patches 指的是是直方圖中那10個矩形對象

  • 添加經驗分布曲線

fig, ax = plt.subplots()n, bins_limits, patches = ax.hist(x, num_bins, normed=1)# add a best fit liney = mlab.normpdf(bins_limits, mu, sigma)ax.plot(bins_limits, y, --)ax.set_xlabel(Smarts)ax.set_ylabel(Probability density)ax.set_title(rHistogram of IQ: $mu=100$, $sigma=15$)plt.show()

1.3.2 不等距分組

上面的直方圖都是等距的,但有時我們需要得到不等距的直方圖,這個時候只需要確定分組上下限,並指定 histtype="bar" 就可以了:

fig, ax = plt.subplots()bins = [50, 60, 70, 90, 100,110, 140, 150]ax.hist(x, bins, normed=1, histtype=bar, color="g",rwidth_=0.8)ax.set_title(不等距分組)plt.show()

1.3.3 多類型直方圖

fig,ax=plt.subplots()x_multi = [np.random.randn(n) for n in [10000, 5000, 2000]]n_bins=10ax.hist(x_multi, n_bins, histtype=bar,label=list("ABC"))ax.set_title(MultiType data)ax.legend(prop={size: 10})fig.tight_layout()plt.show()

實際繪圖代碼與單類型直方圖差異不大,只是增加了一個圖例項

  • 添加圖例
  1. 在 ax.hist 函數中先指定圖例 label 名稱
  2. 通過 ax.legend 函數來添加圖例

1.4 雷達圖(Polar)

# 構造隨機數N = 150r = 2 * np.random.rand(N)theta = 2 * np.pi * np.random.rand(N) area = 20 * r**2 # 指定氣泡麵積大小colors = theta #指定氣泡顏色,可以是一個數值序列ax = plt.subplot(polar=True)c = ax.scatter(theta, r, c=colors, s=area,cmap=hsv, alpha=0.75)plt.show()

細心的童鞋肯定已經發現,在這裡我們使用的函數是 plt.subplot,而不是 plt.subplots。這兩個函數的區別是:

Note:

  1. 這裡的 ~ 表示各自對應的函數
  2. 縮寫」是指比如 nrows=2,ncols=3,要對按行數的第三張圖進行繪圖填充,可以簡寫為 233

本文作者:胡帆

推薦閱讀:

使用Matplotlib畫動態圖實例
Python數據抓取與可視化實戰——網易雲課堂人工智慧與大數據板塊課程實戰
基於matplotlib的2D/3D抽象網格和能量曲線繪製程序
Seaborn(sns)官方文檔學習筆記(第三章 分布數據集的可視化)

TAG:Python | 数据可视化 | Matplotlib |