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)

上一篇下一篇

猜你喜欢

热点阅读