Python3分析考试成绩2 Flask与pyecharts实现统计数据的前端展示

应用场景:在教育教学中,常常要对考试数据进行统计,对自己所带班级的数据有个全盘的掌握,反思自身不足,明确自身优势,从而制定下一阶段的目标。对于家长来说,对于学生的成绩都有一些疑问,也非常关心孩子的学业状况,每一位家长都想问一些关于成绩的问题,而家长会后,家长和教师的面谈时间非常长,就算是30%的家长和该学科教师交流,也会花许多的时间。如果在这个阶段,我们用准确的数据作为我们交流的依据,针对共性问题进行说明,针对个性问题进行分析,会大大提高效率。所以这个在本机进行测试的应用场景,就是家长会的时候,用PPT的形式进行成绩的展示,在家长会后对于学生的成绩进行精确统计从而对每一位学生进行精准施策,即使无法做到极为精准,至少也能够为自己和家长提供较为可靠的决策依据。这些表格并非公开排名,而是针对每一位学生的情况,和家长进行私下的交流使用。本数据来源于网上三国武将的各数值,为了更像是学生的学科成绩,将武力智力等替换为学科。

核心思想:将数据进行统计,生成数据的列表,再通过pyecharts生成html,最后在前端调用并展示。

在实际开发中,我们以这样的文件类型为例:

 

1.文件形式

以日期为文件名,最终要将文件名、选取学科等基础信息,以及相应的统计数据,用pyecharts绘制,并渲染到前端。

一个重要的前提是:pyecharts的安装流程。Pyecharts,官方讲,要pip install pyecharts,但是实际情况是,要pip install --user pytest-runner,再pip install --user pyecharts-javascripthon,pip install --user pyecharts。如果显示什么缺失,则再pip install --user+库名即可。

2.组织数据

首先,构建姓名列表和学科列表,如果在搜索的范围内,则显示,如果不在,则返回“无此人”这类信息。将各个参数,用pandas或者Numpy都设置好,再用pyecharts绘制表格即可。

这里可以将业务,分为数据处理,和生成前端html列表两大类,分别专注于数据生成和绘制。接下来的都是测试,实际上应该分别建立class。

3.填充到前端

生成的html列表,作为参数,传回路由里即可。

用于数据处理的ToPandas.py如下:

import pandas as pd
import os
from pyecharts import Bar

filePath = '/tableData'    #子表所有文件所在的文件夹
name = u'姓名'            #以姓名为核心进行查找

class dataTo():
    zhifangFilePathList = []                                #得到最近3次考试的文件路径
    htmlList = []

    def __init__(self):                                     #初始化类的时候,将类属性完全清空
        self.zhifangFilePathList = []
        self.htmlList = []
    def dataToJson(self,xueke, searchName):
        fileTablePath = os.getcwd()+filePath                #获取数据表的文件路径 也就是当前flask工作路径+文件夹名称,这部分在flask调试时用
        #fileTablePath = '/Volumes/Data/on66/tableData'         #这个路径在单独测试此python文件时候使用
        for filename in os.listdir(fileTablePath):  # 读取文件名称
            if filename[-3:] == 'xls':
                targetPath = fileTablePath + '/' + filename  # 构造文件夹内每一个文件的绝对路径
                everyTable = pd.DataFrame(pd.read_excel(targetPath))
                for columnName in everyTable.columns.values:  # 如果表格中有当前学科的列,则加入列表,为的是最终选出最后三次成绩
                    if columnName == xueke:
                        self.zhifangFilePathList.append(targetPath)     #如果这个excel文件的列名中,有这个学科,才把这个文件路径添加,万一上次考试没考这个学科呢
                        
        last3List = self.zhifangFilePathList[-3:]  # 选取最后三个文件的pandas,用来展示最近三次考试的统计
        searchName = str(searchName)
        if searchName!= '':                          #这里最终要修改为,如果查询学生姓名,在所有学生列表里面
            try:
                for dataPath in last3List:                              #以下统计和绘图部分,都是混着的,其实应该分开,分为不同的类进行处理,提高代码可读性
                    dataPd = pd.DataFrame(pd.read_excel(dataPath))  
                    dataColumn = dataPd[xueke]  # 选取学科列的数值
                    xfanwei = list(range(0, 130, 10))                            #x轴分组
                    #yFanwei = list(range(0,40,5))                  #y轴分组,但还是要在绘制表格的时候改属性
                    fenzu = pd.cut(dataColumn.values, xfanwei, right=False)      #对学科成绩进行切分
                    pinshu = fenzu.value_counts()                               #统计出现的频数
                    xSer = pinshu.reset_index()['index'].apply(lambda x: str(x))    #将频数表重新索引,并获取index列,将index列数据类型改为字符串
                    xZhou = xSer.tolist()                                       #将频数表x轴转为list
                    pinList = pinshu.values.tolist()                            #y轴的值转为list
                    barTitle = dataPath[-15:-4]                                  #获取数据表名称,并提取日期

                    eBar = Bar(title=barTitle, width=400, height=300)                    #用pyecharts绘图,设置大小
                    eBar.add(name=xueke, x_axis=xZhou, y_axis=pinList,xaxis_label_textsize=7, xaxis_interval=0, xaxis_rotate=70,
                             yaxis_force_interval=5, yaxis_min=0, yaxis_max=40, is_toolbox_show=False)              #设置各种参数
                    # javascript_snippet = EChartsTranslator().translate(eBar.options)
                    # optionsIn = javascript_snippet.option_snippet     #获取图表的option属性
                    htmlShow = eBar.render_embed()      #获取这个表的html文本,用于写入前端
                    self.htmlList.append(htmlShow)      #html文本存到列表,最后将列表存入前端
                    #print(self.optionList)
            except:
                self.htmlList = []
        return self.htmlList

