結對第二次作業——某次疫情統計可視化的實現


作業概況

這個作業屬於哪個課程 班級的鏈接
這個作業要求在哪里 作業要求的鏈接
結對學號 221701104,221701116
這個作業的目標 完成疫情webapp的基礎功能包括:
顯示全國地圖數據,點擊省份可以顯示具體的變化趨勢
作業正文 作業正文
其他參考文獻 ...

giithub地址

github倉庫

代碼規范

成品展示

作業鏈接(服務器帶寬很小,渲染和加載需要時間)

接口可能會因為不穩定導致獲取不到數據,可將index.js中獲取接口的.ajax的url更換為https://lab.ahusmart.com/nCoV/api/area進行嘗試。(2020/3/19)
以上鏈接可能由於API的不穩定而失效,如果失效,請使用下面的鏈接(2020/3/22)
作業鏈接
此作業鏈接對應github中release的1.0.1版本

一、主頁

​ 1、在頁面的左上角有個“首頁”的標志,點擊能夠返回主頁(也就是下方圖片顯示的頁面)

​ 2、點擊全國趨勢查看全國數據以及全國新增趨勢圖

​ 3、時間戳會根據當天時間實時更新,地圖采用API接口,也會實時更新數據

圖片

​ 4、省份區塊的顏色按照累計確診人數的多少決定顏色的深淺

​ 5、將鼠標懸浮在省份上,該省份區塊會高亮顯示並顯示累計確診人數(如下圖)

​ 6、點擊該省份區塊,會跳轉至該省份數據顯示以及新增趨勢圖的頁面

​ 7、由於全國數據部分(上半部分,非地圖數據)是將爬取的數據轉化成json文件讀取,所以暫時未能實現實時更新,文件最新日期為2020-03-12


8、可以直接查看數據

二、全國趨勢

​ 1、在頁面的左上角有個“首頁”的標志,下方還有個返回標志,點擊兩處都能夠返回主頁

​ 2、點擊全國趨勢查看全國數據以及全國新增趨勢圖(也就是當前頁面)

​ 3、點擊日期選擇框能夠選擇日期,可選最早日期為2020-01-25,可選最晚日期為2020-03-12(因為數據部分是將爬取的數據轉化成json文件讀取,所以暫時未能實現實時更新,文件最新日期為2020-03-12)

​ 4、選擇日期后點擊確認,下方的數據表和新增趨勢圖就會變換至選擇日期的數據情況

​ 5、點擊圖例,可選擇要顯示的新增類型

​ 6、懸浮在趨勢圖上,可查看某天各個類型的新增人數(已關閉的趨勢圖不會顯示)

​ 7、這里只顯示新增疑似和新增治愈(點擊新增感染和新增死亡的圖例,將這兩幅新增趨勢圖關閉)

​ 8、點擊日期選擇框,會發現可選日期和不可選日期的底色上有差異

​ 9、選擇好日期點擊確認,下方數據表和趨勢圖已變化。

三、省份趨勢

​ 此處效果與全國趨勢圖大同小異,不同點為省份位置的位置會根據所選省份發生變化

結對過程展示

剛剛拿到作業覺得這次作業的問題並不多,因為上次原型制作的時候就使用了Echarts,這次對我們來說的主要難度就是數據的獲取,數據的處理和數據的渲染。

0. 前期工作

創建倉庫和dev,.ignore和ReadMe等部分。溝通GitHub的使用方法。新建代碼規范。

討論GitHub的使用細節

1. 分工

一個人將原型的樣子用前端CSS代碼復現出來,另一個人去尋找相關網頁爬取下來各省數據和全國歷史數據。

2. 數據爬下來后進行數據處理,對Echarts進行渲染

3. 文件合並,實現跳轉和整體邏輯

設計實現過程

設計過程

  • 網頁設計

    • 網頁架構形成
    • CSS處理
    • Echarts導入
  • 數據爬取

    • 找到數據地圖網頁

    • 通過python爬取數據

    • 本地化儲存到MySql中

    • 導出為json保存在網頁中避免多次調用數據庫

    • 通過concat定時執行腳本更新數據庫,保證數據實時性。

    • 數據來源:騰訊平台丁香平台

  • 功能實現

    • 將功能分為:地圖展示趨勢圖展示。兩個模塊分開設計
    • 地圖展示需要獲取全國各地的最新數據,通過爬蟲獲取數據之后返回到頁面,頁面挑選參數,通過js代碼獲取每個地區的數據,然后渲染到Echarts上
    • 趨勢圖展示
    • 地圖展示部分和趨勢圖展示的鏈接和跳轉
    • 通過Echarts的onclick函數獲取到選取的地圖塊位置,點擊后跳轉傳遞url,附帶參數name,通過name傳遞被點擊的地區。
    • 趨勢圖展示接收到傳過來的地區,讀取對應的數據文件,進行處理,得出時間對應的數據。
    • 數據渲染到Echarts圖標上,允許對圖例操作進而進行篩選。

功能結構圖

主要代碼

python部分

爬取數據的代碼類似如下,其他爬取函數類似不再贅述:

def get_tecent_china_data():
    url = 'https://view.inews.qq.com/g2/getOnsInfo?name=disease_other'
   
    r = requests.get(url)
    res = json.loads(r.text)
    data_all = json.loads(res['data'])

    history = {} # 歷史數據
    for i in data_all["chinaDayList"]:
        ds = "2020." + i["date"]
        tup = time.strptime(ds,"%Y.%m.%d")
        ds = time.strftime("%Y-%m-%d",tup)
        confirm = i["confirm"]
        suspect = i["suspect"]
        heal = i["heal"]
        dead = i["dead"]
        history[ds] = {"confirm":confirm, "suspect":suspect, "heal":heal, "dead":dead}
        
    for i in data_all["chinaDayAddList"]:
        ds = "2020." + i["date"]
        tup = time.strptime(ds,"%Y.%m.%d")
        ds = time.strftime("%Y-%m-%d",tup)
        confirm = i["confirm"]
        suspect = i["suspect"]
        heal = i["heal"]
        dead = i["dead"]
        history[ds].update({"confirm_add":confirm, "suspect_add":suspect, "heal_add":heal, "dead_add":dead})
    
    return history

找到騰訊的疫情地圖,通過開發者模式的網頁模式獲取騰訊前端請求的json頁面,也即url = 'https://view.inews.qq.com/g2/getOnsInfo?name=disease_other',然后通過requests組件發出讀取請求讀取到json文件,隨后進行爬取。

def insert_history():
    cursor = None
    conn = None
    try:
        dic = get_tecent_china_data()
        print(f"{time.asctime()}開始插入歷史數據")
        conn, cursor = get_conn()
        sql = "insert into history values(%s, %s, %s, %s, %s, %s, %s, %s, %s)"
        for k, v in dic.items():
            cursor.execute(sql,[k, v.get("confirm"),v.get("confirm_add"),v.get("suspect")
                               , v.get("suspect_add"), v.get("heal"), v.get("heal_add")
                               , v.get("dead"),v.get("dead_add")])
        conn.commit()
        print(f"{time.asctime()}插入歷史數據完畢")
    except:
        traceback.print_exc()
    finally:
        close_conn(conn, cursor)

用python連接MySql數據庫,實現數據的本地化儲存。

html部分

設置日期選擇框,可選最早日期為2020-01-25,最晚為2020-03-12

<input type="date" required min="2020-01-25" max="2020-03-12" id="date">
<input type="button" id="confirm" value="確認">

設置好需要改變數據的位置,便於之后編寫js文件的改變html內容

<!--ip_num:累計確診-->
<div class="num" id="ip_num"></div> 
<!--sp_num:現有疑似-->
<div class="num" id="sp_num"></div> 
<!--cure_num:累計治愈-->
<div class="num" id="cure_num"></div> 
<!--dead_num:累計死亡-->
<div class="num" id="dead_num"></div> 
<!--ip_incrs:(較昨日)新增確診-->
<div class="increase" id="ip_incrs"></div> 
<!--sp_incrs:(較昨日)新增疑似-->
<div class="increase" id="sp_incrs"></div> 
<!--cure_incrs:(較昨日)新增治愈-->
<div class="increase" id="cure_incrs"></div> 
<!--dead_incrs:(較昨日)新增死亡-->
<div class="increase" id="dead_incrs"></div> 

設置繪制圖表位置,引入相應的js文件

<!--趨勢圖-->
<div id="province"></div>
<script src="../js/province.js"></script>

javaScript部分

地圖渲染

function fuc() {
    var list
    $.ajax({
        url:"https://lab.isaaclin.cn/nCoV/api/area",
        async:false,
        type:"get",
        data:{
            "latest":"1"
        },
        dataType:"json",
        success:function (data) {
            list = data["results"];
        },
        error:function () {
            alert("讀取失敗")
        }
    })
    return list
}

利用ajax調用API獲取各地區的數據列表,返回一個json數據類型。

然后簡單地通過js函數實現數據返回

function getNum (province) {
    var l = fuc()
    for (var i in l) {
        if (l[i]["provinceName"] == province) {
            return l[i]["confirmedCount"]
        }
    }
}

數據獲取

1、根據點擊省份區塊傳入的參數,選擇json文件

2、使用javascript原生XMLHttpRequest的方法來讀取json

window.onload = function () { //加載頁面時
	var string = location.search; //獲取url中"?"符后的字串
    var province = decodeURI(string).replace("?","");
    var url;

    switch (province) { //根據得到的字符串,選擇對應的json文件
        case "安徽":
            url = "../json/areaAnHui.json";
            break;
        ...
    }
    var request = new XMLHttpRequest(); //發送http請求
    request.open("get", url);
    request.send(null);
    request.onload = function () {
        if (request.status == 200) { //如果成功
            var json = JSON.parse(request.responseText); //解析json字符串
       		...
            之后進行相應讀取和保存數據的操作
        }
    }
    繪制圖表
}

數據處理

1、時間格式處理(json文件中遇到時間格式為1545299299910,需要轉化為yyyy-mm-dd的格式)

var date = new Date(json.results[0].updateTime);
var month = date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1;
var currentDate = date.getDate() < 10 ? "0" + date.getDate() : date.getDate();
var string = date.getFullYear() + "-" + month + "-" + currentDate; //string就為所需格式

2、某天數據可能不止一條,所以某天時間可能重復出現,采用判斷,將已記錄的時間數據忽略(該方法限於時間按順序出現)

if(temp != dateList[j-1]){ //如果該時間已經記錄過
	dateList[j] = date.getFullYear() + "-" + month + "-" + currentDate;
	ip_num[j] = json.results[i].confirmedCount;
	sp_num[j] = json.results[i].suspectedCount;
	cure_num[j] = json.results[i].curedCount;
	dead_num[j] = json.results[i].deadCount;
	j++;
} else {
	ip_num[j-1] = json.results[i].confirmedCount;
	sp_num[j-1] = json.results[i].suspectedCount;
	cure_num[j-1] = json.results[i].curedCount;
	dead_num[j-1] = json.results[i].deadCount;
}

3、新增人數的獲取:由於爬取的數據並非包含所有的數據,例如各類型新增數據;使用當天該類型人數減前一天該類型人數得到新增數據。

var ip_incrs = new Array(); //(較昨日)新增確診
ip_incrs[0] = 0;
for(var i = 1; i < ip_num.length; i++){
	ip_incrs[i] = ip_num[i] - ip_num[i-1]; //今日-昨日
}

4、根據所選日期處理時間數組,再通過新的時間數組長度限制其他數組

