结对第二次作业——某次疫情统计可视化的实现

这个作业属于哪个课程<班级的链接>
这个作业要求在哪里 https://edu.cnblogs.com/campus/fzu/2020SpringW/homework/10456
这个作业的目标 完成疫情统计可视化,并学习GitHub使用
结对学号 021700915、091700403
作业正文 https://www.cnblogs.com/lxbxyz/p/12489202.html
其他参考文献 node.js教程GitHub使用教程JavaScript教程

程序GitHub仓库地址为:https://github.com/ideaflyit/InfectStatisticWeb

一、成品展示

1.概述

疫情统计系统主要分为两个页面,分别为全国页面和分省页面。全国页面主要包含全国疫情数据、全国疫情统计图、全国确诊总量趋势图、全国确诊增量趋势图等。分省页面主要包含各省疫情数据、各省确诊总量趋势图、各省确诊增量图、省内各市确诊,治愈,死亡人数的详细数据以及实时疫情新闻等。

2.全国页面

全国页面主要包含全国疫情数据、全国疫情统计图、全国确诊总量趋势图、全国确诊增量趋势图等。

(1)全国疫情数据

全国疫情数据以文字形式显示全国实时的疫情数据,包括确诊人数,治愈人数,死亡人数,疑似人数。

img

(2)全国疫情统计图

全国疫情数据是在全国地图上使用不同的颜色代表大概确诊人数区间,颜色的深浅表示疫情的严重程度,可以直观了解高危区域。鼠标移到每个省份会高亮显示,并展示该省份的名称、确诊人数、治愈人数、死亡人数。

img

(3)全国确诊总量趋势图、全国确诊增量趋势图

全国确诊总量趋势图以折线统计图的方式显示全国确诊的总量的趋势,横坐标为日期,纵坐标为确诊人数。并且当鼠标悬浮在某某天的时候会显示该天的日期、确诊、治愈、死亡数据。

同样,全国确诊增量趋势图也以折线统计图的方式显示全国确诊的增量的趋势,横坐标为日期,纵坐标为增量人数。并且当鼠标悬浮在某某天的时候会显示该天的日期、确诊、治愈、死亡数据。

img

(4)总览

img

3.分省页面

分省页面主要包含各省疫情数据、各省确诊总量趋势图、各省确诊增量图、省内各市确诊,治愈,死亡人数的详细数据以及实时疫情新闻等。

(1)各省疫情数据

各省疫情数据以文字形式显示各省实时的疫情数据,包括确诊人数,治愈人数,死亡人数,疑似人数。页面提供选择框,用户可以根据需要选择需要查询的省份来查看目标省份的具体数据。

img

(2)各省确诊总量趋势图、各省确诊增量图

各省确诊总量趋势图以折线统计图的方式显示各省确诊的总量的趋势,横坐标为日期,纵坐标为确诊人数。并且当鼠标悬浮在某某天的时候会显示该天的具体数据。

同样各省确诊增量趋势图也以折线统计图方式显示各省的确诊的总量的趋势,很坐标为日期,纵坐标为确诊人数增量。并且当鼠标悬浮在某某天的时候会显示该天的具体数据。

img

(3)省内各市的详细数据

省内各市的详细数据显示各市的确诊,治愈,死亡人数。

img

(4)疫情实时新闻

疫情实时新闻显示主流媒体播报的疫情新闻,用户可以点击相应的标题查看对应的新闻

img

(5)总览

img

二、实现

1.讨论

img

img

img

img

img

img

img

img

2、功能结构图

疫情统计系统主要分为两个页面,分别为全国页面和分省页面。全国页面主要包含全国疫情数据、全国疫情统计图、全国确诊总量趋势图、全国确诊增量趋势图等。分省页面主要包含各省疫情数据、各省确诊总量趋势图、各省确诊增量图、省内各市确诊,治愈,死亡人数的详细数据以及实时疫情新闻等。

img

3.设计实现过程

本次疫情统计可视化设计主要分为两个页面。一个是全国页面,还有一个是分省页面。通过我们的分析,全国页面主要包含以下功能:查看全国疫情数据、查看全国疫情统计图、查看全国确诊总量趋势图、查看全国确诊增量趋势图。分省页面主要包含以下功能:查看各省疫情数据、查看各省确诊总量趋势图、查看各省确诊增量图、查看省内各市确诊,治愈,死亡人数的详细数据以及查看实时疫情新闻。下面分别讲述以上功能的实现

(1)全国页面

  • 查看全国疫情数据

    调用接口https://lab.ahusmart.com/nCoV/api/overall?latest=1,使用var data = res.results[0];获取json的值,data.confirmedCount data.curedCount data.deadCount data.suspectedCount分别获取全国确诊人数、全国治愈人数、全国死亡人数

  • 查看全国疫情统计图

    使用china.js显示中国地图,使用node.js实现爬虫,然后将爬取的数据放入地图中。具体如下:

    • spider.js

      url指定请求的目标网站url = https://ncov.dxy.cn/ncovh5/view/pneumonia,分析目标页面DOM结构,找到所要抓取的信息的相关DOM元素,提取对应疫情数据

    • index.js

      先引入express,再创建服务器应用,用app.get监听请求,加入res.setHeader("Access-Control-Allow-Origin","*")解决跨域问题,最后用app.listen分配端口号启动服务

    • 将filterData传入到echarts中

  • 全国确诊总量趋势图、全国确诊增量趋势图

    调取api实现疫情数据的获取,在series中用data注入数据,使用echart实现折线统计图的显示。

(2)分省页面

  • 查看各省疫情数据

    调用接口'https://lab.ahusmart.com/nCoV/api/overall?latest=1&province=' + province获取各省份数据,使用 var confirm 存放各省确诊数据,var suspectedCount存放各省疑似数据,var curedCount 存放治愈数据var deadCount存放死亡数据。遍历从接口获取的数据,统计总的确诊,疑似,治愈,死亡数据。

  • 查看全国确诊总量趋势图、全国确诊增量趋势图

    调取api实现疫情数据的获取,在series中用data注入数据,使用echart实现折线统计图的显示。

  • 查看实时疫情新闻

    直接调取爬取的数据并展示数据

  • 查看省内各市确诊,治愈,死亡人数的详细数据

    直接调取爬取的数据并展示数据

四.关键代码

1.country.html

(1)页面总体结构

在这里插入图片描述

(2)获取全国的总数据

  • 调用接口https://lab.ahusmart.com/nCoV/api/overall?latest=1 在这里插入图片描述

  • var data = res.results[0];获取json的值

  • data.confirmedCount data.curedCount data.deadCount data.suspectedCount分别获取全国确诊人数、全国治愈人数、全国死亡人数

var dataUrl = "https://lab.ahusmart.com/nCoV/";
var dataUrlBackup = "https://lab.ahusmart.com/nCoV/";

$(document).ready(function() {
initCoreData();
initTrendChart();
initAddChart();
});
var initCoreData = function(province) {

$.ajax({
url: dataUrl + 'api/overall?latest=1',
type: 'get',
success: function(res) {
if(res.success === true) {
var data = res.results[0];

var html = ' 全国疫情数据:\n' +
'       <div>' +
'<span class="label label-warning data-confirmed">确诊</span>:' + data.confirmedCount + '&nbsp;&nbsp;' +
'<span class="label label-success data-cured">治愈</span>:' + data.curedCount + ' &nbsp;&nbsp; ' +
'<span class="label label-danger data-dead">死亡</span>:' + data.deadCount + '&nbsp;&nbsp;' +
'<span class="label label-info data-dead">疑似</span>:' + data.suspectedCount + '</div>\n' +
' ';

$(".core-data").html(html);

return;
}
alert("获取数据失败");

},
error: function(res) {
if(res.state() === "rejected" && !this.url.includes(dataUrlBackup)) {
this.url = this.url.replace(dataUrl, dataUrlBackup);
$.ajax(this);
}
}
})

};

(3)地图的实现

用node.js实现爬虫

spider.js

  • url指定请求的目标网站url = https://ncov.dxy.cn/ncovh5/view/pneumonia

  • 分析目标页面DOM结构,找到所要抓取的信息的相关DOM元素

  • 提取对应疫情数据

//使用superagent请求目标页面
const superagent = require('superagent')
//使用cheerio获取页面元素,获取目标数据
const cheerio = require('cheerio')
const fs = require('fs')
const path = require('path')


const url = `https://ncov.dxy.cn/ncovh5/view/pneumonia`
superagent
.get(url)
.then(res => {
 
   const $ = cheerio.load(res.text)
   
   var $getListByCountryTypeService1 = $('#getListByCountryTypeService1').html()
   var $getAreaStat = $('#getAreaStat').html()
   var $getStatisticsService = $('#getStatisticsService').html()
   
   var dataObj = {}
   eval($getListByCountryTypeService1.replace(/window/g, 'dataObj'))
   eval($getAreaStat.replace(/window/g, 'dataObj'))
   eval($getStatisticsService.replace(/window/g, 'dataObj'))
 
//写入本地
   fs.writeFile(path.join(__dirname, './data.json'), JSON.stringify(dataObj), err => {
     if (err) throw err
     console.log('数据写入成功')
  })
})
.catch(err => {
   throw err
})

index.js

  • 先引入express

  • 再创建服务器应用

  • 用app.get监听请求

  • 加入res.setHeader("Access-Control-Allow-Origin","*");解决跨域问题

  • 最后用app.listen分配端口号启动服务

const express = require('express')
const fs = require('fs')
const path = require('path')
const app = express()
app.get('/api/data', (req, res) => {
res.setHeader("Access-Control-Allow-Origin","*");
 fs.readFile(path.join(__dirname, './data.json'), 'utf8', (err, data) => {
   if (err) throw err
   console.log(data)
   res.send(data)
})
})
app.listen(8066, () => {
 console.log(`启动成功 http://127.0.0.1:8066/api/data`)
})
  • 获取filterData 在这里插入图片描述

  • 将filterData传入到echarts中

    在这里插入图片描述

(4)全国总量曲线图的echarts实现

  • 获取数据 在这里插入图片描述

  • 在series中用data注入数据

    echartsOption = {
    backgroundColor: '#ddf4df',
    title: {
    text: '全国总量',
    textStyle: {
    fontWeight: 'normal',
    fontSize: 12,
    color: '#161916'
    },
    left: '2%'
    },
    tooltip: {
    trigger: 'axis',
    axisPointer: {
    lineStyle: {
    color: '#57617B'
    }
    }
    },
    legend: {
    icon: 'rect',
    itemWidth: 14,
    itemHeight: 5,
    itemGap: 1,
    data: ['确诊', '治愈', '死亡'],
    right: '2%',
    textStyle: {
    fontSize: 12,
    color: '#161916'
    }
    },
    grid: {
    left: '2%',
    right: '2%',
    bottom: '2%',
    containLabel: true
    },
    xAxis: [{
    type: 'category',
    boundaryGap: false,
    axisLine: {
    lineStyle: {
    color: '#57617B'
    }
    },
    data: date
    }],
    yAxis: [{
    type: 'value',
    axisTick: {
    show: false
    },
    axisLine: {
    lineStyle: {
    color: '#57617B'
    }
    },
    axisLabel: {
    margin: 4,
    textStyle: {
    fontSize: 8
    }
    },
    splitLine: {
    lineStyle: {
    color: '#161916'
    }
    }
    }],
    series: [{
    name: '确诊',
    type: 'line',
    smooth: true,
    symbol: 'circle',
    symbolSize: 5,
    showAllSymbol: false,
    lineStyle: {
    normal: {
    width: 1
    }
    },
    label: {
    show: true,
    position: 'top',
    textStyle: {
    color: '#fff'
    }
    }, areaStyle: {
    normal: {
    color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
    offset: 0,
    color: 'rgba(137, 189, 27, 0.3)'
    }, {
    offset: 0.8,
    color: 'rgba(137, 189, 27, 0)'
    }], false),
    shadowColor: 'rgba(0, 0, 0, 0.1)',
    shadowBlur: 10
    }
    },
    itemStyle: {
    normal: {
    color: '#f1a325',
    borderColor: 'rgba(137,189,2,0.27)',
    borderWidth: 12

    }
    },
    data: confirmedNCoV
    }, {
    name: '治愈',
    type: 'line',
    smooth: true,
    symbol: 'circle',
    symbolSize: 5,
    showSymbol: false,
    lineStyle: {
    normal: {
    width: 1
    }
    },
    areaStyle: {
    normal: {
    color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
    offset: 0,
    color: 'rgba(0, 136, 212, 0.3)'
    }, {
    offset: 0.8,
    color: 'rgba(0, 136, 212, 0)'
    }], false),
    shadowColor: 'rgba(0, 0, 0, 0.1)',
    shadowBlur: 10
    }
    },
    itemStyle: {
    normal: {
    color: '#38b03f',
    borderColor: 'rgba(0,136,212,0.2)',
    borderWidth: 12

    }
    },
    data: curedNCoV
    }, {
    name: '死亡',
    type: 'line',
    smooth: true,
    symbol: 'circle',
    symbolSize: 5,
    showSymbol: false,
    lineStyle: {
    normal: {
    width: 1
    }
    },
    areaStyle: {
    normal: {
    color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
    offset: 0,
    color: 'rgba(0, 136, 212, 0.3)'
    }, {
    offset: 0.8,
    color: 'rgba(0, 136, 212, 0)'
    }], false),
    shadowColor: 'rgba(0, 0, 0, 0.1)',
    shadowBlur: 10
    }
    },
    itemStyle: {
    normal: {
    color: '#ea644a',
    borderColor: 'rgba(0,136,212,0.2)',
    borderWidth: 12

    }
    },
    data: deadNCoV
    }]
    };

2.specific.html

(1)省份确诊,疑似,治愈,死亡数据统计

echartsOption = {
backgroundColor: '#ddf4df',
title: {
text: '全国总量',
textStyle: {
fontWeight: 'normal',
fontSize: 12,
color: '#161916'
},
left: '2%'
},
tooltip: {
trigger: 'axis',
axisPointer: {
lineStyle: {
color: '#57617B'
}
}
},
legend: {
icon: 'rect',
itemWidth: 14,
itemHeight: 5,
itemGap: 1,
data: ['确诊', '治愈', '死亡'],
right: '2%',
textStyle: {
fontSize: 12,
color: '#161916'
}
},
grid: {
left: '2%',
right: '2%',
bottom: '2%',
containLabel: true
},
xAxis: [{
type: 'category',
boundaryGap: false,
axisLine: {
lineStyle: {
color: '#57617B'
}
},
data: date
}],
yAxis: [{
type: 'value',
axisTick: {
show: false
},
axisLine: {
lineStyle: {
color: '#57617B'
}
},
axisLabel: {
margin: 4,
textStyle: {
fontSize: 8
}
},
splitLine: {
lineStyle: {
color: '#161916'
}
}
}],
series: [{
name: '确诊',
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 5,
showAllSymbol: false,
lineStyle: {
normal: {
width: 1
}
},
label: {
show: true,
position: 'top',
textStyle: {
color: '#fff'
}
},
                areaStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(137, 189, 27, 0.3)'
}, {
offset: 0.8,
color: 'rgba(137, 189, 27, 0)'
}], false),
shadowColor: 'rgba(0, 0, 0, 0.1)',
shadowBlur: 10
}
},
itemStyle: {
normal: {
color: '#f1a325',
borderColor: 'rgba(137,189,2,0.27)',
borderWidth: 12

}
},
data: confirmedNCoV
}, {
name: '治愈',
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 5,
showSymbol: false,
lineStyle: {
normal: {
width: 1
}
},
areaStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(0, 136, 212, 0.3)'
}, {
offset: 0.8,
color: 'rgba(0, 136, 212, 0)'
}], false),
shadowColor: 'rgba(0, 0, 0, 0.1)',
shadowBlur: 10
}
},
itemStyle: {
normal: {
color: '#38b03f',
borderColor: 'rgba(0,136,212,0.2)',
borderWidth: 12

}
},
data: curedNCoV
}, {
name: '死亡',
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 5,
showSymbol: false,
lineStyle: {
normal: {
width: 1
}
},
areaStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: 'rgba(0, 136, 212, 0.3)'
}, {
offset: 0.8,
color: 'rgba(0, 136, 212, 0)'
}], false),
shadowColor: 'rgba(0, 0, 0, 0.1)',
shadowBlur: 10
}
},
itemStyle: {
normal: {
color: '#ea644a',
borderColor: 'rgba(0,136,212,0.2)',
borderWidth: 12

}
},
data: deadNCoV
}]
};

(2)省份每日数据统计

var initChart = function(province) {
$.ajax({
url: dataUrl + 'api/area?latest=0&province=' + province,
type: 'get',
success: function(res) {
if(res.success === true) {
var chartData = res.results;
var dateTrend = [];
var dateAdd = [];
var confirm = [];
var confirmAdd = [];
var datalist = [];

for(var i in chartData) {
var dataTime = new Date(chartData[i].updateTime);
var showTime = [dataTime.getFullYear(), dataTime.getMonth() + 1, ("0" + dataTime.getDate()).slice(-2)].join('/');
if(dateTrend.includes(showTime)) {
continue;
}
if(!datalist[showTime] || datalist[showTime] < chartData[i].confirmedCount) {
datalist[showTime] = chartData[i].confirmedCount;
}

}

// 时间排序
const dataListOrdered = {};
Object.keys(datalist).sort((function(a, b) {
a = a.split('/').join('');
b = b.split('/').join('');
return a > b ? 1 : a < b ? -1 : 0;
})).forEach(function(key) {
dataListOrdered[key] = datalist[key];
});

// 使用数据
for(var i in dataListOrdered) {
dateTrend.push(i);
confirm.push(dataListOrdered[i]);

var t = new Date(i);
t.setDate(t.getDate() - 1);
var yesterday = [t.getFullYear(), t.getMonth() + 1, ("0" + t.getDate()).slice(-2)].join('/');
if(!dataListOrdered[yesterday]) {
continue;
}

dateAdd.push(i);
confirmAdd.push(dataListOrdered[i] - dataListOrdered[yesterday]);
}

var title = "确诊总量(" + chartData[0].country + "-" + chartData[0].provinceShortName + ")";
initTrendChart(dateTrend, confirm, title);

title = "确诊增量(" + chartData[0].country + "-" + chartData[0].provinceShortName + ")";
initAddChart(dateAdd, confirmAdd, title);
return;
}
alert("获取数据失败");
},
});

五、心路历程与收获

  • 021700915

    • 心路历程:通过两次结对实践我的确收获很多,最重要的是增强了团队合作的意识。之前一直是一个人写代码,刚开始要合作的时候我还是非常疑惑的,质疑团队合作的意义。既然自己都知道思路,还不如自己写,和队友沟通的时间都能写很多,团队合作还有什么意义呢?但是通过一次的团队编程和两次的结对合作,我意识到了自身想法的错误。好的团队合作可以提高编程效率,加快项目的进度。同时,好的团队也有利于每个团队成员的自身的发展。通过团队内的沟通学习,可以使自己学习到以前没有接触到的或者不熟悉的新技术,并且还可以获取到完全不一样的idea,获得灵感。队友之间还可以相互监督,相互带动,确保能够按时完成任务。就像此次实践,以往我一般都是在deadline前一两天去完成作业,这次提前了,有很多不会的队友也耐心的解答。

    • 收获: 通过本次结对实践,我学到了很多东西。

      首先是进一步了解了GitHub的使用,对GitHub的作用加深了了解,对使用分支、release、issues、pr等其它功能有了更加深入的了解。GitHub的确是一个团队编程的好平台,能够提高编程效率,避免相互传文件的麻烦。

      其次是巩固了前端知识,学习了一些新的知识。虽然说在上学期已经学习了前端的一些技术,如html,javascript,css等,但是到现在也有一些遗忘。通过此次实践巩固了这些知识,尤其是JavaScript部分的知识,因为本次实践大量使用JavaScript语言编写。同时,又学习了一些新知识,如echart的使用,echart各个属性的设置,node.js爬虫的一些相关知识。

      最后是对结对编程有了进一步的认识,对结对编程的意义有了更加深入的了解。相互学习,相互监督,相互促进,提升效率。

    • 队友评价:队友执行力很强,总是在任务布置后的一两天开始做(而不像我,在deadline前才开始着手完成),这直接加快了本次作业的完成进度。队友的编程能力也很强,对于很多没学过的技术也有了解(node.js),并且能够运用该技术,然而我却不怎么了解。但是在队友大量文字以及发视频的耐心讲解下我对该技术有了更加深入的了解,所以我认为这是一位非常尽职,有责任心,耐心的队友。

      img

  • 091700403

    • 收获:此次作业完成后,我学会了Git分支操作,对爬虫等知识也有了一定的了解。也接触了echarts,了解了如何去通过图表的形式将数据可视化表现出来,学习了前端的一些内容,又再次复习了HTML,CSS。在完成作业的过程中遇到了很多困难,比如如何去将爬取下来的内容进行截取,从中提取出所需要的数据内容。 通过此次结对合作,我更加深刻的体会到了团队合作的重要性,在这个过程中,队友也给了我很大的帮助。

    • 队友评价:队友做事认真负责,细心谨慎,在结对完成作业的过程中,从他身上我学会了更加耐心地去完成细节,我们也知道了如何去更好地沟通,去表达自己的想法,将自己的所思所想用语言表达清楚。

posted @ 2020-03-13 21:36  cybinz  阅读(520)  评论(6编辑  收藏  举报