下面是flask的index.py:

from flask import Flask, redirect
from flask import render_template
from flask import request, url_for
import pythonFile.ToPandas as toJJ

app = Flask(__name__)


@app.route('/', methods=['POST', 'GET'])  # 以post 和 get方式获取数据
def index():
    if request.method == 'POST':  # 用post方法获取html中的数据,也就是传入数据
        username = request.form.get('username')  # 获得文本框传入的数据
        xuekeName = request.values.get("xuekeName")
        if len(str(username)) > 1:  # 若输入的身份证号大于1
            print(username)
            print(xuekeName)
            jsonClass = toJJ.dataTo()
            htmlShowList = jsonClass.dataToJson(xueke=xuekeName, searchName=username)
            return render_template('index.html', htmlList=htmlShowList)  # 向模板中传入数据
        else:
            return redirect(url_for('index'))  # 如果身份证号输入有误,则重新定位到index
    return render_template('index.html', htmlList=[])  # 渲染模板 空值


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5050, debug=True)
    # host='0.0.0.0'保证了外网能够访问,port=5050是因为新浪要求监听5050端口

再经过下面的html渲染,就能够展示页面了:

<!DOCTYPE html>
<head>

	<meta charset="UTF-8">
	<!-- Site Title -->
	<title>河北中考化学 数据首页</title>
    <script src="/static/js/echarts.js"></script>
	<link rel="stylesheet" href="/static/css/bootstrap.css">
	<link rel="stylesheet" href="/static/css/main.css">
    <link rel="stylesheet" href="/static/css/styleSearch.css">

</head>

<body>

	<!-- 导航栏头部-->
	<header id="header">
		<div class="container">
			<div class="row align-items-center justify-content-between d-flex">
				<div id="logo">
					<a><img src="/static/img/logo.png" alt="" title="" /></a>
				</div>
				<nav id="nav-menu-container">
					<ul class="nav-menu">
						<li><a href=" " class="primary-btn white">首页</a></li>
						<li><a href=" " class="primary-btn white">新闻中心</a></li>
						<li><a href=" " class="primary-btn white">关于我们</a></li>
					</ul>
				</nav><!-- #nav-menu-container -->
			</div>
		</div>
	</header>
	<!-- End Header Area -->


	<!-- Start Banner Area -->
	<section class="home-banner-area relative">
		<div class="container">
			<div class="row fullscreen d-flex align-items-center justify-content-center">
				<div class="banner-content col-lg-8 col-md-12">
					<h1 class="wow fadeIn" data-wow-duration="4s">欢迎进入数据展示页面</h1>
					<p class="text-white">
						您可以通过搜索栏和单选框,设定您要查询的目标,相应的数据表将被展示在此页面
						<br>您可以扫二维码,关注公众号:河北中考化学
					</p>

                    <div class="col-md-7 col-sm-7 col-xs-12">
                        <div class="romana_domain_search">
                            <form  action="{{ url_for('index') }}" method="POST">
                                <div class="romana_search_input">
                                    <input type="text" name='username' id="searchInput" placeholder="请输入姓名">
                                </div>
                            <div class="romana_search_submit">
                                <input  type="submit" value="搜索">
                            </div>
                            <div>
                                <label><input name="xuekeName" value="语文" type="radio" checked="checked"/>语文</label>
                                <label><input name="xuekeName" value="数学" type="radio" />数学</label>
                                <label><input name="xuekeName" value="英语" type="radio" />英语</label>
                                <label><input name="xuekeName" value="历史" type="radio" />历史</label>
                                <label><input name="xuekeName" value="政治" type="radio" />政治</label>
                                <label><input name="xuekeName" value="化学" type="radio" />化学</label>
                                <label><input name="xuekeName" value="物理" type="radio" />物理</label>
                            </div>
                        </form>
                    </div>
                </div>
				</div>
			</div>
		</div>
	</section>
	<!-- End Banner Area -->


	<!-- 数据展示区域  可重复的DIV,每一个都横着占3个格子-->

    <div class="container">
    <!-- 下面是第一行,是前三次成绩的体现 -->
        <div class="row">
            {% for k in range(0,3) %}
                <div class="col-4" style="width: 600px;height: 400px">
			        {{ htmlList[k] }}
		        </div>
            {% endfor %}
        </div>

以上学科单选框,可以用统计各个表的列名并唯一化来实现。如果在设置pyecharts的时候,参数随意,就会造成下图:

 下图是参数经过仔细优化得到的图:

 

可以想象,在图表下面的空间里,继续开div,将需要的图表渲染,即可作为一个仪表盘,且只要把每次考试的excel放在相应文件夹中即可。

参考资料:https://blog.csdn.net/castinga3t/article/details/79075240

http://pyecharts.org/#/zh-cn/prepare

 


在安装pyecharts的时候,花了很多时间。如果pyecharts能够一键安装,也就是集合所有的依赖库就好了。未来来的太快,再不加油就追不上了。

版权声明:本文为limaning原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/limaning/article/details/87765198