python科学计算——数据可视化(Matplotlib)

写在前面

Matplotlib提供了大量实现数据可视化功能的模块,采用面向对象进行封装,在编写大型应用时通过面向对象方式将更加有效,这里只是对matplotlib的一些简单功能进行总结,需要更高级别的应用时,请多参考官方说明。

pyplot绘图模块

matplotlib的 pyplot模块提供了与Matlab类似的绘图闲数调用接口,方便用户快速绘制二维图表。先看一个比较简单的例子,绘制正弦和余弦函数图像。

# 产生自变量
x = np.linspace(0,10,1000)
# 计算正弦、余弦值
y = np.sin(x)
z = np.cos(x**2)
# 创建Figure对象
plt.figure(figsize=(8,4))
# 绘制数据
plt.plot(x,y,label='$six(x)$',color='red', linewidth=2)
plt.plot(x,z,'b--',label='$cos(x^2$')
# 设置x\y轴标识
plt.xlabel("Time(s)")
plt.ylabel("Volt")
# 设置图标题
plt.title("Pyplot 1st Sample")
# 设置y轴的取值范围
plt.ylim(-1.2,1.2)
plt.legend()
plt.show()

这里写图片描述

配置属性

matplotlib绘制的图像的每一个部分都和一个对象关联,换句话说,图中的每一个部分都是一个对象,可以通过这些对象的set_xxx来设置相关属性,或者通过pyplot模块的setp()方法来设置。下面一个例子展示设置线条的透明度:

plt.figure(figsize=(4,3))
x = np.arange(0,5,0.1)
line = plt.plot(x,0.05*x*x)[0]
line.set_alpha(0.5)

plt.plot()返回一个列表,是其需要绘制的对象,这里为一个line2D对象,下面的例子返回的是两个line2D对象。

lines = plt.plot(x,np.sin(x),x,np.cos(x))
## lines是一个列表,里面包含两个line2D对象,分别是sin(x)和cos(x)对象。

通过setp()函数将同时设置返回的所有对象的属性:

plt.setp(lines, color="red", linewidth=4.0)
## 将同时设置sincos曲线的颜色和线宽。

对象有set_xxx方法,那么也有相应的get_xxx方法:

line.get_linewidth()    # 获取线宽
plt.getp(lines[0],"color")  # 获取颜色

getp函数通常有两个用法:(1)指定属性,则返回某一个对象的某一个属性;(2)不指定属性,则返回某一个对象的所有属性。

多子图绘制

一个Figure对象(通过plt.figure()函数获取)可以包含多个子图(Axes对象),前面的例子中值包含一个子图(默认)。使用subplot()可以绘制多个子图的图标,调用形式如下:
subplot(nRows, nCols, plotNum)
nRows:子图的行数;
nCols:子图的列数;
plotNum:子图对象区域索引。
如果三个参数都小于10,则可以将三个参数连写,如subplot(2,2,4)和subplot(224)等价。如果后创建的子图与之前的子图有重叠,则之前的子图将被删除。

for idx,color in enumerate("rgbyck"):
    plt.subplot(321+idx,axisbg=color)
plt.show()

这里写图片描述
若想子图占据整行或整列,可以按如下方式:

plt.subplot(121)
plt.subplot(222)
plt.subplot(224)
plt.show()

这里写图片描述

plt.subplot(211)
plt.subplot(223)
plt.subplot(224)
plt.show()

这里写图片描述
subplot()返回它所创建的Axes对象,这些对象可以用sca()来替换使之成为当前Axes对象,然后调用plot在上面作图,如果需要绘制多张图,可以传递给figure()函数一个整数来指定Figure对象。如果传递给figure的整数不存在,则创建新的Figure对象,若已经被传递过,则使之成为当前Figure对象。

plt.figure(1)
plt.figure(2)
ax1 = plt.subplot(121)
ax2 = plt.subplot(122)
x = np.linspace(0,3,100)
for i in xrange(5):
    plt.figure(1)
    plt.plot(x, np.exp(i*x/3))
    plt.sca(ax1)
    plt.plot(x,np.sin(i*x))
    plt.sca(ax2)
    plt.plot(x,np.cos(i*x))
