Matplotlib可視化及應(yīng)用

一、概述

深度學(xué)習(xí)的一個(gè)重要手段是訓(xùn)練數(shù)據(jù)和訓(xùn)練過(guò)程的可視化,因此,我們關(guān)于深度學(xué)習(xí)的系列介紹文章就從Matplotlib開始。

Matplotlib是一個(gè)在Python下實(shí)現(xiàn)的類MatLab的第三方庫(kù),是Python下最出色的繪圖庫(kù),功能很完善,同時(shí)也繼承了Python簡(jiǎn)單明了的風(fēng)格,它可以很方便地設(shè)計(jì)和輸出二維以及三維的數(shù)據(jù),提供了常規(guī)的笛卡爾坐標(biāo)、極坐標(biāo)、求坐標(biāo)、三維坐標(biāo)等,可以畫普通圖、散點(diǎn)圖、三維圖、等高線圖等。

Matplotlib有各種應(yīng)用,本文的例子主要集中在深度學(xué)習(xí)方面。如果您希望在股票走勢(shì)、報(bào)表分析或其他方面使用Matplotlib,其中使用的繪圖元素會(huì)有稍有不同。

在學(xué)習(xí)Matplotlib過(guò)程中,筆者也感覺(jué)到,Matplotlib有很多值得改進(jìn)的地方。例如,如果Matplotlib能畫出相對(duì)一條線段特定角度的線段,或者能夠?qū)⒁粭l線段延長(zhǎng)特定的長(zhǎng)度,等等,那么它在平面幾何的求解方面一定會(huì)有更大的作用。Matplotlib是一個(gè)完全開源的項(xiàng)目,實(shí)現(xiàn)這些功能是有可能的,當(dāng)然這有賴于有志之士貢獻(xiàn)自己的精力和時(shí)間。

二、一個(gè)簡(jiǎn)單的例子

我們先從一個(gè)簡(jiǎn)單的例子開始。需要說(shuō)明的是,為了讓更多的用戶能夠?qū)嶒?yàn)本文檔中的示例代碼,我們使用Windows下的交互式Python工具Juypter Notebook作為代碼運(yùn)行環(huán)境。Juypter Notebook的安裝過(guò)程可參見其他文檔,假設(shè)您已經(jīng)成功安裝了該軟件,運(yùn)行Anocoda3軟件包中的Juypter Notebook可以看到你如下的界面。

首先,在文本框中輸入以下命令,并點(diǎn)擊Run按鈕。

%matpplotlib inline

%matplotlib命令可以在當(dāng)前的Jupyter

Notebook環(huán)境中啟用繪圖。這個(gè)命令提供一個(gè)可選參數(shù),指定使用哪個(gè)matplotlib后端。一般情況下,我們都使用inline后臺(tái),這將在Jupyter Notebook輸出中直接呈現(xiàn)繪圖。需要了解,這條命令并不是程序代碼的一部分。當(dāng)在Ubuntu的Python環(huán)境下運(yùn)行時(shí),就必須將這一行去掉。

接下來(lái),是實(shí)際的程序代碼:

import numpy as np

import matplotlib.pyplot as plt

x = np.arange(-np.pi, np.pi, np.pi/100)

y = np.sin(x)

plt.plot(x, y)

plt.show()

以上程序的輸出入下圖所示。

語(yǔ)句import numpy as np導(dǎo)入Python的科學(xué)計(jì)算包。Matplotlib 充分利用了Python下的Numeric(Numarray)模塊,提供了一種利用Python進(jìn)行數(shù)據(jù)可視化的解決方案,進(jìn)一步加強(qiáng)了Python用來(lái)進(jìn)行科學(xué)計(jì)算的能力。

語(yǔ)句import matplotlib.pyplot as plt導(dǎo)入matplotlib包中的pyplot模塊。

語(yǔ)句x = np.arange(-np.pi, np.pi, np.pi/100)在從-π到π,以π/100為步進(jìn),生成一個(gè)數(shù)組。換句話說(shuō),在[-π,π)區(qū)間內(nèi),按平均間隔取100個(gè)值,得到一個(gè)數(shù)組。

語(yǔ)句y

= np.sin(x)對(duì)x數(shù)組計(jì)算正弦函數(shù)值,得到是對(duì)應(yīng)長(zhǎng)度的數(shù)組。

語(yǔ)句plt.plot(x,

y)調(diào)用pyplot模塊的plot函數(shù),傳入x和y數(shù)組。這個(gè)函數(shù)會(huì)用直線將x和y數(shù)組中對(duì)應(yīng)元素的點(diǎn)用直線連接起來(lái),最終得到一條正弦曲線。

最后,調(diào)用plt.show()函數(shù)將這條正弦曲線呈現(xiàn)出來(lái)。

我們看到,在上面的例子中,我們通過(guò)4條有效語(yǔ)句,就繪制了一條正弦曲線。實(shí)際上,matplotlib和python一樣簡(jiǎn)潔明了,只要我們熟悉了其思想,就可以繪制出符合我們需要的各種圖形。

在編寫代碼過(guò)程中,如果需要幫助,您可以訪問(wèn):

[if !supportLists]2???????[endif]畫廊:Matplotlib的Gallery頁(yè)面(https://matplotlib.org/gallery.html)中有上百幅縮略圖,打開之后都有源程序。如果您需要繪制某種類型的圖,可以在畫廊中搜索對(duì)應(yīng)的例子,大多數(shù)情況下,通過(guò)復(fù)制/粘貼基本上就能搞定。

[if !supportLists]2???????[endif]API:如果要了解模塊中某個(gè)函數(shù)的使用方法,可以訪問(wèn)Matplotlib的API文檔(https://matplotlib.org/api/index.html)。

[if !supportLists]2???????[endif]幫助:如果要了解模塊中某個(gè)函數(shù)的使用方法,也可以在Jupyter Notebook環(huán)境下使用 help 命令,如下圖所示。

三、Matplotlib組成

要理解Matplotlib繪圖,可以用我們?nèi)粘I钪械睦L畫來(lái)進(jìn)行類比。一般來(lái)說(shuō),我們繪畫的過(guò)程是這樣的:首先架上畫板,然后在畫板上鋪一張畫紙。有時(shí)候我們也會(huì)在不同位置鋪上幾張畫紙,每張畫紙是各自獨(dú)立的參考系。我們?cè)诋嫾埳袭嫺鞣N類型的圖畫,比如水墨畫、油畫、工筆畫、寫意畫、素描、漫畫等。除此以外,一副完整的畫,還需要加上題跋。書籍、碑帖、字畫等前面的文字叫做題,寫在后面的文字,叫做跋,總稱題跋。

