绘制子图
figure是绘制对象(可理解为一个空白的画布),一个figure对象可以包含多个Axes子图,一个Axes是一个绘图区域,不加设置时,Axes为1,且每次绘图其实都是在figure上的Axes上绘图。
接下来将学习绘制子图的几种方式:
- add_axes():添加区域
- subplot():均等地划分画布,只是创建一个包含子图区域的画布,(返回区域对象)
- subplots():既创建了一个包含子图区域的画布,又创建了一个figure图形对象.(返回图形对象和区域对象)
add_axes
添加区域
Matplotib定义了一个axes类(轴域类),该类的对象被称为axes对象(即轴域对象),它指定了一个有数值范围限制的绘图区域。在一个给定的画布(figure)中可以包含多个axes对象,但是同一个axes对象只能在一个画布中使用。
add_axes(rect)
该方法用来生成一个axes轴域对象,对象的位置由参数rect决定
rect是位置参数,接受一个由4个元素组成的浮点数列表,形如[left, bottom, width, height],它表示添加到画布中的矩形区域的左下角坐标(x, y),以及宽度和高度。
fig = plt.figure(figsize=(4,2),facecolor='gray') f1 = fig.add_axes([0,0,1,0.5]) f2 = fig.add_axes([0.5,0.5,0.2,0.2]) f1.plot([[1,2,3,4,5],[2,3,4,5,6]]) # 指定在f1上绘制 f2.plot([[1,2,3,4,5],[2,3,4,5,6]]) # 指定在f2上绘制
fig = plt.figure(figsize=(4,2),facecolor='gray') f1 = fig.add_axes([0,0,1,0.5]) f2 = fig.add_axes([0.5,0.5,0.2,0.2]) plt.plot([[1,2,3],[2,3,4]]) # 由于f2后赋值 plt.plot([[3,2,1],[-4,-3,-2]]) # 因此全都在f2中绘制
fig = plt.figure() # 获取图形对象 ax = plt.gca() # 获取画布 ax.plot() # 可以在gca返回的画布上进行作画 fig.plot() # 不可以在图像对象想进行plot操作
subplot
该函数用于均匀的划分画布
参数格式如下:
ax = plt.subplot(nrows,ncols,index,*args,**kwargs)
- nrows行
- ncols 列 index:索引
- kwargs: title/xlabel/ylabel等.……
也可以直接将几个值写到一起,如:subplot(233)
返回:区域对象
nrows与ncols表示要划分几行几列的子区域(nrows*nclos表示子图数量),index的初始值为1,用来选定具体的某个子区域。例如: subplot(233)表示在当前画布的右上角创建一个两行三列的绘图区域(如下图所示),同时,选择在第3个位置绘制子图。
# 默认画布分割为2行1列,当前所在第一个区域 plt.subplot(211) # x可以省略,默认[0,....,N-1]递增,N为y轴的元素个数 plt.plot(range(20,40),marker='o') plt.grid() #默认画布分割为2行1列,当前所在第二个区域 plt.subplot(212) plt.plot(np.arange(12)**2)
同时,如果新建的子图与现有的子图重叠,那么重叠部分的子图会被自动删除,因为他们不可以共享绘图区域.
plt.plot([1,2,3]) # 这个会被后面两个子图覆盖 # 默认画布分割为2行1列,当前所在第一个区域 plt.subplot(211) # x可以省略,默认[0,....,N-1]递增,N为y轴的元素个数 plt.plot(range(20,40),marker='o') plt.grid() #默认画布分割为2行1列,当前所在第二个区域 plt.subplot(212) plt.plot(np.arange(12)**2) # 此代码的运行效果如上
如果想要原来的画布不被覆盖,那么就应该新建一个画布,也就是使用figure新建画布
plt.plot([1,2,3]) fig = plt.figure(figsize=(4,2)) # 新建画布 # 默认画布分割为2行1列,当前所在第一个区域 fig.add_subplot(111) # 为新建的画布添加子图 # x可以省略,默认[0,....,N-1]递增,N为y轴的元素个数 plt.plot(range(20,40),marker='o') # plt.plot此时认为画布为fig这个画布 plt.grid() #默认画布分割为2行1列,当前所在第二个区域 fig.add_subplot(221) plt.plot(np.arange(12)**2)
同时我们也可以在subplot内部添加一些title,xlabel的参数
plt.subplot(221,title='sub1',xlabel='sub1_x') plt.plot(np.arange(10)**2) plt.subplot(222,title='sub2',ylabel='sub2_y') plt.plot([1,2,3]) plt.tight_layout() # 紧凑布局 防止标签重叠
具体参数可以在subplot参数处按下shift+tab建查看
也可以通过创建区域,然后通过区域的set方法进行设置
# 对返回的区域设置 ax1 = plt.subplot(211) ax2 = plt.subplot(212) ax1.set_title('ax1') ax1.plot(range(50,70)) ax2.set_title('ax2') ax2.plot(np.arange(12)**2) plt.tight_layout()
subplots
matplotlib.pyplot模块提供了一个subplots()函数,它的使用方法和subplot()函数类似。其不同之处在于,subplots()既创建了一个包含子图区域的画布,又创建了一个 figure图形对象,而subplot()只是创建一个包含子图区域的画布。
subplots的函数格式如下:
fig , axes = plt.subplots(nrows,ncols)
nrows 与ncols表示两个整数参数,它们指定子图所占的行数、列
函数的返回值是一个元组,包括一个图开附象和所有的 axs对象。其中axes对象的数量等于nrows * ncols,且每个axes 对象均可通过索引值访问(从0开始),如下2行2列数据:
# 创建2行2列的子图,返回图形对象(画布),所有子图的坐标轴 fig,axes = plt.subplots(2,2) # 第一个区域ax1 ax1 = axes[0][0] # x轴 x = np.arange(1,5) # 绘制平方函数 ax1.plot(x,x*x) ax1.set_title('square') # 绘制平方根图像 axes[0][1].plot(x,np.sqrt(x)) axes[0][1].set_title('sqrt') # 绘制指数函数 axes[1][0].plot(x,np.exp(x)) axes[1][0].set_title('exp') # 绘制对数函数 axes[1][1].plot(x,np.log10(x)) axes[1][1].set_title('log') # 处理标题遮挡问题 plt.tight_layout()
# 绘制1行2列子图中的第1个子图 plt.subplot(121,facecolor='r') # 绘制2行2列子图中的第2个子图 plt.subplot(222,facecolor='g') # 绘制2行2列子图中的第3个子图 plt.subplot(224,facecolor='b')
plt.subplot(321,facecolor='r') plt.subplot(322,facecolor='r') plt.subplot(323,facecolor='r') plt.subplot(324,facecolor='r') plt.subplot(313,facecolor='b')
柱状图
柱状图是一种用矩形柱来表示数据分少的图表。
柱状图可以垂直绘制,也可以水平绘制。
它的高度与其所表示的数值成正比关系。
柱状图显示了不同类别之间的比较关系,图表的水平轴X指定被比较的类别,垂直轴Y则表示具体的类别值
bar
matplotlib.pyplot.bar(x,height,width:float = 0.8, bottom = None,*, align: str = ‘center’, data = None,**kwargs)
- x表示x坐标,数据类型为float类型,一般为np.arange()生成的固定步长列表
- height 表示柱状图的高度,也就是y坐标值,数据类型为float类型,一般为一个列表,包含生成柱状图的所有y值.
- width表示柱状图的宽度,取值在0~1之间,默认值为0.8
- bottom柱状图的起始位置,也就是y轴的起始坐标,默认值为None.
- align柱状图的中心位置,“center”,"lege"边缘,默认值为’center’. color柱状图颜色,默认为蓝色
- alpha透明度,取值在0~1之间,默认值为1.
- label标签,设置后需要调用plt.legend()生成. edgecolor 边框颜色(ec)
- linewidth边框宽度,浮点数或类数组,默认为None (lw)
- tick _label:柱子的刻度标签,字符串或字符串列表,默认值为None.
- linestyle :线条样式(ls)
这里要求data的数量与x的数量保持一致,否则报错
先来一个简单的柱状图程序
x = range(5) # x坐标 data = [1,2,3,4,5] # y轴对应数据 plt.title('柱状图') # 设置标题 plt.xticks(x) # 设置刻度为x plt.bar(x,data) # 显示柱状图
现在来介绍不太好理解的参数,bottom,这个参数代表的是柱状图的底部距离x轴的距离
例如bottom为3,那么对应的柱子的起始位置为3而不是0,注意这里的bottom接受的是一个数组,也就是每一个数据对应的离x轴的距离
x = range(5) # x坐标 data = [1,2,3,4,5] # y轴对应数据 bottom = [4,5,6,7,8] color = ['r','g','b'] # 循环使用三种颜色 plt.title('柱状图') # 设置标题 plt.xticks(x) # 设置刻度为x plt.bar(x,data,bottom=bottom,color=color,ec='black',ls='--',lw=2) # 显示柱状图
其次由于柱状图主要用于比较数据大小,因此多数据柱状图非常常见,如下
对于这种柱状图需要做到
- x轴不固定,可能是文字,也可能是数字,因此需要对x轴进行转换
- 确定同一x轴中,每个柱状图x轴的起始位置
- 设置图形的宽度
- 图形2的起始位置=图形2起始位置+图形的宽度
- 图形3的起始位置=图形3起始位置+2倍图形宽度
- 需要给每个柱状图循环显示文本内容
- 显示图例,使得每个颜色的柱子代表的是某种分类
years = ['2010','2012','2014','2016','2018','2020','2022'] plt.figure(figsize=(5,4)) one = [12,7,8,4,9,10,15] two = [13,4,9,3,2,1,7] three = [7,4,8,0,1,5,6] four = [9,4,1,4,1,7,5] x = np.arange(len(years)) width=0.2 one_x = x two_x = x + 0.2 three_x = x + 0.2 * 2 four_x = x + 0.2 * 3 plt.xticks(x+width+0.1,labels=years) # 设置x轴名称 for i in range(len(years)): plt.text(x[i],one[i],one[i],va='bottom',ha='center') for i in range(len(years)): plt.text(x[i]+0.2,two[i],two[i],va='bottom',ha='center') for i in range(len(years)): plt.text(x[i]+0.2*2,three[i],three[i],va='bottom',ha='center') for i in range(len(years)): plt.text(x[i]+0.2*3,four[i],four[i],va='bottom',ha='center') plt.bar(one_x,one,width=width) plt.bar(two_x,two,width=width) plt.bar(three_x,three,width=width) plt.bar(four_x,four,width=width)
va和ha代表的分别是vertical和horizental,也就是垂直的和水平的位置
这里需要讲解的首先是xticks为什么要这么写,首先xticks如果不设置,那么默认的x轴刻度名称出现的位置是蓝色柱子的中间,这就是默认的设置,因此为了让图形看起来和谐,需要将下面的刻度移动到四根柱子的中间,那么如果每根柱子的width=0.2,那么要移动到中间,就应该是width+width/2=0.3,因为默认刻度是在中间的,移动到下一根需要width/2
其次就是text的使用,text(x,y,str),首先其实蓝色柱子的x位置还是x这个数组中对应的,我们移动的只是刻度而已,因此需要在蓝色柱子上加上数值标注,需要遍历的是x,而其他颜色的柱子,就需要添加偏移量了.
years = ['2010','2012','2014','2016','2018','2020','2022'] plt.figure(figsize=(5,4)) one = [12,7,8,4,9,10,15] two = [13,4,9,3,2,1,7] three = [7,4,8,0,1,5,6] four = [9,4,1,4,1,7,5] x = np.arange(len(years)) width=0.2 plt.xticks(x,labels=years) # 设置x轴名称 total=0 plt.bar(x,one,width=width) # for i in range(len(one)): three_b = np.zeros(len(one)) for i in range(len(one)): three_b[i]=one[i]+two[i] plt.bar(x,two,bottom=one,width=width) plt.bar(x,three,bottom=three_b,width=width) four_b = np.zeros(len(one)) for i in range(len(one)): four_b[i]=one[i]+two[i]+three[i] plt.bar(x,four,bottom=four_b,width=width)
barh
plt.barh(y,width,height=0.8, left=None,*, align='center,**kwargs)
该函数用于生成水平柱状图
barh()函数的用法与bar()函数的用法基本一样,只是在调用barh()函数时使用y参数传入Y轴数据,使用width参数传入代表条柱宽度的数据,left参数类似于bar函数的bottom,只不过这里代表的是柱子离左侧的距离
one = [12,7,8,4,9,10,15] years = ['2010','2012','2014','2016','2018','2020','2022'] plt.barh(years,one)
years = ['2010','2012','2014','2016','2018','2020','2022'] plt.figure(figsize=(5,4)) one = [12,7,8,4,9,10,15] two = [13,4,9,3,2,1,7] three = [7,4,8,0,1,5,6] y = np.arange(len(years)) y_2 = y + 0.2 y_3 = y + 0.2 * 2 height=0.2 plt.yticks(y+0.2,years) plt.barh(y,one,height=height) plt.barh(y_2,two,height=height) plt.barh(y_3,three,height)
这里也可以自己练习一下,使用text为每一行表上值