[Python] Matplotlib 圖表的繪製和美化技巧

哆啦夢樂園發表於2021-02-20

在一張畫布中繪製多個圖表

Matplotlib模組在繪製圖表時,預設先建立一張畫布,然後在畫布中顯示繪製的圖表。

如果想要在一張畫布中繪製多個圖表,可以使用subplot()函式將畫布劃分為幾個區域,然後在各個區域中分別繪製不同的圖表。

subplot()函式的引數為3個整型數字:

  • 第1個數字代表將整張畫布劃分為幾行;
  • 第2個數字代表將整張畫布劃分為幾列;
  • 第3個數字代表要在第幾個區域中繪製圖表,區域的編號規則是按照從左到右、從上到下的順序,從1開始編號。

演示程式碼如下:

import matplotlib.pyplot as plt

# 如果值中有中文字元,則必須在繪製圖表前加上這兩行程式碼
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
x = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']
y = [50, 45, 65, 76, 75, 85, 55, 78, 86, 89, 94, 90]
plt.subplot(2, 2, 1)
plt.pie(y, labels = x, labeldistance = 1.1, startangle = 90, counterclock = False)
plt.subplot(2, 2, 2)

# 引數width用於設定柱子的寬度,預設值為0.8。如果設定為1,則各個柱子會緊密相連;如果設定為大於1的數,則各個柱子會相互交疊
plt.bar(x, y, width = 0.5, color = 'r')
plt.subplot(2, 2, 3)

# 引數color用於設定柱子的填充顏色,具體取值見後面的說明
plt.stackplot(x, y, color = 'r')
plt.subplot(2, 2, 4)
plt.plot(x, y, color = 'r', linestyle = 'solid', linewidth = 2, marker = 'o', markersize = 10)
plt.show()

輸出結果:

用顏色名的英文單詞或其簡寫定義的8種基礎顏色,具體見:

加圖表元素

import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
x = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']
y = [50, 45, 65, 76, 75, 85, 55, 78, 86, 89, 94, 90]

# 這裡加了標籤
plt.bar(x, y, width=0.6, color='r', label='銷售額(萬元)')

# 這裡加了標題,loc還可以是right和left
plt.title(label='銷售額對比圖', fontdict={'family': 'KaiTi', 'color': 'k', 'size': 30}, loc='center')

# 座標上的標籤
plt.xlabel('月份', fontdict={'family': 'SimSun', 'color': 'k', 'size': 20}, labelpad=20)  
plt.ylabel('銷售額', fontdict={'family': 'SimSun', 'color': 'k', 'size': 20}, labelpad=20)  

# legend()函式用於新增圖例
plt.legend(loc='upper left', fontsize=15)

# zip() 函式用於將可迭代的物件作為引數,將物件中對應的元素打包成一個個元組,然後返回由這些元組組成的列表。
for a,b in zip(x, y):
    # text()函式的功能是在圖表座標系的指定位置新增文字。引數ha是horizontalalignment的簡稱,相對應有va
    plt.text(x=a, y=b, s=b, ha='center', va='bottom', fontdict={'family': 'KaiTi', 'color': 'k', 'size': 20})
plt.show()

輸出結果

氣泡圖

氣泡圖是一種展示三個變數之間關係的圖表,它其實是在散點圖的基礎上升級改造而成的,在原有的x座標和y座標兩個變數的基礎上,引入第三個變數,並用氣泡的大小表示。

pip install openpyxl

產品銷售統計.xls 內容

產品名稱 銷售量(件) 銷售額(元) 毛利率(%)
牛仔褲 125 6800 30
連衣裙 278 5600 20
運動褲 366 7800 35
短褲 452 5800 10
短裙 365 5400 50
揹帶褲 258 10000 22
半身裙 369 3600 15
闊腿褲 566 7800 8

程式碼如下:

import matplotlib.pyplot as plt
import pandas as pd
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
data = pd.read_excel('產品銷售統計.xls')
n = data['產品名稱']
x = data['銷售量(件)']
y = data['銷售額(元)']
z = data['毛利率(%)']
plt.scatter(x, y, s=z * 300, color='r', marker='o')
plt.xlabel('銷售量(件)', fontdict={'family': 'Microsoft YaHei', 'color': 'k', 'size': 20}, labelpad=20)
plt.ylabel('銷售額(元)', fontdict={'family': 'Microsoft YaHei', 'color': 'k', 'size': 20}, labelpad=20)
plt.title('銷售量、銷售額與毛利率關係圖', fontdict={'family': 'Microsoft YaHei', 'color': 'k', 'size': 30}, loc='center')
for a, b, c in zip(x, y, n):
    plt.text(x=a, y=b, s=c, ha='center', va='center', fontsize=15, color='w')
plt.xlim(50, 600)
plt.ylim(2900, 11000)
plt.show()

輸出結果:

組合圖

組合圖是指在一個座標系中繪製多張圖表,其實現方式也很簡單,在使用Matplotlib模組中的函式繪製圖表時設定多組y座標值即可。

銷售業績表.xls

月份 銷售額(萬元) 同比增長率
1月 ¥36.00 10%
2月 ¥25.00 8%
3月 ¥36.12 20%
4月 ¥69.30 50%
5月 ¥26.90 15%
6月 ¥32.00 11%
7月 ¥45.00 26%
8月 ¥56.00 13%
9月 ¥25.60 4%
10月 ¥36.21 5%
11月 ¥25.00 7%
12月 ¥59.00 30%
import pandas as pd
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
data = pd.read_excel('銷售業績表.xlsx')
x = data['月份']
y1 = data['銷售額(萬元)']
y2 = data['同比增長率'] 
plt.bar(x, y1, color = 'c', label = '銷售額(萬元)')  
plt.legend(loc = 'upper left', fontsize = 15)  

# 使用twinx()函式為圖表新增次座標軸
plt.twinx()  
plt.plot(x, y2, color = 'r', linewidth = 3, label = '同比增長率')  
plt.legend(loc = 'upper right', fontsize = 15)  
plt.show()

輸出結果:

直方圖

直方圖用於展示資料的分佈情況,使用Matplotlib模組中的hist()函式可以繪製直方圖

客戶年齡統計表.zip

import pandas as pd
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
data = pd.read_excel('客戶年齡統計表.xlsx')
x = data['年齡']
plt.hist(x, bins = 9)
plt.xlim(15, 60)
plt.ylim(0, 40)
plt.title('年齡分佈直方圖', fontsize = 20)
plt.xlabel('年齡')
plt.ylabel('人數')
plt.grid(b = True, linestyle = 'dotted', linewidth = 1)
plt.show()

輸出結果

雷達圖

雷達圖可以同時比較和分析多個指標。該圖表可以看成一條或多條閉合的折線,因此,使用繪製折線圖的plot()函式也可以繪製雷達圖。

汽車效能指標分值統計表.xlsx

效能評價指標 A品牌 B品牌 C品牌
動力性 1 3 10
燃油經濟性 2 6 7
制動性 1 10 5
操控穩定性 3 10 2
行駛平順性 2 6 1
通過性 4 7 2
安全性 8 2 1
環保性 9 1 3
方便性 10 3 0
舒適性 8 2 1
經濟性 4 1 10
容量性 2 2 8

程式碼如下:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']  
plt.rcParams['axes.unicode_minus'] = False 
data = pd.read_excel('汽車效能指標分值統計表.xlsx')

data = data.dropna(axis=1)
data = data.set_index('效能評價指標')
data = data.T
data.index.name = '品牌'

def plot_radar(data, feature):  
    columns = ['動力性', '燃油經濟性', '制動性', '操控穩定性', '行駛平順性', '通過性', '安全性', '環保性', '方便性', '舒適性', '經濟性', '容量性'] 
    colors = ['r', 'g', 'y']

    # 設定雷達圖的角度,用於平分切開一個平面
    # linspace(1,10,x) 建立1-10的等差陣列,個數為 x,預設50個;endpoint引數指定是否包含終值,預設值為True,即包含終值。
    angles = np.linspace(0.1 * np.pi, 2.1 * np.pi, len(columns), endpoint = False)

    # 使雷達圖封閉起來
    angles = np.concatenate((angles, [angles[0]]))

    # figsize:指定figure的寬和高,單位為英寸;    
    figure = plt.figure(figsize = (6, 6))
    
    # 設定為極座標格式;subplot(nrows,ncols,sharex,sharey,subplot_kw,**fig_kw)建立單個子圖,下面兩句效果相同
    ax = figure.add_subplot(111, polar=True)
   # ax = figure.add_subplot(1, 1, 1, projection = 'polar')
    
    for i, c in enumerate(feature):
        stats = data.loc[c]

        stats = np.concatenate((stats, [stats[0]]))

        ax.plot(angles, stats, '-', linewidth = 2, c = colors[i], label = str(c))
        ax.fill(angles, stats, color = colors[i], alpha = 0.75)

    # bbox_to_anchor這個引數,可以把圖例放在圖外面
    # bbox_to_anchor:表示legend的位置,前一個表示左右,後一個表示上下。
    # 當使用這個引數時。loc將不再起正常的作用,ncol=3表示圖例三列顯示。
    ax.legend(loc = 4, bbox_to_anchor = (1.15, -0.07))

    
    #設定極軸範圍
    ax.set_ylim(0,10)
    # ax.set_yticklabels([2, 4, 6, 8, 10])

    # 新增每個特質的標籤
    columns = np.concatenate((columns, [columns[0]]))
    ax.set_thetagrids(angles*180/np.pi, columns, fontsize = 12)

    #新增標題
    plt.title('汽車效能指標雷達圖')

    plt.show()
    return figure
figure = plot_radar(data, ['A品牌', 'B品牌', 'C品牌'])
# figure = plot_radar(data, ['B品牌'])

樹狀圖

樹狀圖通過矩形的面積、排列和顏色直觀地展示多個專案的資料比例關係。要繪製該圖表,需結合使用Matplotlib模組與squarify模組。

import squarify as sf
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
x = ['上海', '北京', '重慶', '成都', '南京', '青島', '長沙', '武漢', '深圳']  
y = [260, 45, 69, 800, 290, 360, 450, 120, 50] 
colors = ['lightgreen', 'pink', 'yellow', 'skyblue', 'cyan', 'silver', 'lightcoral', 'orange', 'violet']
percent = ['11%', '2%', '3%', '33%', '12%', '15%', '18%', '5%', '2%']
chart = sf.plot(sizes = y, label = x, color = colors, value = percent, edgecolor = 'white', linewidth = 2)
plt.title(label = '城市銷售額分佈及佔比圖',fontdict = {'family' : 'KaiTi', 'color' : 'k', 'size' : 25})
plt.axis('off')
plt.show()

箱形圖

箱形圖是一種用於展示資料的分佈情況的統計圖,因形狀如箱子而得名。使用Matplotlib模組中的boxplot()函式可以繪製箱形圖。

資料

