使用 ECharts GL 實現三維可視化 - 入門款

(題圖是使用 ECharts GL 渲染的紐約市建築群)

ECharts GL (後面統一簡稱 GL)為 ECharts 補充了豐富的三維可視化組件,這篇文章我們會簡單介紹如何基於 GL 實現一些常見的三維可視化作品。實際上如果你對 ECharts 有一定了解的話,也可以很快的上手 GL,GL 的配置項完全是按照 ECharts 的標準和上手難度來設計的。

看完文章有個大概的了解之後,你可以繼續前往 官方示例 和 Gallery 去了解更多使用 GL 製作的示例,對於文章中我們沒法解釋到的代碼,也可以前往 GL 配置項手冊查看具體的配置項使用方法。

如何下載和引入 ECharts GL

為了不再增加已經很大了的 ECharts 完整版的體積,我們將 GL 作為擴展包的形式提供,和諸如水球圖這樣的擴展類似,如果要使用 GL 里的各種組件,只需要在引入echarts.min.js的基礎上再引入一個echarts-gl.min.js。你可以從 官網 下載最新版的 GL,然後在頁面中通過標籤引入:

<script src="lib/echarts.min.js"></scrpt>n<script src="lib/echarts-gl.min.js"></script>n

如果你的項目使用 webpack 或者 rollup 來打包代碼的話,也可以通過 npm 安裝後引入

npm install echartsnnpm install echarts-gln

通過 ES6 的 import 語法引入 ECharts 和 ECharts GL

import echarts from echarts;nimport echarts-gl; n

聲明一個基礎的三維笛卡爾坐標系

引入 ECharts 和 ECharts GL 後,我們先來聲明一個基礎的三維笛卡爾坐標系用於繪製三維的散點圖,柱狀圖,曲面圖等常見的統計圖。

在 ECharts 中我們有 grid 組件用於提供一個矩形的區域放置一個二維的笛卡爾坐標系,以及笛卡爾坐標繫上上的 x 軸(xAxis)和 y 軸(yAxis)。對於三維的笛卡爾坐標系,我們在 GL 中提供了 grid3D 組件用於劃分一塊三維的笛卡爾空間,以及放置在這個 grid3D 上的 xAxis3D, yAxis3D, zAxis3D。

小提示:在 GL 中我們對除了 globe 之外所有的三維組件和系列都加了 3D 的後綴用以區分,例如三維的散點圖就是 scatter3D,三維的地圖就是 map3D 等等。

下面這段代碼就聲明了一個最簡單的三維笛卡爾坐標系

