2020-01-09
2020-01-09 本文已影响0人
少儿创客
import xlrd
import xlrd
from docxtpl import DocxTemplate, InlineImage
from docx.shared import Mm
import pyecharts
import numpy as np
from random import random
import matplotlib.pyplot as plt
import matplotlib
import os
from docxtpl import DocxTemplate, InlineImage
from docx.shared import Mm
#===================开始设置中文字体=================
font = {
'family' : 'SimHei',
'size' : 20
}
matplotlib.rc('font', **font)
#===================结束设置中文字体=================
class GenerateReport:
def __init__(self, files, stuClass='1.1'):
if not files:
return None
else:
self.files = files
self.radarIndex = 0
# TODO:这种字符串可以用字符串分割方法生成数组
# 反之用数字拼接字符串可以降低拼写的效率
# 怪不得校园宝要设置学科
self.subjects = ['语文','数学','英语','历史','道法','地理','生物','物理']
self.subjects_en = ['chinese','maths','english','history','tao','geography','bio','physical']
self.root = stuClass
def mkdir(path):
if not os.path.isdir(path):
mkdir(os.path.split(path)[0],'/')
else:
return
os.mkdir(path)
if not os.path.exists(self.root):
os.mkdir(self.root)
os.mkdir("/{}/doc".format(self.root))
os.mkdir("/{}/line".format(self.root))
os.mkdir("/{}/radar".format(self.root))
self.dataset = self.processFiles(files)
def setTemplate(self, file):
self.template = file
def paraXls(self, filename):
# TODO:要添加异常处理
# {
# 'stuName': 'langxm',
# 'scores': [
# {
# 'chinese': 80,
# 'math' : 90
# },
# ],
# 'grades': [
# {
# 'chinese': A,
# 'math' : B
# },
# ],
# 'sum': 20,
# 'rank': 20,
# 'total': 20
# }
dataset = {}
wb = xlrd.open_workbook(filename)
sht = wb.sheet_by_index(0)
rows = sht.nrows
cols = sht.ncols
header = sht.row_values(0, 0, cols)
self.students = sht.col_values(0, 1, rows)
# 查询index的代码有待优化
def getIndex(value, valuelist):
# TODO:重名的情况
return valuelist.index(value)
subjectIndexes = [getIndex(subject, header) for subject in self.subjects]
# TODO:numpy的数组加载xls处理效率更高,可以用numpy的np数组改写
for i in range(1, rows):
line = sht.row_values(i, 0, cols)
stuName = line[0]
scores = [line[index] for index in subjectIndexes]
grades = [line[index + 1] for index in subjectIndexes]
examData = {}
item = {}
item['scores'] = scores
item['grades'] = grades # 这些项目都是可以做成可以配置的
# 可以用工厂模式改写
item['total'] = sum(scores)
item['avg'] = sum(scores) / len(subjectIndexes)
examData[stuName] = item
dataset[stuName] = examData
return dataset
def processFiles(self, files):
d = {}
def setValue(key, value):
d[key] = value
[setValue(file, self.paraXls(file)) for file in files]
return d
def drawRadar(self, stuName, index=0):
pass
labels = np.array(self.subjects[index:]) # 标签
dataLenth = len(labels) # 数据长度
angles = np.linspace(0, 2*np.pi, dataLenth, endpoint=False) # 分割圆周长
angles = np.concatenate((angles, [angles[0]])) # 闭合
dataset = []
# stuName = '徐文清'
for file in self.files[index:]:
dataset.append(self.dataset[file][stuName][stuName]['scores'])
polars = []
plt.clf()
for ds in dataset:
ds = np.concatenate((ds, [ds[0]]))
p1, = plt.polar(angles, ds, 'o-', linewidth=1) #做极坐标系
polars.append(p1)
plt.legend(polars,[file[0:-5] for file in self.files[index:]] ,prop={'family':'SimHei'})
plt.thetagrids(angles * 180/np.pi, labels, fontproperties='SimHei') # 设置网格、标签
plt.ylim(0,100) # polar的极值设置为ylim
plt.savefig(self.root + '/radar/{}radar.png'.format(stuName))
pass
plt.close('all')
plt.clf()
labels = np.array(self.subjects) # 标签
fig, ax1 = plt.subplots(figsize=(12,9))
# stuName = '徐文清'
# plt.cla()
for file in self.files:
ax1.plot(labels, self.dataset[file][stuName][stuName]['scores'], label=file[0:-5])
plt.title("{}期中期末成绩折线图".format(stuName),fontproperties='SimHei',fontsize=30)
ax1.legend()
ax1.grid(axis="y",color="grey",linestyle="--",alpha=0.5)
ax1.tick_params(axis="x",labelsize=16)
ax1.tick_params(axis="y",labelsize=16)
ax1.set_ylabel("成绩",fontsize = 16)
ax1.set_xlabel("学科",fontsize = 16)
ax1.set_ylim(0,100)
for tl in ax1.get_yticklabels():
tl.set_color('r')
ax1.spines['top'].set_visible(True)
plt.savefig(self.root + '/line/{}line.png'.format(stuName))
plt.close(0)
def drawLine(self, stuName):
pass
labels = np.array(self.subjects) # 标签
fig, ax1 = plt.subplots(figsize=(12,9))
# stuName = '徐文清'
for file in self.files:
ax1.plot(labels, self.dataset[file][stuName][stuName]['scores'], label=file[0:-5])
plt.title("{}期中期末成绩折线图".format(stuName),fontproperties='SimHei',fontsize=30)
ax1.legend()
ax1.grid(axis="y",color="grey",linestyle="--",alpha=0.5)
ax1.tick_params(axis="x",labelsize=16)
ax1.tick_params(axis="y",labelsize=16)
ax1.set_ylabel("成绩",fontsize = 16)
ax1.set_xlabel("学科",fontsize = 16)
ax1.set_ylim(0,100)
for tl in ax1.get_yticklabels():
tl.set_color('r')
ax1.spines['top'].set_visible(True)
plt.savefig(self.root + '/line/{}line.png'.format(stuName))
plt.close()
def saveDoc(self, stuName):
# plt.clear()
pass
# TODO:模板生成word虽然方便但是写模板变量太烦了
# 后面改成直接生成
doc = DocxTemplate(r"./{}".format(self.template))
dataset = []
# stuName = '徐文清'
context = {}
for file in self.files:
dataset.append(self.dataset[file][stuName][stuName])
context['stuName'] = stuName
for key, ds in enumerate(dataset):
context['file'+str(key)] = self.files[key]
scores = ds["scores"]
for i in range(len(scores)):
context[self.subjects_en[i]+str(key)] = scores[i]
context['linechart'] = InlineImage(doc, 'line/{}line.png'.format(stuName), width=Mm(100))
context['radarchart'] = InlineImage(doc, 'radar/{}radar.png'.format(stuName), width=Mm(100))
doc.render(context)
doc.save(r"./{}/doc/{}.docx".format(self.root, stuName))
def genDocs(self):
for stuName in self.students:
# self.drawLine(stuName)
if stuName == '赵烁源':
continue
self.drawRadar(stuName,index=self.radarIndex)
# TODO:文件名应该是可以配置的包括路径
self.saveDoc(stuName)
print('{}的文档已经生成,位于./{}/doc/{}.docx'.format(stuName, self.root, stuName))
if __name__ == "__main__":
pass
gr = GenerateReport(['86.xlsx','861.xlsx','862.xlsx','863.xlsx'])
gr.setTemplate('86temp.docx')
# gr.drawLine('徐文清')
print(len(gr.students))
gr.genDocs()
# print(gr.dataset)