martin
Matplotlib绘图和可视化 matplotlib API 入门Figure和Subplot颜色标记和线型刻度标签和图例注解以及在Subplot上绘图将图表保存到文件绘图是数据分析工作中最重要的任务之一,是探索过程中的一部分。例如帮助我们找出异常值、必要的数据转化、得出有关模型的idea等。Python有许多可视化工具,但是这里主要讲解matplotlib(http://matplotlib.sourceforge.net)。matpllotlib API函数(如plot和close)都位于matplotlib.pyplot模块中,其通常的引入约定是:
>>>import matplotlib.pyplot as pltmatplotlib的图像都位于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()绘制出来的图如下:
除标准的图表对象外,可能还希望绘制一些自定义的注解(比如文本、箭头或者其他图形等)。注解可以通过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图像分辨率,默认为100facecolor、edgecolor图像的背景色、默认为W白色format显式设置文件格式(png,pdf,svg,csv…..)bbox_inches图表需要保存的部分,如果设置为tight,则尝试剪除图表周围的空白部分