echarts、higncharts折線圖或柱狀圖只需要后端傳到前端一段json數據,接送數據的x軸與y周有對應數據,折線圖或柱狀圖就會渲染出這數據。
比如,x軸表示美每天日期,y軸表示數量。他們的數據都在數據庫里存着。如下圖:
它們的數據存放數據庫中,x軸為每周的周一,並且代表當前周的違規次數或人數。由於3月25日到3月31日那周和4月8日到4月14日那周都沒人違規,所以數據庫中並沒有這兩周的任何數據,所以后端從數據庫拿到數據並傳到前端,渲染出來的圖就如上兩圖了。
若要那兩周就算沒數據也想展示到圖里面,如下兩張圖:
解決辦法如下:
后端:
#!/usr/bin/python # -*- coding: utf-8 -*- import web import json import time import datetime from common.util.login_required import login_required from common.config.DatabaseConfig import mysql_db # urls = ( "/visualviolationno***", "VisualViolat***", # 可視化頁面 "/visualviolationno***", "VisualViolat***", # 柱狀圖1數據處理 "/visualviolationno***", "VisualViolat***", # 折線圖2數據處理 "/visualviolationno***", "VisualViolat***", # 餅狀圖3數據處理 "/visualviolationno***", "VisualViolat***", # 柱狀圖4數據處理 ) render = web.template.render('templates') app = web.application(urls, globals()) # 可視化頁面 class VisualViolationNotification(object): def GET(self): render = web.template.render('templates') return render.violationnotification() # 柱狀圖1數據處理 class VisualViolationNot***(object): def GET(self): data_web = web.input() data_name = data_web.i1.encode("gbk") date_min = data_web.get('i2') date_max = data_web.get('i3') if len(date_min) == 7 and len(date_max) == 7: sql = "select count(*) count,division from week_violation where substring(date_min,1,7) <= '" + date_max + "' and substring(date_min,1,7) >= '" + date_min + "' group by division" else: sql = "select count(*) count,division from week_violation where date_min >= '" + date_min + "' and date_max <= '" + date_max + "' group by division" ret = mysql_db.query(sql) ret = list(ret) list_out = [] list_count = [] list_division = [] for i in ret: count = i.get("count") list_count.append(count) division = i.get("division") list_division.append(division) list_out.append(list_division) list_out.append(list_count) return json.dumps(list_out) # 折線圖2數據處理 class VisualViolationNotificationData2(object): def GET(self): data_web = web.input() data_name = data_web.i1.encode("gbk") date_min = data_web.get('i2') date_max = data_web.get('i3') if len(date_min) == 7 and len(date_max) == 7: flag = '月' sql = "select count(*) count,month_min date_min from week_violation where substring(date_min,1,7) <= '" + date_max + "' and substring(date_min,1,7) >= '" + date_min + "' group by month_min" ret = mysql_db.query(sql) ret = list(ret) list1 = [] total_x = [] total_y = [] for tot in ret: total_x.append(str(tot.get("date_min"))) total_y.append(tot.get("count")) list1.append(total_x) list1.append(total_y) list1.append(flag) list1 = json.dumps(list1) else: flag = '周' sql = "select count(*) count,date_min from week_violation where date_min >= '" + date_min + "' and date_max <= '" + date_max + "' group by date_min" ret = mysql_db.query(sql) ret = list(ret) list1 = [] total_x = [] total_y = [] for tot in ret: total_x.append(str(tot.get("date_min"))) total_y.append(tot.get("count")) list1.append(total_x) list1.append(total_y) list1.append(flag) date_min = date_min.encode("utf-8") date_min = datetime.datetime.strptime(date_min, "%Y-%m-%d") date_max = datetime.datetime.strptime(date_max, "%Y-%m-%d") work = workDays(date_min, date_max) ret = list(work.workDays()) l1 = [] for i in range(len(ret)): if i % 2 == 0: l1.append(ret[i].strftime("%Y-%m-%d")) for i in l1: if i not in list1[0]: list1[1].insert(l1.index(i), 0) list1[0] = l1 list1 = json.dumps(list1) return list1 # 餅狀圖3數據處理 class VisualViolationNotificationData3(object): def GET(self): data_web = web.input() data_name = data_web.i1.encode("gbk") date_min = data_web.get('i2') date_max = data_web.get('i3') if len(date_min) == 7 and len(date_max) == 7: sql = "select count(*) count,division from week_violation where substring(date_min,1,7) <= '" + date_max + "' and substring(date_min,1,7) >= '" + date_min + "' group by division" else: sql = "select count(*) count,division from week_violation where date_min >= '" + date_min + "' and date_max <= '" + date_max + "' group by division" ret = mysql_db.query(sql) ret = list(ret) list1 = [] for i in ret: dict = {} dict['y'] = i.get("count") dict['name'] = i.get("division") list1.append(dict) return json.dumps(list1) # 柱狀圖4數據處理 class VisualViolationNotificationData4(object): def GET(self): data_web = web.input() data_name = data_web.i1.encode("gbk") #date_min = data_web.i2.encode("gbk") #date_max = data_web.i3.encode("gbk") date_min = data_web.get('i2') date_max = data_web.get('i3') if len(date_min) == 7 and len(date_max) == 7: flag = '月' sql = "select count(distinct num) count,month_min date_min from week_violation where substring(date_min,1,7) <= '" + date_max + "' and substring(date_min,1,7) >= '" + date_min + "' group by month_min" with mysql_db.transaction(): ret = mysql_db.query(sql) ret = list(ret) list_out = [] list_count = [] list_division = [] for i in ret: count = i.get("count") list_count.append(count) date_min = i.get("date_min") list_division.append(str(date_min)) list_out.append(list_division) list_out.append(list_count) list_out.append(flag) else: flag = '周' sql = "select count(distinct num) count,date_min from week_violation where date_min >= '" +date_min + "' and date_max <= '" + date_max + "' group by date_min" with mysql_db.transaction(): ret = mysql_db.query(sql) ret = list(ret) list_out = [] list_count = [] list_division = [] for i in ret: count = i.get("count") list_count.append(count) date_min1 = i.get("date_min") list_division.append(str(date_min1)) list_out.append(list_division) list_out.append(list_count) list_out.append(flag) date_min = date_min.encode("utf-8") date_min = datetime.datetime.strptime(date_min, "%Y-%m-%d") date_max = datetime.datetime.strptime(date_max, "%Y-%m-%d") work = workDays(date_min, date_max) ret = list(work.workDays()) l1 = [] for i in range(len(ret)): if i % 2 == 0: l1.append(ret[i].strftime("%Y-%m-%d")) for i in l1: if i not in list_out[0]: list_out[1].insert(l1.index(i), 0) list_out[0] = l1 return json.dumps(list_out) # 計算兩個日期之間的周 class workDays(): def __init__(self, start_date, end_date, days_off=None): """days_off:休息日,默認周六日, 以0(星期一)開始,到6(星期天)結束, 傳入tupple 沒有包含法定節假日, """ self.start_date = start_date self.end_date = end_date self.days_off = days_off if self.start_date > self.end_date: self.start_date, self.end_date = self.end_date, self.start_date if days_off is None: self.days_off = 1,2,3,4,5 # 每周工作日列表 self.days_work = [x for x in range(7) if x not in self.days_off] def workDays(self): """實現工作日的 iter, 從start_date 到 end_date , 如果在工作日內,yield 日期 """ # 還沒排除法定節假日 tag_date = self.start_date while True: if tag_date > self.end_date: break if tag_date.weekday() in self.days_work: yield tag_date tag_date += datetime.timedelta(days=1) def daysCount(self): """工作日統計,返回數字""" return len(list(self.workDays())) def weeksCount(self, day_start=0): """統計所有跨越的周數,返回數字 默認周從星期一開始計算 """ day_nextweek = self.start_date while True: if day_nextweek.weekday() == day_start: break day_nextweek += datetime.timedelta(days=1) # 區間在一周內 if day_nextweek > self.end_date: return 1 weeks = ((self.end_date - day_nextweek).days + 1) / 7 weeks = int(weeks) if ((self.end_date - day_nextweek).days + 1) % 7: weeks += 1 if self.start_date < day_nextweek: weeks += 1 return weeks # # date_min = datetime.datetime(2019,1,7) # date_max = datetime.datetime(2019,2,18) # # work = workDays(date_min,date_max) # # ret = list(work.workDays()) # # print ret # l1 = [] # l2 = [] # for i in range(len(ret)): # if i % 2 == 0: # l1.append(ret[i].strftime("%Y-%m-%d")) # # b = ['2019-01-07', '2019-01-21', '2019-01-28', '2019-02-11'] # c = [1,2,3,4] # print b # print l1 # for i in l1: # if i not in b: # c.insert(l1.index(i),0) # print c
前端
<!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <meta name="renderer" content="webkit|ie-comp|ie-stand"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no"/> <meta http-equiv="Cache-Control" content="no-siteapp"/> <!--[if lt IE 9]> <script type="text/javascript" src="../static/ui/lib/html5shiv.js"></script> <script type="text/javascript" src="../static/ui/lib/respond.min.js"></script> <![endif]--> <link rel="stylesheet" type="text/css" href="../static/ui/static/h-ui/css/H-ui.min.css"/> <link rel="stylesheet" type="text/css" href="../static/ui/static/h-ui.admin/css/H-ui.admin.css"/> <link rel="stylesheet" type="text/css" href="../static/ui/lib/Hui-iconfont/1.0.8/iconfont.css"/> <link rel="stylesheet" type="text/css" href="../static/ui/static/h-ui.admin/skin/default/skin.css" id="skin"/> <link rel="stylesheet" type="text/css" href="../static/ui/static/h-ui.admin/css/style.css"/> <!--[if IE 6]> <script type="text/javascript" src="../static/ui/lib/DD_belatedPNG_0.0.8a-min.js"></script> <script>DD_belatedPNG.fix('*');</script> <![endif]--> <title></title> </head> <body> <div> <span class="" id="month" style="margin-left: 500px; margin-top: 20px;"> 日期范圍 <input type="text" id="datemin" class="Wdate startTime input-text" name="startTime" style="width:120px;" value="2018-01" onfocus="WdatePicker({dateFmt:'yyyy-MM',isShowClear:false,isShowToday:false,isShowOK:false,readOnly:true,maxDate:'#F{$$dp.$$D(\'datemax\')}',onpicked:pickedSdate})"/> - <input type="text" id="datemax" class="Wdate endTime input-text" name="endTime" style="width:120px;" value="2018-12" onfocus="WdatePicker({dateFmt:'yyyy-MM',isShowClear:false,isShowToday:false,isShowOK:false,readOnly:true,minDate:'#F{$$dp.$$D(\'datemin\')}',startDate:'#F{$$dp.$$D(\'datemin\',{d:+1})}',onpicked:pickedSdate})"/> <span id="data-name" class="hide"></span> <button type="button" class="btn btn-success radius" id="tijiao" name=""><i class="Hui-iconfont"></i> 搜索 </button> </span> <span class="text-c hide" id="week" style="margin-left: 500px; margin-top: 20px;"> 日期范圍 <input type="text" onfocus="WdatePicker({ maxDate:'#F{$$dp.$$D(\'datemax1\')||\'%y-%M-%d\'}',disabledDays:[0,2,3,4,5,6]})" id="datemin1" class="input-text Wdate" style="width:120px;"> - <input type="text" onfocus="WdatePicker({ minDate:'#F{$$dp.$$D(\'datemin1\')}',maxDate:'%y-%M-%d',disabledDays:[1,2,3,4,5,6]})" id="datemax1" class="input-text Wdate" style="width:120px;"> <button type="button" class="btn btn-success radius" id="tijiao1" name=""><i class="Hui-iconfont"></i> 搜索 </button> </span> <span style="margin-top: 20px;"> <button id="flag" value="month"></button> <a href="javascript: void month()" id="button_month" class=""> <button class="btn btn-success radius" type="button">月查詢</button></a> <a href="javascript: void week()" id="button_week" class="hide"> <button class="btn btn-success radius" type="button">周查詢</button></a> </span> </div> <!--視圖--> <div class="page-container"> <div id="container1" style="width: 50%; float: left"></div> <div id="container2" style="width: 50%; float: left;"></div> <div id="container3" style="width: 50%; float: left;"></div> <div id="container4" style="width: 50%; float: left;"></div> </div> <!--_footer 作為公共模版分離出去--> <script type="text/javascript" src="../static/ui/lib/jquery/1.9.1/jquery.min.js"></script> <script type="text/javascript" src="../static/ui/lib/layer/2.4/layer.js"></script> <script type="text/javascript" src="../static/ui/static/h-ui/js/H-ui.min.js"></script> <script type="text/javascript" src="../static/ui/static/h-ui.admin/js/H-ui.admin.js"></script> <!--/_footer 作為公共模版分離出去--> <!--請在下方寫此頁面業務相關的腳本--> <script type="text/javascript" src="../static/ui/lib/hcharts/Highcharts/5.0.6/js/highcharts.js"></script> <script type="text/javascript" src="../static/ui/lib/hcharts/Highcharts/5.0.6/js/modules/exporting.js"></script> <script type="text/javascript" src="../static/ui/lib/hcharts/Highcharts/5.0.6/js/highcharts-3d.js"></script> <script type="text/javascript" src="../static/ui/lib/My97DatePicker/4.8/WdatePicker.js"></script> <script type="text/javascript" src="../static/ui/lib/datatables/1.10.0/jquery.dataTables.min.js"></script> <script type="text/javascript" src="../static/ui/lib/jquery.contextmenu/jquery.contextmenu.r2.js"></script> <script type="text/javascript" src="../static/ui/lib/laypage/1.2/laypage.js"></script> <script type="text/javascript"> function month() { $$("#month").toggleClass("hide"); $$("#week").toggleClass("hide"); $$("#button_month").toggleClass("hide"); $$("#button_week").toggleClass("hide"); $$("#flag").val("week"); } function week() { $$("#month").toggleClass("hide"); $$("#week").toggleClass("hide"); $$("#button_month").toggleClass("hide"); $$("#button_week").toggleClass("hide"); $$("#flag").val("month"); } // 只讓日期插件顯示年和月份 $$(function () { //日期顯示當月 (function () { var date = new Date(); date.setMonth(date.getMonth() - 6); var date_zero = date.toLocaleDateString().split("/"); console.log(date_zero); var mydate_min = (date_zero[0] < 10 ? "0" + date_zero[0] : date_zero[0]).toString() + "-" + (date_zero[1] < 10 ? "0" + date_zero[1] : date_zero[1]).toString(); date.setMonth(date.getMonth() + 5); var date_none = date.toLocaleDateString().split("/"); var mydate_max = (date_none[0] < 10 ? "0" + date_none[0] : date_none[0]).toString() + "-" + (date_none[1] < 10 ? "0" + date_none[1] : date_none[1]).toString(); console.log(mydate_max); // var year_min = "2018"; // var year_max = "2018"; // // var month = date.getMonth() + 1; // var month_min = "1"; // var month_max = "12"; // month_min = (month_min < 10 ? "0" + month_min : month_min); // month_max = (month_max < 10 ? "0" + month_max : month_max); // var mydate_min = (year_min.toString() + '-' + month_min.toString()); // var mydate_max = (year_max.toString() + '-' + month_max.toString()); $$('.startTime').val(mydate_min); $$('.endTime').val(mydate_max); // 當前庫的名稱 var data_name = "******"; // 處罰搜索框時間 $$('#tijiao').click(function () { // 重新加載 func1(); }); // 處罰搜索框時間 $$('#tijiao1').click(function () { // 重新加載 func1(); }); // 視圖函數 $$( func1() ); function func1() { // 獲取當前日期搜索框日期 var data_min = $$("#datemin").val(); var data_max = $$("#datemax").val(); if ($$("#flag").val() == "month") { data_min = $$("#datemin").val(); data_max = $$("#datemax").val(); } if ($$("#flag").val() == "week") { data_min = $$("#datemin1").val(); data_max = $$("#datemax1").val(); } // 次數-部門 柱狀圖 $$.ajax({ url: "***", type: "GET", data: {"i1": data_name, "i2": data_min, "i3": data_max}, success: function (data) { var data = JSON.parse(data); var data_x = data[0]; var data_y = data[1]; // Set up the chart $$('#container1').highcharts({ chart: { type: 'column' }, title: { text: data_min + '至' + data_max + ' 各部門違規人次' }, subtitle: { text: '人次/部門' }, xAxis: { categories: data_x }, yAxis: { min: 0, title: { text: '違規人次' } }, tooltip: { headerFormat: '<span style="font-size:10px">{point.key}</span><table>', pointFormat: '<tr><td style="color:{series.color};padding:0">共有</td>' + '<td style="padding:0"><b>{point.y:.1f} 次</b></td></tr>', footerFormat: '</table>', shared: true, useHTML: true }, plotOptions: { column: { pointPadding: 0.2, borderWidth: 0, dataLabels: {enabled: true} } }, series: [{ name: '各部門', data: data_y }] }); } }); // 次數-部門 餅狀圖 $$.ajax({ url: "***", type: "GET", data: {"i1": data_name, "i2": data_min, "i3": data_max}, success: function (data) { var data = JSON.parse(data); $$('#container2').highcharts({ chart: { plotBackgroundColor: null, plotBorderWidth: null, plotShadow: false }, title: { text: data_min + '至' + data_max + ' 各部門違規人次占比' }, tooltip: { pointFormat: '{series.name}: <b>{point.percentage:.1f}%</b>' }, plotOptions: { pie: { allowPointSelect: true, cursor: 'pointer', dataLabels: { enabled: true, color: '#000000', connectorColor: '#000000', format: '<b>{point.name}</b>: {point.percentage:.1f} %' } } }, series: [{ type: 'pie', name: '占比', data: data }] }); } }); // 次數-月份 折線圖 $$.ajax({ url: "***", type: "GET", data: {"i1": data_name, "i2": data_min, "i3": data_max}, success: function (data) { var data = JSON.parse(data); var data_x = data[0]; var data_y = data[1]; var date_type = data[2]; $$('#container3').highcharts({ chart: { zoomType: 'xy', spacingRight: 20 }, title: { text: data_min + '至' + data_max + ' 各個' + date_type + '違規人次' }, subtitle: { text: document.ontouchstart === undefined ? '人次/' + date_type : '人次/' + date_type }, xAxis: { type: 'linear', categories: data_x, title: { text: '各' + date_type } }, yAxis: { title: { text: '違規人次' } }, tooltip: { shared: true }, legend: { enabled: false, align: 'center', verticalAlign: 'middle' }, plotOptions: { line: { dataLabels: { enabled: true } }, area: { fillColor: { linearGradient: {x1: 0, y1: 0, x2: 0, y2: 1}, stops: [ [0, Highcharts.getOptions().colors[0]], [1, Highcharts.Color(Highcharts.getOptions().colors[0]).setOpacity(0).get('rgba')] ] }, lineWidth: 1, marker: { enabled: false }, shadow: false, states: { hover: { lineWidth: 1 } }, threshold: null }, }, series: [{ name: "人次", data: data_y }] }); } }); // 人數-月份 柱狀 $$.ajax({ url: "***", type: "GET", data: {"i1": data_name, "i2": data_min, "i3": data_max}, success: function (data) { var data = JSON.parse(data); var data_x = data[0]; var data_y = data[1]; var date_type = data[2]; // Set up the chart $$('#container4').highcharts({ chart: { type: 'column' }, title: { text: data_min + '至' + data_max + ' 各個' + date_type + '違規人數' }, subtitle: { text: '人數/' + date_type }, xAxis: { categories: data_x }, yAxis: { min: 0, title: { text: '違規人數' } }, tooltip: { headerFormat: '<span style="font-size:10px">{point.key}</span><table>', pointFormat: '<tr><td style="color:{series.color};padding:0">本' + date_type + '共</td>' + '<td style="padding:0"><b>{point.y:.1f} 次</b></td></tr>', footerFormat: '</table>', shared: true, useHTML: true }, plotOptions: { column: { pointPadding: 0.2, borderWidth: 0, dataLabels: {enabled: true} } }, series: [{ name: '各' + date_type, data: data_y }] }); } }); } })(); }); //獲取選中的值 function pickedSdate() { var _val = this.value, _name = this.name; if (_name == 'startTime') { $$('.sTime').text(_val); } else if (_name == 'endTime') { $$('.eTime').text(_val); } //執行統一搜索 } </script> </body> </html>
注意:以上后端使用web.py框架和前端使用H-ui框架,認真看並不難
數據庫類型如下:
id 名字 賬戶 違規內容 所屬周周一 所屬周周日 部門 所屬月份
1540 張* ****** 內勤請假登陸堡壘機 2019-02-25 2019-03-03 核心系統開發部 2019-02
1541 李* ****** 堡壘機違規操作 2019-03-11 2019-03-17 核心系統開發部 2019-03