天天看點

[譯]學習IPython進行互動式計算和資料可視化(五)

第四章:互動式繪圖接口

本章我們将展示Python的繪圖功能以及如何在IPython中互動式地使用它們。

NumPy為處理大量的多元數組結構的資料提供了高效的方法。但是看行行列列的數字總不如直接看曲線圖、散點圖、折線圖、圖檔等圖像來的直覺。Matplotlib是一個使用NumPy資料生成高品質圖像的Python包,其包含的内容非常豐富。它提供了和世界上工程與科學領域非常流行的商業軟體atlab非常相似的簡單而進階的繪圖接口。Matplotlib和IPython結合的相當好。

我們也會介紹一些圖形使用者接口(GUI)程式設計方面的内容。全面覆寫這個豐富的主題遠遠超出了本書的範圍。是以我們在本章中将隻是看一些簡單的示例。下面是本章包含的内容:

  • 使用Matplotlib繪圖
  • 圖像處理技術
  • 地理地圖
  • GUI簡介
  • 和IPython的事件循環內建進行GUIs的設計和debug

Matplotlib的圖形功能

有大量的Python包可以用來進行去先繪制,但是截止目前應用最為廣泛的一個是Matplotlib。它是功能最為完整與強大的一個繪圖庫。它既可以用于互動式可視化,也能用來生成科學出版的高品質圖像。除此之外,他的進階接口使得它使用起來非常容易。

在這一節中,我們将展示Matplotlib提供的一些功能以及怎樣友善地在IPython使用它。

開始使用IPython進行互動式可視化

IPython實作了一循環內建系統,這個系統允許從展示指令行接口啟動圖形視窗的同時不阻斷控制台的使用。這一特點在使用Maplotlib或建立圖形使用者接口的時候非常有用。

Matplotlib的使用

使用事件循環內建機制使得在IPython中可以互動式地展現圖形。這些圖形可以通過指令行接口動态地更新。

%pylab

魔法指令(或在IPython啟動的時候開啟

--pylab

選項)将會自動地激活這個內建功能。也可以為Matplotlib和IPython選擇背景渲染器,例如,使用

--pylab qt

,當然這個需要安裝PyQt或PySide。

我們将假設在這一章中

%pylab

模式一直處于激活狀态。當在一個腳本而不是IPython互動環境時,我們可以在腳本的頭部添加上

from pylab import *

這個指令來實作該模式的激活。在一個Python子產品中,使用

import matplotlib.pyplot as plt

也許是個更好的主意,因為這樣就可以讓Matplotlib對象處于Matplotlib所定義的命名空間内。

有一點值得主意,采用腳本方式生成圖像的方式與在IPython中有稍微的不同。在一個腳本中,圖像隻在調用

show()

函數的時候才會被顯示,一般情況下我們都會将這個函數的調用放在腳本的最末端;然而在IPython的指令行接口中,圖像是随着每一個繪圖函數随時更新的。

互動式導航

當使用Matplotlib展示一個圖像的時候,視窗包含一些用于改變圖形選項的帶有圖形式樣的互動式導航(放大、縮小等)。也可以通過視窗将圖像儲存為位圖或矢量格式。

IPython notebook中的Matplotlib

Matplotlib也可以在notebook中使用。當我們以

ipython notebook --pylab inline

指令啟動notebook時,繪制的圖像會以圖檔的形式出現在輸出框内,且可以以base64字元串的形式儲存在IPYNB檔案中。如若沒有開啟

inline

選項,圖像會像使用IPython時一樣在一個單獨分離出來的視窗顯示。也可以在ipython notebok中使用

%pylab inline

指令激活這個選項。

标準繪圖

在這一節中,我們将看到一些标準繪圖的樣例,如直線、曲線、散點圖和條形圖。在下一節,我們将看到圖檔和地圖。但是Matplotlib提供的功能遠比我們在這裡提到的要多的多,如它還提供了3D繪圖、幾何形狀、向量域等功能。

曲線圖

使用Matplotlib繪制曲線圖實際上就是繪制一些連續的線段,當線段的數量足夠多時,這些線段組合起來就足夠平滑讓我們的肉眼開起來就像曲線一樣。繪制某一個數學函數在一給定區間内的圖像就像NumPy根據給定的數值顯示數組一樣。