plt.show()

这里写图片描述
这里写图片描述
subplots可以一时创建多个子图,返回的是Figure和子图列表。此外,subplot2grid可以创建更复杂的布局效果,调用方法是:
subplot2grid(shape, loc, rowspan=1, colspan=1, **kwargs)
shape是表格形状的元组(行数,列数)。loc为子图左上角坐标(行,列),rowspan和colspan是子图所占据的行列数,默认为1。下面的例子是在3x3的网格上创建5个子图。

fig = plt.figure(figsize=(6,6))
ax1 = plt.subplot2grid((3,3),(0,0),colspan=2)
ax2 = plt.subplot2grid((3,3),(0,2),rowspan=2)
ax3 = plt.subplot2grid((3,3),(1,0),rowspan=2)
ax4 = plt.subplot2grid((3,3),(2,1),colspan=2)
ax5 = plt.subplot2grid((3,3),(1,1))
plt.show()

这里写图片描述

Artist对象

前面提到过,matplotlib是一套面向对象的绘图工具,这一套绘图工具有三个层次:

  1. backend_bases.FigureCanvas:绘图用的画布;
  2. backend_bases.Renderer:知道如何在FigureCanvas上绘图;
  3. artisi.Artist:知道如何用Renderer在FigureCanvas上绘图。

这三者的关系可以这样看,FigureCanvas对象是画布,Renderer是画笔,而Artist是会绘画的人,在matplotlib中,“会绘画的人”其实就是各种类型的图形,如线、矩形等,Artist可以分成两种:简单类型和容器类型。简单类型就是标准的绘图元件,如Line2D、Rectangle、Text、AxesImage等,而容器类型就是包含多个Artist对象,使他们组织成一个整体,例如Axis、Axes、Figure。也就是可以放置标准元件的集合,例如我们可以在子图上绘制各种的线(Line2D)、矩形(Rectangle)、文字(Text)等。所以创建Artist进行绘画一般是如下几个步骤:

  1. 创建Figure对象;
  2. 为Figure对象创建一个或多个Axes(子图);
  3. 调用 Axes对象的方法来创建各种简单类型的Artist对象。

Artist属性

由前面的说明可以知道,图表中的每一个元素都是一个Artist对象,而每一个Artist对象都有很多属性来控制其显示效果,例如Figure对象和Axes对象都有一个patch属性,它是一个Rectangle对象,通过该属性可以设置Figure对象或Axes对象的背景和透明度等属性。当调用set_color()设置好背景色之后,有时候并不会立即显示,这时候需要调用figure.canvas.draw()来更新显示界面。

fig = plt.figure()
fig.patch.set_color('g')
fig.canvas.draw()
x = np.linspace(0,10,3000)
y = np.sin(x)
plt.plot(x,y,linewidth=4, color='red')
plt.show()

这里写图片描述
下表展示了Artist对象一些常用属性:
这里写图片描述
这些属性可以通过相应的get_*()和set_*()方法进行操作,如设置曲线的透明度可以使用line.set_alpha(value)来进行操作,也可以通过set方法同时设置多个属性,line.set(alpha=xx, zorder=2…)。也可以通过前面说过的getp方法来获取Artist对象的所有属性,例如plt.getp(fig.patch)。

Figure容器

在所绘制的图表中最上层对象就是Figure对象,它包含了图表组成的所有元素,例如调用add_subplot()和add_axes()添加子图时,这些子图都将添加到axes属性列表中,这两个函数返回的时创建的类型对象,分别时AxesSubplot和Axes对象,前者时后者的派生类。由于支持gca()操作,Figure对象保存的是当前Axes对象信息,所以在对Figure的某一个Axes操作是应该使用add_axes()、add_suplot()、delaxes(),当然在循环中可以忽略这一点。下表是Figure对象的一些常用属性:
这里写图片描述

Axes容器

