今天本来开开心心去洗了个牙,结果拍片子的时候居然发现,我的妈呀,长了智齿,还是那种横着长的,我居然浑然不知。
图: 我的牙齿裸照
吓死我了,一定是平时没怎么更新文章,导致上天给了惩罚。(明明就是懒惰,工作忙都是借口)痛定思痛,我还是好好写一篇文章,攒点人品,保佑拔牙不痛。
所以我们今天来梳理下Matplotlib这个包的基本操作吧。(太难的我也不会,嘻嘻)概要一下:
本次文章主要分以下的几大内容:1.对图表进行布局
2.对轴,网格线,背景颜色的处理
3.对图标内部小组件的布局
4.对字体修改
为什么要研究研究可视化呢?可视化是一件很有趣的事情,它能很好激发学习Python以及数据分析的兴趣与创造力,所以入门的时候,研究研究可视化,能稍微延长下从删库到跑了,从入门到放弃的生命周期。Part 1:建立画布与子图布局
Matplotlib画图的步骤和布置一个餐桌很像,我们可以简单的想象成有朋友来家里做客,然后开始布置餐桌的过程第一步,我们要选一个大小合适的桌布。
第二步,规划好桌布上该放哪些盘子,这些盘子放在上面位置好。
第三步,做好菜该怎么放在盘子里
第四步,该做那些菜好
第五步,这些菜要做怎么做才好
所以我们先建立一个画布
fig=plt.figure(figsize=[10,5],facecolor='red')
画布的长宽在matplotlib中是用的英寸表示,而一英寸的换算成厘米是大概是2.54厘米
为了能让做出来图能很好的放进PPT,PPT 16:9的那种默认的长宽是:33.867厘米,19.05厘米换算成英寸大概是:13.33英寸比上7.5英寸
有了画布以后,我们开始选我们的盘子,一般来说有方形的盘子,也就是笛卡尔坐标系,也有圆形的盘子,极坐标系。
我们选好的方形盘子后,还要确定盘子的位置,和大小,也就是子图的布局啦在Matplotlib中,子图的布局可以简单的分为对称性子图,和非对称性的子图对称性子图
对称性子图很好理解,就是把整个桌布进行等分,得到一样大小的子图
我们可以直接在 add_subplot中确定分割的大小,以及确定是哪一个子图,比如ax1=fig.add_subplot(1,2,1),表示把整个画布分成1*2 块,ax1是从左到右,从上到下顺序的第一个,
import pandas as pd
import datetime
import matplotlib.pyplot as plt
from pylab import mpl
import matplotlib.gridspec as gridspec
fig=plt.figure(figsize=[10,5],facecolor='red')
ax1=fig.add_subplot(1,2,1)
ax2=fig.add_subplot(1,2,2)
fig.show()图:对称性子图
2. 非对称子图
非对称性子图可以让布局更加的灵活,我们同样用分割的思路把画布等分,但是我们可以选取很多个小单位,把他们作为一个子图。
为了能创建不对称的子图。我们引入新的工具gridspec
gs = gridspec.GridSpec(3,3)
可以理解为一个子图的分割器
它会创建一个3*3的 九宫格,和图中例子一样
在创建坐标系的时候 我们用就可以用切片的思维3*3的矩阵
import pandas as pd
import datetime
import matplotlib.pyplot as plt
from pylab import mpl
import matplotlib.gridspec as gridspec
fig=plt.figure(figsize=[10,5],facecolor='red')
gs = gridspec.GridSpec(3, 3)
ax1 = plt.subplot(gs[0, :])
ax2 = plt.subplot(gs[1,:-1])
ax3 = plt.subplot(gs[1:, -1])
ax4 = plt.subplot(gs[-1,0])
ax5 = plt.subplot(gs[-1,-2])
fig.show()
比如在例子中ax1
ax1=fig.add_subplot(gs[0,:])
ax3=fig.add_subplot(gs[1:2,2])
以ax1来看,其实是占了九宫格中 第一行中的第1,2,3列所以用[0,:]来表示,0表示第一个行,:第一行中所有列
ax3 同理,占了九宫格中的第二,三行的 第三列 所以就是[1:3,2] 1:2 表示 1 到2 行 (学过咱们切片都知道 python里切片是左闭右开,也就是1:3 表示的是1,2 没有3)
3. 子图的间距
通过调整wspace=0,hspace=0 的值,可以改变子图间间距
gs = gridspec.GridSpec(3, 3,wspace=0,hspace=0)
4. 关于颜色
坐标系和画布一样 也可以设置背景颜色(如果不设置好颜色,保存时可能变成透明)
Part2 坐标轴与网格线
倒腾完布局后,我们来倒腾一个简单的柱状图,
化妆前:
fig=plt.figure(figsize=[10,5])
mpl.rcParams['font.sans-serif'] = ['Microsoft YaHei'] # 指定默认字体
mpl.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题
ax=fig.add_subplot(1,1,1)
X=[1,2,3,4]
Y=[5,6,7,8]
ax.bar(X,Y,width=0.4)图 柱状图素颜照
1.不显示轴
plt.axis('off') 可以关闭轴
fig=plt.figure(figsize=[10,5])
mpl.rcParams['font.sans-serif'] = ['Microsoft YaHei'] # 指定默认字体
mpl.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题
ax=fig.add_subplot(1,1,1)
X=[1,2,3,4]
Y=[5,6,7,8]
ax.bar(X,Y,width=0.4)
plt.axis('off')
2.上关闭下左右的边框
ax.spines['top'].set_visible(False) 可以灵活的关闭上下左右的边框,但会保留刻度尺
fig=plt.figure(figsize=[10,5])
ax=fig.add_subplot(1,1,1)
X=[1,2,3,4]
Y=[5,6,7,8]
ax.bar(X,Y,width=0.4)
ax.spines[['top','bottom','left','right']].set_visible(False)
ax.spines['bottom'].set_visible(True)
ax.spines['right'].set_visible(False)
ax.spines['left'].set_visible(False)
3.修改轴的刻度尺
在ax.tick_params()中,我们可以修改刻度尺相关的属性
#axis可以选择X轴还是Y轴
#which可以选择主轴还是副轴
#colors可是改变刻度尺和文本的颜色,
#length,width 是刻度的长宽,都是英寸
#pad可以调节文字和刻度间的距离
#labelsize可以调节 文字的大小
#labelcolor 可以调节文字的颜色
#labelrotation 可以调节文字的方向
#grid_color还能修改网格线颜色
比如我们可以画一个 有着金光闪闪的Y轴刻度先的柱状图
fig=plt.figure(figsize=[10,5])
ax=fig.add_subplot(1,1,1)
X=[1,2,3,4]
Y=[5,6,7,8]
ax.bar(X,Y,width=0.4)
ax.tick_params(direction='inout',width=2,length=30,colors='gold',axis='y',pad=20,labelsize=20,labelcolor='blue',labelrotation=45)
4.修改刻度尺上的文字
我们可以通过plt.xticks([],[])来很灵活修改轴上标签的显示
fig=plt.figure(figsize=[10,5])
ax=fig.add_subplot(1,1,1)
X=[1,2,3,4]
Y=[5,6,7,8]
ax.bar(X,Y,width=0.4)
plt.yticks([5.2,6,7.7,8],["一般","合格","良好","优秀"])
6.网格线
plt.grid()可以添加网格线,和设置刻度尺一样,可以通过axis,which来确定怎么加网格线
通过color='r', linestyle='-', linewidth=2 ,alpha=0.3来确定网格线的样式
fig=plt.figure(figsize=[10,5])
ax=fig.add_subplot(1,1,1)
X=[1,2,3,4]
Y=[5,6,7,8]
ax.bar(X,Y,width=0.4)
plt.grid(color='r', linestyle='--', linewidth=2,which='major',axis='y',alpha=0.3)
ax.spines['top'].set_visible(False)
ax.spines['bottom'].set_visible(True)
ax.spines['right'].set_visible(False)
ax.spines['left'].set_visible(False)Part3 小组件数据标签
其实数据标签的思路很简单,确定每一个标签的位置以及内容,然后一个个打在图上,就好了
fig=plt.figure(figsize=[10,5])
ax=fig.add_subplot(1,1,1)
X=[1,2,3,4]
Y=[5,6,7,8]
ax.bar(X,Y,width=0.4)
for a,b in zip(X,Y):
plt.text(x=a,y=b+0.5,s=b,color='r',ha='center', va= 'baseline',fontsize=12)
2. 一些小坑
坑最大的是出现空值时,尤其是把pandas传入matplotlib时,会出现numpy中特有的空值类型numpy.nan
这个numpy.nan有些非常特别的性质
比如
In : numpy.nan==numpy.nan
Out: False
In :type(numpy.nan)
Out: float
所以如果要判断一个对象是否是nan,得使用numpy中的numpy.isnan()方法
In: numpy.isnan(numpy.nan)
Out: True
所以 如果对这样的有断点的图形添加数据标签会报错
ValueError: cannot convert float NaN to integer
所以我要加上一个判断空值的标签
fig=plt.figure(figsize=[10,5])
ax=fig.add_subplot(1,1,1)
X=[1,1.5,2,2,3,4,5]
Y=[1,2,numpy.nan,numpy.nan,6,5,8]
ax.plot(X,Y)
for a,b in zip(X,Y):
if not numpy.isnan(b):
plt.text(a,b+0.5,b,color='r',ha='center', va= 'baseline',fontsize=12)
这样就可以避免遇到空值时报错了
3. 图例
我们可以用plt.legend()设置图例,但是在画图时,我们需要在图表中加入label属性,从而确定图例显示标签
fig=plt.figure(figsize=[10,5])
ax=fig.add_subplot(1,1,1)
X=[1,1.5,2,2,3,4,5]
Y1=[1,2,numpy.nan,numpy.nan,6,5,8]
Y2=[2,2,2,4,7,5,7]
Y3=[2,3,1,5,4,5,3]
l1,=ax.plot(X,Y1,label='label1')
l2,=ax.plot(X,Y2,label='label2')
l3,=ax.plot(X,Y3,label='label3')
plt.legend()
我们也可以更加精细化的操作legend
比如控制要显示label,和图例的样式
fig=plt.figure(figsize=[10,5])
ax=fig.add_subplot(1,1,1)
X=[1,1.5,2,2,3,4,5]
Y1=[1,2,numpy.nan,numpy.nan,6,5,8]
Y2=[2,2,2,4,7,5,7]
Y3=[2,3,1,5,4,5,3]
l1,=ax.plot(X,Y1,label='label1')
l2,=ax.plot(X,Y2,label='label2')
l3,=ax.plot(X,Y3,label='label3')
plt.legend(handles=[l1,l3],ncol=2,frameon=False)
我再handles里传入一个列表,确定我们要显示的labels,
legend里还有很多参数,可以参考官网的文档 官方的文档Part4 中文显示与字体修改简单的显示中文与负号
有时候中文和负号显示会出问题,比如这样
我们可以简单的加入两条命令来实现中文和负数的显示
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
2. 导入字体文件
当然,还可以更加的灵活,比如修改为确定的字体,或者对特点的组件修改字体,比如修改轴的字体,
导入font_manager库,然后导入字体文件,就可以灵活的在各个小组件上修改字体了
import matplotlib.font_manager
font=matplotlib.font_manager,FontProperties(fname='E:\\DroidSansFallback.ttf')
比如在legend中,我们可以加入prop,在其他的里面可以加入fontproperties
plt.legend(prop=font)
plt.xlabel('X轴的名字',fontproperties=font1)
plt.ylabel('Y轴的名字',fontproperties=font1
plt.title('图表的名字',fontproperties=zhfont1)
plt.xticks( ,fontproperties=zhfont1) 在xticks中也可以加入字体属性
还有些和字体相关的属性可以小组件中设置
#fontsize可以设置字体的大小,默认12
#fontweight可以设置字体的粗细,可以直接输入文本 'light' 细字体, 'normal' 正常字体, 'medium' 中等, 'semibold' 半粗不粗, 'bold' 加粗
#fontstyle设置字体要不要倾斜, 'normal'是正常 'italic' 斜体 'oblique' 再斜一点
不过有些字体文件好像不支持修改粗细,倾斜
案例教学
感觉有点长再下去的话,所以下期我们来实战一下,做一个自动化的小周报: