Google Maps API學習筆記-6:畫新冠肺炎分佈圖

Google Maps API學習筆記-6:畫武漢肺炎分佈圖

2020.04.14更新:
昨天讀到了一篇文章:Why I’m not making COVID19 visualizations, and why you (probably) shouldn’t either。想了一下後覺得,確實,其實現有資料很難說是準確的,再加上不論確診人數增加或減少,我們一般人看到其實都是讓自己的心情七上八下而已。今天開始決定關閉Demo頁,這篇就當作是Google Maps API的筆記教學。

2020.03.30更新:
根據資料來源JHU CSSE公告,他們不再更新recovered的資料,因此Demo頁面中,Augustus在今天也刪掉了所有「康復」的部份。

2020.02.13更新:
新增段落「城市、國家名英翻中」。
新增段落「繪製圖表」。
新增段落「infowindow監聽按鈕click事件」。

2020.02.10更新:
因為資料源今天公告改更新在Github上,Google Sheet只會更新到今天以前,因此本篇針對取資料、整理資料的部份,分為上、下二大段。
上段是接Google Sheet的、下段是接Github上CSV格式的。
因為前陣子Sheet的部份常有變動,不是增加列數就是減個欄位,上段用Sheet的截圖會跟實際有所出入,在此告知。

有用到的筆記文列表

這一篇是整合了之前幾篇筆記文,最後會實作出在Google Map上丟標記,標記這次新冠肺炎目前的分佈圖。

整理一下有用到的技術,都是之前寫過的幾篇筆記文,條列如下:

Google Maps API部份

取得資料部份

繪製圖表部份


Google Sheet部份

取得、整理資料

本段的資料來源是Google Sheet,用Google Apps Script來取得資料。

Sheet表格是長這樣:

資料來源的表格
資料來源的表格

Google Maps API要丟上Marker,必須要有經緯度,我們要存下經緯度。

表共有三個sheet:Confirmed、Recovered、Death。

處理資料時就要三個表的資料都取得、整理後,再回傳給client端。

Augustus寫在Google Apps Script的程式碼是這樣子的,處理了要資料、整理資料、回傳資料這三個部份:

部署為網路應用程式後,用postman GET產出的網址,得到的結果如下:

取得整理過的資料
取得整理過的資料

確認有了經緯度跟三個數值,接下來就是把經緯度丟到Google Map上。


將資料寫進Google Maps API

這邊實作產出的Google Map,是一般地圖+標記+熱圖,有幾個考量:

  1. call API、畫出地圖要時間,在頁面加上一層loading,才不會一進來看到一片白。
  2. 這次最嚴重的地方在湖北,map的中心點就設為湖北。(2020.3月改成義大利)
  3. 視覺重心在分佈的城市,因此地圖樣式要客製,隱藏大部份的景點標示+介面按鈕。

loading效果

loading的效果做了一個呼吸燈的樣子,先畫出一個蓋版的漸層,animation的keyframe就是改變這個漸層的透明度。

css如下:

繪製地圖、客製樣式

首先,確認地圖中心點在湖北(2020.3月改成義大利):

let center = {
  lat: 30.97564,
  lng: 112.2707
 };

接著開始把資料寫給API:

把控制地圖的UI關掉,只留全螢幕的按鈕。

styles是要寫客製的樣式,因為很長,這邊不列出來,最後可以從原始碼裡看到。

styles的設定可以參考官方的說明文件:featureType

地圖上放置標記、info window、熱圖

這三件事寫在一起,因為都是在同一個迴圈內一起完成的。

由於資料的格式是object,先用了一行:

let keys = Object.keys(res);

把所有的key都先用成陣列,在用這個陣列跑forEach迴圈。

這邊是丟資料給API的程式碼:

一併在迴圈中處理要給heat map的資料,這邊是接heat map API的程式碼:

最後要記得把loading給拿掉,就完成了這次的實作。

看了圖後才發現,這次竟然連芬蘭都有1個確診,也太可怕。


原始碼

接Google Sheet當資料部份的原始碼放在Gist上了,記得替換掉token:

https://gist.github.com/letswritetw/f386028c675c43250722ed49d5d572b6


Github CSV部份

取得資料

對方更新在Github上的資料格式是CSV,進到Github的專案後會看到二個資料夾,都是這次肺炎的全球資料,只是整理的性質不同:

Github專案
Github專案

daily_case_updates 點進去,會是按日期來分檔案。

time_series 點進去,會像上段取Google Sheet一樣分為confirmed、recovered、death三個檔,這個是本篇實作會用的,所以選擇這個資料夾:

time_series的資料夾
time_series的資料夾

比方我們要取 time_series_2019-ncov-Confirmed.csv 這個的資料,點進去後,會看到Github把csv檔給顯示成完整的表格:

time_series_2019-ncov-Confirmed.csv
time_series_2019-ncov-Confirmed.csv

要怎麼取得這個csv的URL呢?點選上圖標紅框的「Row」就可以了,就會進到這個網址:

https://raw.githubusercontent.com/CSSEGISandData/COVID-19/master/time_series/time_series_2019-ncov-Confirmed.csv

原本Augustus也疑惑這個網址能不能取得資料,後來用postman先用個GET,竟然就真的取到了:

用postman取得Github上的資料
用postman取得Github上的資料

既然postman取得到,那用Google Apps Script也行,要煩惱的就是如何將CSV檔轉成JSON的格式。

轉換CSV成JSON

如果google一下,會看見很多搜尋結果都指向同一種寫法,如下:

接著就會看見地圖開始報錯,畫不出來,原因就出在這一行:

var headers = lines[0].split(',');