日期 成都 上海 北京 重慶 南京
1月1日 25 50 52 25 50
1月2日 12 58 56 26 56
1月3日 26 60 100 78 58
1月4日 23 78 125 45 87
1月5日 18 36 108 46 50
1月6日 15 69 100 50 60
1月7日 19 41 85 53 26
1月8日 20 52 85 61 36
1月9日 26 53 87 87 69
1月10日 27 69 86 25 78
1月11日 28 78 45 16 75
1月12日 54 80 78 69 80
1月13日 50 52 73 68 81
1月14日 51 26 62 45 45
1月15日 52 28 65 40 65
1月16日 36 57 90 50 63
1月17日 38 56 96 60 69
1月18日 45 89 94 36 64
1月19日 40 84 25 52 65
1月20日 41 85 36 54 45
1月21日 26 80 68 58 52
1月22日 29 75 78 56 59
1月23日 36 50 70 52 80
1月24日 33 25 52 57 29
1月25日 31 36 51 69 36
1月26日 15 64 58 54 29
1月27日 18 56 68 25 90
1月28日 25 54 78 36 78
1月29日 14 50 90 78 71
1月30日 39 44 95 56 75
1月31日 48 49 84 25 76
import pandas as pd
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False
data = pd.read_excel('1月銷售統計表.xlsx')
x1 = data['成都']
x2 = data['上海']
x3 = data['北京']
x4 = data['重慶']
x5 = data['南京']
x = [x1, x2, x3, x4, x5]
labels = ['成都', '上海', '北京', '重慶', '南京']

# 引數vert用於設定箱形圖的方向,True表示縱向展示,False表示橫向展示;引數showmeans用於設定是否顯示均值,True表示顯示均值,False表示不顯示均值。
plt.boxplot(x, vert = True, widths = 0.5, labels = labels, showmeans = True )
plt.title('各地區1月銷售額箱形圖', fontsize = 20)
plt.ylabel('銷售額(萬元)')
plt.show()

箱形圖中的5條橫線和1個點所代表的含義如下:

  • 下限:指所有資料中的最小值;
  • 下四分位數:又稱“第一四分位數”,指將所有資料從小到大排列後第25%的值;
  • 中位數:又稱“第二四分位數”,指將所有資料從小到大排列後第50%的值;
  • 上四分位數:又稱“第三四分位數”,指將所有資料從小到大排列後第75%的值;
  • 上限:指所有資料中的最大值;
  • 點:指所有資料的平均值。

玫瑰圖

玫瑰圖可反映多個維度的資料,它將柱形圖轉化為餅圖,在圓心角相同的情況下,以扇面長度展示指標大小。要繪製玫瑰圖,也要用到繪製柱形圖的bar()函式。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']   
plt.rcParams['axes.unicode_minus'] = False

# 將風速的分佈設定為4個區間
index = ['0~0.5', '0.6~2.0', '2.1~4.0', '4.1~6.0']

# 設定了16個方向
columns = ['N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE', 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW']

# seed()函式用於產生相同的隨機數
np.random.seed(0)

# 建立一個4行16列的DataFrame,其中的資料是30~300範圍內的隨機數,行標籤為第6行程式碼設定的風速分佈區間,列標籤為第7行程式碼設定的方向。
data = pd.DataFrame(np.random.randint(30, 300, (4, 16)), index = index, columns = columns)
N = 16

# 生成16個方向的角度值
theta = np.linspace(0, 2 * np.pi, N, endpoint = False)

# 用於計算扇面的寬度
width = np.pi / N 
labels = list(data.columns) 
plt.figure(figsize = (6, 6))
ax = plt.subplot(1, 1, 1, projection = 'polar')
for i in data.index:
    radius = data.loc[i] 
    # 使用bar()函式繪製玫瑰圖中的16根柱子,也就是扇面,引數bottom用於設定每根柱子底部的位置,這裡設定為0.0,表示從圓心開始繪製。
    ax.bar(theta, radius, width = width, bottom = 0.0, label = i, tick_label = labels)

# 設定0°的方向為“N”,即北方
ax.set_theta_zero_location('N') 

# 設定按逆時針方向排列各個柱子
ax.set_theta_direction(-1)    
plt.title('各方向風速頻數玫瑰圖', fontsize = 20)
plt.legend(loc = 4, bbox_to_anchor = (1.3, 0.2)) 
plt.show()

相關文章