データ変換
Apache EChartsTM 5 以降、データ変換
がサポートされています。EChartsでは、データ変換
とは、ユーザーが提供したソースデータと変換関数から新しいデータを作成することを意味します。この機能により、ユーザーは宣言的な方法でデータを処理し、そのようなタスクをすぐに実行できる一般的な「変換関数」を提供します。(文脈の一貫性を保つために、名詞形として「変換」を使い続けます)。
データ変換の抽象的な式は次のとおりです。outData = f(inputData)
。ここで、変換関数f
は、filter
、sort
、regression
、boxplot
、cluster
、aggregate
(準備中)などです。これらの変換メソッドを使用すると、ユーザーは次の機能を実装できます。
- データを複数のシリーズに分割する。
- 統計を行い、結果を視覚化する。
- データに視覚化アルゴリズムを適用し、結果を表示する。
- データをソートする。
- 空のデータや特殊なデータを除去または選択する。
- ...
データ変換の開始
EChartsでは、データ変換はデータセットの概念に基づいて実装されています。dataset.transformは、データセットインスタンスで設定でき、このデータセットがこのtransform
から生成されることを示します。例:
var option = { dataset: [ { // This dataset is on `datasetIndex: 0`. source: [ ['Product', 'Sales', 'Price', 'Year'], ['Cake', 123, 32, 2011], ['Cereal', 231, 14, 2011], ['Tofu', 235, 5, 2011], ['Dumpling', 341, 25, 2011], ['Biscuit', 122, 29, 2011], ['Cake', 143, 30, 2012], ['Cereal', 201, 19, 2012], ['Tofu', 255, 7, 2012], ['Dumpling', 241, 27, 2012], ['Biscuit', 102, 34, 2012], ['Cake', 153, 28, 2013], ['Cereal', 181, 21, 2013], ['Tofu', 395, 4, 2013], ['Dumpling', 281, 31, 2013], ['Biscuit', 92, 39, 2013], ['Cake', 223, 29, 2014], ['Cereal', 211, 17, 2014], ['Tofu', 345, 3, 2014], ['Dumpling', 211, 35, 2014], ['Biscuit', 72, 24, 2014] ] // id: 'a' }, { // This dataset is on `datasetIndex: 1`. // A `transform` is configured to indicate that the // final data of this dataset is transformed via this // transform function. transform: { type: 'filter', config: { dimension: 'Year', value: 2011 } } // There can be optional properties `fromDatasetIndex` or `fromDatasetId` // to indicate that where is the input data of the transform from. // For example, `fromDatasetIndex: 0` specify the input data is from // the dataset on `datasetIndex: 0`, or `fromDatasetId: 'a'` specify the // input data is from the dataset having `id: 'a'`. // [DEFAULT_RULE] // If both `fromDatasetIndex` and `fromDatasetId` are omitted, // `fromDatasetIndex: 0` are used by default. }, { // This dataset is on `datasetIndex: 2`. // Similarly, if neither `fromDatasetIndex` nor `fromDatasetId` is // specified, `fromDatasetIndex: 0` is used by default transform: { // The "filter" transform filters and gets data items only match // the given condition in property `config`. type: 'filter', // Transforms has a property `config`. In this "filter" transform, // the `config` specify the condition that each result data item // should be satisfied. In this case, this transform get all of // the data items that the value on dimension "Year" equals to 2012. config: { dimension: 'Year', value: 2012 } } }, { // This dataset is on `datasetIndex: 3` transform: { type: 'filter', config: { dimension: 'Year', value: 2013 } } } ], series: [ { type: 'pie', radius: 50, center: ['25%', '50%'], // In this case, each "pie" series reference to a dataset that has // the result of its "filter" transform. datasetIndex: 1 }, { type: 'pie', radius: 50, center: ['50%', '50%'], datasetIndex: 2 }, { type: 'pie', radius: 50, center: ['75%', '50%'], datasetIndex: 3 } ] };
データ変換の使用における重要な点をまとめましょう。
- 空のデータセット内の
transform
、fromDatasetIndex
/fromDatasetId
の宣言を介して、宣言済みの既存データから新しいデータを作成する。 - シリーズはこれらのデータセットを参照して結果を表示する。
高度な使用方法
パイプライン変換
パイプライン変換のような構文糖があります。
option = {
dataset: [
{
source: [] // The original data
},
{
// Declare transforms in an array to pipe multiple transforms,
// which makes them execute one by one and take the output of
// the previous transform as the input of the next transform.
transform: [
{
type: 'filter',
config: { dimension: 'Product', value: 'Tofu' }
},
{
type: 'sort',
config: { dimension: 'Year', order: 'desc' }
}
]
}
],
series: {
type: 'pie',
// Display the result of the piped transform.
datasetIndex: 1
}
};
注:理論的には、あらゆる種類の変換は複数の入力データと複数の出力データを持つことができます。しかし、変換がパイプライン化されると、(パイプの最初の変換でない限り)1つの入力しか取ることができず、(パイプの最後の変換でない限り)1つの出力しか生成できません。
複数のデータを出力する
ほとんどの場合、変換関数は1つのデータだけを生成する必要があります。しかし、変換関数が複数のデータ(それぞれが異なるシリーズで使用される可能性がある)を生成する必要があるシナリオもあります。
たとえば、組み込みのboxplot変換では、生成されたboxplotデータに加えて、外れ値データも生成され、散布図シリーズで使用できます。例を参照してください。
この要件を満たすために、プロパティdataset.fromTransformResultを使用します。例:
option = {
dataset: [
{
// Original source data.
source: []
},
{
transform: {
type: 'boxplot'
}
// After this "boxplot transform" two result data generated:
// result[0]: The boxplot data
// result[1]: The outlier data
// By default, when series or other dataset reference this dataset,
// only result[0] can be visited.
// If we need to visit result[1], we have to use another dataset
// as follows:
},
{
// This extra dataset references the dataset above, and retrieves
// the result[1] as its own data. Thus series or other dataset can
// reference this dataset to get the data from result[1].
fromDatasetIndex: 1,
fromTransformResult: 1
}
],
xAxis: {
type: 'category'
},
yAxis: {},
series: [
{
name: 'boxplot',
type: 'boxplot',
// Reference the data from result[0].
datasetIndex: 1
},
{
name: 'outlier',
type: 'scatter',
// Reference the data from result[1].
datasetIndex: 2
}
]
};
さらに、dataset.fromTransformResultとdataset.transformは、どちらも1つのデータセットに表示できます。つまり、変換の入力は、fromTransformResult
で指定された上流の結果から取得されます。例:
{
fromDatasetIndex: 1,
fromTransformResult: 1,
transform: {
type: 'sort',
config: { dimension: 2, order: 'desc' }
}
}
開発環境でのデバッグ
データ変換を使用すると、最終的なチャートが正しく表示されない場合がありますが、設定が間違っている場所がわかりません。そのような場合、プロパティtransform.print
が役立つ場合があります。(transform.print
は開発環境でのみ使用できます)。
option = {
dataset: [
{
source: []
},
{
transform: {
type: 'filter',
config: {},
// The result of this transform will be printed
// in dev tool via `console.log`.
print: true
}
}
]
};
フィルター変換
変換タイプ「filter」は、指定された条件に従ってデータフィルターを提供する組み込み変換です。基本的なオプションは次のとおりです。
option = { dataset: [ { source: [ ['Product', 'Sales', 'Price', 'Year'], ['Cake', 123, 32, 2011], ['Latte', 231, 14, 2011], ['Tofu', 235, 5, 2011], ['Milk Tee', 341, 25, 2011], ['Porridge', 122, 29, 2011], ['Cake', 143, 30, 2012], ['Latte', 201, 19, 2012], ['Tofu', 255, 7, 2012], ['Milk Tee', 241, 27, 2012], ['Porridge', 102, 34, 2012], ['Cake', 153, 28, 2013], ['Latte', 181, 21, 2013], ['Tofu', 395, 4, 2013], ['Milk Tee', 281, 31, 2013], ['Porridge', 92, 39, 2013], ['Cake', 223, 29, 2014], ['Latte', 211, 17, 2014], ['Tofu', 345, 3, 2014], ['Milk Tee', 211, 35, 2014], ['Porridge', 72, 24, 2014] ] }, { transform: { type: 'filter', config: { dimension: 'Year', '=': 2011 } // The config is the "condition" of this filter. // This transform traverse the source data and // and retrieve all the items that the "Year" // is `2011`. } } ], series: { type: 'pie', datasetIndex: 1 } };
これはフィルター変換の別の例です。
次元について
config.dimension
は次のとおりです。
- データセットで宣言された次元名、例:
config: { dimension: 'Year', '=': 2011 }
。次元名の宣言は必須ではありません。 - 次元インデックス(0から始まる)、例:
config: { dimension: 3, '=': 2011 }
。
関係演算子について
関係演算子は次のとおりです。>
(gt
)、>=
(gte
)、<
(lt
)、<=
(lte
)、=
(eq
)、!=
(ne
、<>
)、reg
。(括弧内の名前はエイリアスです)。これらは一般的な意味に従います。一般的な数値比較に加えて、いくつかの追加機能があります。
- 複数の演算子を1つの{}項目に含めることができます。例:
{ dimension: 'Price', '>=': 20, '<': 30 }
は論理「and」(Price >= 20 and Price < 30)を意味します。 - データ値は「数値文字列」にすることができます。数値文字列は、数値に変換できる文字列です。例:' 123 '。空白と改行は変換時に自動的にトリミングされます。
- 「JS
Date
インスタンス」または日付文字列(例:'2012-05-12')を比較する必要がある場合は、parser: 'time'
を手動で指定する必要があります。例:config: { dimension: 3, lt: '2012-05-12', parser: 'time' }
。 - 純粋な文字列比較はサポートされていますが、
=
、!=
でのみ使用できます。>
、>=
、<
、<=
は純粋な文字列比較をサポートしていません(4つの演算子の「右辺の値」は「文字列」にすることはできません)。 - 演算子
reg
を使用して正規表現テストを行うことができます。例:{ dimension: 'Name', reg: /\s+Müller\s*$/ }
を使用して、"Name"次元がMüllerという名字を含むすべてのデータ項目を選択します。
論理関係について
論理関係(and
/or
/not
)を表現する必要がある場合もあります。
option = {
dataset: [
{
source: [
// ...
]
},
{
transform: {
type: 'filter',
config: {
// Use operator "and".
// Similarly, we can also use "or", "not" in the same place.
// But "not" should be followed with a {...} rather than `[...]`.
and: [
{ dimension: 'Year', '=': 2011 },
{ dimension: 'Price', '>=': 20, '<': 30 }
]
}
// The condition is "Year" is 2011 and "Price" is greater
// or equal to 20 but less than 30.
}
}
],
series: {
type: 'pie',
datasetIndex: 1
}
};
and
/or
/not
は次のようにネストできます。
transform: {
type: 'filter',
config: {
or: [{
and: [{
dimension: 'Price', '>=': 10, '<': 20
}, {
dimension: 'Sales', '<': 100
}, {
not: { dimension: 'Product', '=': 'Tofu' }
}]
}, {
and: [{
dimension: 'Price', '>=': 10, '<': 20
}, {
dimension: 'Sales', '<': 100
}, {
not: { dimension: 'Product', '=': 'Cake' }
}]
}]
}
}
パーサーについて
値比較を行う際に、いくつかの「パーサー」を指定できます。現在サポートされているのは、
parser: 'time'
:比較する前に値を日時として解析します。パーサーのルールはecharts.time.parse
と同じで、JSDate
インスタンス、タイムスタンプ数値(ミリ秒単位)、時間文字列(例:'2012-05-12 03:11:22'
)はタイムスタンプ数値に解析されますが、その他の値はNaN
に解析されます。parser: 'trim'
:比較する前に文字列をトリムします。文字列以外の場合、元の値を返します。parser: 'number'
:比較する前に値を数値に変換します。意味のある数値に変換できない場合は、NaN
に変換されます。ほとんどの場合、デフォルトでは可能な限り数値に変換されるため、これは必要ありません。ただし、デフォルトの変換は厳密であるのに対し、このパーサーは緩やかな戦略を提供します。単位サフィックス付きの数値文字列(例:'33%'
、12px
)の場合、比較する前に数値に変換するにはparser: 'number'
を使用する必要があります。
これはparser: 'time'
を示す例です。
option = {
dataset: [
{
source: [
['Product', 'Sales', 'Price', 'Date'],
['Milk Tee', 311, 21, '2012-05-12'],
['Cake', 135, 28, '2012-05-22'],
['Latte', 262, 36, '2012-06-02'],
['Milk Tee', 359, 21, '2012-06-22'],
['Cake', 121, 28, '2012-07-02'],
['Latte', 271, 36, '2012-06-22']
// ...
]
},
{
transform: {
type: 'filter',
config: {
dimension: 'Date',
'>=': '2012-05',
'<': '2012-06',
parser: 'time'
}
}
}
]
};
正式な定義
最後に、フィルター変換設定の正式な定義をここに示します。
type FilterTransform = {
type: 'filter';
config: ConditionalExpressionOption;
};
type ConditionalExpressionOption =
| true
| false
| RelationalExpressionOption
| LogicalExpressionOption;
type RelationalExpressionOption = {
dimension: DimensionName | DimensionIndex;
parser?: 'time' | 'trim' | 'number';
lt?: DataValue; // less than
lte?: DataValue; // less than or equal
gt?: DataValue; // greater than
gte?: DataValue; // greater than or equal
eq?: DataValue; // equal
ne?: DataValue; // not equal
'<'?: DataValue; // lt
'<='?: DataValue; // lte
'>'?: DataValue; // gt
'>='?: DataValue; // gte
'='?: DataValue; // eq
'!='?: DataValue; // ne
'<>'?: DataValue; // ne (SQL style)
reg?: RegExp | string; // RegExp
};
type LogicalExpressionOption = {
and?: ConditionalExpressionOption[];
or?: ConditionalExpressionOption[];
not?: ConditionalExpressionOption;
};
type DataValue = string | number | Date;
type DimensionName = string;
type DimensionIndex = number;
最小バンドルを使用する場合、この組み込み変換を使用するには、
Dataset
コンポーネントに加えて、Transform
コンポーネントをインポートする必要があります。
import {
DatasetComponent,
TransformComponent
} from 'echarts/components';
echarts.use([
DatasetComponent,
TransformComponent
]);
ソート変換
もう1つの組み込み変換は「sort」です。
option = {
dataset: [
{
dimensions: ['name', 'age', 'profession', 'score', 'date'],
source: [
[' Hannah Krause ', 41, 'Engineer', 314, '2011-02-12'],
['Zhao Qian ', 20, 'Teacher', 351, '2011-03-01'],
[' Jasmin Krause ', 52, 'Musician', 287, '2011-02-14'],
['Li Lei', 37, 'Teacher', 219, '2011-02-18'],
[' Karle Neumann ', 25, 'Engineer', 253, '2011-04-02'],
[' Adrian Groß', 19, 'Teacher', null, '2011-01-16'],
['Mia Neumann', 71, 'Engineer', 165, '2011-03-19'],
[' Böhm Fuchs', 36, 'Musician', 318, '2011-02-24'],
['Han Meimei ', 67, 'Engineer', 366, '2011-03-12']
]
},
{
transform: {
type: 'sort',
// Sort by score.
config: { dimension: 'score', order: 'asc' }
}
}
],
series: {
type: 'bar',
datasetIndex: 1
}
// ...
};
「ソート変換」に関する追加機能
- 複数の次元による並べ替えがサポートされています。以下の例を参照してください。
- ソートルール
- デフォルトでは、「数値」(つまり、数値と
' 123 '
のような数値文字列)は数値順にソートできます。 - それ以外の場合、「非数値文字列」もそれらの間で並べ替えることができます。これは、特に複数の次元がソートに関与する場合、同じタグを持つデータ項目をグループ化するのに役立つ場合があります(以下の例を参照)。
- 「数値」と「非数値文字列」を比較する場合、またはそのいずれかを他の種類の値と比較する場合、それらは比較できません。そのため、後者を「比較不能」と呼び、プロパティ
incomparable: 'min' | 'max'
に従って「最小値」または「最大値」として扱います。この機能は通常、空の値(例:null
、undefined
、NaN
、''
、'-'
)やその他の不正な値を先頭または末尾に配置するかどうかを決定するのに役立ちます。
- デフォルトでは、「数値」(つまり、数値と
parser: 'time' | 'trim' | 'number'
を使用できます。「フィルター変換」と同じです。- 時間値(JS
Date
インスタンスまたは'2012-03-12 11:13:54'
のような時間文字列)をソートする場合は、parser: 'time'
を指定する必要があります。例:config: { dimension: 'date', order: 'desc', parser: 'time' }
- 単位サフィックス付きの値(例:
'33%'
、'16px'
)をソートする場合は、parser: 'number'
を使用する必要があります。
- 時間値(JS
複数の順序の例を示します。
option = {
dataset: [
{
dimensions: ['name', 'age', 'profession', 'score', 'date'],
source: [
[' Hannah Krause ', 41, 'Engineer', 314, '2011-02-12'],
['Zhao Qian ', 20, 'Teacher', 351, '2011-03-01'],
[' Jasmin Krause ', 52, 'Musician', 287, '2011-02-14'],
['Li Lei', 37, 'Teacher', 219, '2011-02-18'],
[' Karle Neumann ', 25, 'Engineer', 253, '2011-04-02'],
[' Adrian Groß', 19, 'Teacher', null, '2011-01-16'],
['Mia Neumann', 71, 'Engineer', 165, '2011-03-19'],
[' Böhm Fuchs', 36, 'Musician', 318, '2011-02-24'],
['Han Meimei ', 67, 'Engineer', 366, '2011-03-12']
]
},
{
transform: {
type: 'sort',
config: [
// Sort by the two dimensions.
{ dimension: 'profession', order: 'desc' },
{ dimension: 'score', order: 'desc' }
]
}
}
],
series: {
type: 'bar',
datasetIndex: 1
}
// ...
};
最後に、ソート変換設定の正式な定義をここに示します。
type SortTransform = {
type: 'sort';
config: OrderExpression | OrderExpression[];
};
type OrderExpression = {
dimension: DimensionName | DimensionIndex;
order: 'asc' | 'desc';
incomparable?: 'min' | 'max';
parser?: 'time' | 'trim' | 'number';
};
type DimensionName = string;
type DimensionIndex = number;
最小バンドルを使用する場合、この組み込み変換を使用するには、
Dataset
コンポーネントに加えて、Transform
コンポーネントをインポートする必要があります。
import {
DatasetComponent,
TransformComponent
} from 'echarts/components';
echarts.use([
DatasetComponent,
TransformComponent
]);
外部変換の使用
組み込み変換(例:'filter'、'sort')に加えて、外部変換を使用してより強力な機能を提供することもできます。ここでは、サードパーティライブラリecStatを例として使用します。
この例は、ecStatを使用して回帰線を作成する方法を示しています。
// Register the external transform at first.
echarts.registerTransform(ecStatTransform(ecStat).regression);
option = {
dataset: [
{
source: rawData
},
{
transform: {
// Reference the registered external transform.
// Note that external transform has a namespace (like 'ecStat:xxx'
// has namespace 'ecStat').
// built-in transform (like 'filter', 'sort') does not have a namespace.
type: 'ecStat:regression',
config: {
// Parameters needed by the external transform.
method: 'exponential'
}
}
}
],
xAxis: { type: 'category' },
yAxis: {},
series: [
{
name: 'scatter',
type: 'scatter',
datasetIndex: 0
},
{
name: 'regression',
type: 'line',
symbol: 'none',
datasetIndex: 1
}
]
};
echarts-statの例