总述

2020年8月3日。到了实训的第三周的第一天。
今天主要讲了如何用echarts实现数据的可视化
主要的活动有:

  • 数据打包
  • echarts远程包
  • echarts本地包(重点)
    数据可视化主要旨在借助于图形化手段,清晰有效地传达与沟通信息。但是,这并不就意味着数据可视化就一定因为要实现其功能用途而令人感到枯燥乏味,或者是为了看上去绚丽多彩而显得极端复杂。为了有效地传达思想概念,美学形式与功能需要齐头并进,通过直观地传达关键的方面与特征,从而实现对于相当稀疏而又复杂的数据集的深入洞察。然而,设计人员往往并不能很好地把握设计与功能之间的平衡,从而创造出华而不实的数据可视化形式,无法达到其主要目的,也就是传达与沟通信息。
    因此,我们不仅要掌握数据可视化的办法,也更要懂得如何让组织形式使得传达与沟通的效益最大化。
    今天圆满地完成了主要工作,不仅完成了一边听课一边记录笔记,而且课中也没有遇到什么疑难杂症而纠结良久。

今天的操作流程,一言以蔽之。对于本地存在的Excel数据、CSV数据等等,可以使用pandasxlrd来进行提取,而后用echarts把它绘制在网页上。

ECharts 是一个使用 JavaScript 实现的开源可视化库,涵盖各行业图表,满足各种需求。 ECharts 遵循 Apache-2.0 开源协议,免费商用。 ECharts 兼容当前绝大部分浏览器(IE8/9/10/11,Chrome,Firefox,Safari等)及兼容多种设备,可随时随地任性展示。

pandas&xlrd

Pandas是一个强大的分析结构化数据的工具集;它的使用基础是Numpy(提供高性能的矩阵运算);用于数据挖掘和数据分析,同时也提供数据清洗功能。
Python中操作excel主要用到xlrd和xlwt这两个库,即xlrd是读excel,xlwt是写excel的库。

安装流程

在Terminal中键入pip install pandas即可完成pandas的安装(如果没装过numpy和dateutil也会一并装了)。
出现了以下字样的安装成功信息。

1
Successfully installed numpy-1.19.1 pandas-1.1.0 python-dateutil-2.8.1

再在Terminal中键入pip install xlrd即可完成xlrd的安装。

数据的获取

除了可以用爬虫自己获取网页上的数据外,还可以上阿里云-天池来获取数据。
为了方便练习,选择一些数据量不大的数据集。这里老师选择了NBA数据中的球员勒布朗-詹姆斯的数据。
将网页表格复制到Excel中,得到如下结果。

应用伊始

键入python manage.py startapp echarts新建一个应用。
james.xlsx复制到该应用的文件夹下。

tests.py 文件中,键入如下代码以进行测试。

1
2
3
4
5
from django.test import TestCase
import pandas as pd
# Create your tests here.
data = pd.read_excel('james.xlsx')
print(data)

可以看到输出结果为如下所示。

DataFrame

DataFrame是一种表格型数据结构,它含有一组有序的列,每列可以是不同的值。DataFrame既有行索引,也有列索引,它可以看作是由Series组成的字典,不过这些Series公用一个索引。

DataFrame的创建有多种方式,不过最重要的还是根据dict进行创建,以及读取csv或者txt文件来创建。[1]

将刚刚的测试代码修改为:

1
2
3
4
5
6
7
8
9
from django.test import TestCase
import pandas as pd
# Create your tests here.
data = pd.read_excel('james.xlsx')
df = pd.DataFrame(data=data,index=range(1,17)) #创建了DataFrame, index是行索引, range是列索引
# 输出不同的形式,以便于观察DataFrame。
print(list(df['赛季'])) #强制转换为list, 方便后续使用。
print(type(df['得分']))
print(df['篮板'])

输出结果为:

个人觉得用不用DataFrame,区别仅在于会不会去掉NaN数据。

views的配置

按照之前的实训经验,完成views的配置。
为了使列表的数据以赛季递增,在列表后加入[::-1]完成倒装。

上课时,我以为用list.reverse(),但是reverse()方法是没有返回值的。
这意味着,不能直接将这个方法写在print函数里。
所以为使代码简短,使用[::-1]确实是最佳解。

1
2
3
4
5
6
7
8
9
10
11
12
13
from django.shortcuts import render
import pandas as pd
from django.http import JsonResponse
# Create your views here.
def api_echarts(request):
data = pd.read_excel('james.xlsx') # 这里还有一个路径的问题,如果是现行的代码,会报错,参考下面的图。
df = pd.DataFrame(data=data,index=range(1,17))
print(df)
season = (list(df['赛季'])[::-1])
score = (list(df['得分'])[::-1])
lanban = (list(df['篮板'])[::-1])
zhugong = (list(df['助攻'])[::-1])
return JsonResponse({'season':season,'score':score,'lanban':lanban,'zhugong':zhugong})