資料源裡面的城市名,有些本身就帶有 , ,像是:Seattle, WA、Chicago, IL。

一用 , 來切,就會一起切了出去。

由於Augustus目前對正則表達式還沒有很熟,所以就用了比較笨的方法,就是先把 , 給替換成 -- 後,再來 split(',')。修改過的並在GAS上執行的程式碼如下:

有了把CSV轉成JSON的function後,接下來在GAS上就是取得資料、整理並回傳。在GAS上寫的完整程式碼如下

一樣部署為網路應用程式後,用postman GET的結果如圖:

整理資料後取得的JSON
整理資料後取得的JSON(點擊看原圖)

可以看到跟在Google Sheet取到的資料排法不太一樣,每個城市/國家就是一個陣列。

將資料寫進Google Maps API

這一段大致上跟上段Google Sheet的部份相同,不同的點在於client取得GAS回傳的資料後,怎麼來整理?

以下是Augustus整理的方式,可以參考:

上段的程式碼處理了整理資料、丟資料到Google Maps API。

需要說明的是,這邊改用Vue.js來寫,才會看到 map 改成了 this.map,很多變數也都加了 this,因為都用成了 Vue.js 的 data

另外實作產出的頁面,這幾日也完成了右下方新增列表的卡片,點擊卡片上的城市/國家名時,會移到該城市/國家,並打開infowindow看數據的功能。才會多寫一個 responseData 來依照確診數排序。


城市、國家名英翻中

資料源的城市、國家名都是拼英的,不是中文,所以常常看到一些地名會沒概念是在哪裡,在地圖上看還好,因為還可以從地圖上標示的中文看到,但如果是看列表的話就不方便。

原本想直接找個套件來用,但由於套件得包含大部份的文字,因此往往很大一包,最小的一個在npm上有看到3點多MB的。

最後決定用手動整理對照表的方式來翻,笨了點,但檔案才不會過大拖垮讀取速度。

首先是列出一個陣列,裡面是一個個的物件,key是拼英,value是中文,列完後是這樣:

https://gist.github.com/letswritetw/3e9b4040e752bacacc57233f05cb4e70

接著,在取資料時,就寫一個翻譯的function:

這種自己手寫對照表的,好處是檔案小,讀取快,壞處就是如果資料源有新增城市/國家,就每次都要再補。

為了防止資料面有新增時,程式這邊沒有列進對照中而出現空值,因此最後也寫了對照不到就回傳原拼音,以免列表中看不見文字。

2020.03.12更新:
因為城市數愈來愈多,今天看破四百了,都把對照表寫進頁面裡會很長。
從今日開始,把對照表寫進Google Sheet裡,頁面實際是抓Sheet裡的資料來對照翻譯。
Augustus先用Sheet原有的翻譯功能來翻,翻起來很怪的再去Google查城市中文名。四百多筆有點多,如果有看到很怪的中文名,就代表還未更新到,請見諒。


繪製圖表

最後開發完成的,是點擊地圖上的標記後,加入一個「開啟圖表」按鈕,點下去會生成一個照日期來繪製的圖表,像這樣:

圖表的部份,這邊直接使用套件,推薦一套很好用又開源的Chart.js

它的參數好懂,又有許多的範例可以參考,繪製出來的圖表也漂亮。

圖表這邊比較麻煩的部份,就是要把資料的格式整理成圖表要的。以Chart.js來說,需要的格式是這樣:

data: {
  labels: ['January', 'February', 'March'],
  datasets: [{
    label: 'My First dataset',
    backgroundColor: 'rgb(255, 99, 132)',
    borderColor: 'rgb(255, 99, 132)',
    data: [0, 10, 5]
  }]
}

先建出一個 labels,是圖表下方的說明,接著在 datasets.data 寫出對應這個 labels 的值。像是Augustus的圖表預計放上確診、康復、死亡三個,那在 datasets 的陣列出就得寫三個物件進去。

整理資料成圖表要的格式就不列出了,用幾個迴圈整理就行。

這邊要特別寫的是,因為「開啟圖表」的按鈕是放在infowindow上,要怎麼讓infowindow中的按鈕可以監聽 click 事件?

infowindow監聽按鈕click事件

在跑迴圈時,infowindow的content就支援HTML,因此寫成以下:

button 的部份直接寫入 id="info-btn-${id}",讓每一個infowindow中的按鈕都可以有一個獨立的id。

接著,是要監聽infowindow本身的事件,infowindow有一個事件叫「domready」,就是這個infowindow在dom上就緒時,我們就寫一個當 domready 後,聽這個按鈕的 click 就行了,如下:

就這樣幾行就完成了監聽infowindow中的按鈕click事件。


Google Maps API學習筆記系列

  1. 地圖、標記、客製樣式
  2. 在地圖上畫個日本結界
  3. 用熱圖(Heat map)製作全台12小時雨量分佈圖
  4. place API自動完成地址、地點評論摘要
  5. 抓目前位置、計算到各點距離
  6. 畫新冠肺炎分佈圖

Summary
Google Maps API學習筆記-6:畫新冠肺炎分佈圖
Article Name
Google Maps API學習筆記-6:畫新冠肺炎分佈圖
Description
本篇大綱:有用到的筆記文列表。Google Maps API部份。取得資料部份。Google Sheet部份。取得、整理資料。將資料寫進Google Maps API。原始碼。Github CSV部份。取得資料。轉換CSV成JSON。將資料寫進Google Maps API。
Augustus
Let's Write
Let's Write
Publisher Logo
訂閱
通知
guest
0 Comments
Inline Feedbacks
看所有留言