Matplotlib中專業(yè)術(shù)語(yǔ)大致對(duì)應(yīng)如下:

[if !supportLists]2???????[endif]圖形(Figure):類似于上面提到的畫板??梢哉J(rèn)為是Matplotlib繪圖的基礎(chǔ)。

[if !supportLists]2???????[endif]軸圖(Axes)或子圖(Subplot):類似于上面的畫紙。畫板上有一張或多張畫紙,實(shí)際繪圖是在軸圖或子圖上完成的。

[if !supportLists]2???????[endif]X軸(X Axis)和Y軸(Y Axis):繪圖所依據(jù)的坐標(biāo)系統(tǒng),相對(duì)于上面的參考系。只不過(guò)對(duì)于專業(yè)的畫家,參考系是在自己的頭腦中,并不一定要標(biāo)在圖紙上面。而在Matplotlib是,X軸和Y軸一般都需要呈現(xiàn)出來(lái),包括其標(biāo)簽(Label)、軸線(Spine)、刻度(Tick)以及刻度標(biāo)簽等。

[if !supportLists]2???????[endif]標(biāo)題(Title)和圖例(Legend):類似于上面的題跋,具體來(lái)說(shuō):標(biāo)題對(duì)應(yīng)題,圖例對(duì)應(yīng)跋。和繪畫一樣,Matplotlib中的標(biāo)題和圖例也可以放在軸圖或子圖上的不同位置。

[if !supportLists]2???????[endif]數(shù)據(jù)(Data):無(wú)疑,Matplotlib中的數(shù)據(jù)相對(duì)于繪畫中主要部分:內(nèi)容。Matplotlib支持的繪圖類型包括:普通圖(Plot)、散點(diǎn)圖(Scatter)和三維圖(3D)等。對(duì)于繪圖過(guò)程的每一筆,還可以指定使用的顏色(Color)、樣式(Style)以及記號(hào)(Marker)等。

[if !supportLists]2???????[endif]文本(Text)/注釋(Annotation):這在日常繪畫中并不常見,但我們也可以把它歸入繪畫中的主要內(nèi)容部分。Matplotlib使用文本和注釋對(duì)重要數(shù)據(jù)進(jìn)行說(shuō)明。

上面的術(shù)語(yǔ)也可以參考下面的圖。

上圖顯示的是只有一個(gè)軸圖的情況。Matplotlib也支持在一個(gè)圖形中繪制幾個(gè)軸圖。這個(gè)時(shí)候,就需要通過(guò)調(diào)用特定的函數(shù)將軸圖添加進(jìn)來(lái)。每個(gè)軸圖是一個(gè)擁有自己獨(dú)立坐標(biāo)系統(tǒng)的繪圖區(qū)域,它可以在圖像的任意位置。

當(dāng)然,軸圖也可以一定規(guī)律來(lái)放置,這時(shí)候,我們稱其為子圖(Subplot)。軸圖和子圖是相互關(guān)聯(lián)的:軸圖是靈活的子圖,而子圖是按格柵方式組織,通過(guò)行與列來(lái)定位的特殊軸圖。下圖就是按2行2列排列方式顯示深度學(xué)習(xí)中經(jīng)常使用到的一些激勵(lì)函數(shù)。

四、坐標(biāo)系統(tǒng)

為了說(shuō)明坐標(biāo)系統(tǒng),我們對(duì)第一個(gè)例子進(jìn)行補(bǔ)充,這次我們將加上標(biāo)題、刻度、刻度標(biāo)簽、圖例等,并調(diào)整坐標(biāo)系的位置。我們希望輸出的效果圖如下所示。

因?yàn)橐@示中文標(biāo)題,所以首先在代碼中添加如下語(yǔ)句。

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

接下來(lái)三條語(yǔ)句生成數(shù)據(jù),具體的解釋可以參考前面的例子。

x? = np.arange(-np.pi, np.pi, np.pi/100)

y1? = np.sin(x)

y2? = np.cos(x)

坐標(biāo)系統(tǒng)是相對(duì)于軸域而言的。如前所述,Matplotlib使用Figure和Axes進(jìn)行繪圖,前者類似于畫板,后者類似于畫紙。如果我們沒(méi)有調(diào)用語(yǔ)句添加Figure和Axes,系統(tǒng)將使用默認(rèn)的畫板和畫紙。調(diào)用gcf()和gca()函數(shù)將分別取得系統(tǒng)的默認(rèn)畫板和畫紙,然后就可以調(diào)用畫板和畫紙的函數(shù)進(jìn)行操作。

ax.set_title('正弦函數(shù)和余弦函數(shù)')為Matplotlib繪圖添加標(biāo)題。一般來(lái)說(shuō),標(biāo)題會(huì)顯示在圖像的上方中心位置。您也可以傳入loc=”left”或loc=”right”參數(shù),將標(biāo)題設(shè)置在上方左邊位置或右邊位置。當(dāng)然,也可以在其他位置。

