matplotlib 硬核總結:烏森數據可視化系列

一. matplotlib 系列

Matplotlib 是 Python 中最常用的可視化工具之一, 它比較底層,可定製性強、圖表資源豐富。

1.1Matplotlib 三層結構

1)容器層

容器層主要由 Canvas、Figure、Axes 組成。Canvas 是位於最底層的,在繪圖的過程中充當畫板的角色,即放置畫布(Figure)的工具。Figure 是 Canvas 上方的第一層,也是用戶可操作的最低層級,在繪圖過程中充當畫布的角色。Axes 是 Canvas 上方的第二層,在繪圖過程總相當於畫布上的繪圖區的角色。

2)輔助顯示層
輔助顯示層用於增加相關顯示功能、描述。

3)圖像層
具體描繪的圖像(例如各種常見圖表)。

1.2Matplotlib 繪圖步驟

step 1: 準備數據 step 2: 創建一個畫布(figure)step 3: 在畫布上創建一個或多個繪圖區域(座標系 / 軸,axes)step 4: 繪製圖像(根據不同圖像類別調用不同方法)step 5: 輔助繪製(刻度、圖例等)step 6: 圖像顯示 / 保存

import matplotlib.pyplot as plt
import random

plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False

if __name__ == '__main__':
    # 準備數據
    x = range(60)
    y_shanghai = [random.uniform(15, 18) for i in x]

    # 創建畫布
    plt.figure(figsize=(20, 8)dpi=80)

    # 創建繪圖區域
    ax = plt.subplot(111)
    ax.set_xlabel("時間變化")
    ax.set_ylabel("溫度變化")
    ax.set_title("某城市11點到12點溫度變化")

    # 繪製圖像
    ax.plot(x, y_shanghai, color='b'linestyle='--'label='上海')

    # 輔助繪製:顯示圖例
    ax.legend()

    # 輔助繪製:準備x、y的刻度以及刻度說明
    x_label = ["11點{}分".format(i) for i in x]
    ax.set_xticks(x[::5], x_label[::5])
    ax.set_yticks(range(0, 40, 5))

    # 輔助繪製:添加網格
    ax.grid(linestyle='--'alpha=0.5)

    plt.show()

1.3  其他注意事項

1)繪圖風格

print(plt.style.available)
plt.style.use('seaborn-paper')

2)顯示問題

Matplotlib 默認情況中文和負號不能正常顯示,可以更改如下配置來解決。

plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False

matplotlib 顏色、標記、線型:https://blog.csdn.net/qq_41455420/article/details/79733524
matplotlib 座標軸與刻度:https://blog.csdn.net/wuzlun/article/details/80053277
matplotlib 中文文檔:
https://www.matplotlib.org.cn/

二. 多子圖繪製功能

在 matplotlib 下,一個畫布(Figure)對象可以包含多個子圖(Axes),可以使用 subplot() 快速繪製。

2.1subplot 介紹

subplot(numRows, numCols, plotNum)

圖表的整個繪圖區域被分成 numRows 行和 numCols 列,plotNum 參數指定創建的 Axes 對象所在的區域。

2.2  subplot 應用舉例

import matplotlib.pyplot as plt
import numpy as np
def f(t):
    return np.exp(-t) * np.cos(2 * np.pi * t)

t1 = np.arange(0, 5, 0.1)
t2 = np.arange(0, 5, 0.02)

fig = plt.figure(figsize=(16, 10)dpi= 80)  # 畫布

ax1 = plt.subplot(221)  # 兩行兩列中的第一行第一列位置
ax1.plot(t1, f(t1)'bo', t2, f(t2)'r--')
 
ax2 = plt.subplot(222)  # 兩行兩列中的第一行第二列位置
ax2.plot(t2, np.cos(2 * np.pi * t2)'r--')
 
ax3 = plt.subplot(212)  # 兩行一列中的第二行的位置
ax3.plot([1, 2, 3, 4][1, 4, 9, 16])

plt.show()

三. 繪製二維圖表

matplotlib 提供了常見二維圖表的繪製。

3.1 數據分佈

1)直方圖

#-*- coding:utf-8 -*-
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np

# 正常顯示中文
plt.rcParams['font.sans-serif']=['SimHei']
# 正常顯示負號
plt.rcParams['axes.unicode_minus']=False 

# print(plt.style.available)
plt.style.use('seaborn-paper')

