透過 D3.js 調用外部資料集

資料的真實在於我們用真的資料

(KJH) Kuan-Jung, Huang
7 min readMay 5, 2019

前言

在前面的文章中,我們都是將資料寫死在程式裏面,但是實際上,我們通常的要視覺化的資料是來自不同的地方,所以,本篇文章要探討的是如何存取外部的檔案,並且將這些數據視覺化。

本篇不探討製圖方式(例如如何產生長條圖)、以及視覺化設計(例如 UI/UX、美感等)、Express 專案的使用方式等,主要探討的部分是透過 D3.js,以及透過讀檔、透過 API 呈現視覺化資料為主。

另外,若單純使用靜態網頁讀取檔案、讀 API 會有 CORS 問題,所以會利用到 Node.js 的 Express 架站,解決 CORS 問題。

最後,本文章所舉的範例資料集放在文章的附錄中,大家可以參閱。

External Data Sources

甚麼是外部資料源?在前面的範例中,我們將所有的資料都寫在 js 檔中,透過設定一個參數,然後讀取該參數,使他視覺化成為一張張圖,,但是實際上,我們通常的要視覺化的資料可能來自其他網站的 API,或者是某部門所製作的 Excel 檔,甚至是撈資料庫的資料。

那外部資料源有哪些呢?

我們所讀取的資料來源可能是檔案系統,也就是資料來源在於你自己的 Web Service 上,或者是透過動態撈取資料,例如透過呼叫 Ajax 來取得資料。

Express 專案結構

本次的練習內容,為了解決 CORS 問題,所以建立一個 Web Service ,我們將資料集放到 Express 專案的 /public 資料夾底下,所以檔案結構會如下圖:

這次探討的三個讀取資料方式會統一放在 index.ejs 底下。

你可以複製我的 Repo 並且透過 npm install 跟 npm start ,透過瀏覽器存取 localhost:3000,相關的前端修改可在 views/index.ejs 下製作圖表。

讀取 csv 檔

首先,我們透過調用 d3.csv 的函式,確認能夠讀取到我們放在 /public 資料夾底下的 MonthlySales.csv 檔,並透過 callback 函式先做 log。

執行結果如下,確認讀取的檔案路徑無誤,以及資料可被讀入。

接著,我們定義畫布的資訊,並且將畫圖的工作全部放入一個叫 buildLineChart 的函式內。

接著執行,會得到如下圖的樣式。

通常,我們會針對這種圖表製作文字說明,例如銷售總額,銷售平均等,所以,我們再製作一個 showDetails 函式,把銷售總額,銷售平均顯示在前端。

我們在畫布後面加入一張 table,並且在第 10 行宣告一個 metrics 的陣列,原因是我想把銷售總額,銷售平均等資料變成一個陣列,這樣我在把文字內容 append 進 table 中時,就能利用 tr 元素搭配 .data(metrics).enter() 來使文字訊息填滿。

執行結果如下

這段簡單介紹了讀取 csv 檔,如果這邊成功了,後面的文章作法大同小異,恭喜你可以利用 D3.js 開始處理外部資料集了!

讀取 Json 檔

這次,我們欲透過調用 d3.json 的函式,確認能夠讀取到我們放在 /public 資料夾底下的 MonthlySales.json 檔

做法其實大同小異,我們只要將原本的 d3.csv 改成 d3.json,並且把讀檔的內容改為讀取MonthlySales.json就完成了。

執行的結果會跟前面的一模一樣(MonthlySales.csv 跟 MonthlySales.json 資料內容一樣,可見附錄)。

讀取 API

這邊會主要討論的東西會有:如何調用 Web API,以及將資料做解碼。

我們練習利用中央氣象局的 api 讀取未來一周的氣溫,做成折線圖。

該網站有 swagger 文檔讓你試用其 api 如何呼叫

https://opendata.cwb.gov.tw/api/v1/rest/datastore/F-D0047-091?Authorization=CWB-3727EF81-9A3C-4D34-A0B7-3F7D54B3EDCD&format=JSON&locationName=%E8%87%BA%E5%8C%97%E5%B8%82&elementName=T

其中的

format=JSON&locationName=%E8%87%BA%E5%8C%97%E5%B8%82&elementName=RH

是我取用該資料集的篩選條件,我設定回傳格式為 json 檔,地址及條件分別為台北市跟指撈取濕度,這樣子我得到的回傳結果是如以下截圖:

當然這個資料集需要經過整理,因為只有下面的數字才是我要的資訊。

一樣我們將這個連結放到 d3.json 中先試著撈取資料。

透過 console.log 將取得的資料帶入,便可以發現該 json 格式如下,非常地複雜。

但是只要我們將這些資料做格式調整之後,我們便可以照本宣科地得到折線圖。

let recordset = data.records.locations[0].location[0].weatherElement[0].time;
console.log(recordset);

我們先利用這兩行先縮小資料顯示的範圍,注意到每個資料是一個區段的時間,所以我只取偶數的資料。

接著,我們用 foreach loop 的方式,將每個時間跟氣溫製作成一個獨立的 json 資料,時間戳記我只取當天日期,細節時間會刪掉,並且將日期格式 YYYY-MM-DD 改為 YYYYMMDD,這樣的好處在於我建立 x 軸的時候,可以用減法將第一筆資料變成 0 ,整理的資料如下:

程式碼如下:

最後,我們調整 buildLineChart 裡面的函式,就可以看到如下的成果了。

濕度折線圖

Same Origin Policy 問題

會特別提到這篇的原因是,有時候我們要撈取的 API 會因為同源政策(Same Origin Policy)導致無法存取,所以用一點篇幅解釋這個問題。

以下為一個存取範例,並整理成表格來比較資源是否同源:

在我們存取的「圖片」、「影片」、以及「程式碼」等等,都是該網站的資源,包含我們要撈取的資料集也是。

同源政策的機制是為了防範駭客的攻擊及惡意存取資源,也因為有了這個限制,在一般的情況下,駭客就不能透過一個惡意的網站,去呼叫另外一網路的服務。

假使少了這層機制,壞人就可以任意觸發一網路服務裡的某些功能,進行攻擊。

結論

在本篇,我們介紹到了甚麼是外部資料源,並且介紹了常見的讀檔,透過 D3.js 做好的 API 來使讀檔的工作變得很輕鬆。

最後介紹使用 Web API,並且利用中央氣象局開放資料平臺的資料集練習調用 Web API 的資料集。透過上述文章可以發現我們需要對資料做整理或解碼,還有我們可能遇到同源政策的問題,在調用 API 時,務必要注意到。

附錄

Json 資料集內容

csv 資料集內容

附錄

有很多公開的 API 資料集,這邊貼一些目前找到的,後續會更新

中央氣象局開放資料平臺

Sign up to discover human stories that deepen your understanding of the world.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

(KJH) Kuan-Jung, Huang
(KJH) Kuan-Jung, Huang

Written by (KJH) Kuan-Jung, Huang

CTO at Metablox.co, Founder of AI Users Community in Taiwan

No responses yet

Write a response