Python圖表庫Matplotlib 組成部分介紹

圖表有很多個組成部分,例如標題、x/y軸名稱、大刻度小刻度、線條、數據點、注釋說明等等。

我們來看官方給的圖,圖中標出了各個部分的英文名稱

anatomy.png

Matplotlib提供了很多api,開發者可根據需求訂製圖表的樣式。
前面我們設置了標題和x/y軸的名稱,本文介紹更多設置其他部分的方法。

繪圖

先繪製一個事例圖。然後以此為基礎進行訂製。

def demo2():
    x_list = []
    y_list = []
    for i in range(0, 365):
        x_list.append(i)
        y_list.append(math.sin(i * 0.1))
    ax = plt.gca()
    ax.set_title('rustfisher.com mapplotlib example')
    ax.set_xlabel('x')
    ax.set_ylabel('y = sin(x)')
    ax.grid()
    plt.plot(x_list, y_list)
    plt.show()


if __name__ == '__main__':
    print('rustfisher 圖表講解')
    demo2()

運行得到
figure-ax.png

紅色框框里的是figure;綠色框框里的叫做ax。
程式碼中ax = plt.gca()獲取到的就是綠色框框里的部分(對象)。

Figure 大圖

Figure代表整張圖,暫時稱為「全圖」或者「大圖」。一張圖裡可以有多個子圖表。最少必須要有一個圖表。像上面那樣。

Axes 數據圖

一張張的圖,圖裡顯示著數據,暫稱為「數據圖」。一個大圖裡可以有多個數據圖。但單個數據圖對象只能在1個大圖裡。

多張數據圖 subplots

例如同時存在2個數據圖
subplot1-2.png

def demo_subplot():
    x_list = []
    y_list = []
    y2_list = []
    for i in range(0, 365):
        x_list.append(i)
        y_list.append(math.sin(i * 0.1))
        y2_list.append(math.cos(i * 0.1))
    fig, (ax1, ax2) = plt.subplots(2)
    ax1.set_title('rustfisher.com 1')
    ax2.set_title('rustfisher.com 2')
    ax1.set_xlabel('x')
    ax1.set_ylabel('y = sin(x)')
    ax2.set_xlabel('x')
    ax2.set_ylabel('y = cos(x)')
    ax1.plot(x_list, y_list)
    ax2.plot(x_list, y2_list)
    plt.show()

調用subplots()介面,傳入數字指定要多少張數據圖。
返回的多張圖要用括弧括起來。每個數據圖可以繪製(plot)不同的數據。
標題用set_title()來設置。

可以看到上下兩張圖太擠了,有重疊部分。可以在plt.show()之前加一個fig.tight_layout()讓它們拉開一點距離。
subplot1-2-tight.png

坐標軸

對於2維數據圖,它有2個坐標,橫坐標和縱坐標。有一些介面可以設置參數。
例如控制坐標軸的名字set_xlabel() set_ylabel

顯示數據範圍

set_xlim方法可以控制x軸數據顯示範圍。同理y軸用set_ylim來控制。
對於顯示範圍,set_xlim方法主要參數為leftright;或者用xmin xmax。這兩套不能同時使用。
set_ylim主要參數是top bottom;或者ymin ymax。這兩套不能同時使用。

增加顯示範圍控制的程式碼

def demo3():
    x_list = []
    y_list = []
    y2_list = []
    for i in range(0, 365):
        x_list.append(i)
        y_list.append(math.sin(i * 0.1))
        y2_list.append(math.cos(i * 0.1))
    fig, (ax1, ax2) = plt.subplots(2)
    ax1.set_title('rustfisher.com 1')
    ax1.set_xlabel('x')
    ax1.set_ylabel('y = sin(x)')
    ax2.set_title('rustfisher.com 2')
    ax2.set_xlabel('x')
    ax2.set_ylabel('y = cos(x)')

    ax1.set_xlim(left=50, right=200.6)  # 控制x軸顯示範圍
    ax1.set_ylim(top=1, bottom=0.3)  # 控制y軸顯示範圍

    ax2.set_xlim(xmin=1, xmax=156.6)  # 控制x軸顯示範圍
    ax2.set_ylim(ymin=-0.3, ymax=0.3)  # 控制y軸顯示範圍

    ax1.plot(x_list, y_list)
    ax2.plot(x_list, y2_list)
    fig.tight_layout()
    plt.show()

運行結果
xylim.png

刻度

tick意思是標記。在坐標軸上的是刻度。Major tick暫稱為大刻度,minor tick暫稱為小刻度。
使用set_xticks方法控制刻度顯示。傳入的列表是我們希望顯示的刻度。
minor參數默認為False,不顯示小刻度。

關鍵程式碼如下