var dateList1 = new Array();
for(i = 0; i < dateList.length; i++){
	if(date_limit < dateList[i]) //如果該日期超過選擇日期
		break;
	dateList1[i] = dateList[i];
}

var ip_incrs = new Array(); //(較昨日)新增確診
ip_incrs[0] = 0;
for(var i = 1; i < dateList1.length; i++){ //使用限制時間下的時間數組長度
	ip_incrs[i] = ip_num[i] - ip_num[i-1];
}

心路歷程、收獲和對隊友的評價

221701104 潘晨宇

本次的作業在一開始估計的時候以為應該會比較簡單,畢竟只是數據的爬取和處理渲染,應該不會太難。但是實際操作的時候還是問題多多。我自己負責數據的爬取和固定化,先要去摸索一個新的python語言的語法和方法,然后去尋找各個網頁找到自己需求的數據,最后固定化下來。這個過程其實並不像我想象的簡單,相反還花了很多的時間,后來在渲染全國地圖的時候調用爬蟲返回的數據也沒有很快,還需要讀取覺得水平有待提高。

對我的隊友221701116 陳炎:我覺得他是一個很棒的實干者,說做就做,效率也很高,當時處理數據的時候把json包傳過去后他很快就着手進行處理,在寫代碼上毫不含糊。他寫代碼也十分可靠,在寫代碼的時候,趨勢圖的數據處理完全由他自己進行函數處理,是個很可靠的隊友。

221701116 陳炎

在本次作業發布當天就去瀏覽了作業內容,大致瀏覽完,便發現了很多新知識、新技術,當時便覺得有些不知所措。在之后的實現中,先采取從最必要的開始,也就是GitHub的使用,建立結對倉庫,這樣才能保證代碼寫完后能夠commit,並與隊友共享使用。之后因為爬取數據需要python但並沒有接觸過,也就產生了焦慮心理。在隊友接下爬取數據的重任后,開始按部就班設計頁面樣式,學習讀取數據。在學習讀取數據過程中,也出現了許多問題。之后不斷查找資料,不斷嘗試,雖然每次失敗后會煩躁,但還是會再次搜索出現的問題,瀏覽一個個解決辦法。在本次作業的收獲里,最主要的並非是技術,而是那種學習完成項目中不斷嘗試所磨練的耐心。通過本次作業還發覺自己在新技術面前的學習力還不夠強大,不能夠以更好地心態去面對,這些還需要再做提升。

對我的隊友221701104 潘晨宇:他是一個學習力很強、思維靈活、體貼的隊友,能夠很好地學習新技術,並應用到項目中來;在方法選擇上,能采取更高效的方式;在分工上也很照顧隊友,主動挑起更重的擔子。他像是將管理和工作的結合體,不僅能更好地發揮團隊合作能力,也能夠將自己項目的部分完成得井井有條。

版本更新

1.0.1版本解決了之前的API失效的問題。但代碼尚有不完全的地方,請助教幫忙指正如下:

js代碼
function fuc() {
    var list
    $.ajax({
        url:"https://lab.ahusmart.com/nCoV/api/area",
        async:false,
        type:"get",
        data:{
            "latest":"1"
        },
        dataType:"json",
        success:function (data) {
            list = data["results"]
            console.log(list);
        },
        error:function () {
            alert("讀取失敗")
        }
    })
    return list
}

function f() {
    dataList = fuc().filter(r => {
        return r.country == "中國" && r.provinceName !="待明確地區"
    }).map(r => {
        return {
            name:r.provinceShortName,
            value:r.confirmedCount
        }
    })
}

以上代碼用以處理API返回的數據,但是每次讀取頁面都需要重復執行function f()導致頁面的渲染很慢。希望助教能提出建議改進。
現有想法兩點:1.將API的處理放到服務器上,直接返回處理好的數據。2.將處理好的數據放到本地localstorage或cookie中,這樣只需要第一次讀取,之后的讀取都不會很慢。
以上希望助教能予以思路上的幫助。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM