Django系列(九)之使用ecahrts
一、概述
ECharts(Enterprise Charts)是由百度开源的一款基于 JavaScript 的可视化图表库,专为数据可视化设计, 支持丰富的图表类型、交互能力和跨端适配,是 DBA、数据分析师、前端开发者在数据展示场景中最常用的工具之一。echarts官网:https://echarts.apache.org/zh/index.html
echarts CDN:https://cdn.jsdelivr.net/npm/echarts@6.0.0/dist/
二、使用
2.1简介
ECharts 提供了多种安装方式,你可以根据项目的实际情况选择以下任意一种方式安装。
从 GitHub 获取
从 npm 获取
从 CDN 获取
在线定制
本文介绍从CDN获取的方式:
<!-- 引入ECharts CDN -->
<script src="https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js"></script>
也可以把echats下载到本地然后再引入,也比较简单,这种方式本文不展开介绍
<!-- 或下载到本地引用:<script src="/static/js/echarts.min.js"></script> -->
2.2、前端echarts图表代码示例
echarts支持多种常用图表,有丰富的样式和其他功能,本文只介绍柱状图,折线图,饼图三种图标基本的使用,更多细节请自行参阅官网:https://echarts.apache.org/zh/index.html
# 前端代码:
# 第一步、需要引入echarts
<!-- 引入ECharts CDN -->
<script src="https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js"></script>
# 第二步、需要为每个图表准备一个定义了宽高的DOM。注意这里就是正常的html,css代码,你的图表布局在这里写好
<div class="content-box">
<h3>数据统计</h3>
<!-- 为 ECharts 准备一个定义了宽高的 DOM -->
<div class="top" id="line" style="width: 1100px; height:400px;"></div>
<div class="bottom">
<div id="bar" style="width: 600px; height:400px;"></div>
<div id="pie" style="width: 500px; height:400px;"></div>
</div>
</div>
# 第三步、这里开始使用echarts,分三步:
# 第一:要先初始化ecahrts实例
# 第二:要获取后端获得的数据,后续渲染在echarts中
# 第三:渲染echarts,使用setOption()方法,这步下面有详细说明
<script type="text/javascript">
// 1、基于准备好的dom,初始化echarts实例
const lineChart = echarts.init(document.getElementById('line'));
const barChart = echarts.init(document.getElementById('bar'));
const pieChart = echarts.init(document.getElementById('pie'));
// 2. 获取后端传递的数据(Django模板变量转JS)
// 注意:这里我用的是django的render,也可以使用ajax,后端使用JsonRespons传递数据给前端
const charts_data = {{ charts_data|safe }}
// 3、指定图表的配置项和数据
// 3.1、配置折线图(按天库存统计,按天统计:库存总数量、库存总价值)
// 折线图分为x轴和y轴,下面的title是标题,xAxis就是定义x轴,{ type: 'category', data: charts_data.xAxis_date},
//里面的type: 'category'是固定写法,后面的data表示数据,固定写法,不要变,charts_data.xAxis_date就是后端传过来的数据
lineChart.setOption({
title: { text: '按天统计:库存总数量、库存总价值' },
xAxis: { type: 'category', data: charts_data.xAxis_date},
// Y 轴:定义左右两个,我这里用的是双y轴的折线图,也可以单y轴,[]里去掉一个就行
yAxis: [ // 对y轴的定义
{ // 左侧Y轴
type: 'value', //固定写法,不要变
name: '库存总数量', // y轴 label,就是y轴的名字
position: 'left', //左侧还是右侧的y轴
alignTicks: true // 可选:对齐刻度(让网格线对齐)
},
{ // 右侧 Y 轴标题
type: 'value',
name: '库存总价值',
position: 'right',
alignTicks: true
}
],
// 数据渲染
series: [{
name: '库存总量', //legend名称,也就是图例
type: 'line', // line表示折线图,
yAxisIndex: 0, // 使用第一个 Y 轴(left)
data: charts_data.yAxis_total_quantity, // 这个就是数据
// 是否显示数据以及对数据样式的配置
{#label: {#}
{# show: true,#}。 //是否在折线图上显示数据
{# position: 'top', // 显示在点的上方#}
{# formatter: '{c}', // {c} = 当前值#}
{# fontSize: 10,#}
{# color: '#333'#}
},
{
name: '库存总价值',
type: 'line',
yAxisIndex: 1, // 使用第二个 Y 轴(right)
data: charts_data.yAxis_total_value,
// 显示数据
{#label: {#}
{# show: true,#}
{# position: 'top', // 显示在点的上方#}
{# formatter: '{c}', // {c} = 当前值#}
{# fontSize: 10,#}
{# color: '#333'#}
}],
// 可选:显示图例
legend: {
show: true
}
});
// 3.2、配置柱状图
barChart.setOption({
title: { text: '销售统计:历史总入库数量最高的前10个物品' },
xAxis: { // x轴
type: 'category',
data: charts_data.xAxis_name},
yAxis: {type: 'value'}, //y轴
// 数据渲染
series: [{
type: 'bar', // bar表示柱状图
data: charts_data.yAxis_total_in, //后端传的数据
label: {
show: true, // 显示数值
position: 'top', // 数值显示在柱子顶端
formatter: '{c}', // {c} 表示原始数据值
fontSize: 12,
color: '#333'
}
}]
});
// 3.3、配置饼图(仓库中每种分类的总价值占比)
// 饼图不需要x轴和y轴,渲染数据即可
pieChart.setOption({
title: { text: '占比统计:仓库中每种分类的总价值占比' },
series: [
{
type: 'pie', // pie表示饼图
data: charts_data.data_pie,
// 显示标签(包括百分比和数值)
label: { // 让能显示数据,默认不显示
position: 'outside', // 让标签在外面,有些时候数据会被遮挡,宽度不够,数据显示不出来
show: true,
formatter: '{b}\n{c} ({d}%)' // {b}=名称, {d}=百分比, {c}=原始值, eg {b}: {d}%
// 也可以写成:'{b}\n{c} ({d}%)'
}
}
]
});
// 4. 自适应窗口大小变化,可选
window.addEventListener('resize', () => {
lineChart.resize();
barChart.resize();
pieChart.resize();
});
</script>
# 这个是css 代码,对几个图表做了布局,这个不重要,自己写前端布局就行
# content-box 是包裹这三个图表的div,上面没有写上,不要纠结
.content-box{
margin: 20px 20px;
}
.content-box h3{
color: #333;
margin-bottom: 20px;
border-bottom: 3px solid #007bff; /*为h3 添加一个底部边框*/
}
.content-box .bottom{
display: flex;
justify-content: space-between;
align-items: center;
}
2.3、后端数据和数据格式代码示例
def data_analysis(request):
# 按天统计:库存总数量、库存总价值
with connection.cursor() as cursor:
data_stats_sql = """
select date_format(operate_date, '%Y-%m-%d') as date,
sum(current_quantity) as total_quantity,
sum(current_quantity * price) as total_value
from wms_goodsinoutrecord as record
join wms_goods as goods on record.goods_id = goods.id
where record.id > 10
group by date_format(operate_date, '%Y-%m-%d')
order by date_format(operate_date, '%Y-%m-%d');
"""
cursor.execute(data_stats_sql)
data_line = cursor.fetchall()
# 销售统计:历史总入库数量最高的前10个物品
with connection.cursor() as cursor:
top_10_sql = """
select goods.name, sum(record.amount) as total_in
from wms_goodsinoutrecord as record
join wms_goods as goods on record.goods_id = goods.id
where record.operation_type = 'in'
group by goods.name
order by total_in desc
limit 10;
"""
cursor.execute(top_10_sql)
data_bar = cursor.fetchall()
# 占比统计:仓库中每种分类的总价值占比
with connection.cursor() as cursor:
category_value_sql = """
select category.name, sum(goods.price * goods.current_quantity) as total_value
from wms_goods as goods
join wms_goodscategory as category on goods.category_id = category.id
group by category.name;
"""
cursor.execute(category_value_sql)
data_pie = cursor.fetchall()
# 这里要注意:把每个轴的数据直接封装好,前端直接用,不要传到前端再转换格式
# echarts是js写的,所以需要数组类型,对应django后端就要list类型,把数据全部放到列表中然后传到前端直接用
charts_data = {
# 折线图数据
"xAxis_date": [row[0] for row in data_line], # x轴数据
"yAxis_total_quantity": [float(row[1]) for row in data_line], # y轴库存总数量
"yAxis_total_value": [float(row[2]) for row in data_line], # y轴库存总价值
# 柱状图数据
"xAxis_name": [row[0] for row in data_bar],
"yAxis_total_in": [float(row[1]) for row in data_bar],
# 饼图数据,注意这里的key必须是name和value,不能是别的,echarts里要求
"data_pie": [{"name": name, "value": float(total_value)} for name, total_value in data_pie]
}
# 序列化,因为前端使用数据的是js了(echarts是js写的),不是html,所以数据不能直接返回,如果有中文或者特殊字符可能会显示错误或报错
charts_data = json.dumps(charts_data)
# 如果是AJAX请求,返回JSON数据
# if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
# return JsonResponse(charts_data)
# 否则渲染模板
return render(request, 'bi/bi_data.html', {"charts_data": charts_data})
def data_analysis(request):
# 按天统计:库存总数量、库存总价值
with connection.cursor() as cursor:
data_stats_sql = """
select date_format(operate_date, '%Y-%m-%d') as date,
sum(current_quantity) as total_quantity,
sum(current_quantity * price) as total_value
from wms_goodsinoutrecord as record
join wms_goods as goods on record.goods_id = goods.id
where record.id > 10
group by date_format(operate_date, '%Y-%m-%d')
order by date_format(operate_date, '%Y-%m-%d');
"""
cursor.execute(data_stats_sql)
data_line = cursor.fetchall()
# 销售统计:历史总入库数量最高的前10个物品
with connection.cursor() as cursor:
top_10_sql = """
select goods.name, sum(record.amount) as total_in
from wms_goodsinoutrecord as record
join wms_goods as goods on record.goods_id = goods.id
where record.operation_type = 'in'
group by goods.name
order by total_in desc
limit 10;
"""
cursor.execute(top_10_sql)
data_bar = cursor.fetchall()
# 占比统计:仓库中每种分类的总价值占比
with connection.cursor() as cursor:
category_value_sql = """
select category.name, sum(goods.price * goods.current_quantity) as total_value
from wms_goods as goods
join wms_goodscategory as category on goods.category_id = category.id
group by category.name;
"""
cursor.execute(category_value_sql)
data_pie = cursor.fetchall()
# 这里要注意:把每个轴的数据直接封装好,前端直接用,不要传到前端再转换格式
# echarts是js写的,所以需要数组类型,对应django后端就要list类型,把数据全部放到列表中然后传到前端直接用
charts_data = {
# 折线图数据
"xAxis_date": [row[0] for row in data_line], # x轴数据
"yAxis_total_quantity": [float(row[1]) for row in data_line], # y轴库存总数量
"yAxis_total_value": [float(row[2]) for row in data_line], # y轴库存总价值
# 柱状图数据
"xAxis_name": [row[0] for row in data_bar],
"yAxis_total_in": [float(row[1]) for row in data_bar],
# 饼图数据,注意这里的key必须是name和value,不能是别的,echarts里要求
"data_pie": [{"name": name, "value": float(total_value)} for name, total_value in data_pie]
}
# 序列化,因为前端使用数据的是js了(echarts是js写的),不是html,所以数据不能直接返回,如果有中文或者特殊字符可能会显示错误或报错
charts_data = json.dumps(charts_data)
# 如果是AJAX请求,返回JSON数据
# if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
# return JsonResponse(charts_data)
# 否则渲染模板
return render(request, 'bi/bi_data.html', {"charts_data": charts_data})
最终结果展示:

参考文档:echarts官网

浙公网安备 33010602011771号