ax1.set_xticks([50, 60, 70, 150])
ax1.set_yticks([0.1, 0.2, 0.3, 0.7, 0.9])
ax1.grid()  # 顯示格子

ax2.set_xticks([1, 60, 70, 150], minor=True)
ax2.set_yticks([-0.1, 0, 0.1, 0.3], minor=True)
ax2.grid()

可見當minor=True,傳入的刻度列表有可能不顯示。

也可以控制大刻度上的文字旋轉

    plt.setp(ax1.xaxis.get_majorticklabels(), rotation=-45)
    plt.setp(ax2.xaxis.get_majorticklabels(), rotation=-60)

邊線 spine

spine是脊柱的意思,這裡我們先稱為邊線。有上下左右4條邊線。名稱是top bottom left right
可以直接從圖表對象獲取它的邊線,比如右邊線ax1.spines.right

一些簡單的操作,例如

  • set_visible 顯示和隱藏
  • set_ticks_position 刻度顯示的位置
  • set_bounds 邊線顯示範圍
  • set_linewidth 線的寬度

隱藏右邊線和上邊線

ax1.spines.right.set_visible(False)
ax1.spines.top.set_visible(False)

讓刻度顯示在右邊和上方

ax2.yaxis.set_ticks_position('right')
ax2.xaxis.set_ticks_position('top')

設置邊線顯示範圍

ax3.spines.left.set_bounds(-0.5, 0.5)
ax3.spines.top.set_bounds(340, 400)

設置線的寬度

ax3.spines.bottom.set_linewidth(2)

完整程式碼如下

import math
import matplotlib.pyplot as plt

def demo_spine():
    x_list = []
    y_list = []
    for i in range(0, 365):
        x_list.append(i)
        y_list.append(math.sin(i * 0.1))

    fig, (ax1, ax2, ax3) = plt.subplots(3)
    ax_list = [ax1, ax2, ax3]
    for i in range(0, 3):
        cur_ax = ax_list[i]
        cur_ax.set_title('rustfisher.com ' + str(i))
        cur_ax.plot(x_list, y_list)
        cur_ax.set_xlabel('x')
        cur_ax.set_ylabel('y = sin(x)')

    ax1.spines.right.set_visible(False)
    ax1.spines.top.set_visible(False)

    ax2.spines.bottom.set_visible(False)
    ax2.spines.left.set_visible(False)
    ax2.yaxis.set_ticks_position('right')
    ax2.xaxis.set_ticks_position('top')

    ax3.spines.left.set_bounds(-0.5, 0.5)
    ax3.spines.top.set_bounds(340, 400)
    ax3.spines.bottom.set_linewidth(2)

    fig.tight_layout()
    plt.show()

運行截圖

數據點

控制數據點的樣式。下面我們在一張圖表裡繪製多條數據線。

def demo_line():
    x_list = []
    y_list = []
    y2_list = []
    y3_list = []
    for i in range(0, 20):
        x_list.append(i)
        y_list.append(math.sin(i) * 2 - 4)
        y2_list.append(math.sin(i) * 2)
        y3_list.append(math.cos(i) * 1.3 + 3)

    plt.plot(x_list, y_list, color='blue', linestyle='-.', linewidth=2, markersize=4)
    plt.plot(x_list, y2_list, 'go', linewidth=1)
    plt.plot(x_list, y3_list, 'r+')
    plt.show()

plot()方法中,支援多種選項。

linestyle支援的選項
‘-‘, ‘–‘, ‘-.’, ‘:’, ‘None’, ‘ ‘, ”, ‘solid’, ‘dashed’, ‘dashdot’, ‘dotted’

注釋 legend

添加註釋,調用lengend()方法。

在前面程式碼基礎上添加

    plt.plot(x_list, y_list, color='blue', linestyle='-.', linewidth=2, markersize=4)
    plt.plot(x_list, y2_list, 'go', linewidth=1)
    plt.plot(x_list, y3_list, 'r+')
    plt.legend(['math.sin(i) * 2 - 4', 'math.sin(i) * 2', 'math.cos(i) * 1.3 + 3'])

控制注釋顯示的地方,添加bbox_to_anchorbbox_transform屬性

plt.legend(['math.sin(i) * 2 - 4', 'math.sin(i) * 2', 'math.cos(i) * 1.3 + 3'], bbox_to_anchor=(1, 1),
               bbox_transform=plt.gcf().transFigure)

中文亂碼問題

在設置標題用到中文的時候,可能會出現亂碼。
可以設置rcParams的字體,解決亂碼問題。

plt.rcParams['font.sans-serif'] = ['Arial Unicode MS']

至此,我們把圖表中各個部分都簡要介紹了一下。

參考

本例環境

  • macOS
  • PyCharm CE
  • Python3

參考資料

Tags: