1. 程式人生 > >Python繪圖—Matplotlib教程(詳細版)前半部分

Python繪圖—Matplotlib教程(詳細版)前半部分

一直將matplotlib當做一個工具來用,因為沒有了解到它的特性,所以一直學得不繫統,導致用到的時候經常要查官方文件。這裡翻譯一個官方推薦的matplotlib的介紹文件。
猛戳進入原文連結
文件中包含的內容:

  1. 簡介
  2. 簡單的例子
  3. matplotlib元件(Figures, Subplots, Axes and Ticks)
  4. 動畫
  5. 其他的繪圖型別
  6. 補充

該部落格只翻譯123小節,下一篇部落格介紹下面的

你可以點選圖片上面的原始碼超連結獲取當前圖形的程式碼。這些連結也是原英文文件的作者提供的。

簡介

matplotlib可能是最常用的2D繪圖Python包了。它可以對Python中的資料進行快速的視覺化,並以多種格式輸出。接下來,我們將以互動的方式介紹matplotlib中的大多數情況

pyplot

在matplotlib面向物件的繪相簿中,pyplot是一個方便的介面。

簡單的例子

在這一章,我們想在一個圖中畫一個cosine函式和一個sine函式。對於畫圖時的細節,我們先讓它預設,然後再一步一步按自己的要求豐富figure,讓它變得更visible。
首先,由sine函式和cosine函式獲取資料

import numpy as np
X = np.linspace(-np.pi, np.pi, 256, endpoint=True)
C, S = np.cos(X), np.sin(X)

其中,np.linspace(...)的意思是從-

π到+π均勻的取256個點(包括最後一個點-π)。至此,C就是一個由256個點組成的cosine函式,而S是一個由256個點組成的sine函式。

使用預設值

為了方便起見,matplotlib給出了很多預設設定。 你幾乎可以控制所有matplotlib中提供的屬性值:figure大小和畫素,line的寬度、顏色和樣式,axes,axis和grid屬性,文字和字型屬性等等。儘管大多數情況下,matplotlib的預設值都足夠好了,但在某些情況下,你可能還是想用自己的方式修飾這些屬性。
原始碼和結果如下所示:

import numpy as np
import matplotlib.pyplot
as plt X = np.linspace(-np.pi, np.pi, 256, endpoint=True) C,S = np.cos(X), np.sin(X) plt.plot(X,C) plt.plot(X,S) plt.show()

Using defaults

初始化預設值

在下面的指令碼中,我們初始化一些引數。下面修改的引數實際上與預設值是一樣的,但你可以通過修改這些引數,觀察結果圖形的變化。
原始碼和結果如下所示:

# 模組匯入
import numpy as np
import matplotlib.pyplot as plt

# 建立一個8x6大小的figure,並設定每英寸80個畫素點
plt.figure(figsize=(8, 6), dpi=80)

# 建立在1x1的位置建立一個subplot
plt.subplot(111)

X = np.linspace(-np.pi, np.pi, 256, endpoint=True)
C, S = np.cos(X), np.sin(X)

# 繪製cosine函式,顏色是藍色,line寬為1.0,line型別是實線
plt.plot(X, C, color='blue', linewidth=1.0, linestyle='-')

# 繪製sine函式,顏色是綠色,line寬為1.0,line型別是實線
plt.plot(X, S, color='green', linewidth=1.0, linestyle='-')

# 設定x軸和y軸範圍
plt.xlim(-4.0, 4.0)
plt.ylim(-1.0, 1.0)

# 設定x軸下標和y軸下標
plt.xticks(np.linspace(-4, 4, 9, endpoint=True))
plt.yticks(np.linspace(-1, 1, 5, endpoint=True))

# 儲存圖片,每英寸72個點
# 如果此處報錯,在當前路徑下建立figures資料夾
# savefig("../figures/exercice_2.png", dpi=72)

# 在螢幕上顯示結果
plt.show()

instantiating defaults

修改顏色和line寬度

將cosine函式改成藍色,sine函式改成紅色,將它們的line加寬為2.5,同時也修改了figure的大小,使圖形的比例看起來更好。
原始碼和結果如下所示:

plt.figure(figsize=(10, 6), dpi=80)
plt.plot(X, C, color='blue', linewidth=2.5, linestype='-')
plt.plot(X, S, color="red",  linewidth=2.5, linestyle="-")

changing colors and line widths

設定座標軸範圍

改變了x軸和y軸的範圍,讓圖形看起來既完整又緊緻。
原始碼:和結果如下所示

plt.xlim(X.min() * 1.1, X.max() * 1.1)
plt.ylim(C.min() * 1.1, C.max() * 1.1)

Setting limits

設定座標軸下標

當前的座標軸下標並不理想,因為它們沒有標出我們感興趣的點-π/2和+π/2
原始碼和結果如下所示:

plt.xticks( [-np.pi, -np.pi/2, 0, np.pi/2, np.pi])
plt.yticks([-1, 0, +1])

Setting ticks

設定座標軸下標名

座標軸的下標的位置現在很理想,但是它的名字(也就是表現形式)不應該是3.142,最好是π注意matplotlib的座標軸的下標包括位置(location)和名字(label)兩部分。現在,我們利用latex來命名下標。
原始碼和結果如下所示:

# r''是為了轉義裡面的轉義字元\
plt.xticks([-np.pi, -np.pi/2, 0, np.pi/2, np.pi], [r'$-\pi$', r'$-\pi/2$', r'$0$', r'$+\pi/2$', r'$+\pi$'])
plt.yticks([-1, 0, +1], [r'$-1$', r'$0$', r'$+1$'])

Setting tick labels

移動 spines

spines包括圖片上下左右4條邊界和它們的下標,就是正方形的4條邊。它們可以被挪到任意的位置,現在,它們還在邊界上。我們要把它們移到中間。首先,將上邊界和右邊界的顏色設定為none,就隱藏了。然後我們將下邊界和左邊界移動到資料空間的0處。
原始碼和結果如下所示:

# plt.gca()獲取當前ax
ax = plt.gca()
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
# set_position中的引數元組的第二個值可取-1,0,1分別代表相對‘data’的不同的位置
ax.spines['bottom'].set_position(('data', 0))
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data', 0))

Moving spines

新增legend

legend就是如下圖所示的東西。這個需要調整兩點:一個是引數label,一個是plot命令plt.legend()
原始碼和結果如下所示:

plt.plot(X, C, color="blue", linewidth=2.5, linestyle="-", label="cosine")
plt.plot(X, S, color="red",  linewidth=2.5, linestyle="-", label="sine")
# frameon=True的話,右上角的宣告會在一個框內
plt.legend(loc='upper left', frameon=False)

Adding a legend

標記一些點

讓我們來用plt.annotate()命令來標記一些感興趣的點。我們選了2π/3點來標記它在sine和cosine函式上的值。首先,繪製一個點和虛線。然後我們用annotate命令新增文字和箭頭上去。
原始碼和結果如下所示:

t = 2*np.pi/3
plt.plot([t,t],[0,np.cos(t)], color ='blue', linewidth=1.5, linestyle="--")
plt.scatter([t,],[np.cos(t),], 50, color ='blue')
# 第一個引數s為要標記上去的文字
# 第二個引數xy為標記的位置,必須是可迭代物件(如tuple,list)
# 第三個物件xycoords表示xy的參考系
# 第四個物件xytext為標記文字相對標記位置的位置,必須是可迭代物件iterabl
# 第五個物件textcoords表示xytext的參考系
# 第六個物件fontsize為字型大小
# 第七個物件arrowprops為箭頭樣式
plt.annotate(r'$\sin(\frac{2\pi}{3})=\frac{\sqrt{3}}{2}$', xy=(t, np.sin(t)), xycoords='data', xytext=(+10, +30), textcoords='offset points', fontsize=16, arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=.2"))

plt.plot([t,t],[0,np.sin(t)], color ='red', linewidth=1.5, linestyle="--")
plt.scatter([t,],[np.sin(t),], 50, color ='red')

plt.annotate(r'$\cos(\frac{2\pi}{3})=-\frac{1}{2}$', xy=(t, np.cos(t)), xycoords='data', xytext=(-90, -50), textcoords='offset points', fontsize=16, arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=.2"))

Annotate some points

細節決定成敗

labels現在被紅線和藍線擋住了。我們可以把label的字條調大,讓紅藍線變成半透明的。
原始碼和結果如下所示:

for label in ax.get_xticklabels() + ax.get_yticklabels():
    label.set_fontsize(16)
    label.set_bbox(dict(facecolor='white', edgecolor='None', alpha=0.65))

Devil is in the details

matplotlib元件

到目前為止,我們使用的都是直接了當的單一figure和axes。這可以幫我們方便快速的繪圖。此外,我們還可以使用figure,subplot和axes創造更多的佈局。figure是matplotlib中面向使用者的最大的介面,figure裡面是subplots。subplot指定plots在figure中的位置,axes就是被指定位置後的的plots,這些都可以按照你的意願來佈局。我們之前的程式碼都沒有宣告它們。如果我們要呼叫plot,gca()獲取當前axes,gcf()獲取當前figure。如果沒有當前figure,就建立一個並返回。

Figures

一個figure就是一個在GUI中名為“Figure#”的一個視窗,它的計數是從1開始的,跟普通的Python計數方式不同,而是MATLAB的計數風格。下面是幾個定義figure外形的引數。

引數 預設值 描述
num 1 figure編號
figsize figure.figsize figure長和寬
dpi figure.dpi 畫素
facecolor figure.facecolor 背景顏色
edgecolor figure.edgecolor 邊緣顏色
frameon True 邊框有無

大多數情況下,figure都是使用預設值,只有num引數才會經常改動。
如果你是以GUI的形式工作,可以點選右上角的x關閉figure,也可以通過呼叫函式關閉figure,如plt.close()。無引數表示關閉當前figure,有引數int表示關閉特定figure,還可以通過修改引數關閉所有figure。
figure物件和其他物件一樣,可以通過set_型別的函式修改引數。

Subplots

subplot是用來佈局plots的,需要指定(行、列、序號)。
點選獲取原始碼,效果圖如下:
Subplots
點選獲取原始碼,效果圖如下:
Subplots
點選獲取原始碼,效果圖如下:
Subplots
點選獲取原始碼,效果圖如下:
Subplots

Axes

Axes和subplots很像,但它可以佈局在figure的任意位置。所以如果我們想把一個小plot放在一個大plot裡面,應該採用Axes。
點選獲取原始碼,效果圖如下:
Axes
點選獲取原始碼,效果圖如下:
Axes

Ticks

合適的ticks對於圖片的繪製非常重要。matplotlib提供了一個完整的ticks配置系統,tick locators表明ticks應該處於什麼位置;tick formatters可以提供要展示的tick名字。major ticks和minor ticks是相互獨立的。因為沒有位置資訊,每一個預設的minor ticks是不顯示的,它們只是一個空列表。

Tick Locators

下面是不同的位置資訊:

Class Description
NullLocator 沒有ticks 圖一
IndexLocator 對每一個重要繪圖點都設定一個tick 圖二
FixedLocator 靈活的ticks 圖三
LinearLocator 線性ticks 圖四
MultipleLocator 對每一個繪圖點都設定一個tick 圖五
AutoLocator 選擇不多於n個比較好的ticks 圖六
LogLocator log型別的ticks 圖七

1. NullLocator
2. IndexLocator
3. FixedLocator
4. LinearLocator
5. MultipleLocator
6. AutoLocator
7. LogLocator
所有這些定位器都從基類matplotlib.ticker.Locator派生。 你可以製作自己的定位器。 處理日期作為ticks可能是特別棘手的。 因此,matplotlib在matplotlib.dates中提供了特殊的定位器。