为解决这个错误,将代码更改为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from django.shortcuts import render
import pandas as pd
from django.http import JsonResponse
import os #新增行
# Create your views here.
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) #新增行,获取项目的绝对路径
def api_echarts(request):
data = pd.read_excel(os.path.join(BASE_DIR,'echarts','james.xlsx')) #修改行
df = pd.DataFrame(data=data,index=range(1,17))
print(df)
season = (list(df['赛季'])[::-1])
score = (list(df['得分'])[::-1])
lanban = (list(df['篮板'])[::-1])
zhugong = (list(df['助攻'])[::-1])
return JsonResponse({'season':season,'score':score,'lanban':lanban,'zhugong':zhugong})

这样就可以成功获取数据了。

完成后,为了和下文的HTML文件对接,还需要在view.py中加入:

1
2
def echarts_page(request):
return render(request,'echarts.html')

urls的配置

在项目的路由配置里,加入:

1
path('echarts/',include('echarts.urls')),

在echarts应用的路由里,加入:

1
2
path('api_echarts/',api_echarts),
path('echarts_page',echarts_page),

echarts远程包

远程包:调用CDN需要请求网络资源。

在templates文件夹下新建一个echarts.html


在头部,添加对jQuery和echarts的引用。

1
2
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/echarts/4.8.0/echarts.min.js"></script>

接下来,再在body部分建一个容器来使用echarts。

1
<div id="box" style="width:900px;height:500px;background: rgba(106,11,233,0.4)"></div>

然后,新建一个script标签,在其中键入以下代码。

1
2
3
4
5
6
7
8
9
var mycharts = echarts.init(document.getElementById('box'));   //mycharts的内容放在box容器里
$.ajax({
url: '/echarts/api_echarts/',
type: 'get',
dataType:'json',
success:function(res){
console.log(res);
}
});

打开echarts官网获取一个实例的代码。


复制左边的代码,到script标签的funtion(res)中,修改数据部分为项目的内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
option = {
xAxis: {
type: 'category',
data: res.season,
},
yAxis: {
type: 'value'
},
series: [{
data: res.score,
type: 'line',
smooth: true
}]
};

然后在之后加入以下代码来绘制图形。结果如下图所示。

1
mycharts.setOption(option);

绘制表格

在HTML的body部分加入以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!--table是表格标签-->
<table>
<thead>
<tr>

</tr>
</thead>
<tbody>
<tr>

</tr>
<tr>

</tr>
<tr>

</tr>
</tbody>
</table>
  • <thead>标签定义表格的表头。该标签用于组合 HTML 表格的表头内容。
  • thead 元素应该与 tbody 和 tfoot 元素结合起来使用。
  • tbody 元素用于对 HTML 表格中的主体内容进行分组,而 tfoot 元素用于对 HTML 表格中的表注(页脚)内容进行分组。
  • tr 代表一行;td 代表一列。
  • table的属性中有一个border,默认border=“0”,为无边框。这里就是无边框。
    在Script标签中加入以下代码:
1
2
3
4
5
6
for(var i=0;i<res.score.length;i++){
$('thead tr').append('<td>'+res.season[i]+'</td>');//追加表头
$('tbody tr:eq(0)').append('<td>'+res.score[i]+'</td>');//追加得分
$('tbody tr:eq(1)').append('<td>'+res.lanban[i]+'</td>');//追加篮板
$('tbody tr:eq(2)').append('<td>'+res.zhugong[i]+'</td>');//追加助攻
}

结果如图所示。

echarts本地包

重点。
调用本地资源,不需要网络。
拓展-静态文件的展示、图片或者文件的上传

调用本地图片

如果直接在网页中写以下代码时,浏览器并不能找到该资源。因此需进行路由配置。

1
<img src="/bg1.jpg">

注意到settings.py里有如下内容。因此在项目的根目录新建一个static文件夹。

然后在这句代码的下面,加入下面的代码:

1
2
3
STATICFILES_DIRS=[
os.path.join(BASE_DIR,'static')
]

对于这段代码,援引一段来自Django官方文档的解释。

然后在urls.py中配置static文件夹资源的路由。
先引入下面这几个包并获取项目绝对路径。

1
2
3
4
from django.urls import re_path #正则表达式路径
import os
from django.views import static
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))#项目绝对路径

然后配置下面这条路由。

1
path(r'^static/(?<path>.*)$',static.serve,{'document_root':os.path.join(BASE_DIR,'static')}),

完成后,图片就可以正常的访问了。

调用本地JS或CSS

在配置完毕上面的路由之后。也可以调用本地的JS或CSS资源。
以jQuery为例,直接打开其CDN链接。复制其中的内容到一个本地的js文件中放在static文件夹下即可。

1
<script src="/static/js/jquery.min.js"></script>

echarts增加细节

更多的细节可以查询echarts的API手册

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
option = {
color: ['red','orange'], //图线颜色
xAxis: {
type: 'category',
data: res.season,
},
tooltip:{
trigger: 'axis',
axisPointer:{
type:'shadow' //当鼠标移动在点上时的提示窗口
},
show:true,
},
legend:{
data:['篮板','助攻'] //图例
},
yAxis: {
type: 'value'
},
series: [{
data: res.lanban,
type: 'line',
name:'篮板', //系列名称
smooth: true
},{
data: res.zhugong,
type: 'line',
name: '助攻', //系列名称
smooth: true,
}
]
};


  1. 参考资料:https://www.jianshu.com/p/8024ceef4fe2 ↩︎