def plot_hist(title, x):
    '''
    繪製直方圖
    '''
    fig, ax = plt.subplots(figsize=(16,10)dpi= 80) # 創建一個畫板

    # 標題、座標軸設定
    plt.title(title, fontsize=22)
    plt.xlabel('x'fontsize=16, fontfamily='sans-serif',fontstyle='italic')
    plt.ylabel('y'fontsize=16, fontfamily='sans-serif',fontstyle='italic')

    # 設置座標軸刻度線
    # plt.yticks([1,5,8,15,24], [r'$really\ bad$',r'$bad$',r'$normal$',r'$good$',r'$really\ good$'])

    # 是否顯示網格
    ax.grid(False)

    # 座標軸的一些屬性設定
    # ax.set_aspect('equal')  # 座標軸等比例
    ax.xaxis.set_tick_params(labelsize=16, colors='g') # 座標軸刻度格式
    ax.xaxis.set_major_locator(plt.MultipleLocator(1)) # 座標軸刻度間隔1
    ax.yaxis.tick_right() # y軸座標佈局位置
    ax.yaxis.set_tick_params(labelsize=16)

    # 移動座標軸
    ax.xaxis.set_ticks_position('bottom')
    ax.spines['bottom'].set_position(('data', 0))  # 將bottom即是x座標軸設置到y=0的位置
    ax.yaxis.set_ticks_position('left')
    ax.spines['left'].set_position(('data', 0))  # 將left即是y座標軸設置到x=0的位置

    # 消除邊框
    ax.spines['right'].set_color('none')
    ax.spines['top'].set_color('none')

    # 繪圖
    ax.hist(x,
            bins=25,  # 分段數量
            width=0.2,   # 寬度
            alpha=0.5,   # 不透明度
            #facecolor='white',  # 柱形填充顏色
            #hatch='/',   # 圖形填充形狀,可選['/', '', '|', '-', '+', 'x', 'o', 'O', '.', '*']
            #edgecolor='darkblue'  # 邊緣顏色
            )
    
    # plt.savefig("./"+title+".png") # 保存圖片
    plt.show()

x = np.random.normal(0,1,1000)
plot_hist('測試圖', x)

如果只需要簡單的計算每段區間的樣本數,而並不想畫圖顯示它們,那麼可以直接用 np.histogram()

import numpy as np

x = np.random.normal(0,1,1000)
counts, bin_edges = np.histogram(x, bins=50)
print(counts)

2)箱形圖

#-*- coding:utf-8 -*-
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np

# 正常顯示中文
plt.rcParams['font.sans-serif']=['SimHei']
# 正常顯示負號
plt.rcParams['axes.unicode_minus']=False 

# print(plt.style.available)
plt.style.use('seaborn-paper')

def plot_box(title, data, labels):
    '''
    繪製箱形圖
    '''
    fig, ax = plt.subplots(figsize=(16,10)dpi= 80) # 創建一個畫板

    # 標題、座標軸設定
    plt.title(title, fontsize=22)
    plt.ylabel('y'fontsize=16, fontfamily='sans-serif',fontstyle='italic')

    # 是否顯示網格
    ax.grid(False)

    # 座標軸的一些屬性設定
    ax.xaxis.set_tick_params(labelsize=16)
    ax.yaxis.tick_right() # y軸座標佈局位置
    ax.yaxis.set_tick_params(labelsize=16)

    # 消除邊框
    ax.spines['left'].set_color('none')
    ax.spines['bottom'].set_color('none')
    ax.spines['right'].set_color('none')
    ax.spines['top'].set_color('none')

    # 繪圖
    bplot = ax.boxplot(data,
               widths=0.2,   # 設置箱體寬度
         patch_artist=True, # 箱體是否染色
         notch=False,  # 中位線處不設置凹陷
               medianprops={'linestyle':'--','color':'green','markerfacecolor':'indianred''markersize':4},  # 設置均值點的屬性, 如點的形狀、填充色和點的大小
               # flierprops={'marker':'o','markerfacecolor':'red', 'markersize':3},  # 設置異常點屬性, 如點的形狀、填充色和點的大小
               labels=labels   # 標籤
               )
    colors =["pink""lightgreen","pink""lightgreen"]
    for i, item in enumerate(bplot["boxes"]):
        item.set_facecolor(colors[i])

    # plt.savefig("./"+title+".png") # 保存圖片
    plt.show()

data = [
        [1000, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2500],
        [1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000, 2100],
        [1000, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000],
        [800, 1000, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900]
    ]
labels =["China","America","Britain","Russia"]

plot_box('測試圖', data, labels)

3)小提琴圖

#-*- coding:utf-8 -*-
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np

# 正常顯示中文
plt.rcParams['font.sans-serif']=['SimHei']
# 正常顯示負號
plt.rcParams['axes.unicode_minus']=False 

# print(plt.style.available)
plt.style.use('seaborn-paper')

def plot_violin(title, data, labels):
    '''
    繪製小提琴圖
    '''
    fig, ax = plt.subplots(figsize=(16,10)dpi= 80) # 創建一個畫板

    # 標題、座標軸設定
    plt.title(title, fontsize=22)
    plt.ylabel('y'fontsize=16, fontfamily='sans-serif',fontstyle='italic')

    # 是否顯示網格
    ax.grid(False)

    # 座標軸的一些屬性設定
    ax.xaxis.set_tick_params(labelsize=16)
    ax.set_xticks([i+1 for i in range(len(data))]) 
    ax.set_xticklabels([labels[i] for i in range(len(data))])
    ax.yaxis.tick_right() # y軸座標佈局位置
    ax.yaxis.set_tick_params(labelsize=16)

    # 消除邊框
    ax.spines['left'].set_color('none')
    ax.spines['bottom'].set_color('none')
    ax.spines['right'].set_color('none')
    ax.spines['top'].set_color('none')

    # 繪圖
    vplot = ax.violinplot(data, 
               vert=True,   # 是否豎直顯示
               showmedians=True,  # 顯示中位數
               showmeans=False  # 顯示平均數
               )
    for item, color in zip(vplot['bodies']['cyan''red''blue''green''purple']):
        item.set(facecolor=color, alpha=0.5)
    for item in ['cbars''cmaxes''cmins''cmedians']:
        plt.setp(vplot[item]edgecolor='gray'linewidth=1.5)
        plt.setp(vplot['cmedians']edgecolor='black')

    # plt.savefig("./"+title+".png") # 保存圖片
    plt.show()

data = [
        [1000, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2500],
        [1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000, 2100],
        [300, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000],
        [800, 1000, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900]
    ]
labels =["China","America","Britain","Russia"]

plot_violin('測試圖', data, labels)

3.2  數據比較

1)柱形圖

#-*- coding:utf-8 -*-
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np

# 正常顯示中文
plt.rcParams['font.sans-serif']=['SimHei']
# 正常顯示負號
plt.rcParams['axes.unicode_minus']=False 

# print(plt.style.available)
plt.style.use('seaborn-paper')

def plot_bar(title, x, y):
    '''
    繪製柱形圖
    '''
    fig, ax = plt.subplots(figsize=(16,10)dpi= 80) # 創建一個畫板

    # 標題、座標軸和標籤設定
    plt.title(title, fontsize=22)
    plt.xlabel('xlabel'fontsize=16, fontfamily='sans-serif',fontstyle='italic')
    plt.xlim(-1, 5)
    plt.ylabel('ylabel'fontsize=16, fontfamily='sans-serif',fontstyle='italic')
    plt.ylim(-2, 30)

    # 設置座標軸刻度線
    plt.yticks([1,5,8,15,24][r'$really\ bad$',r'$bad$',r'$normal$',r'$good$',r'$really\ good$'])

    # 是否顯示網格
    ax.grid(False)
       
    # 座標軸的一些屬性設定
    # ax.set_aspect('equal')  # 座標軸等比例
    ax.xaxis.set_tick_params(labelsize=16, colors='g') # 座標軸刻度格式
    ax.xaxis.set_major_locator(plt.MultipleLocator(1)) # 座標軸刻度間隔1
    ax.yaxis.tick_right() # y軸座標佈局位置
    ax.yaxis.set_tick_params(labelsize=16)

    # 移動座標軸
    ax.xaxis.set_ticks_position('bottom')
    ax.spines['bottom'].set_position(('data', 0))  # 將bottom即是x座標軸設置到y=0的位置
    ax.yaxis.set_ticks_position('left')
    ax.spines['left'].set_position(('data', 0))  # 將left即是y座標軸設置到x=0的位置

    # 消除邊框
    ax.spines['right'].set_color('none')
    ax.spines['top'].set_color('none')

    # 繪圖
 &nnbsp;  rects = ax.bar(x, y,
                   width=0.5,   # 寬度
                   alpha=0.5,   # 不透明度
                   #facecolor='white',  # 柱形填充顏色
                   #hatch='/',   # 圖形填充形狀,可選['/', '', '|', '-', '+', 'x', 'o', 'O', '.', '*']
                   #edgecolor='darkblue'  # 邊緣顏色
                   )
    # 爲柱狀圖添加高度值
    for rect in rects:
        x = rect.get_x()
        height = rect.get_height()
        ax.text(x+0.2, 1.01*height, str(height)fontsize=16)
   
    # plt.legend(fontsize=16, loc='upper right')  # 標籤設定
    # plt.savefig("./"+title+".png") # 保存圖片
    plt.show()

x = np.arange(1, 5, 1)
y = np.array([15,20,18,25])
plot_bar('測試圖', x, y)

2)雷達圖

#-*- coding:utf-8 -*-
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np

# 正常顯示中文
plt.rcParams['font.sans-serif']=['SimHei']
# 正常顯示負號
plt.rcParams['axes.unicode_minus']=False

# print(plt.style.available)
plt.style.use('seaborn-paper')

