Matplotlib绘图和可视化
Matplotlib绘图和可视化
matplotlib API 入门
绘图是数据分析工作中最重要的任务之一,是探索过程中的一部分。例如帮助我们找出异常值、必要的数据转化、得出有关模型的idea等。Python有许多可视化工具,但是这里主要讲解matplotlib(http://matplotlib.sourceforge.net)。matpllotlib API函数(如plot和close)都位于matplotlib.pyplot模块中,其通常的引入约定是:
>>>import matplotlib.pyplot as plt
Figure和Subplot
matplotlib的图像都位于Figure对象中。可以用plt.figure创建一个新的Figure:
>>>fig = plt.figure() # 创建对象
>>>plt.show() # 显示图像,无此句代码将不能显示图像
这时会弹出一个空窗口。
plt.figure有一些选项,特别是figsize,它用于确保当图片保存到磁盘时具有一定大小的纵横比。值得注意的是,不能通过空figure绘图,必须用add_subplot创建一个或者多个subplot才行:
>>>ax1 = fig.add_subplot(2,2,1)
这条代码的意思是:图像应该是2*2的(即有2行2列,定义了图像的位置),且当前选中的是第一个,(编号从一开始)。如果再把后面两个subplot也创建出来,最终得到的图像如图:
>>>ax2 = fig.add_subplot(2,2,2)
>>>ax3 = fig.add_subplot(2,2,3)
>>>plt.show()
如果这时发出一条绘图命令(如plt.plot([1.5,3.5,-2,1.6])),matplotlib就会在最后一个用过的subplot(如果没有则创建一个)上进行绘制。因此,如果我们执行下列命令,你就会得到如图所示:
>>>from numpy.random import randn
>>>plt.plot(randn(50).cumsum(),'k--') # 随机选取50个正态分布数进行虚线绘图
plt.show()
k–是一个线型选项,用于告诉matplotlib绘制黑色虚线图。上面那些由fig.add_subplot所返回的对象,直接调用他们的实例方法就可以在其他空着的格子里面画图了,如图:
>>>ax1.hist(randn(100),bins=20,color='k',alpha=0.3) # 20个直方图,alpha透明度
>>>ax2.scatter(np.arange(30),np.arange(30)+3*randn(30)) # 绘制散点图
>>>plt.show()
由于根据特定布局创建figure和subplot是一件非常常见的任务,于是便出现了一个更为方便的方法(plt.subplots),它可以创建一个新的Figure,并返回一个含有已创建的subplot对象的numpy数组:
>>>fig,axes = plt.subplots(2,3)
>>>axes
array([[<matplotlib.axes._subplots.AxesSubplot object at 0x7f2b593c0a90>,
<matplotlib.axes._subplots.AxesSubplot object at 0x7f2b59325890>,
<matplotlib.axes._subplots.AxesSubplot object at 0x7f2b592b1f50>],
[<matplotlib.axes._subplots.AxesSubplot object at 0x7f2b59242090>,
<matplotlib.axes._subplots.AxesSubplot object at 0x7f2b591a39d0>,
<matplotlib.axes._subplots.AxesSubplot object at 0x7f2b59127ad0>]], dtype=object)
>>>
这是非常实用的,因为可以轻松的对axes数组进行索引,就好像是一个二维数组一样,例如,axes[0,1].hist(randn(100),bins=20,color='red',alpha=0.3)
>>>axes[0,1].hist(randn(100),bins=20,color='red',alpha=0.3)
>>>plt.show()
- 调整subplot周围的间距
默认情况下,matplotlib会在subplot外围留下一点的边距,并在subplot之间留下一定的边距。间距跟图像的高度和宽度有关,因此,如果你调整了图像的大小(不管是编程还是手工),间距也会自动调整。利用figure的subplots_adjust方法可以轻而易举的修改间距,此外,他还是个*函数,wspace和hspace用于控制宽度和高度的百分比,可以用作subplot之间的间距,下面是一个简单的例子,其中将间距收缩到了0:
>>>fig,axes = plt.subplots(2,2,sharex=True,sharey=True)
>>>for i in range(2):
... for j in range(2):
... axes[i,j].hist(randn(500),bins=50,color='k',alpha=0.5)
...
>>> plt.subplots_adjust(wspace=0,hspace=0) # 将比例收缩到0
>>> plt.show()
不难看出,其中的轴标签重叠了。matplotlib不会检查标签是否重叠,所以对于这种情况,只能自己手动设定,在后面会详细讲到。
颜色、标记和线型
matplotlib的plot函数接受一组X和Y坐标,还可以接受一个表示颜色和线型的字符串缩写。例如,要根据x,y坐标绘制绿色虚线,可以这样:ax.plot(x,y,'g--')
,这种在一个字符串中指定颜色和线型的方式非常方便,通过下面更明确地指定方式也可以达到相同的效果:ax.plot(x,y,linestyle='--',color='g')
,常用的颜色都有一个缩写词,如红色:r,蓝色:b,要使用其他任意颜色则可以通过指定其RGB值的形式使用(例如,‘#CECECE’)。完成的linestyle列表参见plot文档。线型图还可以加上一些标记(marker),以强调实际的数据点。由于matplotlib创建的连续的线型图(点与点之间插值),因此有时可能不太容易看出真实数据点的位置。标记也可以放到格式字符串中,但标记类型和线型必须放到颜色后面。
>>> plt.plot(randn(30),linestyle='--',color='b',marker='o')
>>> plt.show()
>>> plt.plot(randn(30),linestyle='--',color='r',marker='*')
>>>plt.show()
在线型图中,非实际数据点默认是按线性方式插值的。可以通过drawstyle选项修改:
>>> data = randn(30).cumsum()
>>> plt.plot(data,'k-',drawstyle='steps-post',label='steps-post') # 实线阶跃图
>>> plt.plot(data,'k--',label='Default') # 虚线线性图
>>> plt.legend(loc='best') # 添加图例
>>> plt.show()
对于添加图例,在plot对象中通过label参数添加即可,最后在plt.legend(loc=”)中选择添加位置就轻松完成。下面给出loc的位置参数:
参数 | 代码 | 位置 |
---|---|---|
‘best’ | 0 | 自适应 |
‘upper right’ | 1 | 右上 |
‘upper left’ | 2 | 左上 |
‘lower left’ | 3 | 左下 |
‘lower right’ | 4 | 右下 |
‘right’ | 5 | 右 |
‘center left’ | 6 | 中心偏左 |
‘center right’ | 7 | 中心偏右 |
‘lower center’ | 8 | 中心下方 |
‘upper center’ | 9 | 中心上方 |
‘center’ | 10 | 中间 |
刻度、标签和图例
pyplot的接口设计目的就是交互式使用,含有诸如xlim,xticks和xticklabels之类的方法,他们分别控制图标的范围,刻度位置、刻度标签等。其使用方式有如下两种:
1、调用时不带参数,则返回当前的参数值。例如,plt.xlim()返回当前的X轴绘图范围。
2、调用时带参数,则设置参数值。因此,plt.xlim([0,10])会将X轴的范围设置为0到10
- 设置标题、轴标签、刻度以及刻度标签
为了说明轴的自定义,将创建一个简单的图像并绘制一段随机数:
>>> fig = plt.figure()
>>> ax = fig.add_subplot(1,1,1)
>>> ax.plot(randn(1000).cumsum())
>>> plt.show()
绘制后的图像如图所示:
如果要修改X轴的刻度,最简单的办法是使用set_xticks和set_xticklabels。前者告诉matplotlib要将刻度放在数据范围中的哪些位置,默认情况下,这些位置也就是刻度标签。但我们可以通过set_xticklabels将任何其他的值用作标签:
>>> ticks = ax.set_xticks([0,250,500,750,1000]) # X轴刻度
>>> labels = ax.set_xticklabels(['one','two','three','four','five'],rotation=30,fontsize='small') # X轴标签
最后,再用set_xlabel为X轴设置一个名称,并用set_title设置一个标题:
>>> ax.set_title('My first matplotlib plot') # 设置标题
>>> ax.set_xlabel('Stages') # 设置X轴名
>>> plt.show()
对于Y轴同样的,只需把set_xticks、set_xticklabels等换成set_yticks、set_yticklabels即可,是不是非常方便?最后绘制的图为下:
值得我们思考的是:matplotlib默认字体不是中文而是英文,如果想要将标题设置成中文该如何做呢?我们这里分成两个平台来解决:
linux平台(笔者的linux环境是Ubuntu14.4的)
1、首先要知道linux系统下的中文字体包在哪里,所以我们要在linux终端中输入该语句: fc-list :lang=zh-cn
#注意:前有个空格
给各位截个图:
图中列出了所有包含中文字体的目录或文件,而我们需要的是后缀是.ttf的路径,好的,记住它。
2、找到了中文字体的所在目录,接下来就好办了,只需在程序中写入如下语句即可:
>>>from matplotlib.font_manager import FontProperties
>>>font = FontProperties(fname = "/usr/share/fonts/truetype/droid/DroidSansFallbackFull.ttf", size=14)
3、另外要注意的就是,假如要使用中文,只需在中文前加个字符u
即可,如:plt.title(u'这里写的是中文')
windows平台
windows平台下的操作相对来说简单点,只需在程序中写入如下语句即可:
>>>from pylab import mpl
>>>mpl.rcParams['font.sans-serif'] = ['FangSong'] # 指定默认字体
>>>mpl.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题
同样,在使用中文时要加上字符u
。如:plt.title(u'这里写的是中文')
下面我们实践一下,将图中的英文都换成中文:
>>> fig = plt.figure()
>>> ax = fig.add_subplot(1,1,1)
>>> ax.plot(randn(1000).cumsum())
>>> from matplotlib.font_manager import FontProperties
>>> font = FontProperties(fname='/usr/share/fonts/truetype/droid/DroidSansFallbackFull.ttf',size=14)
>>> ticks = ax.set_xticks([0,250,500,750,1000])
>>> labels = ax.set_xticklabels([u'一',u'二',u'三',u'四',u'五'],rotation=30,fontsize='small',fontproperties=font)
>>> ax.set_title(u'我的第一个绘图',fontproperties=font)
>>> ax.set_xlabel(u'阶段',fontproperties=font)
>>> plt.show()
所绘制的图如下:
- 添加图例
图例(legend)是另一种用于标识图表元素的重要工具。最简单的添加方式是在添加subplot的时候传入label参数:
>>> fig = plt.figure()
>>> ax = fig.add_subplot(1,1,1)
>>> ax.plot(randn(1000).cumsum(),'k',label='one')
>>> ax.plot(randn(1000).cumsum(),'g--',label='two')
>>> ax.plot(randn(1000).cumsum(),'b.',label='three')
>>> ax.legend(loc='best')
>>> plt.show()
绘制出来的图如下:
注解以及在Subplot上绘图
除标准的图表对象外,可能还希望绘制一些自定义的注解(比如文本、箭头或者其他图形等)。注解可以通过text(文本)、arrow(箭头)和annotate(注解)等函数进行添加。text可以将文本绘制在图表的指定坐标(x,y)。注解中可以既含有箭头也含有文本,例如,根据2007年以来的标注普尔500指数收盘价格绘制一张曲线图,并标出2008年到2009年金融危机期间的一些重要日期,代码如下:
>>> from datetime import datetime
>>> import pandas as pd
>>> fig = plt.figure()
>>> ax = fig.add_subplot(1,1,1)
>>> data = pd.read_csv('/home/martin/work/data/ch08/spx.csv',index_col=0,parse_dates=True) # csv数据的路径
>>> spx = data['SPX']
>>> spx.plot(ax=ax,style='k-')
>>> crisis_data = [(datetime(2007,10,11),'Peak of bull market'),(datetime(2008,3,12),'Bear Stearns Fails'),(datetime(2008,9,15),'Lehman Bankruptcy')]
>>> for date,label in crisis_data:
... ax.annotate(label,xy=(date,spx.asof(date)+50),xytext=(date,spx.asof(date)+200),arrowprops=dict(facecolor='black'),horizontalalignment='left',verticalalignment='top')
...
>>> ax.set_xlim(['1/1/2007','1/1/2011']) # 将窗口定在2007-2010年份
>>> ax.set_ylim([600,1800])
>>> ax.set_title('Important dates in 2008-2009 financial crisis')
>>> plt.show()
绘制后的图形如下:
更多有关注解的示例,请访问matplotlib的在线示例库。
将图表保存到文件
利用plt.savefig可以将当前图表保存到文件,例如将图表保存为csv文件,你只需要输入: plt.savefig('example.csv')
。文件类型是通过文件扩展名推断出来的。我们在发布图片时最常用到的两个重要选项是dpi(控制每英寸点数,分辨率)和bbox_inches(可以剪除当前图表周围的空白部分)。要得到一张带有最小白边且分辨率为400DPI的png图片,你可以: plt.savefig('example.png',dpi=400,bbox_inches=''tight)
。下表给出savefig的参数:
参数 | 说明 |
---|---|
fname | 含有文件路径的字符串或python的文件型对象 |
dpi | 图像分辨率,默认为100 |
facecolor、edgecolor | 图像的背景色、默认为W 白色 |
format | 显式设置文件格式(png,pdf,svg,csv…..) |
bbox_inches | 图表需要保存的部分,如果设置为tight ,则尝试剪除图表周围的空白部分 |