Matplotlib軸域的坐標(biāo)系默認(rèn)有l(wèi)eft、bottom、right、top四根軸線,要將坐標(biāo)系顯示在圖形中央,需要隱藏其中的兩條,并移動(dòng)另外兩條。例如:將left軸和bottom軸的位置設(shè)置在中央,將right軸和top軸的顏色設(shè)為none達(dá)到隱藏效果。此外,對(duì)于left軸和bottom軸,調(diào)用set_smart_bounds方法。

ax.spines['left'].set_position('center')

ax.spines['right'].set_color('none')

ax.spines['bottom'].set_position('center')

ax.spines['top'].set_color('none')

ax.spines['left'].set_smart_bounds(True)

ax.spines['bottom'].set_smart_bounds(True)

接下來(lái)三條語(yǔ)句設(shè)置X軸的范圍和刻度。范圍設(shè)置在[-π,π)區(qū)間,并在-π、-π/2、0、π/2和π等位置表示對(duì)應(yīng)的刻度標(biāo)簽。

Matplotlib軸域的坐標(biāo)系默認(rèn)有l(wèi)eft、bottom、right、top四根軸線,要將坐標(biāo)系顯示在圖形中央,需要隱藏其中的兩條,并移動(dòng)另外兩條。例如:將left軸和bottom軸的位置設(shè)置在中央,將right軸和top軸的顏色設(shè)為none達(dá)到隱藏效果。此外,對(duì)于left軸和bottom軸,調(diào)用set_smart_bounds方法。

ax.set_xlim(-np.pi,? np.pi)

ax.set_xticks([-np.pi,? -np.pi/2, 0, np.pi/2, np.pi])

ax.set_xticklabels(['-$\pi$',? '-$\pi$/2', '0', '$\pi$/2', '$\pi$'])

對(duì)于Y軸,我們想呈現(xiàn)主刻度線和輔刻度線的效果。

def? major_tick(y, pos):

??? if not y in [-1.0, -0.5, 0, 0.5, 1.0]:

??????? return ""

??? return y


ax.yaxis.set_major_locator(MultipleLocator(0.500))

ax.yaxis.set_major_formatter(FuncFormatter(major_tick))

ax.yaxis.set_minor_locator(AutoMinorLocator(2))

在坐標(biāo)系統(tǒng)都設(shè)置好之后,調(diào)用plot函數(shù)分別畫正弦和余弦兩條曲線。系統(tǒng)會(huì)默認(rèn)為兩條曲線使用兩種不同的顏色進(jìn)行呈現(xiàn)。這次,我們傳入label參數(shù)為兩條曲線加上標(biāo)簽。

ax.plot(x,? y1, label="sin()")

ax.plot(x,? y2, label="cos()")

之后,調(diào)用legend添加圖例并顯示,它會(huì)將上述兩條曲線的顏色和對(duì)應(yīng)的標(biāo)簽進(jìn)行說(shuō)明。輸出圖紙,圖例顯示在左上角位置,其他情況下可能會(huì)顯示在不同的位置。您也可以通過(guò)參數(shù)指定圖例顯示的位置。

五、數(shù)據(jù)屬性

這里所說(shuō)的屬性,是指Matplotlib基本繪圖元素的屬性,包括顏色、線型、記號(hào)等。用一個(gè)例子可以很清楚地了解。

分析一下這個(gè)例子的實(shí)現(xiàn)。

首先準(zhǔn)備數(shù)據(jù),

t =? np.arange(0.0, 1.0, 0.1)

s =? np.sin(2*np.pi*t)

然后定義線性和記號(hào),

linestyles? = ['_', '-', '--', ':']

markers? = []

for m? in Line2D.markers:

??? try:

??????? if len(m) == 1 and m != ' ':

?????? ?????markers.append(m)

??? except TypeError:

??????? pass


styles? = markers + [

??? r'$\lambda$',

??? r'$\bowtie$',

??? r'$\circlearrowleft$',

??? r'$\clubsuit$',

??? r'$\checkmark$']

然后定義線性和記號(hào),

linestyles? = ['_', '-', '--', ':']

markers? = []

for m? in Line2D.markers:

??? try:

??????? if len(m) == 1 and m != ' ':

??????????? markers.append(m)

??? except TypeError:

??????? pass


styles? = markers + [

??? r'$\lambda$',

??? r'$\bowtie$',

??? r'$\circlearrowleft$',

??? r'$\clubsuit$',

??? r'$\checkmark$']

然后定義顏色。

colors? = ('b', 'g', 'r', 'c', 'm', 'y', 'k')

程序的核心部分是一個(gè)雙層循環(huán)。外層對(duì)行進(jìn)行循環(huán),內(nèi)層對(duì)一行的列進(jìn)行循環(huán)。對(duì)于某一行的某一列,我們?yōu)槠涮砑訉?duì)應(yīng)的子圖,并計(jì)算出對(duì)應(yīng)的顏色、線型和記號(hào),然后進(jìn)行繪制,在繪制時(shí),調(diào)用對(duì)應(yīng)的函數(shù)把左邊系刻度標(biāo)簽去掉了。

axisNum? = 0

for row? in range(6):

??? for col in range(5):

??????? axisNum += 1

??????? ax = plt.subplot(6, 5, axisNum)

??????? color = colors[axisNum % len(colors)]

??????? if axisNum < len(linestyles):

??????????? plt.plot(t, s,? linestyles[axisNum], color=color, markersize=10)

??????? else:

??????????? style = styles[(axisNum -? len(linestyles)) % len(styles)]

??????????? plt.plot(t, s, linestyle='None',? marker=style, color=color, markersize=10)

??????? ax.set_yticklabels([])

??????? ax.set_xticklabels([])

5.1 顏色

在上面的例子中,我們用到'b', 'g', 'r', 'c', 'm', 'y', 'k'等幾種顏色。實(shí)際上,我們可以通過(guò)名字引用更多的顏色。這些顏色定義在colors模塊的BASE_COLORS和mcolors.CSS4_COLORS中。下面是按色彩和飽和度進(jìn)行排序,以4列方式呈現(xiàn)的顏色名稱和效果圖,我們把它放到這里方便查詢。