def plot_radar(title, p1, p2):
    '''
    繪製雷達圖
    '''
    fig = plt.figure(figsize=(10,5))
    ax1 = fig.add_subplot(121, polar=True) # 座標軸爲極座標體系
    ax2 = fig.add_subplot(122, polar=True)
    fig.subplots_adjust(wspace=0.4)  # 設置子圖間的間距爲子圖寬度的40%

    data1 = np.array([for i in p1.values()]).astype(int)
    data2 = np.array([for i in p2.values()]).astype(int)
    label = np.array([for j in p1.keys()]) # 提取標籤

    angle = np.linspace(0, 2*np.pi, len(data1)endpoint=False) # data裏有幾個數據,就把整圓360°分成幾份
    angles = np.concatenate((angle, [angle[0]])) # 增加第一個angle到所有angle裏,以實現閉合

    data1 = np.concatenate((data1, [data1[0]])) # 增加第一組數據的第一個值到第一組數據所有的值裏,以實現閉合
    data2 = np.concatenate((data2, [data2[0]])) # 增加第二組數據的第一個值到第二組數據所有的值裏,以實現閉合

    # 設置第一個座標軸
    ax1.set_thetagrids(angles*180/np.pi, label) # 設置網格標籤
    ax1.plot(angles,data1,"o-")
    ax1.set_theta_zero_location('NW') # 設置極座標0°位置
    ax1.set_rlim(0,100) # 設置顯示的極徑範圍
    ax1.fill(angles,data1,facecolor='g'alpha=0.2) # 填充顏色
    ax1.set_title("甲",fontproperties="SimHei",fontsize=16) # 設置標題

    # 設置第二個座標軸
    ax2.set_thetagrids(angles*180/np.pi, label) # 設置網格標籤
    ax2.plot(angles,data2,"o-")
    ax2.set_theta_zero_location('NW')  #設置極座標0°位置
    ax2.set_rlim(0,100)  # 設置顯示的極徑範圍
    ax2.fill(angles,data2,facecolor='g'alpha=0.2) # 填充顏色
    ax2.set_title("乙",fontproperties="SimHei",fontsize=16) # 設置標題

    plt.show()

p1={"編程能力":60,"溝通技能":70,"專業知識":65,"團體協作":75,"工具掌握":80} #創建第一個人的數據
p2={"編程能力":70,"溝通技能":60,"專業知識":75,"團體協作":65,"工具掌握":70} #創建第二個人的數據
plot_radar('測試圖', p1, p2)

3)折線圖

#-*- coding:utf-8 -*-
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np

# 正常顯示中文
plt.rcParams['font.sans-serif']=['SimHei']
# 正常顯示負號
plt.rcParams['axes.unicode_minus']=False 

# print(plt.style.available)
plt.style.use('seaborn-paper')

def plot_line(title, x, y):
    '''
    繪製折線圖
    '''
    fig, ax = plt.subplots(figsize=(16,10)dpi= 80) # 創建一個畫板

    # 標題、座標軸設定
    plt.title(title, fontsize=22)
    plt.xlabel('x'fontsize=16, fontfamily='sans-serif',fontstyle='italic')
    plt.ylabel('y'fontsize=16, fontfamily='sans-serif',fontstyle='italic')

    # 設置座標軸刻度線
    # plt.yticks([1,5,8,15,24], [r'$really\ bad$',r'$bad$',r'$normal$',r'$good$',r'$really\ good$'])

    # 是否顯示網格
    ax.grid(False)

    # 座標軸的一些屬性設定
    # ax.set_aspect('equal')  # 座標軸等比例
    ax.xaxis.set_tick_params(labelsize=16, colors='g') # 座標軸刻度格式
    ax.xaxis.set_major_locator(plt.MultipleLocator(5)) # 座標軸刻度間隔5
    ax.yaxis.tick_right() # y軸座標佈局位置
    ax.yaxis.set_tick_params(labelsize=16)

    # 移動座標軸
    ax.xaxis.set_ticks_position('bottom')
    ax.spines['bottom'].set_position(('data', 0))  # 將bottom即是x座標軸設置到y=0的位置
    ax.yaxis.set_ticks_position('left')
    ax.spines['left'].set_position(('data', 0))  # 將left即是y座標軸設置到x=0的位置

    # 消除邊框
    ax.spines['right'].set_color('none')
    ax.spines['top'].set_color('none')

    # 繪圖
    ax.plot(x, y,
            linewidth = 3, # 線寬
            linestyle=':'# 線的風格(-是實線,:是虛線)
            alpha=0.5,   # 不透明度
            color='black',  # 折線顏色
            label='a'   # 標籤
            )
    
    plt.legend(fontsize=16, loc='upper right')  # 標籤設定
    # plt.savefig("./"+title+".png") # 保存圖片
    plt.show()

x = np.arange(50)
y = x**2+4
plot_line('測試圖', x, y)

3.3 數據關係

1)散點圖

#-*- coding:utf-8 -*-
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np

# 正常顯示中文
plt.rcParams['font.sans-serif']=['SimHei']
# 正常顯示負號
plt.rcParams['axes.unicode_minus']=False 

# print(plt.style.available)
plt.style.use('seaborn-paper')

