ECharts 4 開始有了 `資料集`(`dataset`)元件來單獨宣告資料,大概長這個樣子:
option = {
dataset: {
// 提供一份資料。
source: [
['product', '2015', '2016', '2017'],
['Matcha Latte', 43.3, 85.8, 93.7],
['Milk Tea', 83.1, 73.4, 55.1],
['Cheese Cocoa', 86.4, 65.2, 82.5],
['Walnut Brownie', 72.4, 53.9, 39.1]
]
},
legend: {},
tooltip: {},
// 宣告一個 X 軸,類目軸(category)。預設情況下,類目軸對應到 dataset 第一列。
xAxis: {type: 'category'},
// 宣告一個 Y 軸,數值軸。
yAxis: {},
// 宣告多個 bar 系列,預設情況下,每個系列會自動對應到 dataset 的每一列。
series: [
{type: 'bar'},
{type: 'bar'},
{type: 'bar'}
]
}
複製程式碼
這個最簡單的例子,得到的效果是這樣的:
資料集帶來的好處是:
- 有了 `dataset` 後,能夠貼近這樣的資料視覺化常見思維方式:基於資料(`dataset` 元件來提供資料),指定資料到視覺的對映(由 `encode` 屬性來指定對映),形成圖表。
- 資料和其他配置可以被分離開來,使用者相對便於進行單獨管理,也省去了一些資料處理的步驟。
- 資料可以被多個系列或者元件複用,對於大資料,不必為每個系列建立一份。
- 支援更多的資料的常用格式,例如二維陣列、物件陣列等,一定程度上避免使用者為了資料格式而進行轉換。
資料到圖形的對映
本篇裡,我們製作資料視覺化圖表的邏輯是這樣的:基於資料,在配置項中指定如何對映到圖形。
概略而言,可以進行這些對映:
- 指定 dataset 的列(column)還是行(row)對映為圖形系列(series)。這件事可以使用 `series.seriesLayoutBy` 屬性來配置。
- 指定 dataset 的哪些列(column)或行(row)對應到座標軸(如 X、Y 軸)、提示框(tooltip)、標籤(label)、圖形元素大小顏色等(visualMap)。這件事可以使用 `series.encode` 屬性來配置。如果有需要對映顏色大小等視覺維度,可以使用 visualMap 元件。
按行還是按列做對映
有了資料表之後,使用者可以靈活得配置:資料如何對應到軸和圖形系列。上面的例子中,沒有給出這種對映配置,那麼ECharts 就按最常見的理解進行預設對映:
- X 座標軸宣告為類目軸,預設情況下會自動對應到 dataset.source 中的第一列;
- 三個柱圖系列,一一對應到 dataset.source 中後面每一列。
使用者可以使用 `seriesLayoutBy` 配置項,改變圖表對於行列的理解。`seriesLayoutBy` 可取值:
- 'column': 預設值。系列被安放到 `dataset` 的列上面。
- 'row': 系列被安放到 `dataset` 的行上面。
option = {
legend: {},
tooltip: {},
dataset: {
source: [
['product', '2012', '2013', '2014', '2015'],
['Matcha Latte', 41.1, 30.4, 65.1, 53.3],
['Milk Tea', 86.5, 92.1, 85.7, 83.1],
['Cheese Cocoa', 24.1, 67.2, 79.5, 86.4]
]
},
xAxis: [
{type: 'category', gridIndex: 0},
{type: 'category', gridIndex: 1}
],
yAxis: [
{gridIndex: 0},
{gridIndex: 1}
],
grid: [
{bottom: '55%'},
{top: '55%'}
],
series: [
// 這幾個系列會在第一個直角座標系中,每個系列對應到 dataset 的每一行。
{type: 'bar', seriesLayoutBy: 'row'},
{type: 'bar', seriesLayoutBy: 'row'},
{type: 'bar', seriesLayoutBy: 'row'},
// 這幾個系列會在第二個直角座標系中,每個系列對應到 dataset 的每一列。
{type: 'bar', xAxisIndex: 1, yAxisIndex: 1},
{type: 'bar', xAxisIndex: 1, yAxisIndex: 1},
{type: 'bar', xAxisIndex: 1, yAxisIndex: 1},
{type: 'bar', xAxisIndex: 1, yAxisIndex: 1}
]
}
複製程式碼
效果是這樣的:
更重要的是,我們可以使用 `encode` 配置項來更細節得指定資料如何對映到圖形。總體是這樣的感覺:
維度(dimension)
介紹 `encode` 之前,首先要介紹“維度(dimension)”的概念。
常用圖表所描述的資料大部分是“二維表”結構,上述的例子中,我們都使用二維陣列來容納二維表。現在,當我們把系列(series)對應到“列”的時候,那麼每一列就稱為一個“維度(dimension)”,而每一行稱為資料項(item)。反之,如果我們把系列(series)對應到錶行,那麼每一行就是“維度(dimension)”,每一列就是資料項(item)。
維度可以有單獨的名字,便於在圖表中顯示。維度名(dimension name)可以在定義在 dataset 的第一行(或者第一列)。例如上面的例子中,'score'、'amount'、'product' 就是維度名。從第二行開始,才是正式的資料。`dataset.source` 中第一行(列)到底包含不包含維度名,ECharts 預設會自動探測。當然也可以設定 `dataset.sourceHeader: true` 顯示宣告第一行(列)就是維度,或者 `dataset.sourceHeader: false` 表明第一行(列)開始就直接是資料。
維度的定義,也可以使用單獨的 `dataset.dimensions` 或者 `series.dimensions` 來定義,這樣可以同時指定維度名,和維度的型別(dimension type):
var option1 = {
dataset: {
dimensions: [
{name: 'score'},
// 可以簡寫為 string,表示維度名。
'amount',
// 可以在 type 中指定維度型別。
{name: 'product', type: 'ordinal'}
],
source: [...]
},
...
};
var option2 = {
dataset: {
source: [...]
},
series: {
type: 'line',
// 在系列中設定的 dimensions 會更優先採納。
dimensions: [
null, // 可以設定為 null 表示不想設定維度名
'amount',
{name: 'product', type: 'ordinal'}
]
},
...
};
複製程式碼
大多數情況下,我們並不需要去設定維度型別,因為會自動判斷。但是如果因為資料為空之類原因導致判斷不足夠準確時,可以手動設定維度型別。
維度型別(dimension type)可以取這些值:
- 'number': 預設,表示普通資料。
- 'ordinal': 對於類目、文字這些 string 型別的資料,如果需要能在數軸上使用,須是 'ordinal' 型別。ECharts 預設會自動判斷這個型別。但是自動判斷也是不可能很完備的,所以使用者也可以手動強制指定。
- 'time': 表示時間資料。設定成 'time' 則能支援自動解析資料成時間戳(timestamp),比如該維度的資料是 '2017-05-10',會自動被解析。時間型別的支援參見 [data](option.html#series.data)。
- 'float': 如果設定成 `float`,在儲存時候會使用 `TypedArray`,對效能優化有好處。
- 'int': 如果設定成 `float`,在儲存時候會使用 `TypedArray`,對效能優化有好處。
資料到圖形的對映(encode)
瞭解了維度的概念後,我們就可以使用 `encode` 來做對映。`encode` 宣告的基本結構如下,其中冒號左邊是座標系、標籤等特定名稱,如 `'x'`, `'y'`, `'tooltip'` 等,冒號右邊是資料中的維度名(string 格式)或者維度的序號(number 格式,從 0 開始計數),可以指定一個或多個維度(使用陣列)。通常情況下,下面各種資訊不需要所有的都寫,按需寫即可。
var option = {
dataset: {
source: [
['score', 'amount', 'product'],
[89.3, 58212, 'Matcha Latte'],
[57.1, 78254, 'Milk Tea'],
[74.4, 41032, 'Cheese Cocoa'],
[50.1, 12755, 'Cheese Brownie'],
[89.7, 20145, 'Matcha Cocoa'],
[68.1, 79146, 'Tea'],
[19.6, 91852, 'Orange Juice'],
[10.6, 101852, 'Lemon Juice'],
[32.7, 20112, 'Walnut Brownie']
]
},
xAxis: {},
yAxis: {type: 'category'},
series: [
{
type: 'bar',
encode: {
// 將 "amount" 列對映到 X 軸。
x: 'amount',
// 將 "product" 列對映到 Y 軸。
y: 'product'
}
}
]
};
複製程式碼
效果如下:
下面給出個更豐富的 `encode` 的 示例。
視覺通道(顏色、尺寸等)的對映
我們可以使用 `visualMap` 元件進行視覺通道的對映。這是一個示例:
var option = {
dataset: {
source: [
['score', 'amount', 'product'],
[89.3, 58212, 'Matcha Latte'],
[57.1, 78254, 'Milk Tea'],
[74.4, 41032, 'Cheese Cocoa'],
[50.1, 12755, 'Cheese Brownie'],
[89.7, 20145, 'Matcha Cocoa'],
[68.1, 79146, 'Tea'],
[19.6, 91852, 'Orange Juice'],
[10.6, 101852, 'Lemon Juice'],
[32.7, 20112, 'Walnut Brownie']
]
},
grid: {containLabel: true},
xAxis: {name: 'amount'},
yAxis: {type: 'category'},
visualMap: {
orient: 'horizontal',
left: 'center',
min: 10,
max: 100,
text: ['High Score', 'Low Score'],
// Map the score column to color
dimension: 0,
inRange: {
color: ['#D7DA8B', '#E15457']
}
},
series: [
{
type: 'bar',
encode: {
// Map the "amount" column to X axis.
x: 'amount',
// Map the "product" column to Y axis
y: 'product'
}
}
]
};
複製程式碼
幾個常見的對映設定方式
問:如何把第三列設定為 X 軸,第五列設定為 Y 軸?
答:
series: {
encode: {x: 3, y: 5},
...
}
複製程式碼
問:如何把第三行設定為 X 軸,第五行設定為 Y 軸?
答:
series: {
encode: {x: 3, y: 5},
seriesLayoutBy: 'row',
...
}
複製程式碼
問:如何把第二列設定為標籤?
答:
關於標籤的顯示(`label.formatter`),現在支援使用這樣的語法:
'aaa{@product}bbb{@score}ccc{@[4]}ddd' 來引用某個具體的維度值。其中 '{@score}' 表示因為 “名為 score” 的維度裡的值,'{@[4]}' 表示引用序號為 4 的維度裡的值。
series: [{
label: {
show: true,
// 標籤中引用第二列。
formatter: 'The value at column 2 is: {@[2]}.'
},
...
}, {
label: {
show: true,
// 標籤中引用維度名為 product 的列。
formatter: 'The product name is: {@product}.'
},
...
}]
複製程式碼
問:如何讓第 2 列和第 3 列顯示在提示框(tooltip)中?
答:
series: {
encode: {
tooltip: [2, 3]
...
},
...
}
複製程式碼
問:資料裡沒有維度名,那麼怎麼給出維度名?
答:
dataset: {
dimensions: ['score', 'amount'],
source: [
[89.3, 3371],
[92.1, 8123],
[94.4, 1954],
[85.4, 829]
]
}
複製程式碼
問:如何把第四列對映為氣泡圖的點的大小?
答:
var option = {
dataset: {
source: [
[12, 323, 11.2],
[23, 167, 8.3],
[81, 284, 12],
[91, 413, 4.1],
[13, 287, 13.5]
]
},
visualMap: {
show: false,
dimension: 2, // 指向第三列(列序號從 0 開始記,所以設定為 2)。
min: 2, // 需要給出數值範圍,最小數值。
max: 15, // 需要給出數值範圍,最大數值。
inRange: {
// 氣泡尺寸:5 畫素到 60 畫素。
symbolSize: [5, 60]
}
},
xAxis: {},
yAxis: {},
series: {
type: 'scatter'
}
};
複製程式碼
問:encode 裡指定了對映,但是不管用?
答:可以查查有沒有拼錯,比如,維度名是:'Life Expectancy',encode 中拼成了 'Life Expectency'。
資料的各種格式
多數常見圖表中,資料適於用二維表的形式描述。廣為使用的資料表格軟體(如 MS Excel、Numbers)或者關係資料資料庫都是二維表。他們的資料可以匯出成 JSON 格式,輸入到 `dataset.source` 中,在不少情況下可以免去一些資料處理的步驟。
假如資料匯出成 csv 檔案,那麼可以使用一些 csv 工具如 [dsv](github.com/d3/d3-dsv) 或者 [PapaParse](github.com/mholt/PapaP…) 將 csv 轉成 JSON。
在 JavaScript 常用的資料傳輸格式中,二維陣列可以比較直觀的儲存二維表。前面的示例都是使用二維陣列表示。
除了二維陣列以外,dataset 也支援例如下面 key-value 方式的資料格式,這類格式也非常常見。但是這類格式中,目前並不支援 `seriesLayoutBy` 引數。
dataset: [{
// 按行的 key-value 形式,這是個比較常見的格式。
source: [
{product: 'Matcha Latte', count: 823, score: 95.8},
{product: 'Milk Tea', count: 235, score: 81.4},
{product: 'Cheese Cocoa', count: 1042, score: 91.2},
{product: 'Walnut Brownie', count: 988, score: 76.9}
]
}, {
// 按列的 key-value 形式。
source: {
'product': ['Matcha Latte', 'Milk Tea', 'Cheese Cocoa', 'Walnut Brownie'],
'count': [823, 235, 1042, 988],
'score': [95.8, 81.4, 91.2, 76.9]
}
}]
複製程式碼
此外,ECharts 4 之前一直以來的資料宣告方式仍然被正常支援,如果系列已經宣告瞭 `series.data`, 那麼就會使用 `series.data` 而非 `dataset`。
最後,給出一個 示例,多個圖表共享一個 `dataset`,並帶有聯動互動。
更詳細的資訊,可以參見這個 教程。