交互式绘图接口

本章我们将展示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的确切位置可以使用xticksyticks进行设定,可以使用grid函数可以用来添加玩个。x坐标和y坐标的区间可以使用xlimylim进行指定。可以使用xlabelylabel设定坐标轴的标签。而且,也可以使用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函数中,stridecstride关键字参数提供曲面的行列步长,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 qtipython --gui qt的方式激活了带有Qt的事件循环,我们就可以使用下面的命令来显示我们创建的窗口:

In [1]: window = HelloWorld()

窗口接着就会出现,且在窗口在被打开的状态下IPython的控制台依旧是可用的。 【图】 点击按钮就会弹出一个带有HelloWorld字样的对话框。

我们也可以在IPython控制台中和这个窗口进行交互。例如,下面的命令就会使得只要我们已经点击了按钮就会弹出HelloWorld对话框:

In [2]: window.clicked()

这个功能在我们设计一个复杂窗体和调试的时非常方便。

总结

在本章中,我们了解了IPython提供的图形功能,Matplotlib以及其他相关的库。我们可以用来创建线图、图表、直方图、地图、显示和处理图片,图形用户接口等等。图形功能还能很容易地集成都notebook中。所有的图形皆可定制。这些因素也就解释了为什么这些工具在科学和工程社区如此受欢迎。在这些领域数据可视化在多数应用中扮演着非常重要的角色。

在下一章,我们将看到进行Python代码加速的技术。