def plot_scatter(title, x, y):
    '''
    繪製散點圖
    '''
    fig, ax = plt.subplots(figsize=(16,10)dpi= 80) # 創建一個畫板

    # 標題、座標軸設定
    plt.title(title, fontsize=22)
    plt.xlabel('x'fontsize=16, fontfamily='sans-serif',fontstyle='italic')
    plt.ylabel('y'fontsize=16, fontfamily='sans-serif',fontstyle='italic')

    # 設置座標軸刻度線
    # plt.yticks([1,5,8,15,24], [r'$really\ bad$',r'$bad$',r'$normal$',r'$good$',r'$really\ good$'])

    # 是否顯示網格
    ax.grid(False)

    # 座標軸的一些屬性設定
    ax.set_aspect('equal')  # 座標軸等比例
    ax.xaxis.set_tick_params(labelsize=16) # 座標軸刻度格式
    ax.yaxis.tick_right() # y軸座標佈局位置
    ax.yaxis.set_tick_params(labelsize=16)

    # 移動座標軸
    ax.xaxis.set_ticks_position('bottom')
    ax.spines['bottom'].set_position(('data', 0))  # 將bottom即是x座標軸設置到y=0的位置
    ax.yaxis.set_ticks_position('left')
    ax.spines['left'].set_position(('data', 0))  # 將left即是y座標軸設置到x=0的位置

    # 消除邊框
    ax.spines['right'].set_color('none')
    ax.spines['top'].set_color('none')

    # 繪圖
    ax.scatter(x, y, 
               alpha =0.8  # 不透明度
               )
    
    # plt.savefig("./"+title+".png") # 保存圖片
    plt.show()

x = np.random.random(100)*10
y = np.random.random(100)*10
plot_scatter('測試圖', x, y)

2)氣泡圖

#-*- coding:utf-8 -*-
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np

# 正常顯示中文
plt.rcParams['font.sans-serif']=['SimHei']
# 正常顯示負號
plt.rcParams['axes.unicode_minus']=False 

# print(plt.style.available)
plt.style.use('seaborn-paper')

def plot_bubble(title, x, y, s):
    '''
    繪製氣泡圖
    '''
    fig, ax = plt.subplots(figsize=(16,10)dpi= 80) # 創建一個畫板

    # 標題、座標軸和標籤設定
    plt.title(title, fontsize=22)
    plt.xlabel('x'fontsize=16, fontfamily='sans-serif',fontstyle='italic')
    plt.ylabel('y'fontsize=16, fontfamily='sans-serif',fontstyle='italic')

    # 設置座標軸刻度線
    # plt.yticks([1,5,8,15,24], [r'$really\ bad$',r'$bad$',r'$normal$',r'$good$',r'$really\ good$'])

    # 是否顯示網格
    ax.grid(False)

    # 座標軸的一些屬性設定
    ax.set_aspect('equal')  # 座標軸等比例
    ax.xaxis.set_tick_params(labelsize=16) # 座標軸刻度格式
    ax.yaxis.tick_right() # y軸座標佈局位置
    ax.yaxis.set_tick_params(labelsize=16)

    # 移動座標軸
    ax.xaxis.set_ticks_position('bottom')
    ax.spines['bottom'].set_position(('data', 0))  # 將bottom即是x座標軸設置到y=0的位置
    ax.yaxis.set_ticks_position('left')
    ax.spines['left'].set_position(('data', 0))  # 將left即是y座標軸設置到x=0的位置
    
    # 消除邊框
    ax.spines['right'].set_color('none')
    ax.spines['top'].set_color('none')

    # 繪圖
    ax.scatter(x, y, 
               s=s, # 點的面積
               c=np.random.choice(['red','blue'], 100),  # 點的顏色
               alpha =0.8  # 不透明度
               )
    
    # plt.savefig("./"+title+".png") # 保存圖片
    plt.show()

x = np.random.random(100)*10
y = np.random.random(100)*10
s = np.random.random(100)*300 # 點的面積
plot_bubble('測試圖', x, y, s)

3.4  數據成分

1)餅圖

#-*- coding:utf-8 -*-
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np

# 正常顯示中文
plt.rcParams['font.sans-serif']=['SimHei']
# 正常顯示負號
plt.rcParams['axes.unicode_minus']=False 

# print(plt.style.available)
plt.style.use('seaborn-paper')

def plot_pie(title, sizes, labels, explode):
    '''
    繪製餅圖
    '''
    fig, ax = plt.subplots(figsize=(16,10)dpi= 80) # 創建一個畫板

    # 標題設定
    plt.title(title, fontsize=22)

    # 是否顯示網格
    ax.grid(False)

    # 座標軸的一些屬性設定
    ax.set_aspect('equal')  # 座標軸等比例

    # 繪圖
    ax.pie(sizes,  # 百分比(list)
           autopct='%1.1f%%'# 百分比顯示設置
           labels=labels,  # (每一塊)餅圖外側顯示的說明文字
           startangle=150, # 開始繪製的角度
           explode=explode,  # (每一塊)離開中心距離
           shadow=False  # 在餅圖下面畫一個陰影。默認值:False,即不畫陰影
           )
    
    # plt.savefig("./"+title+".png") # 保存圖片
    plt.show()

sizes = [2,5,12,70,2,9]
labels = ['娛樂','育兒','飲食','房貸','交通','其它']
explode = (0,0,0,0.1,0,0)
plot_pie('餅圖示例-某家庭支出', sizes, labels, explode)

2)堆積柱形圖

#-*- coding:utf-8 -*-
import matplotlib.pyplot as plt
import numpy as np

# 正常顯示中文
plt.rcParams['font.sans-serif']=['SimHei']
# 正常顯示負號
plt.rcParams['axes.unicode_minus']=False 

# print(plt.style.available)
plt.style.use('seaborn-paper')