Axes是图表中的核心对象,它包含了组成图表的众多Artist对象,并且有许多方法函数帮助我们创建和修改这些对象。和 Figure容器一样,它有一个patch属性作为背景,当它是馆卡尔坐标时,patch属性是一个Rectangle对象;而当它是极坐标时,patch属性则是Circle对象。当调用Axes对象的绘图方法plot时,它将创建一组Line2D对象,并将它们添加进Axes对象的 lines属性中,最后返回包含所有创建的Line2D对象的列表。 plot的所有关键字参数都将传递给这些Line2D对象以设置它们的属性。由于plot返回的是一个列表,所以可以向plot函数传递多个X-Y轴数据,同时绘制多条曲线。

fig = plt.figure()
x = np.linspace(0,10,10000)
y = np.sin(x)
z = np.cos(x)
ax = fig.add_subplot(111)
ax.patch.set_facecolor('b')
lines = ax.plot(x,y,x,z,"-",color='red',linewidth=2)
print len(lines)
plt.show()

这段代码是向Figure对象添加两个曲线,并计算lines的对象个数。绘制柱状图的函数bar()和绘制直方统计图的函数hist()将创建一个Patch对象的列表,每个元素实际上都是从Patch类派生的Rectangle对象,所创建的Patch对象都被添加进了Axes对象的patches属性中。一般我们不对patchs或lines对象直接操作,而是使用add_line()或者add_patch()等方法,如下面画矩形。

fig, ax = plt.subplots()
rect = plt.Rectangle((1,1), width=5, height=12)
ax.add_patch(rect)
ax.autoscale_view() # 调节坐标范围使矩形能够完全显示
plt.show()

这里写图片描述
下表中列出了其他Axes对象中包含其他的Artist对象属性:
这里写图片描述
这里写图片描述
下表列出了Axes创建其它Artist对象的方法:
这里写图片描述

Axis容器

Axis容器包括也标轴上的刻度线、亥lj度文本、猶示网格以及坐标轴标题等内容。亥度包柄主刻度和副刻度,分别通过get_major_ticks和 get_minor_ticks方法获得。每个刻度线都是一个XTick或YTick对象,它包括实际的刻度线和刻度文本。为了方便访问刻度线和文本,Axis对象提供了get_ticklabels和 get_ticklines方法来直接获得刻度线和刻度文本。

fig,ax = plt.subplots()
plt.show()

这里写图片描述
获取该图表的x轴刻度位置:

axis = ax.xaxis
axis.get_ticklocs()
##
array([ 0. ,  0.2,  0.4,  0.6,  0.8,  1. ])

下面获得刻度标签以及标签中的文字:

print axis.get_ticklabels()
print [x.get_text() for x in axis.get_ticklabels()]
##
6 Text major ticklabel objects>
[u'0.0', u'0.2', u'0.4', u'0.6', u'0.8', u'1.0']

获取主刻度线的列表:

axis.get_ticklines()
# 由于上图存在两条X轴,所以获取刻度线列表时有是一个长度为12的列表
<a list of 12 Line2D ticklines objects>

在获取到刻度线和刻度标签之后便可以对其操作,下面的例子是将刻度线设置成绿色粗线,并将刻度文字旋转45°。

fig,ax = plt.subplots()
axis = ax.xaxis
for label in axis.get_ticklabels():
    label.set_color('r')
    label.set_rotation(45)
    label.set_fontsize(16)

for line in axis.get_ticklines():
    line.set_color('g')
    line.set_markersize(25)
    line.set_markeredgewidth(3)
plt.show()

这里写图片描述
实际上,pyplot模块中的xticks()能够快速的对刻度标检进行设置,但是无法对刻度线进行操作。

plt.xticks(fontsize=16, color='red', rotation=45)

常用绘图函数

极坐标绘图

极坐标和笛卡尔坐标完全不同,极坐标中的点是一个角度和距离中心的一条直线来确定的,下面的例子是在极坐标中绘图:

# 生成角度
theta = np.arange(0,2*np.pi,0.02)
# polar开启极坐标绘图方式
plt.subplot(121, polar=True)
# 绘制线
plt.plot(theta,1.6*np.ones_like(theta),"--",color='red', linewidth=2)
plt.plot(3*theta, theta/3, "--",color='blue', linewidth=2)

plt.subplot(122, polar=True)
plt.plot(theta, 1.4*np.cos(5*theta), "--", linewidth=2)
plt.plot(theta, 1.8*np.cos(4*theta), linewidth=2)
# 设置同心圆栅格的半径大小和文字标准角度
plt.rgrids(np.arange(0.5,2,0.5),angle=45)
# 绘制两条放射线栅格线,分别为0°和45°
plt.thetagrids([0, 45])

这里写图片描述

柱状图

x = np.arange(12)
y1 = 3*np.random.uniform(0.5, 1.0, 12)
y2 = 3*np.random.uniform(0.5, 1.0, 12)
error = np.ones_like(y1)*0.2
        # bar(left, height, width=0.8, bottom=None, hold=None, **kwargs)  
        # 绘制柱形图  
        # left:柱形图的x坐标  
        # height柱形图的高度,以0.0为基准  
        # width:柱形图的宽度,默认0.8  
        # facecolor:颜色  
        # edgecolor:边框颜色n  
        # bottom:表示底部从y轴的哪个刻度开始画  
        # yerr:应该是对应的数据的误差范围,加上这个参数,柱状图头部会有一个蓝色的范围标识,标出允许的误差范围,在水平柱状图中这个参数为xerr  
plt.bar(x, y1, width=0.8, facecolor="#9999ff",edgecolor="white",yerr=error)
plt.bar(x,-y2,facecolor="#ff9999",edgecolor="white")  
for x,y1,y2 in zip(x,y1,y2):  
    plt.text(x,y1+0.2,'%.2f' % y1,ha='center',va='bottom')  
    plt.text(x,-(y2+0.05),'%.2f' % y2,ha='center',va='top')  
plt.ylim(-3.5,3.5)

这里写图片描述
横向的柱状图用函数barh,其参数和bar差不多。

people = ('James', 'Durant', 'Kobe', 'Wade', 'Curry','Magic','Hardan')  
y_pos = np.arange(len(people))  
performance = 30 + 70 * np.random.rand(len(people)) #随机产生len(people)个 [0,1)的数  
error = np.random.rand(len(people))  
plt.barh(y_pos, performance, xerr=error, align='center', alpha=0.4)#这里是产生横向柱状图 barh h--horizontal  
plt.yticks(y_pos, people)  
plt.xlabel('Performance')  
plt.xlim(0,100)  
plt.title('How efficient do you want to go today?')  
plt.show()  

这里写图片描述

散列图

使用plot绘制,在绘制时指定样式参数为只绘制数据点,得到的便是一散列图:

x = np.random.random(20)
y = np.random.random(20)

plt.plot(x,y,"o")
plt.show()

这里写图片描述
但这种方式绘制的散列图无法给点指定不同的颜色和大小。利用scatter()绘制时可以解决这一问题:

fig = plt.figure(figsize=(8,4))
x = np.random.random(20)
y = np.random.random(20)
# s:设置点的大小
# c:设置点的颜色,可以为单个的数值或者rgb三元组
# marker:可以是单个的字符表示,当为一个元组时,第一个值表示变数,
#       第二个值表示形 状,取值范围时0多边形,1星形,2放射形,3忽略边数显示为圆形。
# alpha:透明度
# lw:线宽
plt.scatter(x,y,s=x*1000,c=y,marker='o', alpha=1.0, lw=2, facecolors="none")
plt.xlim(0,1)
plt.ylim(0,1)

这里写图片描述

图像显示

imread()和 imshow()提供了简单的图像载入和品示功能。 imread()可以从图像文件读入数据,得到一个表示图像的NumPy数组。它的第一个参数是文件名或文件对象,format参数指定图像类型,如果省略则由文件的扩展名决定图像类型。对于灰度图像,它返回一个形状为(M,N)的数组;对于彩色图像,它返回形状为(M,N,C )的数组。其中M为图像的高度,N为图像的宽度,C为3或4 , 表示图像的通道数。

