举例讲解Python的Tornado框架实现数据可视化的教程


Posted in Python onMay 02, 2015

所用拓展模块

    xlrd:

    Python语言中,读取Excel的扩展工具。可以实现指定表单、指定单元格的读取。
    使用前须安装。
    下载地址:https://pypi.python.org/pypi/xlrd
    解压后cd到解压目录,执行 python setup.py install 即可

    datetime:

    Python内置用于操作日期时间的模块

拟实现功能模块

    读xls文件并录入数据库

    根据年、月、日三个参数获取当天的值班情况

        饼状图(当天完成值班任务人数/当天未完成值班任务人数)

        瀑布图(当天所有值班人员的值班情况)

    根据年、月两个参数获取当月的值班情况

    根据年参数获取当年的值班情况

值班制度

    每天一共有6班:

    8:00 - 9:45
    9:45 - 11:20
    13:30 - 15:10
    15:10 - 17:00
    17:00 - 18:35
    19:00 - 22:00

    每个人每天最多值一班。

    仅值班时间及前后半个小时内打卡有效。

    上班、下班均须打卡,缺打卡则视为未值班。

分析Excel表格

我的指纹考勤机可以一次导出最多一个月的打卡记录。有一个问题是,这一个月可能横跨两个月,也可能横跨一年。比如:2015年03月21日-2015年04月20日、2014年12月15日-2015年01月05日。所以写处理方法的时候一定要注意这个坑。

导出的表格如图所示:

举例讲解Python的Tornado框架实现数据可视化的教程

    =。=看起来好像基本没人值班,对,就是这样。
    大家都好懒T。T
    Sign...

简单分析一下,

  •     考勤记录表是文件的第三个sheet
  •     第三行有起止时间
  •     第四行是所有日期的数字
  •     接下来每两行:第一行为用户信息;第二行为考勤记录

思路

决定用3个collection分别储存相关信息:

  1.     user:用户信息,包含id、name、dept
  2.     record:考勤记录,包含id(用户id)、y(年)、m(月)、d(日)、check(打卡记录)
  3.     duty:值班安排,包含id(星期数,例:1表示星期一)、list(值班人员id列表)、user_id:["start_time","end_time"](用户值班开始时间和结束时间)

读取xls文件,将新的考勤记录和新的用户存入数据库。

根据年月日参数查询对应record,查询当天的值班安排,匹配获得当天值班同学的考勤记录。将值班同学的打卡时间和值班时间比对,判断是否正常打卡,计算实际值班时长、实际值班百分比。

之后输出json格式数据,用echarts生成图表。

分析当月、当年的考勤记录同理,不过可能稍微复杂一些。

    所有的讲解和具体思路都放在源码注释里,请继续往下看源码吧~

源码

    main.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os.path

import tornado.auth
import tornado.escape
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web
from tornado.options import define, options

import pymongo
import time
import datetime
import xlrd

define("port", default=8007, help="run on the given port", type=int)

class Application(tornado.web.Application):
  def __init__(self):
    handlers = [
      (r"/", MainHandler),
      (r"/read", ReadHandler),
      (r"/day", DayHandler),
    ]
    settings = dict(
      template_path=os.path.join(os.path.dirname(__file__), "templates"),
      static_path=os.path.join(os.path.dirname(__file__), "static"),
      debug=True,
      )
    conn = pymongo.Connection("localhost", 27017)
    self.db = conn["kaoqin"]
    tornado.web.Application.__init__(self, handlers, **settings)


class MainHandler(tornado.web.RequestHandler):
  def get(self):
    pass

class ReadHandler(tornado.web.RequestHandler):
  def get(self):
    #获取collection
    coll_record = self.application.db.record
    coll_user = self.application.db.user
    #读取excel表格
    table = xlrd.open_workbook('/Users/ant/Webdev/python/excel/data.xls')
    #读取打卡记录sheet
    sheet=table.sheet_by_index(2)
    #读取打卡月份范围
    row3 = sheet.row_values(2)
    m1 = int(row3[2][5:7])
    m2 = int(row3[2][18:20])
    #设置当前年份
    y = int(row3[2][0:4])
    #设置当前月份为第一个月份
    m = m1
    #读取打卡日期范围
    row4 = sheet.row_values(3)
    #初始化上一天
    lastday = row4[0]
    #遍历第四行中的日期
    for d in row4:
      #如果日期小于上一个日期
      #说明月份增大,则修改当前月份为第二个月份
      if d < lastday:
        m = m2
        #如果当前两个月份分别为12月和1月
        #说明跨年了,所以年份 +1
        if m1 == 12 and m2 == 1:
          y = y + 1
      #用n计数,范围为 3 到(总行数/2+1)
      #(总行数/2+1)- 3 = 总用户数
      #即遍历所有用户
      for n in range(3, sheet.nrows/2+1):
        #取该用户的第一行,即用户信息行
        row_1 = sheet.row_values(n*2-2)
        #获取用户id
        u_id = row_1[2]
        #获取用户姓名
        u_name = row_1[10]
        #获取用户部门
        u_dept = row_1[20]
        #查询该用户
        user = coll_user.find_one({"id":u_id})
        #如果数据库中不存在该用户则创建新用户
        if not user:
          user = dict()
          user['id'] = u_id
          user['name'] = u_name
          user['dept'] = u_dept
          coll_user.insert(user)
        #取该用户的第二行,即考勤记录行
        row_2 = sheet.row_values(n*2-1)
        #获取改当前日期的下标
        idx = row4.index(d)
        #获取当前用户当前日期的考勤记录
        check_data = row_2[idx]
        #初始化空考勤记录列表
        check = list()
        #5个字符一组,遍历考勤记录并存入考勤记录列表
        for i in range(0,len(check_data)/5):
          check.append(check_data[i*5:i*5+5])
        #查询当前用户当天记录
        record = coll_record.find_one({"y":y, "m":m, "d":d, "id":user['id']})
        #如果记录存在则更新记录
        if record:
          for item in check:
            #将新的考勤记录添加进之前的记录
            if item not in record['check']:
              record['check'].append(item)
              coll_record.save(record)
        #如果记录不存在则插入新纪录
        else:
          record = {"y":y, "m":m, "d":d, "id":user['id'], "check":check}
          coll_record.insert(record)

 

class DayHandler(tornado.web.RequestHandler):
  def get(self):
    #获取年月日参数
    y = self.get_argument("y",None)
    m = self.get_argument("m",None)
    d = self.get_argument("d",None)
    #判断参数是否设置齐全
    if y and m and d:
      #将参数转换为整型数,方便使用
      y = int(y)
      m = int(m)
      d = int(d)
      #获取当天所有记录
      coll_record = self.application.db.record
      record = coll_record.find({"y":y, "m":m, "d":d})
      #获取当天为星期几
      weekday = datetime.datetime(y,m,d).strftime("%w")
      #获取当天值班表
      coll_duty = self.application.db.duty
      duty = coll_duty.find_one({"id":int(weekday)})
      #初始化空目标记录(当天值班人员记录)
      target = list()
      #遍历当天所有记录
      for item in record:
        #当该记录的用户当天有值班任务时,计算并存入target数组
        if int(item['id']) in duty['list']:
          #通过用户id获取该用户值班起止时间
          start = duty[item['id']][0]
          end = duty[item['id']][1]
          #计算值班时长/秒
          date1 = datetime.datetime(y,m,d,int(start[:2]),int(start[-2:]))
          date2 = datetime.datetime(y,m,d,int(end[:2]),int(end[-2:]))
          item['length'] = (date2 - date1).seconds
          #初始化实际值班百分比
          item['per'] = 0
          #初始化上下班打卡时间
          item['start'] = 0
          item['end'] = 0
          #遍历该用户打卡记录
          for t in item['check']:
            #当比值班时间来得早
            if t < start:
              #计算时间差
              date1 = datetime.datetime(y,m,d,int(start[:2]),int(start[-2:]))
              date2 = datetime.datetime(y,m,d,int(t[:2]),int(t[-2:]))
              dif = (date1 - date2).seconds
              #当打卡时间在值班时间前半小时内
              if dif <= 1800:
                #上班打卡成功
                item['start'] = start
            elif t < end:
              #如果还没上班打卡
              if not item['start']:
                #则记录当前时间为上班打卡时间
                item['start'] = t
              else:
                #否则记录当前时间为下班打卡时间
                item['end'] = t
            else:
              #如果已经上班打卡
              if item['start']:
                #计算时间差
                date1 = datetime.datetime(y,m,d,int(end[:2]),int(end[-2:]))
                date2 = datetime.datetime(y,m,d,int(t[:2]),int(t[-2:]))
                dif = (date1 - date2).seconds
                #当打卡时间在值班时间后半小时内
                if dif <= 1800:
                  #下班打卡成功
                  item['end'] = end
          #当上班下班均打卡
          if item['start'] and item['end']:
            #计算实际值班时长
            date1 = datetime.datetime(y,m,d,int(item['start'][:2]),int(item['start'][-2:]))
            date2 = datetime.datetime(y,m,d,int(item['end'][:2]),int(item['end'][-2:]))
            dif = (date2 - date1).seconds
            #计算(实际值班时长/值班时长)百分比
            item['per'] = int(dif/float(item['length']) * 100)
          else:
            #未正常上下班则视为未值班
            item['start'] = 0
            item['end'] = 0
          #将记录添加到target数组中
          target.append(item)
      #输出数据
      self.render("index.html",
        target = target
        )


def main():
  tornado.options.parse_command_line()
  http_server = tornado.httpserver.HTTPServer(Application())
  http_server.listen(options.port)
  tornado.ioloop.IOLoop.instance().start()


if __name__ == "__main__":
  main()

  index.html

{
{% for item in target %}
  {
   'id':{{ item['id'] }},
   'start':{{ item['start'] }},
   'end':{{ item['end'] }},
   'length':{{ item['length'] }}, 
   'per':{{ item['per'] }}
   }
{% end %}
}

最后

暂时只写到读文件和查询某天值班情况,之后会继续按照之前的计划把这个小应用写完的。

因为涉及到一堆小伙伴的隐私,所以没有把测试文件发上来。不过如果有想实际运行看看的同学可以跟我说,我把文件发给你。

可能用到的一条数据库插入语句:db.duty.insert({"id":5,"list":[1,2],1:["19:00","22:00"],2:["19:00","22:00"]})

希望对像我一样的beginner们有帮助!

Python 相关文章推荐
Python logging模块学习笔记
May 24 Python
python 获取list特定元素下标的实例讲解
Apr 09 Python
Tensorflow使用tfrecord输入数据格式
Jun 19 Python
用Django写天气预报查询网站
Oct 21 Python
在Python 字典中一键对应多个值的实例
Feb 03 Python
Python多进程fork()函数详解
Feb 22 Python
Python定时任务工具之APScheduler使用方式
Jul 24 Python
Python paramiko模块使用解析(实现ssh)
Aug 30 Python
python 魔法函数实例及解析
Sep 25 Python
python学生信息管理系统实现代码
Dec 17 Python
python 利用Pyinstaller打包Web项目
Oct 23 Python
Jupyter Notebook 安装配置与使用详解
Jan 06 Python
Python的Bottle框架中返回静态文件和JSON对象的方法
Apr 30 #Python
使用Python编写提取日志中的中文的脚本的方法
Apr 30 #Python
简单的连接MySQL与Python的Bottle框架的方法
Apr 30 #Python
Python的Bottle框架中实现最基本的get和post的方法的教程
Apr 30 #Python
Python中使用Beautiful Soup库的超详细教程
Apr 30 #Python
Python中正则表达式的详细教程
Apr 30 #Python
详解在Python程序中使用Cookie的教程
Apr 30 #Python
You might like
php array_merge下进行数组合并的代码
2008/07/22 PHP
对比分析php中Cookie与Session的异同
2016/02/19 PHP
laravel5.4利用163邮箱发送邮件的步骤详解
2017/09/22 PHP
php统计数组不同元素的个数的实例方法
2019/09/26 PHP
深入浅析安装PhpStorm并激活的步骤详解
2020/09/17 PHP
制作高质量的JQuery Plugin 插件的方法
2010/04/20 Javascript
javascript面向对象编程(一) 实例代码
2010/06/25 Javascript
js动态添加删除,后台取数据(示例代码)
2013/11/25 Javascript
js网页实时倒计时精确到秒级
2014/02/10 Javascript
php中给js数组赋值方法
2014/03/10 Javascript
JavaScript中匿名、命名函数的性能测试
2014/09/04 Javascript
JS实现漂亮的窗口拖拽效果(可改变大小、最大化、最小化、关闭)
2015/10/10 Javascript
有关json_decode乱码及NULL的问题
2015/10/13 Javascript
JavaScript实现输入框(密码框)出现提示语
2016/01/12 Javascript
原生js实现addClass,removeClass,hasClass方法
2016/04/27 Javascript
深入理解JavaScript中为什么string可以拥有方法
2016/05/24 Javascript
jQuery EasyUI常用数据验证汇总
2016/09/18 Javascript
vue+swiper实现组件化开发的实例代码
2017/10/26 Javascript
用Angular实现一个扫雷的游戏示例
2020/05/15 Javascript
Django中间件基础用法详解
2019/07/18 Python
Django 权限认证(根据不同的用户,设置不同的显示和访问权限)
2019/07/24 Python
Django框架 querySet功能解析
2019/09/04 Python
详解CSS3的perspective属性设置3D变换距离的方法
2016/05/23 HTML / CSS
微软英国官方网站:Microsoft英国
2016/10/15 全球购物
迷你唐卡软皮鞋:Minnetonka Moccasin
2018/05/01 全球购物
澳洲在线厨具商店:Kitchen Style
2018/05/05 全球购物
SQL Server 2000数据库的文件有哪些,分别进行描述。
2015/11/09 面试题
行政部主管岗位职责
2013/12/28 职场文书
二年级数学教学反思
2014/01/21 职场文书
计算机应用专业毕业生求职信
2014/06/03 职场文书
尊师重教演讲稿
2014/09/04 职场文书
2014年检验员工作总结
2014/11/19 职场文书
个人思想政治总结
2015/03/05 职场文书
物业工程部经理岗位职责
2015/04/09 职场文书
JavaScript如何优化逻辑判断代码详解
2021/06/08 Javascript
win10+RTX3050ti+TensorFlow+cudn+cudnn配置深度学习环境的方法
2022/06/25 Servers