def plot_stackedbar(title, x, ys):
    '''
    繪製堆積柱形圖
    '''
    fig, ax = plt.subplots(figsize=(16,10)dpi= 80) # 創建一個畫板

    # 標題、座標軸設定
    plt.title(title, fontsize=22)
    plt.xlabel('xlabel'fontsize=16, fontfamily='sans-serif',fontstyle='italic')
    plt.ylabel('ylabel'fontsize=16, fontfamily='sans-serif',fontstyle='italic')

    # 是否顯示網格
    ax.grid(False)

    # 座標軸的一些屬性設定
    # ax.set_aspect('equal')  # 座標軸等比例
    ax.xaxis.set_tick_params(labelsize=16, colors='g') # 座標軸刻度格式
    ax.yaxis.tick_right() # y軸座標佈局位置
    ax.yaxis.set_tick_params(labelsize=16)

    # 消除邊框
    ax.spines['right'].set_color('none')
    ax.spines['top'].set_color('none')

    t = 0
    for y, c, label in zip(ys, ['r''g''c']['label1''label2''label3']):
        plt.bar(x, y, width=0.2, bottom=t, color=c, label=label)
        t += y

    plt.legend(fontsize=16, loc='upper right')  # 標籤設定
    # plt.savefig("./"+title+".png") # 保存圖片
    plt.show()

x = np.linspace(0, 5, 20)
y1 = np.random.randint(50, 100, 20)
y2 = np.random.randint(50, 100, 20)
y3 = np.random.randint(50, 100, 20)
plot_stackedbar('測試圖', x, [y1,y2,y3])

50 張 matplotlib 圖表:
https://www.machinelearningplus.com/plots/top-50-matplotlib-visualizations-the-master-plots-python/

四. 繪製三維圖表

matplotlib 繪製三維圖表主要通過 mplot3d 模塊實現,但由於三維圖表實際上是在二維畫布上展示,因此同樣需要載入 pyplot 模塊。

matplotlib 繪製三維圖表主要通過 mplot3d 模塊實現,但由於三維圖表實際上是在二維畫布上展示,因此同樣需要載入 pyplot 模塊。
1)三維空間中的點

#-*- coding:utf-8 -*-
import matplotlib as mpl
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np

# 正常顯示中文
plt.rcParams['font.sans-serif']=['SimHei']
# 正常顯示負號
plt.rcParams['axes.unicode_minus']=False 

def plot_scatter_3d(title, x, y, z):
    '''
    繪製3D散點圖
    '''
    fig = plt.figure(figsize=(16, 10)dpi= 80) # 創建一個畫板
    ax = Axes3D(fig)
    ax.scatter(xs=x, 
               ys=y, 
               zs=z, 
               c='r',  # 顏色
               marker='o'# 點的標記
               label='positive' # 標籤
               )

    # 設置座標軸顯示以及旋轉角度
    ax.set_xlabel('x'fontsize=16)
    ax.set_ylabel('y'fontsize=16)
    ax.set_zlabel('z'fontsize=16)
    ax.view_init(elev=10, azim=235)

    plt.title(title, fontsize=22)
    plt.grid(False)   # 是否顯示網格
    ax.set_aspect('equal')  # 座標軸間比例一致
    ax.legend(loc='upper left'fontsize=16)
    # plt.savefig("./"+title+".png") # 保存圖片
    plt.show()

x = (40 - 15) * np.random.rand(100) + 15
y = (25 - 5) * np.random.rand(100) - 5
z = (15 - 4) * np.random.rand(100) + 4
plot_scatter_3d('測試圖', x, y, z)

2)三維空間中的線

#-*- coding:utf-8 -*-
import matplotlib as mpl
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np

# 正常顯示中文
plt.rcParams['font.sans-serif']=['SimHei']
# 正常顯示負號
plt.rcParams['axes.unicode_minus']=False 

def plot_line_3d(title, x, y, z):
    '''
    繪製3D折線圖
    '''
    fig = plt.figure(figsize=(16, 10)dpi= 80) # 創建一個畫板
    ax = Axes3D(fig)
    ax.plot(xs=x,
            ys=y, 
            zs=z, 
            c='r',  # 顏色
            label='parametric curve' # 標籤
            )

    # 設置座標軸顯示以及旋轉角度
    ax.set_xlabel('x'fontsize=16)
    ax.set_ylabel('y'fontsize=16)
    ax.set_zlabel('z'fontsize=16)
    ax.view_init(elev=10, azim=235)

    plt.title(title, fontsize=22)
    plt.grid(False)   # 是否顯示網格
    ax.set_aspect('equal')  # 座標軸間比例一致
    ax.legend(loc='upper left'fontsize=16)
    # plt.savefig("./"+title+".png") # 保存圖片
    plt.show()

z = np.linspace(-2, 2, 100) 
r = np.linspace(-2, 2, 100) ** 2 + 1
x = r * np.sin(np.linspace(-8 * np.pi, 8 * np.pi, 100))  # [-5,5]
y = r * np.cos(np.linspace(-8 * np.pi, 8 * np.pi, 100))  # [-5,5]
plot_line_3d('測試圖', x, y, z)