img = plt.imread("D:\dd.jpg")
fig, ax = plt.subplots(2,4,figsize=(11,4))
fig.subplots_adjust(0,0,1,1,0.5,0.5)
axes = ax.ravel()
axes[0].imshow(img)
# lower 会将图像的(0,0)点映射到左下点,所以图像时上下颠倒的
axes[1].imshow(img, origin='lower')
# 图像的值要么是0-255的点,要么是0.0-1.0的值,超出这个范围会显示出错
axes[2].imshow(img*1.0)
# 将和原图像一样
axes[3].imshow(img/255.0)
# 将超出范围的限制在0-1范围内,图像将会变亮
axes[4].imshow(np.clip(img/200.0,0,1))
#对红色通道进行映射
axe_img = axes[5].imshow(img[:,:,0])
plt.colorbar(axe_img,ax=axes[5])
# 指定映射方式
axe_img = axes[6].imshow(img[:,:,0],cmap="copper")
plt.colorbar(axe_img,ax=axes[6])

for ax in axes:
    ax.set_axis_off()

matplotlib中预先定义了一些颜色映射表,以ColorMap对象封装,使用imshow()可以显示任意的二维数据,例如下面显示的二元函数 f(x,y)=xex2y2

# 生成数据
y,x = np.ogrid[-2:2:200j,-2:2:200j]
z = x*np.exp(-x**2-y**2)
# 确定x、y的取值范围
extent = [np.min(x), np.max(x), np.min(y), np.max(y)]
plt.figure(figsize=(10,3))
plt.subplot(121)
plt.imshow(z,extent=extent,origin="lower")
plt.colorbar()
plt.subplot(122)
plt.imshow(z,extent=extent,cmap=cm.gray,origin="lower")
plt.colorbar()

这里写图片描述

等值线图

等值线(或者叫等高线)是指函数值相等点的连线,通过等值线可以直观的观察到函数值的变化,例如等值线比较密集的地方表示函数值变换比较频繁,在matplotlib中,等值线可以通过contour()或者contourf()来显示,两者的区别是后者是带填充的等值线。依旧以二元函数 f(x,y)=xex2y2 为例:

y,x = np.ogrid[-2:2:200j,-3:3:300j]
z = x*np.exp(-x**2-y**2)
extent = [np.min(x), np.max(x), np.min(y), np.max(y)]
plt.figure(figsize=(10,4))
plt.subplot(121)
## contour返回QuadContourSet对象,是等值线上的值,显示10个值等值线
cs = plt.contour(z,10,extent=extent)
## 显示等值线的值
plt.clabel(cs)
plt.subplot(122)
plt.contourf(x.reshape(-1), y.reshape(-1), z, 20)

这里写图片描述

箭头图

使用quiver()可以用大量的箭头表示矢量场,下面的代码显示 f(x,y)=xex2y2 的梯度场,该函数的前5个参数中,X,Y是箭头的起点坐标,U,V是箭头的方向和大小,C是箭头对应的值。

def f(x,y):
    return x*np.exp(-x**2-y**2)

# 计算偏导
def vec_field(f,x,y,dx=1e-6, dy=1e-6):
    x2 = x+dx
    y2 = y+dy
    v = f(x,y)
    vx = (f(x2,y)-v)/dx
    vy = (f(x,y2)-v)/dy
    return vx,vy

X,Y = np.mgrid[-2:2:20j,-2:2:20j]
C = f(x,y)
U,V = vec_field(f,X,Y)
plt.quiver(X,Y,U,V,C)
plt.colorbar()
plt.gca().set_aspect("equal")

这里写图片描述
quiver()还有许多配置参数,具体的参考matplotlib文档。

小结

Matplotlib功能强大,能满足大多绘图需求,这里说的也是一小部分,除此Matplotlib也支持鼠标点击、三位绘图功能,具体的可到Matplotlib官网参看说明文档。

你可能感兴趣的:(机器学习与大数据,python科学计算笔记)