上例也是通過(guò)一個(gè)Matplotlib程序輸出的,這個(gè)程序可以在畫廊中搜索到。

5.2 線型

前面的例子中,給出了四種線性:'_', '-', '--', ':',效果如下圖。

如果您希望用到更多的線型,可以將linestyle參數(shù)指定為(, ())形式,如下表所示。

'solid'(0, ())

'loosely dotted' (0, (1, 10))

'dotted' (0, (1, 5))

'densely dotted' (0, (1, 1))

'loosely dashed' (0, (5, 10))

'dashed' (0, (5, 5))

'densely dashed' (0, (5, 1))

'loosely dashdotted' (0, (3, 10, 1, 10))

'dashdotted'(0, (3, 5, 1, 5))

'densely dashdotted' (0, (3, 1, 1, 1))

'loosely dashdotdotted'(0, (3, 10, 1, 10, 1, 10))

'dashdotdotted' (0, (3, 5, 1, 5, 1, 5))

'densely dashdotdotted' (0, (3, 1, 1, 1, 1, 1)))

這些形式對(duì)應(yīng)的效果圖如下。

5.3 記號(hào)

前面例子中的記號(hào)從Line2D.markers數(shù)組中進(jìn)行遍歷。具體使用時(shí),我們可以將marker參數(shù)指定為以下類型之一:'.',',','o','v','^','<','>','1','2','3','4','8','s','p','P','*',

'h','H','+','x','X','D','d','|','_',對(duì)應(yīng)效果如下圖。

六、注釋和文本

接下來(lái)給出一個(gè)注釋的例子。

這個(gè)例子要在一個(gè)程序里畫兩個(gè)圖。其實(shí)現(xiàn)方式也很直接。

首先創(chuàng)建第一個(gè)figure,并添加一個(gè)子圖。

fig? = plt.figure(1, figsize=(8, 5))

ax? = fig.add_subplot(111, autoscale_on=False, xlim=(-1, 5), ylim=(-4, 3))

創(chuàng)建第二個(gè)Figure和子圖的邏輯相似,只不過(guò)是,這里需要調(diào)用figure的clf方法將前面畫板上的內(nèi)容清空。

fig? = plt.figure(2)

fig.clf()

ax? = fig.add_subplot(111, autoscale_on=False, xlim=(-1, 5), ylim=(-5, 3))

在第二個(gè)子圖上,我們畫了一個(gè)橢圓,代碼如下。

el? = Ellipse((2, -1), 0.5, 0.5)

ax.add_patch(el)

當(dāng)然,我們關(guān)注的還是注釋部分,下面分別介紹。

第一個(gè)圖的第一個(gè)注釋內(nèi)容是staight,所注釋的點(diǎn)座位為(0, 1)。

ax.annotate('straight',? xy=(0, 1), xycoords='data', xytext=(-50, 30), textcoords='offset points', arrowprops=dict(arrowstyle="->"))

第一個(gè)圖的第二個(gè)注釋內(nèi)容包括兩行內(nèi)容,第一行為arc3,,第二行為rad 0.2。所注釋的點(diǎn)座位為(0.5, -1)