3)三維空間中的面

#-*- coding:utf-8 -*-
import matplotlib as mpl
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np

# 正常顯示中文
plt.rcParams['font.sans-serif']=['SimHei']
# 正常顯示負號
plt.rcParams['axes.unicode_minus']=False 

def plot_surface_3d(title, x, y, z):
    '''
    繪製3D曲面圖
    '''
    fig = plt.figure(figsize=(16, 10)dpi= 80) # 創建一個畫板
  nbsp;  ax = Axes3D(fig)
    ax.plot_surface(X=x, 
                    Y=y, 
                    Z=z
                    )

    # 設置座標軸顯示以及旋轉角度
    ax.set_xlabel('x'fontsize=16)
    ax.set_ylabel('y'fontsize=16)
    ax.set_zlabel('z'fontsize=16)
    ax.view_init(elev=10, azim=235)

    plt.title(title, fontsize=22)
    plt.grid(False)   # 是否顯示網格
    ax.set_aspect('equal')  # 座標軸間比例一致
    # plt.savefig("./"+title+".png") # 保存圖片
    plt.show()

# 生成[-5,5]間隔0.25的數列,間隔越小,曲面越平滑
x = np.arange(-5, 5, 0.25)    
y = np.arange(-5, 5, 0.25)
# 格點矩陣,原來的x行向量向下複製len(y)次,形成len(y)*len(x)的矩陣,即爲新的x矩陣;
# 原來的y列向量向右複製len(x)次,形成len(y)*len(x)的矩陣,即爲新的y矩陣;新的x矩陣和新的y矩陣shape相同
x, y = np.meshgrid(x,y)
r = np.sqrt(x ** 2 + y ** 2)
z = np.sin(r)
plot_surface_3d('測試圖', x, y, z)

4)三維空間中的體

#-*- coding:utf-8 -*-
import matplotlib as mpl
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
from mpl_toolkits.mplot3d.art3d import Poly3DCollection, Line3DCollection

# 正常顯示中文
plt.rcParams['font.sans-serif']=['SimHei']
# 正常顯示負號
plt.rcParams['axes.unicode_minus']=False 

def plot_body_3d(title, verts, faces):
    '''
    繪製3D實體圖
    '''
    fig = plt.figure(figsize=(16, 10)dpi= 80) # 創建一個畫板
    ax = Axes3D(fig)

    # 獲得每個面的頂點
    poly3d = [[verts[vert_id] for vert_id in face] for face in faces]
    # 繪製頂點
    x, y, z = zip(*verts)
    ax.scatter(x, y, z)

    # 繪製多邊形面
    ax.add_collection3d(Poly3DCollection(poly3d, facecolors='w'linewidths=1, alpha=0.3))
    # 繪製多邊形的邊
    ax.add_collection3d(Line3DCollection(poly3d, colors='k'linewidths=0.5, linestyles=':'))

    # 設置座標軸顯示以及旋轉角度
    ax.set_xlabel('x'fontsize=16)
    ax.set_ylabel('y'fontsize=16)
    ax.set_zlabel('z'fontsize=16)
    ax.view_init(elev=10, azim=235)

    plt.title(title, fontsize=22)
    plt.grid(False)   # 是否顯示網格
    ax.set_aspect('equal')  # 座標軸間比例一致
    # plt.savefig("./"+title+".png") # 保存圖片
    plt.show()

# 六面體頂點和麪
verts = [(0, 0, 0)(0, 1, 0)(1, 1, 0)(1, 0, 0)(0, 0, 1)(0, 1, 1)(1, 1, 1)(1, 0, 1)]
faces = [[0, 1, 2, 3][4, 5, 6, 7][0, 1, 5, 4][1, 2, 6, 5][2, 3, 7, 6][0, 3, 7, 4]]

# 四面體頂點和麪
# verts = [(0, 0, 0), (1, 0, 0), (1, 1, 0), (1, 0, 1)]
# faces = [[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]]

plot_body_3d('測試圖', verts, faces)

五. 高級封裝

seaborn 是對 matplotlib 更高級的 API 封裝,讓你能用更少的代碼去調用 matplotlib 的方法,從而使得作圖更加容易。

5.1 分佈圖

1)核密度估計圖

單變量核密度估計圖:

import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np

mean, cov = [0, 2][(1, .5)(.5, 1)]
x, y = np.random.multivariate_normal(mean, cov, size=50).T

sns.kdeplot(x,
            shade=True, 
            shade_lowest=False)

plt.show()

代碼片段:可切換語言,無法單獨設置文字格式

雙變量核密度估計圖:

import imp
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
from sklearn.datasets import load_iris

iris = load_iris()
d = pd.DataFrame(iris.data, columns=["sepal_length","sepal_width","petal_length","petal_width"])
d["species"] = iris.target

d.loc[d["species"]==0, "species"] = "setosa"  # 把類別這一列數值爲0的替換爲setosa
d.loc[d["species"]==1, "species"] = "versicolor"  # 把類別這一列數值爲1的替換爲versicolor
d.loc[d["species"]==2, "species"] = "virginica"  # 把類別這一列數值爲2的替換爲virginica