例如,一個時間序列信号就可以以表示為一個一定時間段内樣例值組成的一維向量(例如,每毫秒1KHz的取樣頻率),這樣信号每一秒就是1000個資料單元組成的向量。

plot

函數可以用來在螢幕上繪制出這個信号圖像。如下:

【圖】

這裡我們使用獨立随機值生成了一個向量。生成的信号就是所謂的白噪音信号(具有平坦功率譜密度的随機信号)。當在開啟

--pylab inline

選項的notebook中繪制這個圖像的時候,Matplotlib将生成一個這個曲線圖的圖檔并自動地将其插入到輸出框内。

plot

函數接收一個單向量作為參數的時候,它将認為這個向量包含了y軸的值,x軸将自動的生成為0到

len(y)

之間的整數值。我們可以使用`plot(x,y)指令來專門指定x軸的坐标。

散點圖

散點圖使用但像素或其他的辨別展現二位空間點的集合。讓我們繼續進行我們的

cities

執行個體。假設我們在正确的目錄中(

citiesdata alias

),我們可以加載資料并繪制出所有城市的地理坐标:

In [1]: import pandas as pd
In [2]: cd citiesdata
In [3]: filename = \'worldcitiespop.txt\'
In [4]: data = pd.read_csv(filename)
In [5]: plot(data.Longitude, data.Latitude, \',\')
           

【圖】

在這個示例中,我們繪制了所有城市的經度(x軸)和緯度(y軸)。

plot

函數的第三個參數

(\',\')

用來指定辨別類型。在這裡預設使用單像素來表示每一個城市。雖然有些扭曲,我們依然可以從中識别出各大洲的形狀。扭曲的原因是我們是在一個笛卡爾坐标系中繪制的地理坐标點,相對來說,更适合繪制地理坐标的方式是采用地圖投影法。我們将會在本章後續部分回來再談這個問題。

條形圖

條形圖一班用來繪制表現不同間隔内的數值分布的直方圖。Maplotlib的

hist

函數接受一個數值向量來繪制直方圖。

bins

關鍵字用來指定劃割塊的數目或劃割塊清單。

例如,讓我們來繪制Facebook圖示例中結點度的直方圖:

In [1]: cd fbdata
In [2]: import networkx as nx
In [3]: g = nx.read_edgelist(\'0.edges\')
In [4]: hist(g.degree().values(), bins=20)
           

【圖】

在這裡,

g.degree

是包含每一個節點的度的字典(也就是與其相連的結點的數目)。

values

方法傳回所有度的清單。

Matplotlib中還有比我們在這裡展示的多得多的圖形類型,且繪制功能似乎無窮無盡。可以在其官網的Matplotlib Gallery和 Nicolas Rougier的教程中找到大量的圖形繪制示例:①(http://matplotlib.org/

gallery.html) ② (http://www.loria.fr/~rougier/

teaching/matplotlib/).

圖繪定制

Matplotlib提供了大量的定制選項。在這裡,我們将展示怎樣改變一個圖形的樣式和顔色;怎樣配置坐标軸和圖例;怎樣在同意個視窗顯示多付圖像。

樣式和顔色

預設情況下,曲線是連續的且使用統一的一種顔色。在

plot

函數中可以很友善地指定曲線的樣式和顔色。

plot

函數的第三個參數采用一種簡潔的文法來制定曲線的樣式和顔色。例如,

-r

表示"連續的線條且顔色為紅色",

--g

表示“虛線且顔色為綠色”。有十幾種樣式可以使用:

:

表示點線,

-.

表示虛線點線交替,

.

表示點線,

,

表示單像素,

o

表示圓圈辨別等等。

同時,有八個單字元表示八中顔色,他們是:

r

,

g

,

b

(主原色:紅綠藍),

c

,

m

,

y

(副原色:青、品紅、黃),

k

,

w

(黑、白)。任何顔色都可以使用十六進制、RGB或RGBA元組進行指定(值介于0到1之間)等等。

使用一個字元串來指定樣式和顔色來定制樣式顔色隻是更通用地使用專門的參數進行樣式和顔色定制的縮寫。這些參數包括:

linestyle( 或ls)

,

linewidth(或 lw)

,

marker

,

markerfacecolor(或 mfc)

,

markersize(或 ms)

等。完整的選項清單可以參閱Maplotlib的官方文檔。

還有就是,當在一個視窗展示多個圖像的時候,每一個圖像的顔色可以循環使用一個預先定義好的顔色集合,如藍、綠、紅等等。這個循環使用的清單是可以被定制的:

In [1]: rcParams[\'axes.color_cycle\'] = [\'r\', \'k\', \'c\']
           
定制Matplotlib:

rcParams

是Matplotlib中一個帶有可定制參數的全局字典樣式的變量。幾乎Maplotlib的每一方面都可以在這裡進行配置。而且,可以通過将配置儲存為名為

matplotlibrc

的ASCII文本檔案中指定永久配置,這個檔案可以儲存在目前目錄(針對本地選項)或`~/.matplotlib(針對全局選項)。在這個檔案中,每一行包含一個定制的參數,例如,axes.color_cycle:[\'r\',\'k\',\'c\']。

網格,坐标軸和圖例

一個圖像如果沒有圖例和坐标軸是不能傳達資料的所有有用資訊的。預設狀态下,Matplotlib會自動顯示坐标軸和ticks。ticks的确切位置可以使用

xticks

yticks

進行設定,可以使用

grid

函數可以用來添加玩個。x坐标和y坐标的區間可以使用

xlim

ylim

進行指定。可以使用

xlabel

ylabel

設定坐标軸的标簽。而且,也可以使用

legend

關鍵字指定圖例。最後,

title

指令用來顯示圖像的名字。下面的示例描述了怎樣使用這些選項:

【圖】

圖形疊加:在Maplotlib中可以實作調用不同的繪圖函數來跟新同一圖像。這也是實作多個圖形顯示在衣服圖像中的方法。要在一個新的視窗中建立一個新的圖像,我們需要調用

figture()

函數。最後,就像我們将在後續小節中看到的,可以使用subplot來實作在同一視窗展示多個獨立的圖像。

IPython的互動式功能

通過使用事件循環內建機制來在IPython控制台建立Matplotlib圖像允許在控制台通過變成和圖像進行互動。進而可以實時建立一個新的圖像或更新一個圖形。示例如下:

In [1]: plot(randn(1000, 2))
Out[1]: [<matplotlib.lines.Line2D at 0x4cf4310>,
<matplotlib.lines.Line2D at 0x4cf4450>]
           

我們首先使用兩個白噪音信号來建立一個圖像(

plot

函數會把每一列當作一個獨立的曲線顯示出來)。當帶有圖像的視窗打開後,我們不必關閉視窗就可以傳回IPython控制台。輸出

Out[1]

包含一個

line2D

對象清單。事實上,Matplotlib使用的是圖像的面向對象式的描述。讓我們像下面這樣擷取第一個對象(也就是第一個曲線):

In [2]: line = _[0]
           

line

變量的Tab不全将會顯示我們可以用來更新圖像的方法清單。例如,要把線條從藍色改為紅色,我們可以使用下面的指令:

In [3]: line.set_color(\'r\')
           

圖像接着會是以更新。有時可能需要進行強制重新整理圖像,例如放大和縮小操作。

最後,讓我們提一下用來提供更新一些圖像屬性的的GUI視窗中的這個編輯(Edit)按鈕。

繪制多幅圖像

多個獨立的圖形可以展示在同一個圖像上。我們可以使用表示行和列的任意數字來定義一個網格,再在每一個方框内繪制圖像。方框可以被擴充至多行多列(使用

subplot2grid

)。例如,下面的示例逐漸展示了怎樣在不同的坐标系統内繪制兩幅圖像:

x = linspace(0, 2 * pi, 1000)
y = 1 + 2 * cos(5 * x)
subplot(1,2,1)
plot(x, y)
subplot(1,2,2, polar=True)
polar(x, y)
           

【圖】

subplot

函數同時指定了分割為多少列(第一個參數)多少行(第二個參數)以及将會被渲染的圖像雖在盒子的索引(第三個參數,從1開始索引,從左到右,從上到下)。·

polar=True

關鍵字參數制訂了第二個子圖是一個極坐标圖像。

polar

函數與

plot

函數是相似的,隻不過極坐标系包含的是表示角度的

theta

和半徑的

r

這兩個屬性。

進階繪圖

在這一節中我們将展示Matplotlib提供的與圖檔和地圖相關的進階繪圖功能。而且我們也會浏覽一些其它的繪圖庫。

圖檔處理

一個N X M的彩色圖檔可以表示為一個 N X M X 3的NumPy數組,也就是三個代表紅綠藍通道的 NXM矩陣。圖檔處理算法有NumPy和SciPy高效實作,圖檔顯示可以有Matplotlib實作。

加載圖檔

Matplotlib的

imread

函數可以從硬碟打開一個PNG格式的圖檔并傳回一個 N X M X 3 的NumPy數組(如果有一個alpha透明通道的劃就是 N X M X 3)。PIL包也提供了讀取任意格式圖檔的

open

函數(BMP,GIF,JPEG,TIFF等)。

在下面的示例,我們将從遠端URL下載下傳一個PNG圖檔并使用

imread

加載它:

In [1]: import urllib2
In [2]: png = urllib2.urlopen
(\'http://ipython.rossant.net/squirrel.png\')
In [3]: im = imread(png)
In [4]: im.shape
Out[4]: (300, 300, 3)

           

imread

函數接受一個圖檔檔案名活一個Python中類似檔案的對象(就像在這個示例中我們使用的是

urlopen

傳回的緩沖區)。

imread

函數傳回的對象是一個三維的NumPy數組。

我們也可以使用PIL讀取圖檔。我們可以使用

Image.open

直接讀取圖檔或使用

Image.fromarray

函數将一個NumPy數組轉換成一個PIL圖檔:

In [5]: from PIL import Image
In [6]: img = Image.fromarray((im * 255).astype(\'uint8\'))
           

fromarray

函數接受一個0到250直接的無符号8位整數組成的數組。這就是為什麼我們需要将NumPy數組從浮點數轉換成所需資料格式的原因。反過來,我們可以使用

array

函數——

im = array(img)

将一個PIL圖檔轉換成一個NumPy數組。

圖檔展示

Matplotlib的

imshow

函數可以用來顯示一個源自NumPy數組的圖檔。就像下面的示例這樣:

In [7]: imshow(im)
           

【圖】

imshow

函數也接受二位NumPy數組(灰階圖)。可以通過顔色映射指定0-1間數值和實際像素顔色之間的映射關系。顔色映射是一個定義0-1之間任意值的顔色的線性梯度。Matplotlib中有很多預定義的顔色映射,完整的清單可以從這裡獲得: http://www.scipy.org/

Cookbook/Matplotlib/Show_colormaps

我們可以使用

cmap=get_cmap(name)

關鍵字參數在

imshow

中指定顔色映射,其中

name

是顔色映射的名稱。

PIL的使用

PIL提供了一些基礎圖檔處理功能,如:旋轉、剪切、濾鏡、複制、粘貼以及幾何變換等。例如,我們可以使用下面的指令來旋轉一個圖檔:

In [9]: imshow(array(img.rotate(45.)))
           

【圖】

這裡我們把圖檔逆時針旋轉了45度并将其由PIL圖檔轉換成NumPy數組顯示出來。

進階圖檔處理——color quantization

PIL提供了基礎的圖檔處理函數,而Scipy提供了更為進階的算法。

在這裡我們将展示一個被稱為 color quantization的進階圖檔處理算法的樣例。該算法的原理是在保持圖檔大部分可視結構的條件下減少圖檔色彩的數目。在這個示例中,我們将使用

scipy.cluser

包實作這個算法。我們将使用K均值(K-means)算法将顔色值聚集到少數的幾個聚類中,并把每一個色素指派給他所屬聚類的顔色。代碼如下:

In [10]: from scipy.cluster.vq import *
M = im[:,:,0].ravel()
centroids, _ = kmeans(M, 4)
qnt, _ = vq(M, centroids)
clustered = centroids[reshape(qnt, (300, 300))]
           

我們在這裡隻采用了紅色通道的資料,所有像素具有相同的權重。使用

ravel

函數使圖檔平坦化(也就是我們會得到一個一維向量,而不是二維矩陣)。接着,

kmeans

函數尋找色彩空間的聚類并傳回中心顔色。最後

vg

函數将每一個像素指派給它所屬的中心索引,我們就得到了由中心顔色(centroids)生成的中心索引(在qnt)有趣索引聚類生成的最終圖檔。由于這個算法的輸出結果是一個灰階圖檔,是以我們需要指定一個顔色映射。我們将使用一組曾經非常流行的顔色,結果就像下面這樣:

In [11]: cmap = matplotlib.colors.
ListedColormap([(0,.2,.3),(.85,.1,.13),(.44,.6,.6),
(1.,.9,.65)])
In [12]: imshow(clustered, cmap=cmap)
           

【圖】

這裡的

ListedColormap

函數使用一個離散的顔色集建立了一個定制的顔色映射。

最後我們可以使用Matplotlib的

imsave

函數将最終的圖檔儲存為一個PNG檔案。如下:

In [13]: imsave(\'squirrelama.png\', clustered, cmap=cmap)
           

地圖

地圖是一種雖複雜但又非常重要的圖像類型。basemap tookit給Matplotlib提供了地圖處理能力(需單獨安裝)。它非常強大,我們在這一章中隻會簡單對他進行介紹。特别的,我們将繼續我們的

cities

的例子來繪制真實世界的人口密度圖。

首先,我們先像下面這樣獲得城市的地理位置和人口數目:

In [6]: locations = data[[\'Longitude\',\'Latitude\']].as_matrix()
In [7]: population = data.Population
           

接着,我們像下面這樣通過指定投影類型和地圖邊界來初始化一個世界地圖:

In [8]: from mpl_toolkits.basemap import Basemap
In [9]: m = Basemap(projection=\'mill\', llcrnrlat=-65, urcrnrlat=85,
llcrnrlon=-180, urcrnrlon=180)
           

有很多方法可以将地球的表面投影到一個平面上,具體選用何種投影方式取決于具體的應用。這裡我們使用的是米勒圓柱投影(Miller cylindrical projection)。另外一個關鍵字參數給出左下角和右上角的經度和緯度。

下一步就是根據世界人口密度資料生成一個二維圖檔。要完成這一步我們需要将城市的地理位置映射到我們的地圖上。如下:

In [10]: x, y = m(locations[:,0],locations[:,1])
           

調用

m(long,lat)

函數可以獲得地理位置的經緯度坐标(x,y)。要生成密度地圖,我們還需要地圖的邊界坐标。如下:

In [11]: x0, y0 = m(-180, -65)
In [12]: x1, y1 = m(180, 85)
           

好了,現在讓我們來生成密度圖吧。在這裡我們将使用

histogram2d

函數,這個函數将根據點集資料傳回一個二位的直方圖。每一個點代表一個城市,把每一城市的人口數作為對應城市的權重。必須要注意沒有人口資料的城市,我們這裡将這些城市的權重設定為1000。如下:

In [13]: weights = population.copy()
In [14]: weights[isnan(weights)] = 1000
In [15]: h, _, _ = histogram2d(x, y, weights=weights,
bins=(linspace(x0, x1, 500), linspace(y0, y1, 500)))
           

現在

h

展開圖變量儲存着整個500x500網格的球形平面小方格的人口計數。我們可以使用SciPy的高斯濾波器對

log(h)

進行處理來生成一張密度地圖(應用的是一種核密度估計)。當資料值跨越幾個數量級的時候使用對數是非常有用的。我們還需要注意一下0值(指空區域),因為0的對數是未定義/無意義的:

In [16]: h[h == 0] = 1
In [17]: import scipy.ndimage.filters
In [18]: z = scipy.ndimage.filters.gaussian_filter(log(h.T), 1)
           

log(h.T)

進行濾波處理的原因是相對于地圖坐标系

h

值的坐标系轉換得到的。我們在這裡使用數值1進行過濾。

最後,我們将密度地圖和海岸線繪制出來,結果如下:

In [19]: m.drawcoastlines()
In [20]: m.imshow(z, origin=\'lower\', extent=[x0,x1,y0,y1],
cmap=get_cmap(\'Reds\'))

           

【圖檔】

3D繪圖

Matplotlib包含一個可以用來基礎3D繪圖的3D工具包——

mplot3d

,基礎功能有3D曲線、曲面圖繪制等。作為一個示範示例,我們來建立一個曲面圖。首先需要導入

mplot3d

工具包:

In [1]: from mpl_toolkits.mplot3d import Axes3D
           

接着,我們使用下面的指令建立曲面圖的x、y、z坐标:

In [2]: # we create a (X, Y) grid
X = linspace(-5, 5, 50)
Y = X
X, Y = meshgrid(X, Y)
# we compute the Z values
R = sqrt(X**2 + Y**2)
Z = sin(R)
           

NumPy的

meshgrid

函數傳回由X和Y向量定義的矩形區域展開網格内所有點的坐标值。最後,我們建立一個3D畫布,并在上面繪制曲面圖:

In [3]: ax = gca(projection=\'3d\')
surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1,
cmap=mpl.cm.coolwarm, linewidth=0)
           

Matplotlib的

gca

函數傳回目前的坐标軸執行個體,需要指出的是這個示例應該使用3D投影。

plot_surface

函數中,

stride

cstride

關鍵字參數提供曲面的行列步長,

cmap

提供顔色映射,

linewidth

提供線框的寬度。下面的截圖展示了最終結果:

【圖】

動畫

Matplotlib能用來建立動畫,并使用FFmpeg或MEncoder導出為MP4視訊。思路是建立一個圖像,并寫一個函數在一個确定時間間隔頻率下更新它。動畫子產品的文檔可以在下面的連接配接中找到:http//matplotlib.org/api/animation_api.html。除此之外,還有一個 Jake Vanderplas制作的教程: http://jakevdp.github.com/

blog/2012/08/18/matplotlib-animation-tutorial/。

其它的可視化包

Matplotlib不是唯一的Python可視化包。這裡是一些可視化方面的庫:

  • Chao:一個Matplotlib的替代庫

    (http://code.enthought.com/chaco/)

  • PyQwt:基于PyQt的繪圖庫
  • PyQtGraph:基于PyQt,提供2D、3D繪圖功能
  • Visvis:基于OpenGL;提供一種面向對象式的繪圖接口
  • Mayavi:提供3D可互動式可視化接口
  • PyOpenGL:提供應用廣泛的OpenGL的Python原始接口;提供低級的硬體加速的2D/3D繪圖功能
  • Galry:用于處理百萬千萬個點大資料集的高性能互動式可視化包,基于PyOpenGL。

圖形使用者接口(GUI)

有一段時間隻能通過指令行接口進行人機互動。現在大部分一般計算機使用者

相對于鍵盤和帶有閃爍光标的黑色螢幕對滑鼠和圖形視窗更為熟悉。正由于這個原因。任何開發者在某些時候可能會被要求寫一個圖形接口,以使得非開發人員能很友善的和程式進行互動。

一個GUI界面可以被內建到任意Python包中。對于Python來說有大量的圖形工具包可以使用,它們中的大多數是原生或C++圖形庫的封裝。比較有名的工具包有Qt、wxWidgets、TKinter、GTK等等。在本書的示例中我們将使用Qt。

GUI變成是一個相當困難的主題,因為它需要作業系統的底層細節的高深知識、多線程程式設計和一些人機互動的基本概念認識。在本書中,我們将展示一個PyQt的非常基礎的一個”HelloWorld“示例。我們還将看到怎樣使用IPython互動式地處理GUI。

使用IPythonn進行互動式GUI程式設計

IPython實作的循環內建系統可以用來從指令行接口展示圖形視窗時不阻斷控制台。這對于建立GUI來說非常有用,因為這樣就可以通過指令行和圖形視窗進行動态的互動。

可以用

%gui

魔法指令來激活事件循環內建。我們需要提供将要使用的圖形庫的名字。可用的名字有wx,qt,gtk,和tk。這裡我們使用Qt。是以我們可以輸入

%gui qt

。Qt主程式接着就會在IPython中自動啟動。另外一種方式是使用

ipython --gui qt

指令啟動IPython。

這一節的示例需要PyQt4或PySide。我們将假設PyQt4已經安裝好了,如果安裝的是PySide,隻需再導入的時候将PyQt4替換成PySide即可。兩個庫綁定的Qt API基本上是一緻的。

一個“Hello World”示例

在這個“Hello World”示例中,我們将展示一個視窗,在這個視窗内有一個用來出發消息框的按鈕。我們還将展示如何在IPython控制太和視窗進行互動。

我們需要建立一個繼承自

QWidget

基類的類來定義一個視窗。

QWidget

是所有Qt視窗和控制的基類,也被稱為widgets(部件)。這裡是“Hello World”示例的代碼:

from PyQt4 import QtGui
class HelloWorld(QtGui.QWidget):
	def __init__(self):
		super(HelloWorld, self).__init__()
		# create the button
		self.button = QtGui.QPushButton(\'Click me\', self)
		self.button.clicked.connect(self.clicked)
		# create the layout
		vbox = QtGui.QVBoxLayout()
		vbox.addWidget(self.button)
		self.setLayout(vbox)
		# show the window
		self.show()
	def clicked(self):
		msg = QtGui.QMessageBox(self)
		msg.setText("Hello World !")
		msg.show()
           

大部分工作都在

HelloWorld

部件的構造函數中發生。我們首先需要調用父類的構造函數。接着,我們分幾步去顯示按鈕:

  1. 我們首先建立了一個按鈕,也就是

    QPushButton

    類的執行個體。第一個參數是按鈕上要顯示的文本,第二個參數是父部件的執行個體(self)。每一個特定的控制操作和部件由一個繼承自

    QWidget

    基類的類所定義,且能夠在

    QtGui

    命名空間中找到。
  2. 我們定義了當使用者點選按鈕時調用的回調方法。

    cliked

    屬性表示一旦使用者點選了按鈕Qt信号就發射。我們将這個信号連接配接到我們的

    HelloWorld

    部件的

    clicked

    方法(被稱作——槽)。信号槽機制是Qt中不同部件進行消息傳遞的方法。但某些事件發生是信号會被觸發,信号被處觸發後,連接配接這些信号的“槽”就會被調用。任何部件都包含很多預定義好的信号。當然,也可以自己來定制信号。
  3. 接着,我們需要将這個新建立的按鈕放置在視窗上。首先我們需要建立一個承載部件并對部件進行垂直布局的

    QVBoxLayout

    部件。這裡我們僅僅是使用

    addWidget

    方法将按鈕放置到它上面。我們還制定了這個盒子/方框是視窗的布局。通過這種方式,主視窗承載這個盒子,這個盒子承載我們的按鈕。
  4. 最後,我們需要使用

    self.show()

    這個指令來顯示我們的視窗。

clicked

這個方法中,我們建立了一個用來顯示資訊的

QMessageBox

,預設情況下,這個部件就是帶有一個文本一個OK按鈕的對話框。

setText

方法指定了文本,

show

方法用來顯示視窗。

現在假設IPython已經通過

%gui qt

ipython --gui qt

的方式激活了帶有Qt的事件循環,我們就可以使用下面的指令來顯示我們建立的視窗:

In [1]: window = HelloWorld()
           

視窗接着就會出現,且在視窗在被打開的狀态下IPython的控制台依舊是可用的。

【圖】

點選按鈕就會彈出一個帶有HelloWorld字樣的對話框。

我們也可以在IPython控制台中和這個視窗進行互動。例如,下面的指令就會使得隻要我們已經點選了按鈕就會彈出HelloWorld對話框:

In [2]: window.clicked()
           

這個功能在我們設計一個複雜窗體和調試的時非常友善。

總結

在本章中,我們了解了IPython提供的圖形功能,Matplotlib以及其他相關的庫。我們可以用來建立線圖、圖表、直方圖、地圖、顯示和處理圖檔,圖形使用者接口等等。圖形功能還能很容易地內建都notebook中。所有的圖形皆可定制。這些因素也就解釋了為什麼這些工具在科學和工程社群如此受歡迎。在這些領域資料可視化在多數應用中扮演着非常重要的角色。

在下一章,我們将看到進行Python代碼加速的技術。