ax.annotate('arc3,\nrad? 0.2', xy=(0.5, -1), xycoords='data', xytext=(-80, -60), textcoords='offset? points', arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=.2"))

第一個(gè)圖的第三個(gè)注釋內(nèi)容也包括兩行內(nèi)容,第一行為arc,,第二行為angle 50。所注釋的點(diǎn)座位為(1, 1)。

ax.annotate('arc,\nangle? 50', xy=(1., 1), xycoords='data', xytext=(-90, 50), textcoords='offset? points', arrowprops=dict(arrowstyle="->",? connectionstyle="arc,angleA=0,armA=50,rad=10"))

第一個(gè)圖的第四個(gè)注釋。

ax.annotate('arc,\narms',? xy=(1.5, -1), xycoords='data', xytext=(-80, -60), textcoords='offset points',? arrowprops=dict(arrowstyle="->", connectionstyle="arc,angleA=0,armA=40,angleB=-90,armB=30,rad=7"))

第一個(gè)圖的第五個(gè)注釋。

ax.annotate('angle,\nangle? 90', xy=(2., 1), xycoords='data', xytext=(-70, 30), textcoords='offset? points', arrowprops=dict(arrowstyle="->", connectionstyle="angle,angleA=0,angleB=90,rad=10"))

第一個(gè)圖的第六個(gè)注釋。

ax.annotate('angle3,\nangle? -90', xy=(2.5, -1), xycoords='data', xytext=(-80, -60), textcoords='offset? points', arrowprops=dict(arrowstyle="->", connectionstyle="angle3,angleA=0,angleB=-90"))

第一個(gè)圖的第七個(gè)注釋。

ax.annotate('angle,\nround',? xy=(3., 1), xycoords='data', xytext=(-60, 30), textcoords='offset points',? bbox=dict(boxstyle="round", fc="0.8"), arrowprops=dict(arrowstyle="->",? connectionstyle="angle,angleA=0,angleB=90,rad=10"))

第一個(gè)圖的第八個(gè)注釋。

ax.annotate('angle,\nround4',? xy=(3.5, -1), xycoords='data', xytext=(-70, -80), textcoords='offset points',? size=20, bbox=dict(boxstyle="round4,pad=.5", fc="0.8"), arrowprops=dict(arrowstyle="->",? connectionstyle="angle,angleA=0,angleB=-90,rad=10"))

第一個(gè)圖的第九個(gè)注釋。

ax.annotate('angle,\nshrink',? xy=(4., 1), xycoords='data', xytext=(-60, 30), textcoords='offset points', bbox=dict(boxstyle="round",? fc="0.8"), arrowprops=dict(arrowstyle="->", shrinkA=0,? shrinkB=10,???????????????????????????

? connectionstyle="angle,angleA=0,angleB=90,rad=10"))

第一個(gè)圖的第十個(gè)注釋。

#? You can pass an empty string to get only annotation arrows rendered

ann? = ax.annotate('', xy=(4., 1.), xycoords='data', xytext=(4.5, -1),? textcoords='data', arrowprops=dict(arrowstyle="<->", connectionstyle="bar",? ec="k", shrinkA=5, shrinkB=5))

第二個(gè)圖的第一個(gè)注釋。

ax.annotate('$->$',? xy=(2., -1), xycoords='data', xytext=(-150, -140), textcoords='offset points',? bbox=dict(boxstyle="round", fc="0.8"), arrowprops=dict(arrowstyle="->",? patchB=el,???????????????????????????

? connectionstyle="angle,angleA=90,angleB=0,rad=10"))

第二個(gè)圖的第二個(gè)注釋。

ax.annotate('arrow\nfancy',? xy=(2., -1), xycoords='data', xytext=(-100, 60), textcoords='offset points',? size=20,

#? bbox=dict(boxstyle="round", fc="0.8"),

arrowprops=dict(arrowstyle="fancy",? fc="0.6", ec="none", patchB=el,???????????????????????????

? connectionstyle="angle3,angleA=0,angleB=-90"))

第二個(gè)圖的第三個(gè)注釋。

ax.annotate('arrow\nsimple',? xy=(2., -1), xycoords='data', xytext=(100, 60), textcoords='offset points',? size=20,

#? bbox=dict(boxstyle="round", fc="0.8"),

arrowprops=dict(arrowstyle="simple",? fc="0.6", ec="none", patchB=el, connectionstyle="arc3,rad=0.3"))

第二個(gè)圖的第四個(gè)注釋。

ax.annotate('$->$',? xy=(2., -1), xycoords='data', xytext=(-150, -140), textcoords='offset? points', bbox=dict(boxstyle="round", fc="0.8"), arrowprops=dict(arrowstyle="->",? patchB=el,???????????????????????????

? connectionstyle="angle,angleA=90,angleB=0,rad=10"))

第二個(gè)圖的第五個(gè)注釋。

ann? = ax.annotate('bubble,\ncontours', xy=(2., -1), xycoords='data', xytext=(0,? -70), textcoords='offset points', size=20,? bbox=dict(boxstyle="round", fc=(1.0, 0.7, 0.7), ec=(1., .5, .5)),

arrowprops=dict(arrowstyle="wedge,tail_width=1.",? fc=(1.0, 0.7, 0.7), ec=(1., .5, .5), patchA=None, patchB=el, relpos=(0.2,? 0.8), connectionstyle="arc3,rad=-0.1"))

第二個(gè)圖的第六個(gè)注釋。

ann? = ax.annotate('bubble', xy=(2., -1), xycoords='data', xytext=(55, 0),? textcoords='offset points', size=20, va="center", bbox=dict(boxstyle="round",? fc=(1.0, 0.7, 0.7), ec="none"), arrowprops=dict(arrowstyle="wedge,tail_width=1.",? fc=(1.0, 0.7, 0.7), ec="none", patchA=None, patchB=el, relpos=(0.2,? 0.5)))

在Matplotlib繪圖的過(guò)程中,必須會(huì)用到一些特殊文本,例如數(shù)學(xué)符號(hào)。

第一行對(duì)應(yīng)的輸入為r"$W^{3\beta}_{\delta_1 \rho_1 \sigma_2} = U^{3\beta}_{\delta_1

\rho_1} + \frac{1}{8 \pi 2} \int^{\alpha_2}_{\alpha_2} d \alpha^\prime_2

\left[\frac{ U^{2\beta}_{\delta_1 \rho_1} - \alpha^\prime_2U^{1\beta}_{\rho_1

\sigma_2} }{U^{0\beta}_{\rho_1 \sigma_2}}\right]$";

第二行對(duì)應(yīng)的字符串為:r"$\alpha_i > \beta_i,\ \alpha_{i+1}^j = {\rm sin}(2\pi f_j

t_i) e^{-5 t_i/\tau},\ \ldots$",

第三行對(duì)應(yīng)的字符串為:r"$\frac{3}{4},\ \binom{3}{4},\ \stackrel{3}{4},\ \left(\frac{5

- \frac{1}{x}}{4}\right),\ \ldots$";

第四行對(duì)應(yīng)的字符串為:r"$\sqrt{2},\ \sqrt[3]{x},\ \ldots$";

第五行對(duì)應(yīng)的字符串為:r"$\mathrm{Roman}\ , \ \mathit{Italic}\ , \ \mathtt{Typewriter}

\ \mathrm{or}\ \mathcal{CALLIGRAPHY}$";

第六行對(duì)應(yīng)的字符串為:r"$\acute a,\ \bar a,\ \breve a,\ \dot a,\ \ddot a, \ \grave a,

\ \hat a,\ \tilde a,\ \vec a,\ \widehat{xyz},\ \widetilde{xyz},\ \ldots$";

第七行對(duì)應(yīng)的字符串為:r"$\alpha,\ \beta,\ \chi,\ \delta,\ \lambda,\ \mu,\ \Delta,\

\Gamma,\ \Omega,\ \Phi,\ \Pi,\ \Upsilon,\ \nabla,\ \aleph,\ \beth,\ \daleth,\

\gimel,\ \ldots$";

第八行對(duì)應(yīng)的字符串為:r"$\coprod,\ \int,\ \oint,\ \prod,\ \sum,\ \log,\ \sin,\

\approx,\ \oplus,\ \star,\ \varpropto,\ \infty,\ \partial,\ \Re,\ \leftrightsquigarrow,

\ \ldots$"。

有時(shí)候,我們需要將文本旋轉(zhuǎn)一定角度呈現(xiàn)。只需要在調(diào)用pyplot的text方法時(shí)指定rotate參數(shù)。例如,下面的例子中,先畫了一條角度為45度的直線。

