blob: ca184a66bdc37b4e77f6363f1391e7904f0972e0 [file] [log] [blame]
__NUXT_JSONP__("/en/concepts/data-transform", (function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,_,$,aa,ab,ac,ad,ae,af,ag,ah,ai,aj,ak,al,am,an,ao,ap){return {data:[{article:{slug:K,toc:[{id:L,depth:z,text:M},{id:N,depth:z,text:O},{id:P,depth:z,text:Q},{id:R,depth:z,text:S},{id:T,depth:z,text:U}],body:{type:"root",children:[{type:b,tag:"h1",props:{id:K},children:[{type:b,tag:h,props:{href:"#data-transform",ariaHidden:r,tabIndex:s},children:[{type:b,tag:t,props:{className:[u,v]},children:[]}]},{type:a,value:"Data Transform"}]},{type:a,value:c},{type:b,tag:f,props:{},children:[{type:b,tag:d,props:{},children:[{type:a,value:"Data transform"}]},{type:a,value:" has been supported since Apache ECharts"},{type:b,tag:"sup",props:{},children:[{type:a,value:"TM"}]},{type:a,value:" 5. In echarts, the term "},{type:b,tag:d,props:{},children:[{type:a,value:"data transform"}]},{type:a,value:" means that generate new data from user provided source data and transform functions. both This feature is enable users to process data in declarative way, and provides users some common \"transform functions\" to make that kind of tasks \"out-of-the-box\". (For consistency in the context, the noun form of the word we keep using the \"transform\" rather than \"transformation\")."}]},{type:a,value:c},{type:b,tag:f,props:{},children:[{type:a,value:"The abstract formula of data transform is: "},{type:b,tag:d,props:{},children:[{type:a,value:"outData = f(inputData)"}]},{type:a,value:", where the transform function "},{type:b,tag:d,props:{},children:[{type:a,value:"f"}]},{type:a,value:" can be like "},{type:b,tag:d,props:{},children:[{type:a,value:"filter"}]},{type:a,value:i},{type:b,tag:d,props:{},children:[{type:a,value:"sort"}]},{type:a,value:i},{type:b,tag:d,props:{},children:[{type:a,value:"regression"}]},{type:a,value:i},{type:b,tag:d,props:{},children:[{type:a,value:"boxplot"}]},{type:a,value:i},{type:b,tag:d,props:{},children:[{type:a,value:"cluster"}]},{type:a,value:i},{type:b,tag:d,props:{},children:[{type:a,value:"aggregate"}]},{type:a,value:"(todo) ...\nWith the help of those transform methods, users can be implements the features like:"}]},{type:a,value:c},{type:b,tag:w,props:{},children:[{type:a,value:c},{type:b,tag:e,props:{},children:[{type:a,value:"Partition data into multiple series."}]},{type:a,value:c},{type:b,tag:e,props:{},children:[{type:a,value:"Make some statistics and visualize the result."}]},{type:a,value:c},{type:b,tag:e,props:{},children:[{type:a,value:"Adapt some visualization algorithms to data and display the result."}]},{type:a,value:c},{type:b,tag:e,props:{},children:[{type:a,value:"Sort data."}]},{type:a,value:c},{type:b,tag:e,props:{},children:[{type:a,value:"Remove or choose some kind of empty or special datums."}]},{type:a,value:c},{type:b,tag:e,props:{},children:[{type:a,value:"..."}]},{type:a,value:c}]},{type:a,value:c},{type:b,tag:A,props:{id:L},children:[{type:b,tag:h,props:{href:"#get-started-to-data-transform",ariaHidden:r,tabIndex:s},children:[{type:b,tag:t,props:{className:[u,v]},children:[]}]},{type:a,value:M}]},{type:a,value:c},{type:b,tag:f,props:{},children:[{type:a,value:"In echarts, data transform is implemented based on the concept of "},{type:b,tag:h,props:{href:"~https:\u002F\u002Fecharts.apache.org\u002Foption.html##dataset"},children:[{type:a,value:"dataset"}]},{type:a,value:". A "},{type:b,tag:h,props:{href:V,rel:[l,m,n],target:o},children:[{type:a,value:W}]},{type:a,value:" can be configured in a dataset instance to indicate that this dataset is to be generated from this "},{type:b,tag:d,props:{},children:[{type:a,value:X}]},{type:a,value:Y}]},{type:a,value:c},{type:b,tag:j,props:{className:[k]},children:[{type:b,tag:Z,props:{lang:p,layout:_},children:[{type:a,value:"var option = {\n dataset: [\n {\n \u002F\u002F This dataset is on `datasetIndex: 0`.\n source: [\n ['Product', 'Sales', 'Price', 'Year'],\n ['Cake', 123, 32, 2011],\n ['Cereal', 231, 14, 2011],\n ['Tofu', 235, 5, 2011],\n ['Dumpling', 341, 25, 2011],\n ['Biscuit', 122, 29, 2011],\n ['Cake', 143, 30, 2012],\n ['Cereal', 201, 19, 2012],\n ['Tofu', 255, 7, 2012],\n ['Dumpling', 241, 27, 2012],\n ['Biscuit', 102, 34, 2012],\n ['Cake', 153, 28, 2013],\n ['Cereal', 181, 21, 2013],\n ['Tofu', 395, 4, 2013],\n ['Dumpling', 281, 31, 2013],\n ['Biscuit', 92, 39, 2013],\n ['Cake', 223, 29, 2014],\n ['Cereal', 211, 17, 2014],\n ['Tofu', 345, 3, 2014],\n ['Dumpling', 211, 35, 2014],\n ['Biscuit', 72, 24, 2014]\n ]\n \u002F\u002F id: 'a'\n },\n {\n \u002F\u002F This dataset is on `datasetIndex: 1`.\n \u002F\u002F A `transform` is configured to indicate that the\n \u002F\u002F final data of this dataset is transformed via this\n \u002F\u002F transform function.\n transform: {\n type: 'filter',\n config: { dimension: 'Year', value: 2011 }\n }\n \u002F\u002F There can be optional properties `fromDatasetIndex` or `fromDatasetId`\n \u002F\u002F to indicate that where is the input data of the transform from.\n \u002F\u002F For example, `fromDatasetIndex: 0` specify the input data is from\n \u002F\u002F the dataset on `datasetIndex: 0`, or `fromDatasetId: 'a'` specify the\n \u002F\u002F input data is from the dataset having `id: 'a'`.\n \u002F\u002F [DEFAULT_RULE]\n \u002F\u002F If both `fromDatasetIndex` and `fromDatasetId` are omitted,\n \u002F\u002F `fromDatasetIndex: 0` are used by default.\n },\n {\n \u002F\u002F This dataset is on `datasetIndex: 2`.\n \u002F\u002F Similarly, if neither `fromDatasetIndex` nor `fromDatasetId` is\n \u002F\u002F specified, `fromDatasetIndex: 0` is used by default\n transform: {\n \u002F\u002F The \"filter\" transform filters and gets data items only match\n \u002F\u002F the given condition in property `config`.\n type: 'filter',\n \u002F\u002F Transforms has a property `config`. In this \"filter\" transform,\n \u002F\u002F the `config` specify the condition that each result data item\n \u002F\u002F should be satisfied. In this case, this transform get all of\n \u002F\u002F the data items that the value on dimension \"Year\" equals to 2012.\n config: { dimension: 'Year', value: 2012 }\n }\n },\n {\n \u002F\u002F This dataset is on `datasetIndex: 3`\n transform: {\n type: 'filter',\n config: { dimension: 'Year', value: 2013 }\n }\n }\n ],\n series: [\n {\n type: 'pie',\n radius: 50,\n center: ['25%', '50%'],\n \u002F\u002F In this case, each \"pie\" series reference to a dataset that has\n \u002F\u002F the result of its \"filter\" transform.\n datasetIndex: 1\n },\n {\n type: 'pie',\n radius: 50,\n center: ['50%', '50%'],\n datasetIndex: 2\n },\n {\n type: 'pie',\n radius: 50,\n center: ['75%', '50%'],\n datasetIndex: 3\n }\n ]\n};\n"}]}]},{type:a,value:c},{type:b,tag:f,props:{},children:[{type:a,value:"Let's summarize the key points of using data transform:"}]},{type:a,value:c},{type:b,tag:w,props:{},children:[{type:a,value:c},{type:b,tag:e,props:{},children:[{type:a,value:"Generate new data from existing declared data via the declaration of "},{type:b,tag:d,props:{},children:[{type:a,value:X}]},{type:a,value:i},{type:b,tag:d,props:{},children:[{type:a,value:"fromDatasetIndex"}]},{type:a,value:E},{type:b,tag:d,props:{},children:[{type:a,value:"fromDatasetId"}]},{type:a,value:" in some blank dataset."}]},{type:a,value:c},{type:b,tag:e,props:{},children:[{type:a,value:"Series references these datasets to show the result."}]},{type:a,value:c}]},{type:a,value:c},{type:b,tag:A,props:{id:N},children:[{type:b,tag:h,props:{href:"#advanced-usage",ariaHidden:r,tabIndex:s},children:[{type:b,tag:t,props:{className:[u,v]},children:[]}]},{type:a,value:O}]},{type:a,value:c},{type:b,tag:F,props:{id:"piped-transform"},children:[{type:b,tag:h,props:{href:"#piped-transform",ariaHidden:r,tabIndex:s},children:[{type:b,tag:t,props:{className:[u,v]},children:[]}]},{type:a,value:"Piped Transform"}]},{type:a,value:c},{type:b,tag:f,props:{},children:[{type:a,value:"There is a syntactic sugar that pipe transforms like:"}]},{type:a,value:c},{type:b,tag:j,props:{className:[k]},children:[{type:b,tag:q,props:{lang:p,"line-highlights":g,"file-name":g},children:[{type:a,value:"option = {\n dataset: [\n {\n source: [] \u002F\u002F The original data\n },\n {\n \u002F\u002F Declare transforms in an array to pipe multiple transforms,\n \u002F\u002F which makes them execute one by one and take the output of\n \u002F\u002F the previous transform as the input of the next transform.\n transform: [\n {\n type: 'filter',\n config: { dimension: 'Product', value: 'Tofu' }\n },\n {\n type: 'sort',\n config: { dimension: 'Year', order: 'desc' }\n }\n ]\n }\n ],\n series: {\n type: 'pie',\n \u002F\u002F Display the result of the piped transform.\n datasetIndex: 1\n }\n};\n"}]}]},{type:a,value:c},{type:b,tag:"blockquote",props:{},children:[{type:a,value:c},{type:b,tag:f,props:{},children:[{type:a,value:"Note: theoretically any type of transform is able to have multiple input data and multiple output data. But when a transform is piped, it is only able to take one input (except it is the first transform of the pipe) and product one output (except it is the last transform of the pipe)."}]},{type:a,value:c}]},{type:a,value:c},{type:b,tag:F,props:{id:"output-multiple-data"},children:[{type:b,tag:h,props:{href:"#output-multiple-data",ariaHidden:r,tabIndex:s},children:[{type:b,tag:t,props:{className:[u,v]},children:[]}]},{type:a,value:"Output Multiple Data"}]},{type:a,value:c},{type:b,tag:f,props:{},children:[{type:a,value:"In most cases, transform functions only need to produce one data. But there is indeed scenarios that a transform function needs to produce multiple data, each of whom might be used by different series."}]},{type:a,value:c},{type:b,tag:f,props:{},children:[{type:a,value:"For example, in the built-in boxplot transform, besides boxplot data produced, the outlier data are also produced, which can be used in a scatter series. See the "},{type:b,tag:h,props:{href:"https:\u002F\u002Fecharts.apache.org\u002Fexamples\u002Fen\u002Feditor.html?c=boxplot-light-velocity",rel:[l,m,n],target:o},children:[{type:a,value:"example"}]},{type:a,value:B}]},{type:a,value:c},{type:b,tag:f,props:{},children:[{type:a,value:"We use prop "},{type:b,tag:h,props:{href:$,rel:[l,m,n],target:o},children:[{type:a,value:aa}]},{type:a,value:" to satisfy this requirement. For example:"}]},{type:a,value:c},{type:b,tag:j,props:{className:[k]},children:[{type:b,tag:q,props:{lang:p,"line-highlights":g,"file-name":g},children:[{type:a,value:"option = {\n dataset: [\n {\n \u002F\u002F Original source data.\n source: []\n },\n {\n transform: {\n type: 'boxplot'\n }\n \u002F\u002F After this \"boxplot transform\" two result data generated:\n \u002F\u002F result[0]: The boxplot data\n \u002F\u002F result[1]: The outlier data\n \u002F\u002F By default, when series or other dataset reference this dataset,\n \u002F\u002F only result[0] can be visited.\n \u002F\u002F If we need to visit result[1], we have to use another dataset\n \u002F\u002F as follows:\n },\n {\n \u002F\u002F This extra dataset references the dataset above, and retrieves\n \u002F\u002F the result[1] as its own data. Thus series or other dataset can\n \u002F\u002F reference this dataset to get the data from result[1].\n fromDatasetIndex: 1,\n fromTransformResult: 1\n }\n ],\n xAxis: {\n type: 'category'\n },\n yAxis: {},\n series: [\n {\n name: 'boxplot',\n type: 'boxplot',\n \u002F\u002F Reference the data from result[0].\n datasetIndex: 1\n },\n {\n name: 'outlier',\n type: 'scatter',\n \u002F\u002F Reference the data from result[1].\n datasetIndex: 2\n }\n ]\n};\n"}]}]},{type:a,value:c},{type:b,tag:f,props:{},children:[{type:a,value:"What more, "},{type:b,tag:h,props:{href:$,rel:[l,m,n],target:o},children:[{type:a,value:aa}]},{type:a,value:" and "},{type:b,tag:h,props:{href:V,rel:[l,m,n],target:o},children:[{type:a,value:W}]},{type:a,value:" can both appear in one dataset, which means that the input of the transform is from retrieved from the upstream result specified by "},{type:b,tag:d,props:{},children:[{type:a,value:"fromTransformResult"}]},{type:a,value:Y}]},{type:a,value:c},{type:b,tag:j,props:{className:[k]},children:[{type:b,tag:q,props:{lang:p,"line-highlights":g,"file-name":g},children:[{type:a,value:"{\n fromDatasetIndex: 1,\n fromTransformResult: 1,\n transform: {\n type: 'sort',\n config: { dimension: 2, order: 'desc' }\n }\n}\n"}]}]},{type:a,value:c},{type:b,tag:F,props:{id:"debug-in-develop-environment"},children:[{type:b,tag:h,props:{href:"#debug-in-develop-environment",ariaHidden:r,tabIndex:s},children:[{type:b,tag:t,props:{className:[u,v]},children:[]}]},{type:a,value:"Debug in Develop Environment"}]},{type:a,value:c},{type:b,tag:f,props:{},children:[{type:a,value:"When using data transform, we might run into the trouble that the final chart do not display correctly but we do not know where the config is wrong. There is a property "},{type:b,tag:d,props:{},children:[{type:a,value:ab}]},{type:a,value:" might help in such case. ("},{type:b,tag:d,props:{},children:[{type:a,value:ab}]},{type:a,value:" is only available in dev environment)."}]},{type:a,value:c},{type:b,tag:j,props:{className:[k]},children:[{type:b,tag:q,props:{lang:p,"line-highlights":g,"file-name":g},children:[{type:a,value:"option = {\n dataset: [\n {\n source: []\n },\n {\n transform: {\n type: 'filter',\n config: {},\n \u002F\u002F The result of this transform will be printed\n \u002F\u002F in dev tool via `console.log`.\n print: true\n }\n }\n ]\n};\n"}]}]},{type:a,value:c},{type:b,tag:A,props:{id:P},children:[{type:b,tag:h,props:{href:"#filter-transform",ariaHidden:r,tabIndex:s},children:[{type:b,tag:t,props:{className:[u,v]},children:[]}]},{type:a,value:Q}]},{type:a,value:c},{type:b,tag:f,props:{},children:[{type:a,value:"Transform type \"filter\" is a built-in transform that provide data filter according to specified conditions. The basic option is like:"}]},{type:a,value:c},{type:b,tag:j,props:{className:[k]},children:[{type:b,tag:Z,props:{lang:p,layout:_},children:[{type:a,value:"option = {\n dataset: [\n {\n source: [\n ['Product', 'Sales', 'Price', 'Year'],\n ['Cake', 123, 32, 2011],\n ['Latte', 231, 14, 2011],\n ['Tofu', 235, 5, 2011],\n ['Milk Tee', 341, 25, 2011],\n ['Porridge', 122, 29, 2011],\n ['Cake', 143, 30, 2012],\n ['Latte', 201, 19, 2012],\n ['Tofu', 255, 7, 2012],\n ['Milk Tee', 241, 27, 2012],\n ['Porridge', 102, 34, 2012],\n ['Cake', 153, 28, 2013],\n ['Latte', 181, 21, 2013],\n ['Tofu', 395, 4, 2013],\n ['Milk Tee', 281, 31, 2013],\n ['Porridge', 92, 39, 2013],\n ['Cake', 223, 29, 2014],\n ['Latte', 211, 17, 2014],\n ['Tofu', 345, 3, 2014],\n ['Milk Tee', 211, 35, 2014],\n ['Porridge', 72, 24, 2014]\n ]\n },\n {\n transform: {\n type: 'filter',\n config: { dimension: 'Year', '=': 2011 }\n \u002F\u002F The config is the \"condition\" of this filter.\n \u002F\u002F This transform traverse the source data and\n \u002F\u002F and retrieve all the items that the \"Year\"\n \u002F\u002F is `2011`.\n }\n }\n ],\n series: {\n type: 'pie',\n datasetIndex: 1\n }\n};\n"}]}]},{type:a,value:c},{type:b,tag:f,props:{},children:[{type:a,value:"This is another example of filter transform:"}]},{type:a,value:c},{type:b,tag:G,props:{src:"data-transform-filter"},children:[{type:a,value:c}]},{type:a,value:c},{type:b,tag:f,props:{},children:[{type:b,tag:C,props:{},children:[{type:a,value:"About dimension:"}]}]},{type:a,value:c},{type:b,tag:f,props:{},children:[{type:a,value:"The "},{type:b,tag:d,props:{},children:[{type:a,value:"config.dimension"}]},{type:a,value:" can be:"}]},{type:a,value:c},{type:b,tag:w,props:{},children:[{type:a,value:c},{type:b,tag:e,props:{},children:[{type:a,value:"Dimension name declared in dataset, like "},{type:b,tag:d,props:{},children:[{type:a,value:"config: { dimension: 'Year', '=': 2011 }"}]},{type:a,value:". Dimension name declaration is not mandatory."}]},{type:a,value:c},{type:b,tag:e,props:{},children:[{type:a,value:"Dimension index (start from 0), like "},{type:b,tag:d,props:{},children:[{type:a,value:"config: { dimension: 3, '=': 2011 }"}]},{type:a,value:B}]},{type:a,value:c}]},{type:a,value:c},{type:b,tag:f,props:{},children:[{type:b,tag:C,props:{},children:[{type:a,value:"About relational operator:"}]}]},{type:a,value:c},{type:b,tag:f,props:{},children:[{type:a,value:"The relational operator can be:\n"},{type:b,tag:d,props:{},children:[{type:a,value:ac}]},{type:a,value:y},{type:b,tag:d,props:{},children:[{type:a,value:"gt"}]},{type:a,value:x},{type:b,tag:d,props:{},children:[{type:a,value:ad}]},{type:a,value:y},{type:b,tag:d,props:{},children:[{type:a,value:"gte"}]},{type:a,value:x},{type:b,tag:d,props:{},children:[{type:a,value:ae}]},{type:a,value:y},{type:b,tag:d,props:{},children:[{type:a,value:"lt"}]},{type:a,value:x},{type:b,tag:d,props:{},children:[{type:a,value:af}]},{type:a,value:y},{type:b,tag:d,props:{},children:[{type:a,value:"lte"}]},{type:a,value:x},{type:b,tag:d,props:{},children:[{type:a,value:ag}]},{type:a,value:y},{type:b,tag:d,props:{},children:[{type:a,value:"eq"}]},{type:a,value:x},{type:b,tag:d,props:{},children:[{type:a,value:ah}]},{type:a,value:y},{type:b,tag:d,props:{},children:[{type:a,value:"ne"}]},{type:a,value:i},{type:b,tag:d,props:{},children:[{type:a,value:"\u003C\u003E"}]},{type:a,value:x},{type:b,tag:d,props:{},children:[{type:a,value:ai}]},{type:a,value:". (The name in the parentheses are aliases). They follows the common semantics.\nBesides the common number comparison, there is some extra features:"}]},{type:a,value:c},{type:b,tag:w,props:{},children:[{type:a,value:c},{type:b,tag:e,props:{},children:[{type:a,value:"Multiple operators are able to appear in one {} item like "},{type:b,tag:d,props:{},children:[{type:a,value:"{ dimension: 'Price', '\u003E=': 20, '\u003C': 30 }"}]},{type:a,value:", which means logical \"and\" (Price \u003E= 20 and Price \u003C 30)."}]},{type:a,value:c},{type:b,tag:e,props:{},children:[{type:a,value:"The data value can be \"numeric string\". Numeric string is a string that can be converted to number. Like ' 123 '. White spaces and line breaks will be auto trimmed in the conversion."}]},{type:a,value:c},{type:b,tag:e,props:{},children:[{type:a,value:"If we need to compare \"JS "},{type:b,tag:d,props:{},children:[{type:a,value:H}]},{type:a,value:" instance\" or date string (like '2012-05-12'), we need to specify "},{type:b,tag:d,props:{},children:[{type:a,value:D}]},{type:a,value:" manually, like "},{type:b,tag:d,props:{},children:[{type:a,value:"config: { dimension: 3, lt: '2012-05-12', parser: 'time' }"}]},{type:a,value:B}]},{type:a,value:c},{type:b,tag:e,props:{},children:[{type:a,value:"Pure string comparison is supported but can only be used in "},{type:b,tag:d,props:{},children:[{type:a,value:ag}]},{type:a,value:i},{type:b,tag:d,props:{},children:[{type:a,value:ah}]},{type:a,value:". "},{type:b,tag:d,props:{},children:[{type:a,value:ac}]},{type:a,value:i},{type:b,tag:d,props:{},children:[{type:a,value:ad}]},{type:a,value:i},{type:b,tag:d,props:{},children:[{type:a,value:ae}]},{type:a,value:i},{type:b,tag:d,props:{},children:[{type:a,value:af}]},{type:a,value:" do not support pure string comparison (the \"right value\" of the four operators can not be a \"string\")."}]},{type:a,value:c},{type:b,tag:e,props:{},children:[{type:a,value:"The operator "},{type:b,tag:d,props:{},children:[{type:a,value:ai}]},{type:a,value:" can be used to make regular expression test. Like using "},{type:b,tag:d,props:{},children:[{type:a,value:"{ dimension: 'Name', reg: \u002F\\s+Müller\\s*$\u002F }"}]},{type:a,value:" to select all data items that the \"Name\" dimension contains family name Müller."}]},{type:a,value:c}]},{type:a,value:c},{type:b,tag:f,props:{},children:[{type:b,tag:C,props:{},children:[{type:a,value:"About logical relationship:"}]}]},{type:a,value:c},{type:b,tag:f,props:{},children:[{type:a,value:"Sometimes we also need to express logical relationship ( "},{type:b,tag:d,props:{},children:[{type:a,value:aj}]},{type:a,value:ak},{type:b,tag:d,props:{},children:[{type:a,value:al}]},{type:a,value:ak},{type:b,tag:d,props:{},children:[{type:a,value:am}]},{type:a,value:" ):"}]},{type:a,value:c},{type:b,tag:j,props:{className:[k]},children:[{type:b,tag:q,props:{lang:p,"line-highlights":g,"file-name":g},children:[{type:a,value:"option = {\n dataset: [\n {\n source: [\n \u002F\u002F ...\n ]\n },\n {\n transform: {\n type: 'filter',\n config: {\n \u002F\u002F Use operator \"and\".\n \u002F\u002F Similarly, we can also use \"or\", \"not\" in the same place.\n \u002F\u002F But \"not\" should be followed with a {...} rather than `[...]`.\n and: [\n { dimension: 'Year', '=': 2011 },\n { dimension: 'Price', '\u003E=': 20, '\u003C': 30 }\n ]\n }\n \u002F\u002F The condition is \"Year\" is 2011 and \"Price\" is greater\n \u002F\u002F or equal to 20 but less than 30.\n }\n }\n ],\n series: {\n type: 'pie',\n datasetIndex: 1\n }\n};\n"}]}]},{type:a,value:c},{type:b,tag:f,props:{},children:[{type:b,tag:d,props:{},children:[{type:a,value:aj}]},{type:a,value:E},{type:b,tag:d,props:{},children:[{type:a,value:al}]},{type:a,value:E},{type:b,tag:d,props:{},children:[{type:a,value:am}]},{type:a,value:" can be nested like:"}]},{type:a,value:c},{type:b,tag:j,props:{className:[k]},children:[{type:b,tag:q,props:{lang:p,"line-highlights":g,"file-name":g},children:[{type:a,value:"transform: {\n type: 'filter',\n config: {\n or: [{\n and: [{\n dimension: 'Price', '\u003E=': 10, '\u003C': 20\n }, {\n dimension: 'Sales', '\u003C': 100\n }, {\n not: { dimension: 'Product', '=': 'Tofu' }\n }]\n }, {\n and: [{\n dimension: 'Price', '\u003E=': 10, '\u003C': 20\n }, {\n dimension: 'Sales', '\u003C': 100\n }, {\n not: { dimension: 'Product', '=': 'Cake' }\n }]\n }]\n }\n}\n"}]}]},{type:a,value:c},{type:b,tag:f,props:{},children:[{type:b,tag:C,props:{},children:[{type:a,value:"About parser:"}]}]},{type:a,value:c},{type:b,tag:f,props:{},children:[{type:a,value:"Some \"parser\" can be specified when make value comparison. At present only supported:"}]},{type:a,value:c},{type:b,tag:w,props:{},children:[{type:a,value:c},{type:b,tag:e,props:{},children:[{type:b,tag:d,props:{},children:[{type:a,value:D}]},{type:a,value:": Parse the value to date time before comparing. The parser rule is the same as "},{type:b,tag:d,props:{},children:[{type:a,value:"echarts.time.parse"}]},{type:a,value:", where JS "},{type:b,tag:d,props:{},children:[{type:a,value:H}]},{type:a,value:" instance, timestamp number (in millisecond) and time string (like "},{type:b,tag:d,props:{},children:[{type:a,value:"'2012-05-12 03:11:22'"}]},{type:a,value:") are supported to be parse to timestamp number, while other value will be parsed to "},{type:b,tag:d,props:{},children:[{type:a,value:I}]},{type:a,value:B}]},{type:a,value:c},{type:b,tag:e,props:{},children:[{type:b,tag:d,props:{},children:[{type:a,value:"parser: 'trim'"}]},{type:a,value:": Trim the string before making comparison. For non-string, return the original value."}]},{type:a,value:c},{type:b,tag:e,props:{},children:[{type:b,tag:d,props:{},children:[{type:a,value:J}]},{type:a,value:": Force to convert the value to number before making comparison. If not possible to be converted to a meaningful number, converted to "},{type:b,tag:d,props:{},children:[{type:a,value:I}]},{type:a,value:". In most cases it is not necessary, because by default the value will be auto converted to number if possible before making comparison. But the default conversion is strict while this parser provide a loose strategy. If we meet the case that number string with unit suffix (like "},{type:b,tag:d,props:{},children:[{type:a,value:an}]},{type:a,value:i},{type:b,tag:d,props:{},children:[{type:a,value:"12px"}]},{type:a,value:"), we should use "},{type:b,tag:d,props:{},children:[{type:a,value:J}]},{type:a,value:" to convert them to number before making comparison."}]},{type:a,value:c}]},{type:a,value:c},{type:b,tag:f,props:{},children:[{type:a,value:"This is an example to show the "},{type:b,tag:d,props:{},children:[{type:a,value:D}]},{type:a,value:":"}]},{type:a,value:c},{type:b,tag:j,props:{className:[k]},children:[{type:b,tag:q,props:{lang:p,"line-highlights":g,"file-name":g},children:[{type:a,value:"option = {\n dataset: [\n {\n source: [\n ['Product', 'Sales', 'Price', 'Date'],\n ['Milk Tee', 311, 21, '2012-05-12'],\n ['Cake', 135, 28, '2012-05-22'],\n ['Latte', 262, 36, '2012-06-02'],\n ['Milk Tee', 359, 21, '2012-06-22'],\n ['Cake', 121, 28, '2012-07-02'],\n ['Latte', 271, 36, '2012-06-22']\n \u002F\u002F ...\n ]\n },\n {\n transform: {\n type: 'filter',\n config: {\n dimension: 'Date',\n '\u003E=': '2012-05',\n '\u003C': '2012-06',\n parser: 'time'\n }\n }\n }\n ]\n};\n"}]}]},{type:a,value:c},{type:b,tag:f,props:{},children:[{type:b,tag:C,props:{},children:[{type:a,value:"Formally definition:"}]}]},{type:a,value:c},{type:b,tag:f,props:{},children:[{type:a,value:"Finally, we give the formally definition of the filter transform config here:"}]},{type:a,value:c},{type:b,tag:j,props:{className:[k]},children:[{type:b,tag:q,props:{lang:ao,"line-highlights":g,"file-name":g},children:[{type:a,value:"type FilterTransform = {\n type: 'filter';\n config: ConditionalExpressionOption;\n};\ntype ConditionalExpressionOption =\n | true\n | false\n | RelationalExpressionOption\n | LogicalExpressionOption;\ntype RelationalExpressionOption = {\n dimension: DimensionName | DimensionIndex;\n parser?: 'time' | 'trim' | 'number';\n lt?: DataValue; \u002F\u002F less than\n lte?: DataValue; \u002F\u002F less than or equal\n gt?: DataValue; \u002F\u002F greater than\n gte?: DataValue; \u002F\u002F greater than or equal\n eq?: DataValue; \u002F\u002F equal\n ne?: DataValue; \u002F\u002F not equal\n '\u003C'?: DataValue; \u002F\u002F lt\n '\u003C='?: DataValue; \u002F\u002F lte\n '\u003E'?: DataValue; \u002F\u002F gt\n '\u003E='?: DataValue; \u002F\u002F gte\n '='?: DataValue; \u002F\u002F eq\n '!='?: DataValue; \u002F\u002F ne\n '\u003C\u003E'?: DataValue; \u002F\u002F ne (SQL style)\n reg?: RegExp | string; \u002F\u002F RegExp\n};\ntype LogicalExpressionOption = {\n and?: ConditionalExpressionOption[];\n or?: ConditionalExpressionOption[];\n not?: ConditionalExpressionOption;\n};\ntype DataValue = string | number | Date;\ntype DimensionName = string;\ntype DimensionIndex = number;\n"}]}]},{type:a,value:c},{type:b,tag:A,props:{id:R},children:[{type:b,tag:h,props:{href:"#the-transform-sort",ariaHidden:r,tabIndex:s},children:[{type:b,tag:t,props:{className:[u,v]},children:[]}]},{type:a,value:S}]},{type:a,value:c},{type:b,tag:f,props:{},children:[{type:a,value:"Another built-in transform is \"sort\"."}]},{type:a,value:c},{type:b,tag:j,props:{className:[k]},children:[{type:b,tag:q,props:{lang:p,"line-highlights":g,"file-name":g},children:[{type:a,value:"option = {\n dataset: [\n {\n dimensions: ['name', 'age', 'profession', 'score', 'date'],\n source: [\n [' Hannah Krause ', 41, 'Engineer', 314, '2011-02-12'],\n ['Zhao Qian ', 20, 'Teacher', 351, '2011-03-01'],\n [' Jasmin Krause ', 52, 'Musician', 287, '2011-02-14'],\n ['Li Lei', 37, 'Teacher', 219, '2011-02-18'],\n [' Karle Neumann ', 25, 'Engineer', 253, '2011-04-02'],\n [' Adrian Groß', 19, 'Teacher', null, '2011-01-16'],\n ['Mia Neumann', 71, 'Engineer', 165, '2011-03-19'],\n [' Böhm Fuchs', 36, 'Musician', 318, '2011-02-24'],\n ['Han Meimei ', 67, 'Engineer', 366, '2011-03-12']\n ]\n },\n {\n transform: {\n type: 'sort',\n \u002F\u002F Sort by score.\n config: { dimension: 'score', order: 'asc' }\n }\n }\n ],\n series: {\n type: 'bar',\n datasetIndex: 1\n }\n \u002F\u002F ...\n};\n"}]}]},{type:a,value:c},{type:b,tag:G,props:{src:"data-transform-sort-bar"},children:[{type:a,value:c}]},{type:a,value:c},{type:b,tag:f,props:{},children:[{type:a,value:"Some extra features about \"sort transform\":"}]},{type:a,value:c},{type:b,tag:w,props:{},children:[{type:a,value:c},{type:b,tag:e,props:{},children:[{type:a,value:"Order by multiple dimensions is supported. See examples below."}]},{type:a,value:c},{type:b,tag:e,props:{},children:[{type:a,value:"The sort rule:\n"},{type:b,tag:w,props:{},children:[{type:a,value:c},{type:b,tag:e,props:{},children:[{type:a,value:"By default \"numeric\" (that is, number and numeric-string like "},{type:b,tag:d,props:{},children:[{type:a,value:"' 123 '"}]},{type:a,value:") are able to sorted by numeric order."}]},{type:a,value:c},{type:b,tag:e,props:{},children:[{type:a,value:"Otherwise \"non-numeric-string\" are also able to be ordered among themselves. This might help to the case like grouping data items with the same tag, especially when multiple dimensions participated in the sort (See example below)."}]},{type:a,value:c},{type:b,tag:e,props:{},children:[{type:a,value:"When \"numeric\" is compared with \"non-numeric-string\", or either of them is compared with other types of value, they are not comparable. So we call the latter one as \"incomparable\" and treat it as \"min value\" or \"max value\" according to the prop "},{type:b,tag:d,props:{},children:[{type:a,value:"incomparable: 'min' | 'max'"}]},{type:a,value:". This feature usually helps to decide whether to put the empty values (like "},{type:b,tag:d,props:{},children:[{type:a,value:"null"}]},{type:a,value:i},{type:b,tag:d,props:{},children:[{type:a,value:"undefined"}]},{type:a,value:i},{type:b,tag:d,props:{},children:[{type:a,value:I}]},{type:a,value:i},{type:b,tag:d,props:{},children:[{type:a,value:"''"}]},{type:a,value:i},{type:b,tag:d,props:{},children:[{type:a,value:"'-'"}]},{type:a,value:") or other illegal values to the head or tail."}]},{type:a,value:c}]},{type:a,value:c}]},{type:a,value:c},{type:b,tag:e,props:{},children:[{type:b,tag:d,props:{},children:[{type:a,value:"filter: 'time' | 'trim' | 'number'"}]},{type:a,value:" can be used, the same as \"filter transform\".\n"},{type:b,tag:w,props:{},children:[{type:a,value:c},{type:b,tag:e,props:{},children:[{type:a,value:"If intending to sort time values (JS "},{type:b,tag:d,props:{},children:[{type:a,value:H}]},{type:a,value:" instance or time string like "},{type:b,tag:d,props:{},children:[{type:a,value:"'2012-03-12 11:13:54'"}]},{type:a,value:x},{type:b,tag:d,props:{},children:[{type:a,value:D}]},{type:a,value:" should be specified. Like "},{type:b,tag:d,props:{},children:[{type:a,value:"config: { dimension: 'date', order: 'desc', parser: 'time' }"}]}]},{type:a,value:c},{type:b,tag:e,props:{},children:[{type:a,value:"If intending to sort values with unit suffix (like "},{type:b,tag:d,props:{},children:[{type:a,value:an}]},{type:a,value:i},{type:b,tag:d,props:{},children:[{type:a,value:"'16px'"}]},{type:a,value:"), need to use "},{type:b,tag:d,props:{},children:[{type:a,value:J}]},{type:a,value:B}]},{type:a,value:c}]},{type:a,value:c}]},{type:a,value:c}]},{type:a,value:c},{type:b,tag:f,props:{},children:[{type:a,value:"See an example of multiple order:"}]},{type:a,value:c},{type:b,tag:j,props:{className:[k]},children:[{type:b,tag:q,props:{lang:p,"line-highlights":g,"file-name":g},children:[{type:a,value:"option = {\n dataset: [\n {\n dimensions: ['name', 'age', 'profession', 'score', 'date'],\n source: [\n [' Hannah Krause ', 41, 'Engineer', 314, '2011-02-12'],\n ['Zhao Qian ', 20, 'Teacher', 351, '2011-03-01'],\n [' Jasmin Krause ', 52, 'Musician', 287, '2011-02-14'],\n ['Li Lei', 37, 'Teacher', 219, '2011-02-18'],\n [' Karle Neumann ', 25, 'Engineer', 253, '2011-04-02'],\n [' Adrian Groß', 19, 'Teacher', null, '2011-01-16'],\n ['Mia Neumann', 71, 'Engineer', 165, '2011-03-19'],\n [' Böhm Fuchs', 36, 'Musician', 318, '2011-02-24'],\n ['Han Meimei ', 67, 'Engineer', 366, '2011-03-12']\n ]\n },\n {\n transform: {\n type: 'sort',\n config: [\n \u002F\u002F Sort by the two dimensions.\n { dimension: 'profession', order: 'desc' },\n { dimension: 'score', order: 'desc' }\n ]\n }\n }\n ],\n series: {\n type: 'bar',\n datasetIndex: 1\n }\n \u002F\u002F ...\n};\n"}]}]},{type:a,value:c},{type:b,tag:G,props:{src:"doc-example\u002Fdata-transform-multiple-sort-bar"},children:[{type:a,value:c}]},{type:a,value:c},{type:b,tag:f,props:{},children:[{type:a,value:"Finally, we give the formally definition of the sort transform config here:"}]},{type:a,value:c},{type:b,tag:j,props:{className:[k]},children:[{type:b,tag:q,props:{lang:ao,"line-highlights":g,"file-name":g},children:[{type:a,value:"type SortTransform = {\n type: 'filter';\n config: OrderExpression | OrderExpression[];\n};\ntype OrderExpression = {\n dimension: DimensionName | DimensionIndex;\n order: 'asc' | 'desc';\n incomparable?: 'min' | 'max';\n parser?: 'time' | 'trim' | 'number';\n};\ntype DimensionName = string;\ntype DimensionIndex = number;\n"}]}]},{type:a,value:c},{type:b,tag:A,props:{id:T},children:[{type:b,tag:h,props:{href:"#use-external-transforms",ariaHidden:r,tabIndex:s},children:[{type:b,tag:t,props:{className:[u,v]},children:[]}]},{type:a,value:U}]},{type:a,value:c},{type:b,tag:f,props:{},children:[{type:a,value:"Besides built-in transforms (like 'filter', 'sort'), we can also use external transforms to provide more powerful functionalities. Here we use a third-party library "},{type:b,tag:h,props:{href:"https:\u002F\u002Fgithub.com\u002Fecomfe\u002Fecharts-stat",rel:[l,m,n],target:o},children:[{type:a,value:"ecStat"}]},{type:a,value:" as an example:"}]},{type:a,value:c},{type:b,tag:f,props:{},children:[{type:a,value:"This case show how to make a regression line via ecStat:"}]},{type:a,value:c},{type:b,tag:j,props:{className:[k]},children:[{type:b,tag:q,props:{lang:p,"line-highlights":g,"file-name":g},children:[{type:a,value:"\u002F\u002F Register the external transform at first.\necharts.registerTransform(ecStatTransform(ecStat).regression);\n"}]}]},{type:a,value:c},{type:b,tag:j,props:{className:[k]},children:[{type:b,tag:q,props:{lang:p,"line-highlights":g,"file-name":g},children:[{type:a,value:"option = {\n dataset: [\n {\n source: rawData\n },\n {\n transform: {\n \u002F\u002F Reference the registered external transform.\n \u002F\u002F Note that external transform has a namespace (like 'ecStat:xxx'\n \u002F\u002F has namespace 'ecStat').\n \u002F\u002F built-in transform (like 'filter', 'sort') does not have a namespace.\n type: 'ecStat:regression',\n config: {\n \u002F\u002F Parameters needed by the external transform.\n method: 'exponential'\n }\n }\n }\n ],\n xAxis: { type: 'category' },\n yAxis: {},\n series: [\n {\n name: 'scatter',\n type: 'scatter',\n datasetIndex: 0\n },\n {\n name: 'regression',\n type: 'line',\n symbol: 'none',\n datasetIndex: 1\n }\n ]\n};\n"}]}]},{type:a,value:c},{type:b,tag:f,props:{},children:[{type:a,value:"Examples with echarts-stat:"}]},{type:a,value:c},{type:b,tag:w,props:{},children:[{type:a,value:c},{type:b,tag:e,props:{},children:[{type:b,tag:h,props:{href:"https:\u002F\u002Fecharts.apache.org\u002Fexamples\u002Fen\u002Feditor.html?c=data-transform-aggregate&edit=1&reset=1",rel:[l,m,n],target:o},children:[{type:a,value:"Aggregate"}]}]},{type:a,value:c},{type:b,tag:e,props:{},children:[{type:b,tag:h,props:{href:"https:\u002F\u002Fecharts.apache.org\u002Fexamples\u002Fen\u002Feditor.html?c=bar-histogram&edit=1&reset=1",rel:[l,m,n],target:o},children:[{type:a,value:"Bar histogram"}]}]},{type:a,value:c},{type:b,tag:e,props:{},children:[{type:b,tag:h,props:{href:"https:\u002F\u002Fecharts.apache.org\u002Fexamples\u002Fen\u002Feditor.html?c=scatter-clustering&edit=1&reset=1",rel:[l,m,n],target:o},children:[{type:a,value:"Scatter clustering"}]}]},{type:a,value:c},{type:b,tag:e,props:{},children:[{type:b,tag:h,props:{href:"https:\u002F\u002Fecharts.apache.org\u002Fexamples\u002Fen\u002Feditor.html?c=scatter-linear-regression&edit=1&reset=1",rel:[l,m,n],target:o},children:[{type:a,value:"Scatter linear regression"}]}]},{type:a,value:c},{type:b,tag:e,props:{},children:[{type:b,tag:h,props:{href:"https:\u002F\u002Fecharts.apache.org\u002Fexamples\u002Fen\u002Feditor.html?c=scatter-exponential-regression&edit=1&reset=1",rel:[l,m,n],target:o},children:[{type:a,value:"Scatter exponential regression"}]}]},{type:a,value:c},{type:b,tag:e,props:{},children:[{type:b,tag:h,props:{href:"https:\u002F\u002Fecharts.apache.org\u002Fexamples\u002Fen\u002Feditor.html?c=scatter-logarithmic-regression&edit=1&reset=1",rel:[l,m,n],target:o},children:[{type:a,value:"Scatter logarithmic regression"}]}]},{type:a,value:c},{type:b,tag:e,props:{},children:[{type:b,tag:h,props:{href:"https:\u002F\u002Fecharts.apache.org\u002Fexamples\u002Fen\u002Feditor.html?c=scatter-polynomial-regression&edit=1&reset=1",rel:[l,m,n],target:o},children:[{type:a,value:"Scatter polynomial regression"}]}]},{type:a,value:c}]}]},dir:"\u002Fen\u002Fconcepts",path:"\u002Fen\u002Fconcepts\u002Fdata-transform",extension:".md",createdAt:ap,updatedAt:ap},postPath:"en\u002Fconcepts\u002Fdata-transform"}],fetch:{},mutations:[]}}("text","element","\n","code","li","p","","a",", ","div","nuxt-content-highlight","nofollow","noopener","noreferrer","_blank","js","md-code-block","true",-1,"span","icon","icon-link","ul","), ","(",2,"h2",".","strong","parser: 'time'","\u002F","h4","md-example","Date","NaN","parser: 'number'","data-transform","get-started-to-data-transform","Get Started to Data Transform","advanced-usage","Advanced Usage","filter-transform","Filter Transform","the-transform-sort","The transform \"sort\"","use-external-transforms","Use External Transforms","https:\u002F\u002Fecharts.apache.org\u002Foption.html##dataset.transform","dataset.transform","transform",". For example:","md-live","tb","https:\u002F\u002Fecharts.apache.org\u002Foption.html##dataset.fromTransformResult","dataset.fromTransformResult","transform.print","\u003E","\u003E=","\u003C","\u003C=","=","!=","reg","and"," \u002F ","or","not","'33%'","ts","2021-08-02T05:33:02.867Z")));