Matplotlib可以说是Python最声名远扬的可视化库了,也是Python数据分析库的“三驾马车”之一。Matplotlib是基础而非常强大的可视化库,Seaborn等好用的可视化库是在前者的基础上进行的封装。Matplotlib擅长快速出简单的图、有丰富的接口进行精细化绘图、和Numpy结合做科学可视化及三维图配合默契、三维图。但也有些缺点,如不容易基于实用目的绘制有一定难度的图表(如小提琴图等)、标签等元素需指定坐标而不能自适应优化显示、难以实现交互。
官网说:
Matplotlib tries to make easy things easy and hard things possible.
我越用越认可这句话,Matplotlib非常强大,Hard things是possible但并非easy and fast。
Matplotlib出图示例
可视化基础框架对于一个数据表df(通过pandas读入为DataFrame)来说,用Matplotlib对其进行可视化的基础框架为:
fig, ax = plt.subplots() ax.plot(df['x'],df['y'])
通过上面几行代码就可以画出df表周一到周五y指标的变化折线。
折线图绘制示例
Matplotlib其实为作图提供了两套可视化接口:
- plt.plot()系列
- fig, ax = plt.subplots() ax.plot() 系列
根据官网教程,分别对应MATLAB的陈述式语法和面向对象写法,
个人理解,plt.plot()适合用于快速出图,读入一个数据表后想快速知道数据分布、指标关系等,通过plt.plot()系列语句直接出图,而ax.plot()更方便用来精细绘图,接口对各种图表元素的编辑很友好。
在Matplotlib官网搜索,通常能看到两套接口,如搜绘制饼图的关键词pie,结果中的axes.Axes.pie对应ax.pie()的用法,pyplot.pie对应plt.pie()的函数接口。
ax.×××()的写法看起来要写的语句多些,但这种面向对象(object-oriented)的写法通过fig, ax = plt.subplots()建立画布(figure)和定义轴域(axes),能更明确在哪作画和映射规则,给用户更大的自由度和更精细的调参能力。Axes包含了一套坐标轴(axis),确定了x/y坐标轴之后,数值再确定对应坐标,也就唯一确定了所在位置(这是二维情况下,更高维度就会对应着更多的axis),散点图是去确定点在轴域下的位置,柱状图是确定每个柱柱所在的位置,因此一套Axes就确定了唯一的独立的图,一个画布可以有多套Axes。简单说就是ax.×××()更方便调细节,初学者尽量避免用plt.×××系列来画图。
基础图表绘制
数据可视化从目的来说,是为了更直观展示数据或数据之间的对比、分布或关联关系。散点图、折线图、柱状图、条形图、饼图、直方图是非常常用而基础的可视化图。个人认为通过画这几种基础图并调细节是很好的学可视化实践。
将数据映射为可视图表
为了整体的美观和一致性,本文都用了一套自定义配色,通过mpl.rcParams["axes.prop_cycle"] = mpl.cycler('color', ['1EAFAE', 'A3FFFF', '69FFFF']) 语句实现简单改配色,具体关于mpl.rcParams后面再展开。
画散点图可以用两种主要的方法,scatter(x,y)和plot(x,y,'o') 。 通过ax.scatter(x,y)绘制以x为横坐标,y为纵坐标的散点图,scatter的重要参数如下:
- x,y:对应着x轴和y轴的数据,散点画在坐标轴里的[xi,yi]处。
- s,c,alpha: 对应散点大小(size)、颜色(color)、透明度,都可以传一个和点数量相同长度的数组,如s=df['z']可以做气泡图,一般气泡图为了防止遮盖问题,通常设置一定的透明度,alpha的范围为0到1。c='#BA5C25'设置点颜色,c赋值为一个数组可以做出每个点一个颜色的效果。
- marker:设置点的形状;
- cmap:颜色映射;
- norm:当颜色c为一组浮点数时,把值标准化到[0,1]做颜色映射,vmin和vamx参数是结合 norm 来用的;
散点图参数示例
ax.plot(x,y,'o')也可以画散点图,ax.plot()核心是绘制坐标系下的点和点之间的连线的,当突出点的大小而省略线时,就是散点图了,同样突出线就变成了折线图。通过fmt(也就是format_string)参数来控制这些,包括点的形状、颜色、线的风格颜色等。折线图基础绘制效果可回看上一部分可视化基础框架。
plot()的常用参数如下:
- x,y: x轴和y轴的数据,当plot()只有一个输入列表或数组时,参数被当做y轴,也就是value,x轴以索引自动生成,也就是ax.plot(y)相当于ax.plot(range(len(y)),y);
- fmt: 控制x,y绘制的折线的点形状、颜色、线的风格、颜色;
- 其他的lines.Line2D支持的属性, 如color控制线颜色,marker控制点形状,linestyle控制线风格类型及linewidth控制线宽等,如果既设置了fmt又指定了color呢?可以实践一下,线的颜色会根据color属性最终显示。
常用fmt字符意义整理(可收藏方便查阅)
plot()除了plot(x,y,[fmt])这种写法之外,还可以传多套x,y以绘制多条折线,写法是plot(x,y,[fmt],x2,y2,[fmt2],…)。
另外plot()还支持plot('col1','col2',data=df)这种写法,这是对二维表格数据更友好的接口。本文讲到的其他图形如bar、barh等基本也都是支持ax.×××(df['x'],df['y']) 和ax.×××(x,y,data)写法的。
通过ax.bar(x,height)绘制柱状图,条形图的绘制用ax.barh(y,width),因bar和barh的用法很类似,参数之间有对应关系,这里结合着看。
x,height: x轴的值和各柱的高,相当于折线图的x,y; width: 柱的宽度,默认是0.8,也可以传入一个数组,画不等宽的柱状图; bottom: 每个柱底部开始位置,默认是0,改bottom可以画堆积柱状图、瀑布图等; align: 柱状的x是在柱底部中心还是边缘,{'center', 'edge'},默认是center; data: 可以传入一个DataFrame,用法和前面说到的ax.plot('col1','col2',data=df)一致; 其他像color(柱颜色)、edgecolor(柱边框色)、linewidth(边框线宽)等图元属性用法都一致,linewidth也是可以简写为lw的,颜色可以传一个数组,可以画出五彩斑斓的柱,也可借由这个参数美化瀑布图; 条形图barh的参数有barh(y,width,height,left,align),y是Y轴的值,每个柱的位置,因此barh的y对应bar的x,barh的width对应bar的height,barh的height对应bar的width。每个柱开始的位置是left,对应bar的bottom。align、data、color等一致。 注意的是柱状图绘制语句ax.bar(x,height)的返回值是一个容器(BarContainer),包含了所有画出来的柱。通过这个返回值可以对柱进行一些个性化的处理,另外的应用就是根据返回柱的属性给每个柱标上文本标签。
#给柱状图标上标签 fig,ax= plt.subplots() rects=ax.bar(df['x'],df['y']) ax.set_ylim(0,100) for rect in rects: height = rect.get_height() ax.annotate('{}'.format(height), xy=(rect.get_x() rect.get_width() / 2, height), xytext=(0,1), # 1 points vertical offset textcoords="offset points", ha='center', va='bottom')
通过给x以一定的偏移量,绘制簇状柱形图。代码如下:
#簇状柱 ClusterBar x = list(range(1,len(df) 1)) width = 0.2 #每个柱的宽度 x1=[i-width for i in x] x2=[i width for i in x] fig, ax = plt.subplots(figsize=(6,5)) rects1 = ax.bar(x1,df['y'], width*2, label='Men',color='#1EAFAE') rects2 = ax.bar(x2,df['z'], width*2, label='Women',color='#69FFFF') ax.set_xticks(x) ax.set_xticklabels(df['x']) ax.legend()
通过给bottom参数传一个数组,可以画堆叠柱状图:堆叠柱除了等值堆叠之外,还可以等比堆叠,思路就是将每个x对应的柱都做一下数值变换,把柱的高度约束在[0,1],且堆叠之和为1,height=h[i]/sum(h)。
#堆叠柱状图 fig,ax= plt.subplots() ax.bar(df['x'],df['y'],label='Men') ax.bar(df['x'],df['z'],bottom=df['y'],label='Women') ax.legend() #等比例堆叠柱 fig,ax= plt.subplots() df['y1']=df.apply(lambda x:(x['y'])*100/(x['y'] x['z']),axis=1) df['z1']=df.apply(lambda x:(x['z'])*100/(x['y'] x['z']),axis=1) ax.bar(df['x'],df['y1']) ax.bar(df['x'],df['z1'],bottom=df['y1']) ax.set_ylim(0,100) #标签设置等代码省略
堆叠柱状图绘制效果
调节width参数使得柱和柱之间的宽度为0,并对数据进行统计在画图,可以用ax.bar()绘制直方图,但也不需要这么复杂,Matplotlib提供了绘制直方图的接口ax.hist(x,bins,normed),可以直接对某列数据绘制直方图。x是需要统计分布的数据列,bins控制分箱的个数,默认是10。
箱线图在数据分析中挺常用的,箱线图对于数据分布有很好的展示作用,Matplotlib提供了boxplot(x)用于绘制箱线图。
fig, ax= plt.subplots() ax.boxplot(df['y']) #箱线图
饼图是可视化中基础而重要的图形,是各种数据报告的常客,Matplotlib绘制饼图时因为xy轴默认比例尺不同,为了得到不扁的饼,需设置xy轴1像素对应的值相等。
#绘制饼图 fig,ax=plt.subplots(subplot_kw=dict(aspect="equal")) ax.pie(df['y']) #为了得到不扁的饼,设置xy轴比例尺相同 #--- #环状图 fig, ax = plt.subplots(subplot_kw=dict(aspect="equal")) wps=dict(width=0.3, edgecolor='w') ax.pie(df['y'], radius=1,startangle=90,counterclock=False,wedgeprops=wps) ax.pie(df['z'], radius=1-0.3,startangle=90,counterclock=False,wedgeprops=wps)
本文近五千字,从基础图表入手拆解对应绘制函数的重点参数,共10张图,基本都是个人绘制和排版的,个人认为较系统讲了Matplotlib的用法和核心功能,下篇会实践更有趣的内容。
画心形线(下篇彩蛋)
,