#? Plot diagonal line (45 degrees)

h? = plt.plot(np.arange(0, 10), np.arange(0, 10))

我們?cè)诘谝粋€(gè)位置寫上一條45度的文本。

#? Locations to plot text

l1? = np.array((1, 1))


#? Rotate angle

angle? = 45


#? Plot text

th1? = plt.text(l1[0], l1[1], 'text not rotated correctly', fontsize=16,? rotation=angle, rotation_mode='anchor')

上面的方法只限于坐標(biāo)系X軸和Y軸比例相同的情況。如果不相同,則需要進(jìn)行變換。下面的代碼中,我們?cè)诘诙€(gè)位置寫下角度變換后的文本。

#? set limits so that it no longer looks on screen to be 45 degrees

plt.xlim([-10,? 20])


#? Locations to plot text

l2? = np.array((5, 5))


#? Rotate angle

trans_angle? = plt.gca().transData.transform_angles(np.array((45,)),

???????????????????????????? ??????????????????????l2.reshape((1, 2)))[0]


#? Plot text

th2? = plt.text(l2[0], l2[1], 'text rotated correctly', fontsize=16, rotation=trans_angle,? rotation_mode='anchor')

從下圖可以看到,沒(méi)有變換角度的文本和所畫的直線不對(duì)應(yīng),而變換過(guò)角度的文本和所畫的直線則完全對(duì)應(yīng)。

七、軸圖和子圖

軸圖和子圖的區(qū)別在前面已經(jīng)介紹過(guò)。簡(jiǎn)而言之,子圖是特殊的軸圖,軸圖是靈活的子圖。它們分別調(diào)用add_axes和add_subplot函數(shù)向圖形中添加一個(gè)軸圖,兩個(gè)函數(shù)都返回matplotlib.axes.Axes對(duì)象。但是,兩個(gè)函數(shù)的調(diào)用機(jī)制有很大不同。

函數(shù)add_axes的調(diào)用方法是add_axes(rect),其中rect是一個(gè)列表[x0, y0,

width, height],標(biāo)記新軸圖在圖形坐標(biāo)系中左下角的位置(x0,y0),以及新軸圖的寬度width和高度height。因此,軸圖定位在畫板的絕對(duì)坐標(biāo)位置。例如,以下語(yǔ)句在畫板上添加一個(gè)和畫板一樣大小的軸圖。

Fig =? plt.figure()

ax? = fig.add_axes([0,0,1,1])

函數(shù)add_subplot的調(diào)用方法并不直接提供放置軸圖的位置選項(xiàng)。而是指定按照子圖柵格擺放軸圖的方式。最常用也是最簡(jiǎn)單的指定位置的方法是使用3個(gè)整數(shù)的記號(hào)。

fig? = plt.figure()

ax? = fig.add_subplot(231)

上述語(yǔ)句,一個(gè)新的軸圖會(huì)在2行3列的柵格中的第一個(gè)位置創(chuàng)建。如果只要?jiǎng)?chuàng)建一個(gè)軸圖,可以調(diào)用add_subplot(111)(在1行1列的柵格中的第一個(gè)位置創(chuàng)建軸圖)。

這個(gè)方法的優(yōu)點(diǎn)是讓matplotlib來(lái)計(jì)算軸圖的確切位置。默認(rèn)情況下,add_subplot(111)將軸圖定位在[0.125,0.11,0.775,0.77],或者類似的位置,已經(jīng)為軸圖周圍的標(biāo)題和刻度(標(biāo)簽)保留的足夠的空間。

大多數(shù)情況下,在畫板上創(chuàng)建軸圖,最常使用的方法是add_subplot。只有在您需要為軸圖指定確切位置時(shí),才會(huì)用到add_axes。

7.1 軸域

我們看一個(gè)軸域的例子。

如果您需要在任意位置創(chuàng)建軸圖,調(diào)用figure的add_axes函數(shù)添加軸域。該函數(shù)有一個(gè)列表參數(shù)[left, bottom,

width, height],分別為軸域在圖形中的左下角位置以及長(zhǎng)度和寬度。這些參數(shù)以圖形的坐標(biāo)體系為參數(shù),范圍在0到1之間。(0, 0)表示Figure的左下角位置,(1, 1)表示Figure的全部長(zhǎng)度和寬度。

因此以下語(yǔ)句段,在(0.1,

0.1)位置處添加一個(gè)長(zhǎng)和寬均為0.8的軸域。

ax1? = fig.add_axes([0.1,0.1,.8,.8])

ax1.set_xticks([])

ax1.set_yticks([])

ax1.text(0.6,? 0.6, 'axes([0.1,0.1,.8,.8])', ha='center', va='center', size=16,alpha=.5)

以下語(yǔ)句段,在(0.2, 0.2)位置處添加一個(gè)長(zhǎng)和寬均為0.3的軸域。

ax2? = fig.add_axes([0.2,0.2,.3,.3])

ax2.set_xticks([])

ax2.set_yticks([])

ax2.text(0.5,? 0.5, 'axes([0.2,0.2,.3,.3])', ha='center', va='center', size=12, alpha=.5)

7.2 子域

我們?cè)倏匆粋€(gè)子域的例子。

這個(gè)例子通過(guò)GridSpec機(jī)制添加子圖,我們先定義一個(gè)3×3的柵格。

G? = gridspec.GridSpec(3, 3)

第一個(gè)子圖位于第一行,占據(jù)所有三個(gè)列,因此行號(hào)指定為0,列號(hào)用冒號(hào)表示所有列。

ax1? = fig.add_subplot(G[0, :])

ax1.set_xticks([])

ax1.set_yticks([])

