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

ECharts發表於2018-01-26

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>
<script src="lib/echarts-gl.min.js"></script>
複製程式碼

如果你的專案使用 webpack 或者 rollup 來打包程式碼的話,也可以通過 npm 安裝後引入

npm install echarts
npm install echarts-gl
複製程式碼

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

import echarts from 'echarts';
import 'echarts-gl'; 
複製程式碼

宣告一個基礎的三維笛卡爾座標系

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

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

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

下面這段程式碼就宣告瞭一個最簡單的三維笛卡爾座標系

let option = {
    // 需要注意的是我們不能跟 grid 一樣省略 grid3D
    grid3D: {},
    // 預設情況下, x, y, z 分別是從 0 到 1 的數值軸
    xAxis3D: {},
    yAxis3D: {},
    zAxis3D: {}
} 
複製程式碼

效果如下:

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


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

繪製三維的散點圖

宣告好笛卡爾座標系後,我們先試試用一份程式生成的正態分佈資料在這個三維的笛卡爾座標系中畫散點圖。

下面這段是生成正態分佈資料的程式碼,你可以先不用關心這段程式碼是怎麼工作的,只需要知道它生成了一份三維的正態分佈資料放在data陣列中。

function makeGaussian(amplitude, x0, y0, sigmaX, sigmaY) {
    return function (amplitude, x0, y0, sigmaX, sigmaY, x, y) {
        let exponent = -(
                ( Math.pow(x - x0, 2) / (2 * Math.pow(sigmaX, 2)))
                + ( Math.pow(y - y0, 2) / (2 * Math.pow(sigmaY, 2)))
            )
        return amplitude * Math.pow(Math.E, exponent);
    }.bind(null, amplitude, x0, y0, sigmaX, sigmaY);
}
// 建立一個高斯分佈函式
const gaussian = makeGaussian(50, 0, 0, 20, 20);

let data = [];
for (var i = 0; i < 1000; i++) {
    // x, y 隨機分佈
    let x = Math.random() * 100 - 50;
    let y = Math.random() * 100 - 50;
    let z = gaussian(x, y);
    data.push([x, y, z]);
}
複製程式碼

生成的正態分佈的資料大概長這樣:

[
  [46.74395071259907, -33.88391024738553, 0.7754030099768191],
  [-18.45302873809771, 16.88114775416834, 22.87772504105404],
  [2.9908128281121336, -0.027699444453467947, 49.44400635911886],
  ...
]複製程式碼

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

然後我們可以使用 GL 提供的 scatter3D 系列型別把這些資料畫成三維空間中正態分佈的點。

let option = {
    grid3D: {},
    xAxis3D: {},
    yAxis3D: {},
    zAxis3D: { max: 100 },
    series: [{
        type: 'scatter3D',
        data: data
    }]
}
複製程式碼


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


使用真實資料的三維散點圖

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

開始之前可以先從 www.echartsjs.com/examples/da… 獲取這份資料。 

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

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

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

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


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


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

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

myChart.setOption({
    grid3D: {},
    xAxis3D: {
        // 因為 x 軸和 y 軸都是類目資料,所以需要設定 type: 'category' 保證正確顯示資料。
        type: 'category'
    },
    yAxis3D: {
        type: 'category'
    },
    zAxis3D: {},
    dataset: {
        source: data
    },
    series: [
        {
            type: 'scatter3D',
            symbolSize: 2.5,
            encode: {
                // 維度的名字預設就是表頭的屬性名
                x: 'Country',
                y: 'Year',
                z: 'Income',
                tooltip: [0, 1, 2, 3, 4]
            }
        }
    ]
}); 
複製程式碼

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

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

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

這段程式碼中我們又在剛才的例子基礎上加入了 visualMap 元件,將Life Expectancy這一列資料對映到了不同的顏色。

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

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


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

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

在笛卡爾座標系上顯示其它型別的三維圖表

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

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


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

let data = [];
// 曲面圖要求給入的資料是網格形式按順序分佈。
for (let y = -50; y <= 50; y++) {
    for (let x = -50; x <= 50; x++) {
        let z = gaussian(x, y);
        data.push([x, y, z]);
    }
}
option = {
    grid3D: {},
    xAxis3D: {},
    yAxis3D: {},
    zAxis3D: { max: 60 },
    series: [{
        type: 'surface',
        data: data
    }]
}
複製程式碼


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


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

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

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

3D堆積柱狀圖

3D柱狀圖


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


相關文章