结对第二次作业 ——某次疫情统计可视化的实现
结对第二次作业——某次疫情统计可视化的实现
这个作业属于哪个课程 | https://edu.cnblogs.com/campus/fzu/2020SpringW/ |
---|---|
这个作业要求在哪里 | https://edu.cnblogs.com/campus/fzu/2020SpringW/homework/10456 |
这个作业的目标 | 某次疫情统计可视化的实现 |
结对学号 | 061700150、071703434 |
作业正文 | 作业正文 |
其他参考文献 | ... |
1.Github仓库地址
2.展示你的成品
功能1:实现通过地图的形式来直观显示疫情的大致分布情况,还可以查看具体省份的疫情统计情况
-
可以选择具体的日期
-
显示对应的感染患者人数、疑似患者人数、治愈人数、死亡人数;
-
在全国地图上使用不同的颜色代表大概确诊人数区间,颜色的深浅表示疫情的严重程度,可以直观了解高危区域;
-
鼠标移到每个省份会高亮显示;
-
点击鼠标会显示该省具体疫情情况;
功能2:点击某个省份显示该省疫情的具体情况
-
显示该省份对应的感染患者人数、疑似患者人数、治愈人数、死亡人数;
-
该省份到目前为止的新增确诊趋势、新增疑似趋势、治愈趋势和死亡趋势
-
绘制该省份的趋势变化曲线图;
3.结对讨论过程描述
-
初步讨论分工
-
前端布局过程
-
开始拓展功能
-
发现遗漏需求,放弃扩展功能
-
数据清洗处理,首先找了GitHub上开源的数据,发现数据不可以直接拿来用,因为数据多且不是每天对应的每个省份的数据,因此数据处理和清洗太花了很多时间,还是放弃,然后又用了天行的数据接口,数据处理很简化也还是花了很长的时间
4.描述设计实现过程
前端
- 概况:使用vue-cli,易上手的MVVM框架,由于组件较少没有使用vuex和vue-router
- 页面结构:index.html内挂载了statis.vue(其内又有bar.vue)、navi.vue、query.vue(胎死腹中)
- 页面布局:都是现写的,
后端
- 概况:使用node环境下的express,nginx负责代理及分发api
- 数据来源:首先是https://lab.isaaclin.cn/nCoV/api/area,但它提供的省份时间数据过于混乱和离谱,后期又在前人大佬的启发下紧急换上了http://api.tianapi.com/txapi//ncovcity/
- 调用:
https://ncov.funx.pro/api/ncov/getAll POST请求无参数,返回全国最新数据
https://ncov.funx.pro/api/ncov/getAllTime POST请求,参数为time:时间,例如'2020-02-20',返回全国最新数据
https://ncov.funx.pro/api/ncov/getProv POST请求,参数为name:省份短写,例如'黑龙江',返回全国最新数据
5.代码说明
-
前端关键代码说明
```
前端部分,使用Vue:
```
//部分代码,完整部分位于开头链接仓库
updateDataList(info, date) {
var baseURL = "https://ncov.funx.pro" //后端base地址
var url = !date?"/api/ncov/getAll":'/api/ncov/getAllTime' //根据是否携带时间参数,调用不同的api
var param = !date?{}:{time:date} //根据是否有时间参数,判断是否将其携带
return new Promise(resolve => { //异步Promise,返回一个拿到数据后的状态
$ajax.post(baseURL + url, param).then(doc => { //Ajax
var arr = JSON.parse(doc.data.data); //string至object
arr.data.forEach(v => {
this.dataList.forEach((l, i) => { //遍历拿到的省份数据,将其添加至响应式数据中
if (l.name == v.provinceShortName)
this.$set(this.dataList[i], "value", v[info]); //改变数组的值
});
});
resolve(arr); //返回状态,以便下一步进行
});
});
},
initAll(info, date) {
this.showDialog = false; //显示loading和过度用的,没有使用echarts自带loading
if (this.myChart) this.myChart.dispose(); //因为框架内遇到了一些无法解决的bug,只能在重载时销毁ec实例
this.updateDataList(info, date).then(arr => {
if (this.allNum.inj[0] == 0 || date) { // 判断 数据源未提供的标识 显示为'--'
Object.keys(this.allNum).forEach(name => { // 六项基本疫情信息遍历
if(!arr.statis[name] || (date&&name=='sus')){
this.allNum[name]=[-9999,-9999] // 数据源未提供的标识 显示为'--'
return
}
var Time = 30, t = 0;
var base = this.allNum[name][0] // 加了一点很无聊的数字动画....
var base2 = this.allNum[name][1] // 0是总项、1是变化项
var piece = ((arr.statis[name][0]-this.allNum[name][0]) / Time).toFixed(2); // 单次变化值
var piece2 = ((arr.statis[name][1]-this.allNum[name][1]) / Time).toFixed(2);// 单次变化值
//console.log(`目标${arr.statis[name][0]},当前${this.allNum[name][0]}`)
var timer = setInterval(() => {
this.$set(this.allNum[name], 0, base+ parseInt(piece * ++t));
this.$set(this.allNum[name], 1, base2+parseInt(piece2 * ++t));
if (t == Time) {
this.allNum[name][0] = arr.statis[name][0];
this.allNum[name][1] = arr.statis[name][1];
clearInterval(timer);
}
}, 16.6*2);
});
}
this.myChart = echarts.init(document.getElementById("main"));
-
后端关键代码说明
```
后端部分,nodejs环境下获得数据,再存入数据库:
知名疫情网站的数据都是写死的,所以,爬虫是不存在的... ...
这是GitHub上某仓库提供的(脏数据,浪费了很多很多时间)
```
//部分代码,完整部分位于开头链接仓库
$ajax.get("https://lab.isaaclin.cn/nCoV/api/area").then(doc => {
// console.dir(doc.data)
var arr = [];
var obj = {
curInj: [0, 0],
inj: [0, 0],
sus: [0, 0],
cur: [0, 0],
dead: [0, 0],
bad: [0, 0]
};
doc.data.results.forEach(d => {
if (d.countryName == "中国") {
delete d.cities;
delete d.locationId;
delete d.continentEnglishName;
delete d.countryEnglishName;
delete d.continentName;
delete d.provinceEnglishName;
arr.push(d);
}
});
$ajax.get("https://lab.isaaclin.cn/nCoV/api/overall").then(doc2 => {
var doc2 = doc2.data.results[0];
obj.inj[0] = doc2.confirmedCount;
obj.curInj[0] = doc2.currentConfirmedCount;
obj.sus[0] = doc2.suspectedCount;
obj.cur[0] = doc2.curedCount;
obj.dead[0] = doc2.deadCount;
obj.bad[0] = doc2.seriousCount;
obj.inj[1] = doc2.confirmedIncr;
obj.curInj[1] = doc2.currentConfirmedIncr;
obj.sus[1] = doc2.suspectedIncr;
obj.cur[1] = doc2.curedIncr;
obj.dead[1] = doc2.deadIncr;
obj.bad[1] = doc2.seriousIncr;
var ncov = new Ncov({
name: "全国",
data: JSON.stringify({
data: arr,
statis: obj
})
});
ncov.save((err, data) => {
if (!err) console.log("ok");
});
});
});
-
数据处理关键代码说明
```
上段小部分代码整理出了很多脏数据,又花费了非常大量时间清理,但效果依旧不好。
所以最后,唉,还是用了前人大佬们发现的tianapi:
(国际后仰:什么是爬虫啊 )
```
//部分代码,完整部分位于开头链接仓库
const mongoose = require("mongoose");
// const $ajax = require('axios')
mongoose.connect(MONGOURL, {
useNewUrlParser: true,
useUnifiedTopology: true
});
const Ncov = mongoose.model("NCOV", new mongoose.Schema({
name: String,
data: String,
},
{ collection: "NCOV" }));
var MONTH = [-1, 31, 29, 10]
var m, d, i
var calen = []
for (m = 2; m <= 3; m++) {
for (m == 2 ? (d = 14) : (d = 1); d <= MONTH[m]; d++) {
var strd = d
if (strd <= 9) strd = '0' + strd
calen.push(`2020-0${m}-${strd}`)
}
}
var last = {}
function sleep(wait) {
return new Promise((res,rej) => {
setTimeout(() => {
res(wait);
},wait);
});
}
var last = {curInj: 0, inj: 0, dead: 0, sus: 0, cur: 0}
async function run(){
for (let i = 0; i < calen.length; i++) {
let calenItem = calen[i]
let doc = await $ajax.get(
`http://api.tianapi.com/txapi//ncovcity/index?key=${KEY}&date=${calenItem}`
)
console.log(calenItem)
var obj = {
data: [],
statis: {curInj: [0, 0], inj: [0, 0], dead: [0, 0], sus: [0, 0], cur: [0, 0]}
}
doc = doc.data.newslist
doc.forEach(v => {
delete v.provinceName
delete v.cities
delete v.comment
delete v.locationId
delete v.statisticsData
obj.data.push(v)
obj.statis.curInj[0] += v.currentConfirmedCount
obj.statis.inj[0] += v.confirmedCount
obj.statis.sus[0] += v.suspectedCount
obj.statis.cur[0] += v.curedCount
obj.statis.dead[0] += v.deadCount
})
obj.statis.curInj[1] = obj.statis.curInj[0] - last.curInj
obj.statis.inj[1] = obj.statis.inj[0] - last.inj
obj.statis.sus[1] = obj.statis.sus[0] - last.sus
obj.statis.cur[1] = obj.statis.cur[0] - last.cur
obj.statis.dead[1] = obj.statis.dead[0] - last.dead
last.curInj=obj.statis.curInj[0]
last.inj=obj.statis.inj[0]
last.sus=obj.statis.sus[0]
last.cur=obj.statis.cur[0]
last.dead=obj.statis.dead[0]
console.log(obj.statis)
var ncov = new Ncov({
name: calenItem,
data: JSON.stringify(obj)
});
ncov.save((err, data) => {
if (!err) console.log("ok");
});
await sleep(2000)
}
}
run()
```
6.心路历程与收获
061700150
单单从结果上来看,这次作业的完成应该是不怎么理想的... ...首先是自己比较缺乏协作经验,不靠谱的数据源耽误了大量时间。其次是分工不够明确,有些任务两人同时做,效率算是1+1 << 1,这也导致后续的新增功能,难以通过分工合作的方式进行下去。最后我依旧是要通过《构建之法》中的内容进行反思,自己对于多人依赖合作、完成任务的要求并不熟稔于心 —— 众多原因与自身的理解不到位,导致,项目一步步滑入深渊。
071703434
这次作业可以完成几乎都是队友的功劳,我其实不是很明白这个作业整个的流程,因为在作业开始之前队友就已经把一部分完成了,无论是功能还是数据
之后呢,我做的事情几乎就像是在添乱一样,本以为我们的基础功能算是完成,于是我就开始给扩展功能页面开始排版,排版的结果就是,反而加大队友的工作量;之后,前端的某些小小功能效果没有实现,我又花了一晚上和一早上快速入门VUE,仅仅完成了两部分按钮的效果;在接下来,队友看到其他队的成品,才意识到我们漏了一个功能需求,就放弃扩展功能,于是我开始重新捡起Python处理清洗数据,但是因为API不熟悉,还有要求没有看清又花了一个晚上一个早上处理出一堆没有用处的数据;由于程序功能几乎都不是我实现的,所以博客内容我也无从下手.....
反正,就是蛮挫败的,花了很多时间,做了很多无用功,没有做出啥实质性的贡献,收获就是,更清醒的认识到自己的不足,明白自己在合作中能够发挥的作用其实不大,自身的编程能力很不OK的,还有很大的进步空间。
还有就是关于《构建之法》里关于团队合作说到,团队成员要有各自的分工,互相依赖合作,共同完成任务,反思这次就是没有很好地进行规划合作,希望多多吸取经验,毕竟合作能力在软件工程中是很重要的一部分
7.评价结对队友
061700150
队友很乐于学习新技术并愿意为之付出,而且撰文思路清晰流畅,即便是遇到一些障碍和困难,也会想方设法加以解决
071703434
队友还是很靠谱的,认真负责,技术很强,经过这次结对合作之后,在他的指导下也学到了不少东西