ax1.text(0.5,? 0.5, ',ha='center', va='center', size=20, alpha=.5)

第一個(gè)子圖位于第二行,占據(jù)前面兩個(gè)列,因此行號(hào)指定為1,列號(hào)用冒號(hào)-1表示倒數(shù)第1列之前的所有列,即第一列和第二列。

ax2? = fig.add_subplot(G[1,:-1])

ax2.set_xticks([])

ax2.set_yticks([])

ax2.text(0.5,? 0.5, ',ha='center', va='center', size=20, alpha=.5)

第三個(gè)子圖占據(jù)第二行和第三行,位于最后一個(gè)列,因此行號(hào)用1冒號(hào)表示第1列之后的所有列,即第二列和第三列,列號(hào)指定為-1表示倒數(shù)第1列,即第三列。

ax3? = fig.add_subplot(G[1:, -1])

ax3.set_xticks([])

ax3.set_yticks([])

ax3.text(0.5,? 0.5, ',ha='center', va='center', size=20, alpha=.5)

第四個(gè)子圖位于第三行第一列,因此行號(hào)用-1表示倒數(shù)第1行,即第三行,列號(hào)指定為0。

ax4? = fig.add_subplot(G[-1,0])

ax4.set_xticks([])

ax4.set_yticks([])

ax4.text(0.5,? 0.5, ',ha='center', va='center', size=20, alpha=.5)

第五個(gè)子圖位于第三行第二列,因此行號(hào)用-1表示倒數(shù)第1行,即第三行,列號(hào)用-2表示倒數(shù)第2列,即第二列。

ax5? = fig.add_subplot(G[-1,-2])

ax5.set_xticks([])

ax5.set_yticks([])

ax5.text(0.5,? 0.5, ',ha='center', va='center', size=20, alpha=.5)

八、圖的形狀

8.1 普通圖

前面介紹過(guò)許國(guó)普通圖的例子,這里不再贅述。

8.2 散點(diǎn)圖

以下是散點(diǎn)圖的例子。

在深度學(xué)習(xí)中,線性回歸算法是基礎(chǔ)的一環(huán)。我們需要訓(xùn)練出一條直線能夠擬合如上圖中的數(shù)據(jù)。

首先生成模擬數(shù)據(jù)。

x = np.arange(0, 2.0, 0.1)?? #生成一個(gè)0到50的序列

y = x * 0.1 + 0.3 + np.random.normal(0.0,? 0.03, 20)

接下來(lái),以散點(diǎn)的方式呈現(xiàn)上面的數(shù)據(jù)。

ax.scatter(x,y,? label='Sample Data')

ax.set_title('Linear

? Regression',fontsize=20) # 添加標(biāo)題,并設(shè)置字體大小

ax.set_xlabel('X

? Axis', fontsize=15) # 添加x軸,并設(shè)置字體大小

ax.set_ylabel('Y

? Axis', fontsize=15) # 添加y軸,并設(shè)置字體大小

ax.set_ylim(0.2,? 0.6)

8.3 三維圖

Matplotlib通過(guò)axes3d模塊支持三維圖。

import? matplotlib.pyplot as plt

from? matplotlib import cm

from? mpl_toolkits.mplot3d import axes3d


fig? = plt.figure()

ax? = fig.gca(projection='3d')


X,? Y, Z = axes3d.get_test_data(0.05)

ax.plot_surface(X,? Y, Z, rstride=8, cstride=8, alpha=0.3)

cset? = ax.contourf(X, Y, Z, zdir='z', offset=-100, cmap=cm.coolwarm)

cset? = ax.contourf(X, Y, Z, zdir='x', offset=-40, cmap=cm.coolwarm)

cset? = ax.contourf(X, Y, Z, zdir='y', offset=40, cmap=cm.coolwarm)


ax.set_xlabel('X')

ax.set_xlim(-40,? 40)

ax.set_ylabel('Y')

ax.set_ylim(-40,? 40)

ax.set_zlabel('Z')

ax.set_zlim(-100,? 100)


plt.show()

8.4 等高圖

Matplotlib支持繪制等高圖。

import? numpy as np

import? matplotlib.pyplot as plt


#

? 定義等高線高度函數(shù)

def? f(x, y):

??? return (1 - x / 2 + x ** 5 + y ** 3) *? np.exp(- x ** 2 - y ** 2)


#

? 數(shù)據(jù)數(shù)目

n? = 256

#

? 定義x, y

x? = np.linspace(-3, 3, n)

y? = np.linspace(-3, 3, n)


#

? 生成網(wǎng)格數(shù)據(jù)

X,? Y = np.meshgrid(x, y)


#

? 填充等高線的顏色, 8是等高線分為幾部分

plt.contourf(X,? Y, f(X, Y), 8, alpha = 0.75, cmap = plt.cm.hot)

#

? 繪制等高線

C? = plt.contour(X, Y, f(X, Y), 8, colors = 'black')

#

? 繪制等高線數(shù)據(jù)

plt.clabel(C,? inline = True, fontsize = 10)


#

? 去除坐標(biāo)軸

plt.xticks(())

plt.yticks(())

plt.show()

九、動(dòng)畫

9.1 二維動(dòng)畫

Matplotlab支持生成二維動(dòng)畫。例如,我們可以將在曲線上某點(diǎn)P的求導(dǎo)做成一個(gè)動(dòng)畫,以更形象地闡述導(dǎo)數(shù)的概念,提高教學(xué)效果。

9.2 三維動(dòng)畫

我們通過(guò)動(dòng)畫的方式來(lái)呈現(xiàn)一個(gè)三維圖形的效果。

首先導(dǎo)入需要的包。

#? First import everthing you need

import? numpy as np

from? matplotlib import pyplot as plt

from? matplotlib import animation

from? mpl_toolkits.mplot3d import Axes3D

接下來(lái)準(zhǔn)備數(shù)據(jù)。

x? = np.linspace(-10, 10, 101)

y? = x

x,? y = np.meshgrid(x, y)

z = x? ** 2 + y ** 2

創(chuàng)建畫板和畫紙。

#? Create a figure and a 3D Axes

fig? = plt.figure()

ax =? Axes3D(fig)

畫出動(dòng)畫的初始圖。

#? Create an init function and the animate functions.

#? Both are explained in the tutorial. Since we are changing

#? the the elevation and azimuth and no objects are really

#? changed on the plot we don't have to return anything from

#? the init and animate function. (return value is explained

#? in the tutorial.

def? init():

??? ax.plot_surface(x, y, z, rstride=1,? cstride=1)

??? return fig,

定義動(dòng)畫的動(dòng)態(tài)函數(shù)。

def? animate(i):

??? print(i)

??? ax.view_init(elev=30., azim=i)

??? return fig,

按固定套路生成動(dòng)畫對(duì)象。

#? Animate

anim =? animation.FuncAnimation(fig, animate, init_func=init, frames=360,? interval=20, blit=True)

將動(dòng)畫保存在文件中。需要說(shuō)明的是,必須在環(huán)境中安裝ffmpeg模塊,才能進(jìn)行保存。

#? Save

anim.save('3danim.mp4')

最后,我們可以打開保存的文件查看動(dòng)畫效果。

十、Matplotlib可視化應(yīng)用

Matplotlib是深度學(xué)習(xí)一個(gè)行之有效的手段。首先,它可以實(shí)現(xiàn)訓(xùn)練數(shù)據(jù)的可視化,無(wú)論是監(jiān)督學(xué)習(xí)的分類問(wèn)題和回歸問(wèn)題,還是無(wú)監(jiān)督學(xué)習(xí)的聚類問(wèn)題,都可以幫助我們?cè)O(shè)計(jì)有效的模型進(jìn)行訓(xùn)練。例如,對(duì)于鳶尾花分類問(wèn)題,我們將數(shù)據(jù)如下圖可視化,就很清除地知道可以使用感知機(jī)或線性回歸算法進(jìn)行處理了。

在深度學(xué)習(xí)中,Matplotlib還可以實(shí)現(xiàn)訓(xùn)練過(guò)程的可視化,從而判斷出訓(xùn)練算法或訓(xùn)練參數(shù)是否需要調(diào)整,以及在什么時(shí)候可以停止訓(xùn)練。這里需要一張訓(xùn)練過(guò)程收斂和不收斂的圖進(jìn)行比較。

此外,深度學(xué)習(xí)在平面幾何和立體幾何中能夠幫助呈現(xiàn)動(dòng)畫效果,從而起到輔助教學(xué)和求解的作用。例如,下面是一道經(jīng)典的平面幾何試題。

已知:如圖,O是半圓的圓心,C、E是圓上的兩點(diǎn),CD⊥AB,EF⊥AB,EG⊥CO,求證:CD=GF。

就這道題而言,我們可以將C固定,讓E在圓上變動(dòng),更直觀地感知GF的變化。用Matplotlib可視化出來(lái)的動(dòng)畫效果如下:

下面是一個(gè)立體幾何的例子。

如圖,AD與BC是四面體ABCD中相互垂直的棱,BC=2,若AD=2c,且AB+BD=AC+CD=2a,其中a、c為常數(shù),則四面體的體積的最大值是____。

雖然不完美,我們還是可以用Matplotlib畫出在BC變化的情況下,四面體的變化情況,從而推測(cè)出四面體體積的最大值應(yīng)該出現(xiàn)在中間位置,為求解提供一定的方向。

下面是另一個(gè)立體幾何的例子。

如圖,在四棱錐S-ABCD中,底面ABCD為正方形,側(cè)棱SD底面ABCD,E、F分別是AB、SC的中點(diǎn)。

[if !supportLists](1)?????? [endif]求證:EF//平面SAD

[if !supportLists](2)?????? [endif]設(shè)SD=2CD,求二面角A-EF-D的大小。

我們可以用Matplotlib畫出上述題目的形狀,然后手動(dòng)調(diào)整它的觀察位置和角度,全方位了解上述立體圖形。

上面第一個(gè)圖為題中的正視圖,我們拖動(dòng)鼠標(biāo)旋轉(zhuǎn),在轉(zhuǎn)到第二個(gè)圖示,我們發(fā)現(xiàn),似乎兩條紅邊是相等的,這可以通過(guò)計(jì)算證明。然后就可以找到題中的關(guān)鍵點(diǎn),即線段EF的中點(diǎn)。從而最終得到此題的答案。

結(jié)束語(yǔ)

本文介紹了Python的繪圖模塊Matplotlib以及在深度學(xué)習(xí)等方面的應(yīng)用。需要知道,Matplotlib僅僅是一個(gè)工具,我們掌握它,為我們要實(shí)現(xiàn)的目標(biāo)更好的服務(wù)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 文章圖片上傳不正常,如需文檔,可聯(lián)系微信:1017429387 目錄 1 安裝... 4 1.1 配置探針... ...
    Mrhappy_a7eb閱讀 6,949評(píng)論 0 5
  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5? 答:HTML5是最新的HTML標(biāo)準(zhǔn)。 注意:講述HT...
    kismetajun閱讀 28,878評(píng)論 1 45
  • 對(duì)于java中的思考的方向,1必須要看前端的頁(yè)面,對(duì)于前端的頁(yè)面基本的邏輯,如果能理解最好,不理解也要知道幾點(diǎn)。 ...
    神尤魯?shù)婪?/span>閱讀 907評(píng)論 0 0
  • 方案一:將文件后綴改為 .mjs 方案二:使用babel插件將es6轉(zhuǎn)碼為es5 需要加入'.babelrc'文件...
    嘆玖閱讀 2,200評(píng)論 0 1
  • 提起我的爸爸,認(rèn)識(shí)他的人基本都會(huì)知道他的習(xí)慣:愛看書。 看書的習(xí)慣堅(jiān)持了近30年。每天早上晚上都要看一個(gè)小時(shí)左右。...
    蘇菲親子閱讀 281評(píng)論 1 2

友情鏈接更多精彩內(nèi)容