let option = {n // 需要注意的是我們不能跟 grid 一樣省略 grid3Dn grid3D: {},n // 默認情況下, x, y, z 分別是從 0 到 1 的數值軸n xAxis3D: {},n yAxis3D: {},n zAxis3D: {}n} n

效果如下:

跟二維的笛卡爾坐標系一樣,每個軸都會有多種類型,默認是數值軸,如果需要是類目軸的話,簡單的設置為 type: category就行了。

繪製三維的散點圖

聲明好笛卡爾坐標系後,我們先試試用一份程序生成的正態分布數據在這個三維的笛卡爾坐標系中畫散點圖。

下面這段是生成正態分布數據的代碼,你可以先不用關心這段代碼是怎麼工作的,只需要知道它生成了一份三維的正態分布數據放在data數組中。

function makeGaussian(amplitude, x0, y0, sigmaX, sigmaY) {n return function (amplitude, x0, y0, sigmaX, sigmaY, x, y) {n let exponent = -(n ( Math.pow(x - x0, 2) / (2 * Math.pow(sigmaX, 2)))n + ( Math.pow(y - y0, 2) / (2 * Math.pow(sigmaY, 2)))n )n return amplitude * Math.pow(Math.E, exponent);n }.bind(null, amplitude, x0, y0, sigmaX, sigmaY);n}n// 創建一個高斯分布函數nconst gaussian = makeGaussian(50, 0, 0, 20, 20);nnlet data = [];nfor (var i = 0; i < 1000; i++) {n // x, y 隨機分布n let x = Math.random() * 100 - 50;n let y = Math.random() * 100 - 50;n let z = gaussian(x, y);n data.push([x, y, z]);n}n

生成的正態分布的數據大概長這樣:

[n [46.74395071259907, -33.88391024738553, 0.7754030099768191],n [-18.45302873809771, 16.88114775416834, 22.87772504105404],n [2.9908128281121336, -0.027699444453467947, 49.44400635911886],n ...n

每一項都包含了x, y, z三個值,這三個值會分別被映射到笛卡爾坐標系的 x 軸,y 軸和 z 軸上。

然後我們可以使用 GL 提供的 scatter3D 系列類型把這些數據畫成三維空間中正態分布的點。

let option = {n grid3D: {},n xAxis3D: {},n yAxis3D: {},n zAxis3D: { max: 100 },n series: [{n type: scatter3D,n data: datan }]n}n

使用真實數據的三維散點圖

接下來我們來看一個使用真實多維數據的三維散點圖例子。

開始之前可以先從 echartsjs.com/examples/ 獲取這份數據。

編輯器里格式化一下可以看到這份數據是很傳統轉成 JSON 後的表格格式。第一行是每一列數據的屬性名,可以從這個屬性名看出來每一列數據的含義,分別是人均收入,人均壽命,人口數量,國家和年份。

[n["Income", "Life Expectancy", "Population", "Country", "Year"],n[815, 34.05, 351014, "Australia", 1800],n[1314, 39, 645526, "Canada", 1800],n[985, 32, 321675013, "China", 1800],n[864, 32.2, 345043, "Cuba", 1800],n[1244, 36.5731262, 977662, "Finland", 1800],n...n]n

在 ECharts 4 中我們可以使用 dataset 組件非常方便地引入這份數據。如果對 dataset 還不熟悉的話可以看 dataset使用教程

$.getJSON(data/asset/data/life-expectancy-table.json, function (data) {n myChart.setOption({n grid3D: {},n xAxis3D: {},n yAxis3D: {},n zAxis3D: {},n dataset: {n source: datan },n series: [n {n type: scatter3D,n symbolSize: 2.5n }n ]n })n});n

ECharts 默認會把前三列,也就是收入(Income),人均壽命(Life Expectancy),人口(Population)分別放到 x、 y、 z 軸上。

使用 encode 屬性我們還可以將指定列的數據映射到指定的坐標軸上,從而省去很多繁瑣的數據轉換代碼。例如我們將 x 軸換成是國家(Country),y 軸換成年份(Year),z 軸換成收入(Income),可以看到不同國家不同年份的人均收入分布。

myChart.setOption({n grid3D: {},n xAxis3D: {n // 因為 x 軸和 y 軸都是類目數據,所以需要設置 type: category 保證正確顯示數據。n type: categoryn },n yAxis3D: {n type: categoryn },n zAxis3D: {},n dataset: {n source: datan },n series: [n {n type: scatter3D,n symbolSize: 2.5,n encode: {n // 維度的名字默認就是表頭的屬性名n x: Country,n y: Year,n z: Income,n tooltip: [0, 1, 2, 3, 4]n }n }n ]n}); n

利用 visualMap 組件對三維散點圖進行視覺編碼

剛才多維數據的例子中,我們還有幾個維度(列)沒能表達出來,利用 ECharts 內置的 visualMap 組件我們可以繼續將第四個維度編碼成顏色。

myChart.setOption({n grid3D: {n viewControl: {n // 使用正交投影。n projection: orthographicn }n },n xAxis3D: {n // 因為 x 軸和 y 軸都是類目數據,所以需要設置 type: category 保證正確顯示數據。n type: categoryn },n yAxis3D: {n type: logn },n zAxis3D: {},n visualMap: {n calculable: true,n max: 100,n // 維度的名字默認就是表頭的屬性名n dimension: Life Expectancy,n inRange: {n color: [#313695, #4575b4, #74add1, #abd9e9, #e0f3f8, #ffffbf, #fee090, #fdae61, #f46d43, #d73027, #a50026]n }n },n dataset: {n source: datan },n series: [n {n type: scatter3D,n symbolSize: 5,n encode: {n // 維度的名字默認就是表頭的屬性名n x: Country,n y: Population,n z: Income,n tooltip: [0, 1, 2, 3, 4]n }n }n ]n}) n

這段代碼中我們又在剛才的例子基礎上加入了 visualMap 組件,將Life Expectancy這一列數據映射到了不同的顏色。

除此之外我們還把原來默認的透視投影改成了正交投影。正交投影在某些場景中可以避免因為近大遠小所造成的表達錯誤。

除了 visualMap 組件,你還可以利用其它的 ECharts 內置組件並且充分利用這些組件的交互效果,比如 legend。也可以像 三維散點圖和散點矩陣結合使用 這個例子一樣實現二維和三維的系列混搭。

在實現 GL 的時候我們儘可能地把 WebGL 和 Canvas 之間的差異屏蔽了到最小,從而讓 GL 的使用可以更加方便自然。

在笛卡爾坐標繫上顯示其它類型的三維圖表

除了散點圖,我們也可以通過 GL 在三維的笛卡爾坐標繫上繪製其它類型的三維圖表。比如剛才例子中將 scatter3D 類型改成 bar3D 就可以變成一個三維的柱狀圖。

還有機器學習中會用到的三維曲面圖 surface,三維曲面圖常用來表達平面上的數據走勢,剛才的正態分布數據我們也可以像下面這樣畫成曲面圖。

let data = [];n// 曲面圖要求給入的數據是網格形式按順序分布。nfor (let y = -50; y <= 50; y++) {n for (let x = -50; x <= 50; x++) {n let z = gaussian(x, y);n data.push([x, y, z]);n }n}noption = {n grid3D: {},n xAxis3D: {},n yAxis3D: {},n zAxis3D: { max: 60 },n series: [{n type: surface,n data: datan }]n}n

老闆想要立體的柱狀圖效果

最後,我們經常會被問到如何用 ECharts 畫只有二維數據的立體柱狀圖效果。一般來說我們是不推薦這麼做的,因為這種不必要的立體柱狀圖很容易造成錯誤的表達,具體可以見我們 柱狀圖使用指南 中的解釋。

但是如果有一些其他客觀因素導致必須得畫成立體的柱狀圖的話,用 GL 也可以實現。丶灬豆奶 和 阿洛兒啊 在 Gallery 已經寫了類似的例子,大家可以參考。

3D堆積柱狀圖gallery.echartsjs.com

3D柱狀圖gallery.echartsjs.com


推薦閱讀:

R語言數據可視化之——TreeMap
從數據可視化中看美國大選結果
Learn R | 交互可視化之rCharts包(二)
給你的圖表增值加分(1):簇狀柱形圖上顯示增幅百分比

TAG:前端开发 | 数据可视化 | WebGL |