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