python有许多可视化工具,本书主要讲解matplotlib。matplotlib是用于创建出版质量图表的桌面绘图包(主要是2D方面)。matplotlib的目的是为了构建一个MATLAB式的绘图接口。本书中的大部分图都是用它生成的。除了图形界面显示,还可以把图片保存为pdf、svg、jpg、png、gif等形式。
1、matplotlib API入门
Ipython可以用close()关闭界面。
Figure和Subplot
matplotlib的图像都位于Figure对象中。用plt.figure创建一个新的Figure。
import numpy as npimport pandas as pdimport matplotlib.pyplot as plt'''#plt.plot(np.arange(10))fig = plt.figure()#plt.show()#figsize 有一些重要的选项,特别是figsize,规定的是图片保存到磁盘时具有一定大小的纵横比。#plt.gcf()即可得到当前Figure的引用ax1 = fig.add_subplot(2,2,1)ax2 = fig.add_subplot(2,2,2)ax3 = fig.add_subplot(2,2,3)plt.plot(np.random.randn(50).cumsum(),'k--')#fig.add_subplot 返回的对象是AxesSubplot对象,下面调用就可以了_ = ax1.hist(np.random.randn(100),bins = 20,color = 'k',alpha = 0.3)ax2.scatter(np.arange(30),np.arange(30) + 3 * np.random.randn(30))plt.show()'''#由于Figure 和 subplot是一件非常常见的任务,于是出现了更为方便的方法(plt.subplots ),它可以创建一个新的Figure,#并返回一个含有已创建的subplot对象的Numpy数组fig,axes = plt.subplots(2,3)#print figprint axes[0][0]#axes[0][0].hist(np.random.randn(100),bins = 20,color = 'k',alpha = 0.3)plt.show()#这是非常实用的,因为可以轻松地对axes数组进行索引,就好像一个是一个二维数组一样,例如#axes[0,1].还可以通过sharex和sharey指定subplot具有相同的x轴和y轴。在比较相同范围的数据时,这是#非常实用的,否则matplotlib会自动缩放各图表的界限。
看一下subplots的作用:
pyplot.subplots的选项还有:
上面的**fig_k可以有很多的参数,文档中有更多的内容。
调整subplot周围的间距
默认情况下,matplotlib会在subplot外围留下一定的边距,并在subplot之间留下一定的间距。间距和图像的高度和宽度有关,会自动调整。利用Figure的subplots——adjust方法可以修改间距,因此,它是一个顶级函数。
import numpy as npimport pandas as pdimport matplotlib.pyplot as pltsubplots_adjust(left = None,bottom = None,right = None,top = None,wspace = None,hspace = None)#wspace和space用于控制宽度和高度的百分比,可以用做subplot之间的间距,下面是个例子:'''fig,ax = plt.subplots(2,2,sharex = True,sharey = True)for i in range(2):for j in range(2):ax[i,j].hist(np.random.randn(500),bins = 50,color = 'k',alpha = 0.5)plt.subplots_adjust(wspace = 0.5,hspace = 0.5)plt.show()#matplotlib不会检查标签的重叠(确实是这样)。
# -*- encoding: UTF-8 -*- import numpy as npimport pandas as pdimport matplotlib.pyplot as pltfig,ax = plt.subplots(2,2)#cecece是白色……ax[0,0].plot(np.arange(10),linestyle = '--',color = '#CECECE')#线上面还可以添加一些标记(marker),以强调实际的数据点。由于matplotlib创建的是连续的线形图,因此有时可能不太容易看到真实点的位置,标记可以放到格式字符串中,但是标记类型和线性必须在颜色的后面ax[0,1].plot(np.random.randn(30).cumsum(),'ko--')ax[1,0].plot(np.random.randn(30).cumsum(),color = 'k',linestyle = '--',marker = 'o')#在线型图中,非实际数据点默认是按照线性插值的,可以通过drawstyle选项修改这一点。data = np.random.randn(30).cumsum()ax[1,1].plot(data,'ko--')ax[1,1].plot(data,'k--',drawstyle = 'steps-post')plt.show()
注意上面的drawstyle选项可以规定点与点之间的连接方式,或者说是插值方式,结果为:
设置标题、轴标签、刻度以及刻度标签
# -*- encoding: UTF-8 -*- import numpy as npimport pandas as pdimport matplotlib.pyplot as pltimport numpy.random as nprfig = plt.figure()ax = fig.add_subplot(1,1,1)ax.plot(npr.randn(1000).cumsum())#要想修改x的刻度,最简单的方法就是使用set_xticks和set_xticklabels.前者告诉matplotlib将#刻度放在数据范围中的哪些位置,默认情况下,这些位置就是刻度标签。但是可以使用set_xticklabels将#任何其他的值用作标签ticks = ax.set_xticks([0,250,500,700,900,1000])#下面的totation是规定旋转角度labels = ax.set_xticklabels(['a','b','c','d','e','f'],rotation = 30,fontsize = 'small')#可以为x轴设置名称ax.set_xlabel('Stages')plt.show()
图例
# -*- encoding: UTF-8 -*- import numpy as npimport pandas as pdimport matplotlib.pyplot as pltimport numpy.random as nprfrom datetime import datetime#添加图例fig = plt.figure()ax = fig.add_subplot(1,1,1)ax.plot(npr.randn(1000).cumsum(),'k',label = 'one')ax.plot(npr.randn(1000).cumsum(),'k--',label = 'two')ax.plot(npr.randn(1000).cumsum(),'k.',label = 'three')ax.legend(loc = 'best')plt.show()
注解与绘图
# -*- encoding: UTF-8 -*- import numpy as npimport pandas as pdimport matplotlib.pyplot as pltimport numpy.random as nprfrom datetime import datetimefig = plt.figure()ax = fig.add_subplot(1,1,1)data = pd.read_csv('E:\\spx.csv',index_col = 0,parse_dates = True)spx = data['SPX']spx.plot(ax = ax,style = 'k-')crisis_data = [(datetime(,10,11),'Peak of bull market'),(datetime(,3,12),'Bear Stearns Fails'),(datetime(,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/','1/1/'])ax.set_ylim([600,1800])ax.set_title('Important dates in - finacial crisis')plt.show()#更多关于注解的示例,请看文档#图形的绘制要麻烦些,有一些常见的图形的对象,这些对象成为块(patch)#如Rectangle 和 Circle,完整的块位于matplotlib.patches#要绘制图形,需要创建一个块对象shp,然后通过ax.add_patch(shp)将其添加到subplot中fig = plt.figure()ax = fig.add_subplot(1,1,1)rect = plt.Rectangle((0.2,0.75),0.4,0.15,color = 'k',alpha = 0.3)circ = plt.Circle((0.7,0.2),0.15,color = 'b',alpha = 0.3)pgon = plt.Polygon([[0.15,0.15],[0.35,0.4],[0.2,0.6]],color = 'g',alpha = 0.5)ax.add_patch(rect)ax.add_patch(circ)ax.add_patch(pgon)plt.show()
将图表保存到文件
# -*- encoding: UTF-8 -*- import numpy as npimport pandas as pdimport matplotlib.pyplot as pltimport numpy.random as nprfrom datetime import datetimefrom io import StringIO#将图标保存到文件#savefig函数可以保存图形文件,不同的扩展名保存为不同的格式fig = plt.figure()ax = fig.add_subplot(1,1,1)rect = plt.Rectangle((0.2,0.75),0.4,0.15,color = 'k',alpha = 0.3)circ = plt.Circle((0.7,0.2),0.15,color = 'b',alpha = 0.3)pgon = plt.Polygon([[0.15,0.15],[0.35,0.4],[0.2,0.6]],color = 'g',alpha = 0.5)ax.add_patch(rect)ax.add_patch(circ)ax.add_patch(pgon)#注意下面的dpi(每英寸点数)和bbox_inches(可以剪除当前图标周围的空白部分)(确实有效)#plt.savefig('pic.jpg',dpi = 100,bbox_inches = 'tight')#不一定save到文件中,也可以写入任何文件型对象,比如StringIO:buffer = StringIO()plt.savefig(buffer)plot_data = buffer.getvalue()#这对Web上提供动态生成的图片是很实用的#plt.show()
savefig的一些选项:
matplotlib配置
matplotlib的一些属性是可以设置的,比如图像大小、subplot边距、配色方案、字体大小、网格类型等。有两种方式进行操作。第一种是Python变成方式,即利用rc方法。比如:
plt.rc('figure',figsize = (10,10))
rc的第一个参数是希望自定义的对象,比如‘figure’、‘axes’、‘xtick’、‘ytick’、‘grid’、‘legend’等。其后可以跟上一系列的关键字参数。最简单的就是写成一个字典:
font_options = {'family':'monospace','weight':'bold','size':'small'}plt.rc('font',**font_options)
matplotlibrc是配置文件,定义好以后每次加载就会用设置的参数。
2、pandas中的绘图函数
matplotlib是一种比较低级的工具,需要将各种组件组合好:数据展示(线型图、柱状图等)、图例、标题、刻度标签以及注解。这是因为制作一张图表一般需要用到多个对象。在pandas中,会省事不少。pandas能够利用DataFrame的对象特点创建标准图表的高级绘图方法。作者说pandas在线文档时最好的学习工具,书上的代码可能过时了。
线型图
#-*- encoding:utf-8 -*-import numpy as npimport pandas as pdimport matplotlib.pyplot as pltfrom pandas import Series,DataFrames = Series(np.random.randn(10).cumsum(),index = np.arange(0,100,10))#该Series对象的索引会被传给matplotlib,并绘制X轴。#可以用use_index = False 禁用该功能s.plot(use_index = False)#X轴的刻度和界限可以通过xticks和xlim选项进行调节,Y轴通过xticks和ylim调节plt.show()#pandas的大部分方法都有一个可选的ax参数,可以是一个subplot对象。这可以#使在网格中更为灵活地处理subplot的位置。#DataFrame的plot方法会在一个subplot中为各列绘制线型图,并自动添加图例df = DataFrame(np.random.randn(10,4).cumsum(0),columns = ['A','B','C','D'],index = np.arange(0,100,10))df.plot()plt.show()
下面把参数贴一下:
DataFrame还有一些对列进行处理的参数:
自下面开始就有一些专门的图形,绘制的时候可以与R语言进行对比:/batteryhp/p/4733474.html。
柱状图
#-*- encoding:utf-8 -*-import numpy as npimport pandas as pdimport matplotlib.pyplot as pltfrom pandas import Series,DataFrame#生成的线形图中代码加上kind = ‘bar’(垂直柱图) 或者 (水平)kind = ‘barh’(水平柱图)#Series和DataFrame的索引被用作X(bar)或者Y(barh)的刻度fig,axes = plt.subplots(2,1)data = Series(np.random.randn(16),index = list('abcdefghijklmnop'))data.plot(kind = 'barh',ax = axes[0],color = 'k',alpha = 0.7)data.plot(kind = 'bar',ax = axes[1],color = 'k',alpha = 0.7)#DataFrame会按照行对数据进行分组df = DataFrame(np.random.randn(6,4),index = ['one','two','three','four','five','six'],columns = pd.Index(['A','B','C','D'],name = 'Genus')) #注意这里的name会被用作图例的标题,因为,这本来就是列的名字print dfdf.plot(kind = 'bar')plt.show()#这里的stacked是标明画累计柱图df.plot(kind = 'bar',stacked = True,alpha = 0.5)plt.show()#Series的value_counts可以用来显示Series中各值的频数(实验证明)s = Series([1,2,2,3,4,4,4,5,5,5])s.value_counts().plot(kind = 'bar')plt.show()
下面看一个例子:
#-*- encoding:utf-8 -*-import numpy as npimport pandas as pdimport matplotlib.pyplot as pltfrom pandas import Series,DataFrame#下面是一个例子:做一张堆积柱状图来显示每天各种聚会规模的数据点百分比tips = pd.read_csv('E:\\tips.csv')party_counts = pd.crosstab(tips.day,tips.size)print party_countsparty_counts = party_counts.ix[:,2:5]#然后进行归一化是各行和为1party_pcts = party_counts.div(party_counts.sum(1).astype(float),axis = 0)print party_pctsparty_pcts.plot(kind = 'bar',stacked = True)plt.show()
直方图和密度图
#-*- encoding:utf-8 -*-import numpy as npimport pandas as pdimport matplotlib.pyplot as pltfrom pandas import Series,DataFrame#绘制小费百分比直方图tips = pd.read_csv('E:\\tips.csv')tips['tip_pct'] = tips['tip'] / tips['total_bill']#bins规定一共分多少个组tips['tip_pct'].hist(bins = 50)plt.show()#与此相关的是密度图:他是通过计算“可能会产生观测数据的连续概率分布的估计”#而产生的。一般的过程将该分布金思维一组核(诸如正态之类的较为简单的分布)。#此时的密度图称为KDE图。kind = ‘kde’即可。tips['tip_pct'].plot(kind = 'kde')plt.show()#显然,直方图和密度图经常会在一起出现comp1 = np.random.normal(0,1,size = 200)comp2 = np.random.normal(10,2,size = 200)values = Series(np.concatenate([comp1,comp2]))print valuesvalues.hist(bins = 100,alpha = 0.3,color = 'k',normed = True)values.plot(kind = 'kde',style = 'k--')plt.show()
散布图
散布图(scantter plot)是观察两个一维数据序列之间的关系的有效手段。matplotlib中的scantter方法是绘制散布图的主要方法。
#-*- encoding:utf-8 -*-import numpy as npimport pandas as pdimport matplotlib.pyplot as pltfrom pandas import Series,DataFrame#下面加载macrodata中的数据集,选择其中几列并计算对数差macro = pd.read_csv('E:\\macrodata.csv')data = macro[['cpi','m1','tbilrate','unemp']]#这里的diff函数是用来计算相邻两数只差,对每一列,后一个数减前一个数trans_data = np.log(data).diff().dropna()#print np.log(data).head()#print np.log(data).diff().head()print trans_data.head()plt.scatter(trans_data['m1'],trans_data['unemp'])plt.title('Changes in log %s vs. log %s'%('m1','unemp'))plt.show()#画散布图矩阵式很有意义的pandas提供了scantter_matrix函数来创建散步矩阵#关于 diagonal 参数,是为了不让对角线上的图形(自己和自己的散布图)显示为一条直线而设置的关于这种数据的某些图形显示#比如 diagonal = 'kde'就是画密度图且核为kde,若diagonal='hist',则为直方图pd.scatter_matrix(trans_data,diagonal = 'kde',color = 'k',alpha = 0.3)pd.scatter_matrix(trans_data,diagonal = 'hist',color = 'k',alpha = 0.3)plt.show()
绘制地图:图形化显示海地地震危机数据
这是一个例子。
#-*- encoding:utf-8 -*-import numpy as npimport pandas as pdimport matplotlib.pyplot as pltfrom pandas import Series,DataFramefrom mpl_toolkits.basemap import Basemap#下面的例子应该是比较综合的data = pd.read_csv('E:\\Haiti.csv')#print data#下面处理一下数据,下面的为日期,纬度、经度#print data[['INCIDENT DATE','LATITUDE','LONGITUDE']][:10]#print data['CATEGORY'][:6] #这些代表消息的类型#数据中很有可能有异常值、缺失值,下面看一下#print data.describe()#清除错误信息并移除缺失分类信息是“一件简单的事情”data = data[(data.LATITUDE > 18) & (data.LATITUDE < 20) & (data.LONGITUDE > -75) &(data.LONGITUDE < -70) & data.CATEGORY.notnull()]#我们想根据分类对数据做一些分析或者图形化工作,但是各个分类字段中可能含有多个分类。此外,各个分类信息#不仅有一个编码,还有一个英语(法语)名称。因此需要对数据进行规整化处理。下面编写两(三)个#函数,一个用于获取所有分类的列表,一个用于将各个分类信息拆分为编码和英语明名称#sptrip 是删除空白字符,'\n'等;注意作者这种隐式循环写法def to_cat_list(catstr):stripped = (x.strip() for x in catstr.split(','))return [x for x in stripped if x]def get_all_categoties(cat_series):cat_sets = (set(to_cat_list(x)) for x in cat_series)return sorted(set.union(*cat_sets))def get_english(cat):code,names = cat.split('.')if '|' in names:names = names.split('|')[1]return code,names.strip()#下面进行一下ceshi#print get_english('2.Urgences logistiques | Vital Lines')#接下来做了一个将编码跟名称映射起来的字典,这是因为我们等会要用编码进行分析。#下面将所有组合弄出来all_cats = get_all_categoties(data.CATEGORY)#print data.CATEGORY[:10]#print all_cats#生成器表达式#生成字典english_mapping = dict(get_english(x) for x in all_cats)#print english_mapping['2a']#print english_mapping['6c']#根据分类选取记录的方式有很多,其中之一就是添加指标(或者哑变量)列,每个分类一列。#为此,首先抽取出唯一的分类编码,并构造一个全零DataFrame(列为分类编码,索引跟data的索引一样)def get_code(seq):return [x.split('.')[0] for x in seq if x]#下面是将所有的key取出来all_codes = get_code(all_cats)#print all_codescode_index = pd.Index(np.unique(all_codes))#print code_indexdummy_frame = DataFrame(np.zeros((len(data),len(code_index))),index = data.index,columns = code_index)#print len(data)#print dummy_frame.ix[:,:6]#下面将各行中适当的项设置为1,然后再与data进行连接:for row,cat in zip(data.index,data.CATEGORY):codes = get_code(to_cat_list(cat))dummy_frame.ix[row,codes] = 1#添加前缀,并且合并一下data = data.join(dummy_frame.add_prefix('category_'))#print data#接下来开始画图吧,我们希望把数据绘制在海地的地图上。basemap数据集是matplotloib的一个插件#使得能够用Python在地图上绘制2D数据。basemap提供了许多不同的地球投影以及一种将地球上的经纬度#坐标投影转换为二维matplotlib图的方式。#“经过一遍又一遍的尝试”,作者编写了下面的函数,绘制出一张简单的黑白地图。def basic_haiti_map(ax = None,lllat = 17.25,urlat = 20.25,lllon = -75,urlon = -71):#创建极球面投影的Basemap实例。m = Basemap(ax = ax,projection = 'stere',lon_0 = (urlon + lllon) / 2,lat_0 = (urlat + lllat) / 2,llcrnrlat = lllat,urcrnrlat = urlat,llcrnrlon = lllon,urcrnrlon = urlon,resolution = 'f' )
由于window下安装geos不成功,这部分等ubuntu装好了再接着写。
4、Python图形化工具生态系统
介绍几个其他的绘图工具。
Chaco
特点:静态图 + 交互图形,非常适合用复杂的图形化方法表示数据的内部关系。对交互支持的好的多,交互式GUI是个不错选择。
mayavi
这是一个基于开源C++图形库VTK的3D图形工具包。可以集成到Ipython交互使用。
其他库
其他库或者应用还有:PyQwt、Veusz、gnuplotpy、biggles等,大部库都在向基于Web的技术发展,并逐渐远离桌面图形技术。
图形化工具的未来
基于Web技术(如Javascript)的图形化是必然的发展趋势,现在已经有不少了,higncharts等。
如果觉得《《利用python进行数据分析》读书笔记--第八章 绘图和可视化》对你有帮助,请点赞、收藏,并留下你的观点哦!