如何用matplotlib画好看的堆积柱状图
- 1. 效果图
- 2. 代码解析
- 2.1 导入库
- 2.2 读取数据
- 2.3 建立画布,并定义颜色
- 2.4 画图
- 2.5 修改图片细节
- 2.6 添加legend
- 3 完整代码
1. 效果图
堆积柱状图很常见,python matplotlib画出来的效果一点不比origin差,又比NCL方便太多。同时,画这幅图的时候还学到了一些matplotlib的小细节,所以把这个学习过程也记录了下来。
2. 代码解析
2.1 导入库
用到的库只有matplotlib里的pyplot,同时还导入了MultipleLocator来设置x轴和y轴数字显示的间隔。当然啦,也必不可少pandas来读取excel数据。
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator
mpl.rcParams["font.family"] = 'Arial' #默认字体类型
mpl.rcParams["mathtext.fontset"] = 'cm' #数学文字字体
mpl.rcParams["font.size"] = 16
2.2 读取数据
数据存储在excel里,有4列,第一列为x轴,第2-4列为三组y数据。pandas按列读取excel数据有两种方式,一种是用data.loc[:, ‘hour’],第二个维度写为列标签名,另一种方式是data.iloc[:,0],用列的数字来代表,从0开始计数。
#read data
data = pd.read_excel("data3.xlsx", sheet_name='Sheet1')
x = data.loc[:,'Hour']
y1 = data.loc[:,'data1']
y2 = data.loc[:,'data2']
y3 = data.loc[:,'data3']
2.3 建立画布,并定义颜色
建立画布,并定义三种颜色。可以用rgb来定义数组,每种颜色有三个元素,是xxx/255的形式。这三个颜色是看某个文章里用的,少女心满满啊。
fig = plt.figure(figsize=(6,4)) # 创建画布
ax = plt.gca()
rgbcolor=[(255/255, 159/255, 127/255),(50/255, 196/255, 233/255),(252/255, 114/255, 147/255)]
2.4 画图
画图用到的是ax.bar,从下到上绘制三个bar,其中,第二个bar以第一个bar的高度为bottom,第三个bar以第二个+第一个bar的高度为bottom,以此类推。同时,可以同width, color, label来定义柱之间的间距,颜色和标签。
ax.bar(x,y1,width=0.5,color=rgbcolor[0], label='Data 1')
ax.bar(x,y2,width=0.5,bottom=y1,color=rgbcolor[1],label='Data 2')
ax.bar(x,y3,width=0.5,bottom=y2+y1,color=rgbcolor[2],label='Data 3')
2.5 修改图片细节
ax.set_xlim, ax.set_ylim来设置x轴和y轴刻度的数字范围, ax.xaxis.set_major_locator(MultipleLocator(2))来设置x轴每隔2个数字显示,同样也可用在y轴上,只要修改成yaxis就行。
ax.set_ylabel中用到了在python中设置上下标的问题,可以参考下。^为上标,_为下标。
ax.spines则用来设置图片中四个轴线的粗细。默认的太细了。
ax.set_xlim(-1,len(x))
ax.set_ylim(0,40)
ax.xaxis.set_major_locator(MultipleLocator(2))
ax.set_ylabel('Concentration (μg m$^{\mathregular{-3}}$)')
ax.set_xlabel('Hour')
ax.spines['bottom'].set_linewidth(1.5);###设置底部坐标轴的粗细
ax.spines['top'].set_linewidth(1.5);###设置底部坐标轴的粗细
ax.spines['left'].set_linewidth(1.5);###设置底部坐标轴的粗细
ax.spines['right'].set_linewidth(1.5);###设置底部坐标轴的粗细
2.6 添加legend
不同于以往的legend,是handle+label的形式,最近看文献很多高水平的图都不放handle,直接写上label,然后用颜色做区分,这样更简洁明了。方法就是handlelength=0,把handle长度设为0就好啦。leg2.texts[0].set_color(rgbcolor[0])来设置legend字体的颜色。
#legend
font={'weight':'bold'}
leg2=ax.legend(loc='upper left',frameon=False, handlelength=0,borderaxespad=0,handletextpad=0.1, prop=font)
leg2.texts[0].set_color(rgbcolor[0])
leg2.texts[1].set_color(rgbcolor[1])
leg2.texts[2].set_color(rgbcolor[2])
plt.savefig('stack.png',bbox_inches = 'tight')
plt.show()
3 完整代码
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator
mpl.rcParams["font.family"] = 'Arial' #默认字体类型
mpl.rcParams["mathtext.fontset"] = 'cm' #数学文字字体
mpl.rcParams["font.size"] = 16
#read data
data = pd.read_excel("data3.xlsx", sheet_name='Sheet1')
x = data.loc[:,'Hour']
y1 = data.loc[:,'data1']
y2 = data.loc[:,'data2']
y3 = data.loc[:,'data3']
fig = plt.figure(figsize=(6,4)) # 创建画布
ax = plt.gca()
rgbcolor=[(255/255, 159/255, 127/255),(50/255, 196/255, 233/255),(252/255, 114/255, 147/255)]
ax.bar(x,y1,width=0.5,color=rgbcolor[0], label='Data 1')
ax.bar(x,y2,width=0.5,bottom=y1,color=rgbcolor[1],label='Data 2')
ax.bar(x,y3,width=0.5,bottom=y2+y1,color=rgbcolor[2],label='Data 3')
ax.set_xlim(-1,len(x))
ax.set_ylim(0,40)
ax.xaxis.set_major_locator(MultipleLocator(2))
ax.set_ylabel('Concentration (μg m$^{\mathregular{-3}}$)')
ax.set_xlabel('Hour')
ax.spines['bottom'].set_linewidth(1.5);###设置底部坐标轴的粗细
ax.spines['top'].set_linewidth(1.5);###设置底部坐标轴的粗细
ax.spines['left'].set_linewidth(1.5);###设置底部坐标轴的粗细
ax.spines['right'].set_linewidth(1.5);###设置底部坐标轴的粗细
#legend
font={'weight':'bold'}
leg2=ax.legend(loc='upper left',frameon=False, handlelength=0,borderaxespad=0,handletextpad=0.1, prop=font)
leg2.texts[0].set_color(rgbcolor[0])
leg2.texts[1].set_color(rgbcolor[1])
leg2.texts[2].set_color(rgbcolor[2])
plt.savefig('stack.png',bbox_inches = 'tight')
plt.show()
大功告成!