一、为什么要绘制高考成绩每分人数、一分一段可视化图?
本号前几天在微头条发布了河南省、山西省、广东省的高考成绩每分人数、一分一段可视化图,受到了广大网友的好评。最高的一篇展现量达到17万多。由于数据可视化能够带给人非常直不雅观、震荡的感想熏染,能够非常方便地帮助广大考生理解与自己同分数的考生人数、自己的成绩所处的位次,以及全体考天生就的分布概况,从而能够有助于广东考生填报志愿。
部分每分人数、一分一段图和网友评论如下面截图所示。
图1 高考成绩每分人数、一分一段图和网友评论截图
一些网友讯问如何绘制这样的图。作者紧张利用了Python和二维可视化库Matplotlib。本文就将绘图方法公开,以飨读者。
二、绘图工具
本文利用Anaconda Python和二维可视化库Matplotlib来绘制图形。Anaconda Python集成了许多常用的库,非常适宜初学者练习。如果你还不知道如何下载、安装、利用Anaconda Python,请参考本号的免费专栏Anaconda Python的安装和利用。想理解更多的函数绘图方法,请参考本号的专栏学点Python画函数图像。
三、数据准备
要绘制高考成绩每分人数、一分一段图,首先要有一分一段数据。每个省的招生办都公布了本省的高考成绩一分一段表。可惜的是,官方公布的一样平常是图片格式数据,无法复制粘贴。只能一个一个地录入excel表格,这非常的费韶光。虽然有一些小程序供应了表格扫描功能,但是只能试用几张,要多扫描得收费。为便于读者练习,本文供应高考一分一段的仿照数据。
四、读入数据
如果你已经把数据录入excel表格,可以利用pandas的read_excel()方法读取excel数据文件。其代码如下:
import pandas as pd#读取excel数据文件df_score=pd.read_excel('.../score2020.xlsx')print(df_score.columns)
读取的表格返回一个DataFrame工具,你可以把它理解为一种数据构造。代码中columns返回该DataFrame工具的全部字段名称,即excel表里的列名称。例如我的excel表里有2列'score'和'n_stu', 分别表示分数和该分数的人数。则上述代码输出:
Index(['score', 'n_stu'], dtype='object')
可以直策应用df_score['score'], df_score['n_stu']来访问这两列的值。也可以将它们转换为Numpy数组,以更灵巧地进行各种操作。转换为数组的方法是访问形如df_score['score']的DataFrame工具的values属性,如以下代码所示:
score=df_score['score'].values #分数n_stu=df_score['n_stu'].values #每分人数
如果没有网络到一分一段表,请忽略上述代码。下面将利用仿照数据来绘图。
五、产生高考成绩一分一段仿照数据
首先导入Numpy模块,它支持强大的数组运算功能。然后导入二维可视化库Matplotlib模块的子模块pyplot,用于绘图。
首先利用numpy的arange()方法天生700到160之间共541个分数,它是一个等差数列,步长为-1. 然后天生每个分数对应的人数。这须要分为两步,首先利用numpy.random.randint()天生1到1500(假定每分人数最多为1500人)间541个随机整数元素作为每分人数,其次将其前半部分从小到大排序,后半部分从大到小排序,然后合并,以仿照人数峰值在中间,越往两头人数越少的情形。代码如下:
import numpy as npimport matplotlib.pyplot as plt#导入matplotlib.pyplot库score=np.arange(700,159,-1) #仿照高考成绩n_stu=np.random.randint(1,1500,len(score)) #仿照每分人数#使人数峰值位于中间n_stu=np.hstack((np.sort(n_stu[0:int(len(score)/2)]), np.sort(n_stu[int(len(score)/2):])[::-1]))
其次,哀求出最高分数、最低分数、每分人数最大值,以便于后面设置坐标轴的范围。
score_max=np.max(score)score_min=np.min(score)n_stu_max=np.max(n_stu)n_stu_min=np.min(n_stu)print('score形状:',score.shape,'n_stu形状',n_stu.shape)print('最高分数:',score_max,'最低分数:',score_min)print('每分最多人数:',n_stu_max,'每分最少人数:',n_stu_min)
第三步,须要打算分数的位次,即每分人数的累计,可以利用numpy的cumsum()方法,它将打算传入数组的累加和。然后将分数和累计人数转化为字符串,以便于在图中标注。代码如下:
all_labels=np.array(score).astype(np.str) #分数作为刻度标签#print(all_labels)#从每分人数打算累计人数,并转化为字符串leiji=np.array(np.cumsum(n_stu)).astype(np.str) #print(leiji)
六、绘制图形
做完上述准备,就可以绘图了。首先应确定将成绩放在横轴和纵轴上。由于成绩比较多(本文中541个),可以将成绩放在纵轴上。这样图做的足够高,而又不是太宽,便于在手机上查看。
如果用纵轴表示成绩,则横轴表示人数。可以利用Matplotlib的barh()方法,将人数以水平柱状图表示。
绘图需设置图的大小,这个大小须要根据绘制效果来反复调度,终极使得各个横条、笔墨间距适宜,看起来都雅、方便。此外,须要利用text()方法在每个横条右边标注每分人数、累计人数。利用plot()方法绘制一本分数线、二本分数线。利用text()方法标注一本分数线、二本分数线。标注各个文本的位置须要反复调度,达到都雅的效果。其余还须要设置坐标轴的刻度、范围、图的标题等等。详细看下面的代码及注释。
plt.rcParams['font.sans-serif'] = 'SimHei'#设置字体为SimHei显示中文plt.rc('font', size=12)#设置图中字号大小plt.figure(figsize=(10,120))#设置画布plt.barh(score, width=n_stu, height=0.5,color='b')plt.plot([0,n_stu_max+700],[544,544],c='g',linewidth=3,linestyle='--')plt.text(1900,544+1,'一本分数线')plt.plot([0,n_stu_max+700],[418,418],c='r',linewidth=3,linestyle='--')plt.text(1900,418+1,'二本分数线')plt.yticks(score,all_labels)#横轴刻度与标签对准#plt.yticks(score[0],labels[0],rotation=60)#横轴刻度与标签对准plt.xlim(0,n_stu_max+700)plt.ylim(score_min-1,score_max+1)plt.title('高考成绩仿照数据每分人数、一分一段图')plt.xlabel('人数')plt.ylabel('高考成绩')#标注每分人数、累计人数for s,num,n in zip(score,leiji,n_stu): plt.text(n+50,s-0.4,str(n)+'人,累计'+num)plt.show()
末了的运行效果如下图所示。为节约篇幅,只给出了部分截图。
图2 绘制结果
怎么样,Python是不是很有用,你学会了吗?如果有任何疑问,请在评论区留言。