sns.kdeplot(d.sepal_length[d.species=="setosa"], 
            d.sepal_width[d.species=="setosa"],
            cmap="Reds", 
            shade=True, 
            shade_lowest=False)
sns.kdeplot(d.sepal_length[d.species=="versicolor"], 
            d.sepal_width[d.species=="versicolor"],
            cmap="Blues", 
            shade=True, 
            shade_lowest=False)
plt.show()

2)聯合分佈圖
聯合概率分佈簡稱聯合分佈,是兩個及以上隨機變量組成的隨機向量的概率分佈。

import imp
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
from sklearn.datasets import load_iris

iris = load_iris()
d = pd.DataFrame(iris.data, columns=["sepal_length","sepal_width","petal_length","petal_width"])
d["species"] = iris.target

d.loc[d["species"]==0, "species"] = "setosa"  # 把類別這一列數值爲0的替換爲setosa
d.loc[d["species"]==1, "species"] = "versicolor"  # 把類別這一列數值爲1的替換爲versicolor
d.loc[d["species"]==2, "species"] = "virginica"  # 把類別這一列數值爲2的替換爲virginica

sns.jointplot(d.sepal_length, 
              d.sepal_width,
              data=d,
              kind='kde',  # scatter|reg|resid|kde|hex
              dropna=True)
plt.show()

3)變量關係組圖

變量關係組圖非常有用,人們經常用它來查看多個變量之間的聯繫。

import imp
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
from sklearn.datasets import load_iris

iris = load_iris()
d = pd.DataFrame(iris.data, columns=["sepal_length","sepal_width","petal_length","petal_width"])
d["species"] = iris.target

d.loc[d["species"]==0, "species"] = "setosa"  # 把類別這一列數值爲0的替換爲setosa
d.loc[d["species"]==1, "species"] = "versicolor"  # 把類別這一列數值爲1的替換爲versicolor
d.loc[d["species"]==2, "species"] = "virginica"  # 把類別這一列數值爲2的替換爲virginica

sns.pairplot(d, hue="species")
plt.show()

seaborn 分佈數據可視化:
https://blog.csdn.net/qq_42554007/article/details/82625118

5.2 迴歸圖

簡單線性迴歸的模型非常容易擬合。

import imp
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
from sklearn.datasets import load_iris

iris = load_iris()
d = pd.DataFrame(iris.data, columns=["sepal_length","sepal_width","petal_length","petal_width"])
d["species"] = iris.target

d.loc[d["species"]==0, "species"] = "setosa"  # 把類別這一列數值爲0的替換爲setosa
d.loc[d["species"]==1, "species"] = "versicolor"  # 把類別這一列數值爲1的替換爲versicolor
d.loc[d["species"]==2, "species"] = "virginica"  # 把類別這一列數值爲2的替換爲virginica

sns.lmplot(x="sepal_length",
           y="sepal_width",
           data=d[d.species == "setosa"])
plt.show()

多項式迴歸模型可以擬合數據集中的一些簡單的非線性趨勢。

import imp
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
from sklearn.datasets import load_iris

iris = load_iris()
d = pd.DataFrame(iris.data, columns=["sepal_length","sepal_width","petal_length","petal_width"])
d["species"] = iris.target

d.loc[d["species"]==0, "species"] = "setosa"  # 把類別這一列數值爲0的替換爲setosa
d.loc[d["species"]==1, "species"] = "versicolor"  # 把類別這一列數值爲1的替換爲versicolor
d.loc[d["species"]==2, "species"] = "virginica"  # 把類別這一列數值爲2的替換爲virginica

sns.lmplot(x="sepal_length",
           y="sepal_width", 
           hue="species", 
           data=d,
           order=2, # 二階多項式
           ci=None, 
           scatter_kws={"s": 80})
plt.show()

5.3  矩陣圖

1)熱圖

import imp
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
from sklearn.datasets import load_iris

iris = load_iris()
d = pd.DataFrame(iris.data, columns=["sepal_length","sepal_width","petal_length","petal_width"])
d["species"] = iris.target

d.loc[d["species"]==0, "species"] = "setosa"  # 把類別這一列數值爲0的替換爲setosa
d.loc[d["species"]==1, "species"] = "versicolor"  # 把類別這一列數值爲1的替換爲versicolor
d.loc[d["species"]==2, "species"] = "virginica"  # 把類別這一列數值爲2的替換爲virginica

sns.heatmap(d.corr(), 
            xticklabels=d.corr().columns, 
            yticklabels=d.corr().columns, 
            cmap='RdYlGn', 
            center=0, 
            annot=True)

plt.show()

2)聚類圖

import imp
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
from sklearn.datasets import load_iris

iris = load_iris()
d = pd.DataFrame(iris.data, columns=["sepal_length","sepal_width","petal_length","petal_width"])

sns.clustermap(d)

plt.show()
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/m9xunyxfzDwBxmxXDsorVw