You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@echarts.apache.org by su...@apache.org on 2020/11/21 07:14:24 UTC

[incubator-echarts-examples] branch next updated (26fce5f -> d60366d)

This is an automated email from the ASF dual-hosted git repository.

sushuang pushed a change to branch next
in repository https://gitbox.apache.org/repos/asf/incubator-echarts-examples.git.


    from 26fce5f  Merge pull request #26 from apache/fix-scripts
     new e2cf106  example: aggregate
     new 6439359  Merge branch 'next' of github.com:ecomfe/echarts-examples into next
     new d60366d  example: update aggregate.

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 public/data/asset/js/myTransform.js     | 697 +++++++++++++++++++++-----------
 public/data/data-transform-aggregate.js | 125 ++++++
 2 files changed, 588 insertions(+), 234 deletions(-)
 create mode 100644 public/data/data-transform-aggregate.js


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org


[incubator-echarts-examples] 02/03: Merge branch 'next' of github.com:ecomfe/echarts-examples into next

Posted by su...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sushuang pushed a commit to branch next
in repository https://gitbox.apache.org/repos/asf/incubator-echarts-examples.git

commit 643935931d0769228d9abcac82451a3a3952736a
Merge: e2cf106 26fce5f
Author: 100pah <su...@gmail.com>
AuthorDate: Thu Nov 19 19:49:12 2020 +0800

    Merge branch 'next' of github.com:ecomfe/echarts-examples into next

 package.json                              | 5 +++--
 public/data/scatter-clustering-process.js | 2 --
 src/explore/Explore.vue                   | 1 +
 3 files changed, 4 insertions(+), 4 deletions(-)


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org


[incubator-echarts-examples] 03/03: example: update aggregate.

Posted by su...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sushuang pushed a commit to branch next
in repository https://gitbox.apache.org/repos/asf/incubator-echarts-examples.git

commit d60366d9d42b1734dd356c3335a87050d666dfed
Author: 100pah <su...@gmail.com>
AuthorDate: Sat Nov 21 15:14:07 2020 +0800

    example: update aggregate.
---
 public/data/data-transform-aggregate.js | 63 ++++++++++++++++++++++++++++-----
 1 file changed, 54 insertions(+), 9 deletions(-)

diff --git a/public/data/data-transform-aggregate.js b/public/data/data-transform-aggregate.js
index 4a8c467..b6c7764 100644
--- a/public/data/data-transform-aggregate.js
+++ b/public/data/data-transform-aggregate.js
@@ -1,8 +1,8 @@
 /*
 title: Data Transform Simple Aggregate
-category: bar
+category: boxplot
 titleCN: 简单的数据聚合
-difficulty: 3
+difficulty: 4
 */
 
 $.when(
@@ -21,14 +21,18 @@ function run(_rawData) {
             id: 'raw',
             source: _rawData
         }, {
-            id: 'income_aggregate',
+            id: 'since_year',
             fromDatasetId: 'raw',
             transform: [{
                 type: 'filter',
                 config: {
                     dimension: 'Year', gte: 1950
                 }
-            }, {
+            }]
+        }, {
+            id: 'income_aggregate',
+            fromDatasetId: 'since_year',
+            transform: [{
                 type: 'myTransform:aggregate',
                 config: {
                     resultDimensions: [
@@ -44,7 +48,7 @@ function run(_rawData) {
             }, {
                 type: 'sort',
                 config: {
-                    dimension: 'max',
+                    dimension: 'Q3',
                     order: 'asc'
                 }
             }]
@@ -53,17 +57,32 @@ function run(_rawData) {
             text: 'Income since 1950'
         },
         tooltip: {
-            trigger: 'axis'
+            trigger: 'axis',
+            confine: true
         },
         xAxis: {
             name: 'Income',
             nameLocation: 'middle',
-            nameGap: 30
+            nameGap: 30,
+            scale: true,
         },
         yAxis: {
             type: 'category'
         },
-        series: {
+        grid: {
+            bottom: 100
+        },
+        legend: {
+            selected: { detail: false }
+        },
+        dataZoom: [{
+            type: 'inside'
+        }, {
+            type: 'slider',
+            height: 20,
+        }],
+        series: [{
+            name: 'boxplot',
             type: 'boxplot',
             datasetId: 'income_aggregate',
             encode: {
@@ -72,7 +91,33 @@ function run(_rawData) {
                 itemName: ['Country'],
                 tooltip: ['min', 'Q1', 'median', 'Q3', 'max']
             }
-        }
+        }, {
+            name: 'detail',
+            type: 'scatter',
+            datasetId: 'since_year',
+            symbolSize: 6,
+            tooltip: {
+                trigger: 'item'
+            },
+            label: {
+                show: true,
+                position: 'top',
+                align: 'left',
+                verticalAlign: 'middle',
+                rotate: 90,
+                fontSize: 12
+            },
+            itemStyle: {
+                color: '#d00000'
+            },
+            encode: {
+                x: 'Income',
+                y: 'Country',
+                label: 'Year',
+                itemName: 'Year',
+                tooltip: ['Country', 'Year', 'Income']
+            }
+        }]
     };
 
     myChart.setOption(option);


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org


[incubator-echarts-examples] 01/03: example: aggregate

Posted by su...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sushuang pushed a commit to branch next
in repository https://gitbox.apache.org/repos/asf/incubator-echarts-examples.git

commit e2cf1068c84faf72dfd828a9c35672a3cc1d4feb
Author: 100pah <su...@gmail.com>
AuthorDate: Thu Nov 19 19:48:46 2020 +0800

    example: aggregate
---
 public/data/asset/js/myTransform.js     | 697 +++++++++++++++++++++-----------
 public/data/data-transform-aggregate.js |  80 ++++
 2 files changed, 543 insertions(+), 234 deletions(-)

diff --git a/public/data/asset/js/myTransform.js b/public/data/asset/js/myTransform.js
index 1d72b52..a2f97b5 100644
--- a/public/data/asset/js/myTransform.js
+++ b/public/data/asset/js/myTransform.js
@@ -1,247 +1,476 @@
-/*
-* Licensed to the Apache Software Foundation (ASF) under one
-* or more contributor license agreements.  See the NOTICE file
-* distributed with this work for additional information
-* regarding copyright ownership.  The ASF licenses this file
-* to you under the Apache License, Version 2.0 (the
-* "License"); you may not use this file except in compliance
-* with the License.  You may obtain a copy of the License at
-*
-*   http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing,
-* software distributed under the License is distributed on an
-* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-* KIND, either express or implied.  See the License for the
-* specific language governing permissions and limitations
-* under the License.
-*/
-
-(function (exports) {
-
-    /**
-     * @usage
-     *
-     * ```js
-     * dataset: [{
-     *     source: [
-     *         ['aa', 'bb', 'cc', 'tag'],
-     *         [12, 0.33, 5200, 'AA'],
-     *         [21, 0.65, 7100, 'AA'],
-     *         [51, 0.15, 1100, 'BB'],
-     *         [71, 0.75, 9100, 'BB'],
-     *         ...
-     *     ]
-     * }, {
-     *     transform: {
-     *         type: 'my:aggregate',
-     *         config: {
-     *             resultDimensions: [
-     *                 // by default, use the same name with `from`.
-     *                 { from: 'aa', method: 'sum' },
-     *                 { from: 'bb', method: 'count' },
-     *                 { from: 'cc' }, // method by default: use the first value.
-     *                 { from: 'tag' }
-     *             ],
-     *             groupBy: 'tag'
-     *         }
-     *     }
-     *     // Then the result data will be:
-     *     // [
-     *     //     ['aa', 'bb', 'cc', 'tag'],
-     *     //     [12, 0.33, 5200, 'AA'],
-     *     //     [21, 0.65, 8100, 'BB'],
-     *     //     ...
-     *     // ]
-     * }]
-     * ```
-     */
-    var transform = {
-
-        type: 'myTransform:aggregate',
-
-        /**
-         * @param params
-         * @param params.config.resultDimensions Mandatory.
-         *        {
-         *            // Optional. The name of the result dimensions.
-         *            // If not provided, inherit the name from `from`.
-         *            name: DimensionName;
-         *            // Mandatory. `from` is used to reference dimension from `source`.
-         *            from: DimensionIndex | DimensionName;
-         *            // Optional. Aggregate method. Currently only these method supported.
-         *            // If not provided, use `'first'`.
-         *            method: 'sum' | 'count' | 'first';
-         *        }[]
-         * @param params.config.groupBy DimensionIndex | DimensionName Optional.
-         */
-        transform: function (params) {
-            var upstream = params.upstream;
-            var config = params.config;
-            var resultDimensionsConfig = config.resultDimensions;
-
-            var resultDimInfoList = [];
-            var resultDimensions = [];
-            for (var i = 0; i < resultDimensionsConfig.length; i++) {
-                var resultDimInfoConfig = resultDimensionsConfig[i];
-                var resultDimInfo = upstream.getDimensionInfo(resultDimInfoConfig.from);
-                assert(resultDimInfo, 'Can not find dimension by `from`: ' + resultDimInfoConfig.from);
-                resultDimInfo.method = resultDimInfoConfig.method;
-                resultDimInfoList.push(resultDimInfo);
-                if (resultDimInfoConfig.name != null) {
-                    resultDimInfo.name = resultDimInfoConfig.name;
-                }
-                resultDimensions.push(resultDimInfo.name);
-            }
-
-            var resultData = [];
-
-            var groupBy = config.groupBy;
-            var groupByDimInfo;
-            if (groupBy != null) {
-                var groupMap = {};
-                groupByDimInfo = upstream.getDimensionInfo(groupBy);
-                assert(groupByDimInfo, 'Can not find dimension by `groupBy`: ' + groupBy);
-
-                for (var dataIndex = 0, len = upstream.count(); dataIndex < len; dataIndex++) {
-                    var groupByVal = upstream.retrieveValue(dataIndex, groupByDimInfo.index);
-
-                    if (!groupMap.hasOwnProperty(groupByVal)) {
-                        var newLine = createLine(upstream, dataIndex, resultDimInfoList, groupByDimInfo, groupByVal);
-                        resultData.push(newLine);
-                        groupMap[groupByVal] = newLine;
-                    }
-                    else {
-                        var targetLine = groupMap[groupByVal];
-                        aggregateLine(upstream, dataIndex, targetLine, resultDimInfoList, groupByDimInfo);
-                    }
-                }
-            }
-            else {
-                var targetLine = createLine(upstream, 0, resultDimInfoList);
-                resultData.push(targetLine);
-                for (var dataIndex = 0, len = upstream.count(); dataIndex < len; dataIndex++) {
-                    aggregateLine(upstream, dataIndex, targetLine, resultDimInfoList);
-                }
-            }
-
-            return {
-                dimensions: resultDimensions,
-                data: resultData
-            };
+(function (global, factory) {
+  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (global = global || self, factory(global.myTransform = {}));
+})(this, function (exports) {
+  'use strict';
+
+  var transform = {
+    type: 'myTransform:id',
+    transform: function (params) {
+      var upstream = params.upstream;
+      var config = params.config;
+      var dimensionIndex = config.dimensionIndex;
+      var dimensionName = config.dimensionName;
+      var dimsDef = upstream.cloneAllDimensionInfo();
+      dimsDef[dimensionIndex] = dimensionName;
+      var data = upstream.cloneRawData();
+
+      for (var i = 0, len = data.length; i < len; i++) {
+        var line = data[i];
+        line[dimensionIndex] = i;
+      }
+
+      return {
+        dimensions: dimsDef,
+        data: data
+      };
+    }
+  };
+  var arrayProto = Array.prototype;
+  var nativeForEach = arrayProto.forEach;
+  var nativeSlice = arrayProto.slice;
+  var nativeMap = arrayProto.map;
+
+  var ctorFunction = function () {}.constructor;
+
+  var protoFunction = ctorFunction ? ctorFunction.prototype : null;
+
+  function each(arr, cb, context) {
+    if (!(arr && cb)) {
+      return;
+    }
+
+    if (arr.forEach && arr.forEach === nativeForEach) {
+      arr.forEach(cb, context);
+    } else if (arr.length === +arr.length) {
+      for (var i = 0, len = arr.length; i < len; i++) {
+        cb.call(context, arr[i], i, arr);
+      }
+    } else {
+      for (var key in arr) {
+        if (arr.hasOwnProperty(key)) {
+          cb.call(context, arr[key], key, arr);
         }
+      }
+    }
+  }
+
+  function map(arr, cb, context) {
+    if (!arr) {
+      return [];
+    }
+
+    if (!cb) {
+      return slice(arr);
+    }
+
+    if (arr.map && arr.map === nativeMap) {
+      return arr.map(cb, context);
+    } else {
+      var result = [];
+
+      for (var i = 0, len = arr.length; i < len; i++) {
+        result.push(cb.call(context, arr[i], i, arr));
+      }
+
+      return result;
+    }
+  }
+
+  function bindPolyfill(func, context) {
+    var args = [];
+
+    for (var _i = 2; _i < arguments.length; _i++) {
+      args[_i - 2] = arguments[_i];
+    }
+
+    return function () {
+      return func.apply(context, args.concat(nativeSlice.call(arguments)));
     };
+  }
 
-    function createLine(upstream, dataIndex, resultDimInfoList, groupByDimInfo, groupByVal) {
-        var newLine = [];
-        for (var j = 0; j < resultDimInfoList.length; j++) {
-            var resultDimInfo = resultDimInfoList[j];
-            var method = resultDimInfo.method;
-            newLine[j] = (groupByDimInfo && resultDimInfo.index === groupByDimInfo.index)
-                ? groupByVal
-                : (method === 'sum' || method === 'count')
-                ? 0
-                // By default, method: 'first'
-                : upstream.retrieveValue(dataIndex, resultDimInfo.index);
-        }
-        return newLine;
-    }
-
-    function aggregateLine(upstream, dataIndex, targetLine, resultDimInfoList, groupByDimInfo) {
-        for (var j = 0; j < resultDimInfoList.length; j++) {
-            var resultDimInfo = resultDimInfoList[j];
-            var method = resultDimInfo.method;
-            if (!groupByDimInfo || resultDimInfo.index !== groupByDimInfo.index) {
-                if (method === 'sum') {
-                    targetLine[j] += upstream.retrieveValue(dataIndex, resultDimInfo.index);
-                }
-                else if (method === 'count') {
-                    targetLine[j] += 1;
-                }
-            }
+  var bind = protoFunction && isFunction(protoFunction.bind) ? protoFunction.call.bind(protoFunction.bind) : bindPolyfill;
+
+  function isFunction(value) {
+    return typeof value === 'function';
+  }
+
+  function slice(arr) {
+    var args = [];
+
+    for (var _i = 1; _i < arguments.length; _i++) {
+      args[_i - 1] = arguments[_i];
+    }
+
+    return nativeSlice.apply(arr, args);
+  }
+
+  function assert(condition, message) {
+    if (!condition) {
+      throw new Error(message);
+    }
+  }
+
+  function hasOwn(own, prop) {
+    return own.hasOwnProperty(prop);
+  }
+
+  function quantile(ascArr, p) {
+    var H = (ascArr.length - 1) * p + 1;
+    var h = Math.floor(H);
+    var v = +ascArr[h - 1];
+    var e = H - h;
+    return e ? v + e * (ascArr[h] - v) : v;
+  }
+
+  var METHOD_INTERNAL = {
+    'SUM': true,
+    'COUNT': true,
+    'FIRST': true,
+    'AVERAGE': true,
+    'Q1': true,
+    'Q2': true,
+    'Q3': true,
+    'MIN': true,
+    'MAX': true
+  };
+  var METHOD_NEEDS_COLLECT = {
+    AVERAGE: ['COUNT']
+  };
+  var METHOD_NEEDS_GATHER_VALUES = {
+    Q1: true,
+    Q2: true,
+    Q3: true
+  };
+  var METHOD_ALIAS = {
+    MEDIAN: 'Q2'
+  };
+
+  var ResultDimInfoInternal = function () {
+    function ResultDimInfoInternal(index, indexInUpstream, method, name, needGatherValues) {
+      this.collectionInfoList = [];
+      this.gatheredValuesByGroup = {};
+      this.gatheredValuesNoGroup = [];
+      this.needGatherValues = false;
+      this._collectionInfoMap = {};
+      this.method = method;
+      this.name = name;
+      this.index = index;
+      this.indexInUpstream = indexInUpstream;
+      this.needGatherValues = needGatherValues;
+    }
+
+    ResultDimInfoInternal.prototype.addCollectionInfo = function (item) {
+      this._collectionInfoMap[item.method] = this.collectionInfoList.length;
+      this.collectionInfoList.push(item);
+    };
+
+    ResultDimInfoInternal.prototype.getCollectionInfo = function (method) {
+      return this.collectionInfoList[this._collectionInfoMap[method]];
+    };
+
+    ResultDimInfoInternal.prototype.gatherValue = function (groupByDimInfo, groupVal, value) {
+      value = +value;
+
+      if (groupByDimInfo) {
+        if (groupVal != null) {
+          var groupValStr = groupVal + '';
+          var values = this.gatheredValuesByGroup[groupValStr] || (this.gatheredValuesByGroup[groupValStr] = []);
+          values.push(value);
         }
+      } else {
+        this.gatheredValuesNoGroup.push(value);
+      }
+    };
+
+    return ResultDimInfoInternal;
+  }();
+
+  var transform$1 = {
+    type: 'myTransform:aggregate',
+    transform: function (params) {
+      var upstream = params.upstream;
+      var config = params.config;
+      var groupByDimInfo = prepareGroupByDimInfo(config, upstream);
+
+      var _a = prepareDimensions(config, upstream, groupByDimInfo),
+          finalResultDimInfoList = _a.finalResultDimInfoList,
+          collectionDimInfoList = _a.collectionDimInfoList;
+
+      var collectionResult;
+
+      if (collectionDimInfoList.length) {
+        collectionResult = travel(groupByDimInfo, upstream, collectionDimInfoList, createCollectionResultLine, updateCollectionResultLine);
+      }
+
+      each(collectionDimInfoList, function (dimInfo) {
+        dimInfo.__collectionResult = collectionResult;
+        asc(dimInfo.gatheredValuesNoGroup);
+        each(dimInfo.gatheredValuesByGroup, function (values) {
+          asc(values);
+        });
+      });
+      var finalResult = travel(groupByDimInfo, upstream, finalResultDimInfoList, createFinalResultLine, updateFinalResultLine);
+      return {
+        dimensions: map(finalResultDimInfoList, function (item) {
+          return item.name;
+        }),
+        data: finalResult.outList
+      };
     }
+  };
+
+  function prepareDimensions(config, upstream, groupByDimInfo) {
+    var resultDimensionsConfig = config.resultDimensions;
+    var finalResultDimInfoList = [];
+    var collectionDimInfoList = [];
+    var gIndexInLine = 0;
+
+    for (var i = 0; i < resultDimensionsConfig.length; i++) {
+      var resultDimInfoConfig = resultDimensionsConfig[i];
+      var dimInfoInUpstream = upstream.getDimensionInfo(resultDimInfoConfig.from);
+      assert(dimInfoInUpstream, 'Can not find dimension by `from`: ' + resultDimInfoConfig.from);
+      var rawMethod = resultDimInfoConfig.method;
+      assert(groupByDimInfo.index !== dimInfoInUpstream.index || rawMethod == null, "Dimension " + dimInfoInUpstream.name + " is the \"groupBy\" dimension, must not have any \"method\".");
+      var method = normalizeMethod(rawMethod);
+      assert(method, 'method is required');
+      var name_1 = resultDimInfoConfig.name != null ? resultDimInfoConfig.name : dimInfoInUpstream.name;
+      var finalResultDimInfo = new ResultDimInfoInternal(finalResultDimInfoList.length, dimInfoInUpstream.index, method, name_1, hasOwn(METHOD_NEEDS_GATHER_VALUES, method));
+      finalResultDimInfoList.push(finalResultDimInfo);
+      var needCollect = false;
 
-    function assert(cond, msg) {
-        if (!cond) {
-            throw new Error(msg || 'transition player error');
+      if (hasOwn(METHOD_NEEDS_COLLECT, method)) {
+        needCollect = true;
+        var collectionTargetMethods = METHOD_NEEDS_COLLECT[method];
+
+        for (var j = 0; j < collectionTargetMethods.length; j++) {
+          finalResultDimInfo.addCollectionInfo({
+            method: collectionTargetMethods[j],
+            indexInLine: gIndexInLine++
+          });
         }
+      }
+
+      if (hasOwn(METHOD_NEEDS_GATHER_VALUES, method)) {
+        needCollect = true;
+      }
+
+      if (needCollect) {
+        collectionDimInfoList.push(finalResultDimInfo);
+      }
     }
 
-    var myTransform = exports.myTransform = exports.myTransform || {};
-    myTransform.aggregate = transform;
-
-})(this);
-
-
-
-
-
-(function (exports) {
-
-    /**
-     * @usage
-     *
-     * ```js
-     * dataset: [{
-     *     source: [
-     *         ['aa', 'bb', 'cc', 'tag'],
-     *         [12, 0.33, 5200, 'AA'],
-     *         [21, 0.65, 8100, 'AA'],
-     *         ...
-     *     ]
-     * }, {
-     *     transform: {
-     *         type: 'my:id',
-     *         config: {
-     *             dimensionIndex: 4,
-     *             dimensionName: 'ID'
-     *         }
-     *     }
-     *     // Then the result data will be:
-     *     // [
-     *     //     ['aa', 'bb', 'cc', 'tag', 'ID'],
-     *     //     [12, 0.33, 5200, 'AA', 0],
-     *     //     [21, 0.65, 8100, 'BB', 1],
-     *     //     ...
-     *     // ]
-     * }]
-     * ```
-     */
-    var transform = {
-
-        type: 'myTransform:id',
-
-        /**
-         * @param params.config.dimensionIndex DimensionIndex
-         *        Mandatory. Specify where to put the new id dimension.
-         * @param params.config.dimensionName DimensionName
-         *        Optional. If not provided, left the dimension name not defined.
-         */
-        transform: function (params) {
-            var upstream = params.upstream;
-            var config = params.config;
-            var dimensionIndex = config.dimensionIndex;
-            var dimensionName = config.dimensionName;
-
-            var dimsDef = upstream.cloneAllDimensionInfo();
-            dimsDef[dimensionIndex] = dimensionName;
-
-            var data = upstream.cloneRawData();
-
-            for (var i = 0, len = data.length; i < len; i++) {
-                var line = data[i];
-                line[dimensionIndex] = i;
-            }
-
-            return {
-                dimensions: dimsDef,
-                data: upstream.data
-            };
+    return {
+      collectionDimInfoList: collectionDimInfoList,
+      finalResultDimInfoList: finalResultDimInfoList
+    };
+  }
+
+  function prepareGroupByDimInfo(config, upstream) {
+    var groupByConfig = config.groupBy;
+    var groupByDimInfo;
+
+    if (groupByConfig != null) {
+      groupByDimInfo = upstream.getDimensionInfo(groupByConfig);
+      assert(groupByDimInfo, 'Can not find dimension by `groupBy`: ' + groupByConfig);
+    }
+
+    return groupByDimInfo;
+  }
+
+  function travel(groupByDimInfo, upstream, resultDimInfoList, doCreate, doUpdate) {
+    var outList = [];
+    var mapByGroup;
+
+    if (groupByDimInfo) {
+      mapByGroup = {};
+
+      for (var dataIndex = 0, len = upstream.count(); dataIndex < len; dataIndex++) {
+        var groupByVal = upstream.retrieveValue(dataIndex, groupByDimInfo.index);
+
+        if (groupByVal == null) {
+          continue;
+        }
+
+        var groupByValStr = groupByVal + '';
+
+        if (!hasOwn(mapByGroup, groupByValStr)) {
+          var newLine = doCreate(upstream, dataIndex, resultDimInfoList, groupByDimInfo, groupByVal);
+          outList.push(newLine);
+          mapByGroup[groupByValStr] = newLine;
+        } else {
+          var targetLine = mapByGroup[groupByValStr];
+          doUpdate(upstream, dataIndex, targetLine, resultDimInfoList, groupByDimInfo, groupByVal);
         }
+      }
+    } else {
+      var targetLine = doCreate(upstream, 0, resultDimInfoList);
+      outList.push(targetLine);
+
+      for (var dataIndex = 1, len = upstream.count(); dataIndex < len; dataIndex++) {
+        doUpdate(upstream, dataIndex, targetLine, resultDimInfoList);
+      }
+    }
+
+    return {
+      mapByGroup: mapByGroup,
+      outList: outList
     };
+  }
+
+  function normalizeMethod(method) {
+    if (method == null) {
+      return 'FIRST';
+    }
+
+    var methodInternal = method.toUpperCase();
+    methodInternal = hasOwn(METHOD_ALIAS, methodInternal) ? METHOD_ALIAS[methodInternal] : methodInternal;
+    assert(hasOwn(METHOD_INTERNAL, methodInternal), "Illegal method " + method + ".");
+    return methodInternal;
+  }
+
+  var createCollectionResultLine = function (upstream, dataIndex, collectionDimInfoList, groupByDimInfo, groupByVal) {
+    var newLine = [];
+
+    for (var i = 0; i < collectionDimInfoList.length; i++) {
+      var dimInfo = collectionDimInfoList[i];
+      var collectionInfoList = dimInfo.collectionInfoList;
+
+      for (var j = 0; j < collectionInfoList.length; j++) {
+        var collectionInfo = collectionInfoList[j];
+        newLine[collectionInfo.indexInLine] = +lineCreator[collectionInfo.method](upstream, dataIndex, dimInfo, groupByDimInfo, groupByVal);
+      }
+
+      if (dimInfo.needGatherValues) {
+        var val = upstream.retrieveValue(dataIndex, dimInfo.indexInUpstream);
+        dimInfo.gatherValue(groupByDimInfo, groupByVal, val);
+      }
+    }
+
+    return newLine;
+  };
+
+  var updateCollectionResultLine = function (upstream, dataIndex, targetLine, collectionDimInfoList, groupByDimInfo, groupByVal) {
+    for (var i = 0; i < collectionDimInfoList.length; i++) {
+      var dimInfo = collectionDimInfoList[i];
+      var collectionInfoList = dimInfo.collectionInfoList;
+
+      for (var j = 0; j < collectionInfoList.length; j++) {
+        var collectionInfo = collectionInfoList[j];
+        var indexInLine = collectionInfo.indexInLine;
+        targetLine[indexInLine] = +lineUpdater[collectionInfo.method](targetLine[indexInLine], upstream, dataIndex, dimInfo, groupByDimInfo, groupByVal);
+      }
+
+      if (dimInfo.needGatherValues) {
+        var val = upstream.retrieveValue(dataIndex, dimInfo.indexInUpstream);
+        dimInfo.gatherValue(groupByDimInfo, groupByVal, val);
+      }
+    }
+  };
+
+  var createFinalResultLine = function (upstream, dataIndex, finalResultDimInfoList, groupByDimInfo, groupByVal) {
+    var newLine = [];
+
+    for (var i = 0; i < finalResultDimInfoList.length; i++) {
+      var dimInfo = finalResultDimInfoList[i];
+      var method = dimInfo.method;
+      newLine[i] = isGroupByDimension(groupByDimInfo, dimInfo) ? groupByVal : lineCreator[method](upstream, dataIndex, dimInfo, groupByDimInfo, groupByVal);
+    }
+
+    return newLine;
+  };
+
+  var updateFinalResultLine = function (upstream, dataIndex, targetLine, finalResultDimInfoList, groupByDimInfo, groupByVal) {
+    for (var i = 0; i < finalResultDimInfoList.length; i++) {
+      var dimInfo = finalResultDimInfoList[i];
+
+      if (isGroupByDimension(groupByDimInfo, dimInfo)) {
+        continue;
+      }
+
+      var method = dimInfo.method;
+      targetLine[i] = lineUpdater[method](targetLine[i], upstream, dataIndex, dimInfo, groupByDimInfo, groupByVal);
+    }
+  };
+
+  function isGroupByDimension(groupByDimInfo, targetDimInfo) {
+    return groupByDimInfo && targetDimInfo.indexInUpstream === groupByDimInfo.index;
+  }
+
+  function asc(list) {
+    list.sort(function (a, b) {
+      return a - b;
+    });
+  }
+
+  var lineCreator = {
+    'SUM': function () {
+      return 0;
+    },
+    'COUNT': function () {
+      return 1;
+    },
+    'FIRST': function (upstream, dataIndex, dimInfo) {
+      return upstream.retrieveValue(dataIndex, dimInfo.indexInUpstream);
+    },
+    'MIN': function (upstream, dataIndex, dimInfo) {
+      return upstream.retrieveValue(dataIndex, dimInfo.indexInUpstream);
+    },
+    'MAX': function (upstream, dataIndex, dimInfo) {
+      return upstream.retrieveValue(dataIndex, dimInfo.indexInUpstream);
+    },
+    'AVERAGE': function (upstream, dataIndex, dimInfo, groupByDimInfo, groupByVal) {
+      var collectLine = groupByDimInfo ? dimInfo.__collectionResult.mapByGroup[groupByVal + ''] : dimInfo.__collectionResult.outList[0];
+      return upstream.retrieveValue(dataIndex, dimInfo.indexInUpstream) / collectLine[dimInfo.getCollectionInfo('COUNT').indexInLine];
+    },
+    'Q1': function (upstream, dataIndex, dimInfo, groupByDimInfo, groupByVal) {
+      return lineCreatorForQ(0.25, dimInfo, groupByDimInfo, groupByVal);
+    },
+    'Q2': function (upstream, dataIndex, dimInfo, groupByDimInfo, groupByVal) {
+      return lineCreatorForQ(0.5, dimInfo, groupByDimInfo, groupByVal);
+    },
+    'Q3': function (upstream, dataIndex, dimInfo, groupByDimInfo, groupByVal) {
+      return lineCreatorForQ(0.75, dimInfo, groupByDimInfo, groupByVal);
+    }
+  };
+  var lineUpdater = {
+    'SUM': function (val, upstream, dataIndex, dimInfo) {
+      return val + upstream.retrieveValue(dataIndex, dimInfo.indexInUpstream);
+    },
+    'COUNT': function (val) {
+      return val + 1;
+    },
+    'FIRST': function (val) {
+      return val;
+    },
+    'MIN': function (val, upstream, dataIndex, dimInfo) {
+      return Math.min(val, upstream.retrieveValue(dataIndex, dimInfo.indexInUpstream));
+    },
+    'MAX': function (val, upstream, dataIndex, dimInfo) {
+      return Math.max(val, upstream.retrieveValue(dataIndex, dimInfo.indexInUpstream));
+    },
+    'AVERAGE': function (val, upstream, dataIndex, dimInfo, groupByDimInfo, groupByVal) {
+      var collectLine = groupByDimInfo ? dimInfo.__collectionResult.mapByGroup[groupByVal + ''] : dimInfo.__collectionResult.outList[0];
+      return val + upstream.retrieveValue(dataIndex, dimInfo.indexInUpstream) / collectLine[dimInfo.getCollectionInfo('COUNT').indexInLine];
+    },
+    'Q1': function (val, upstream, dataIndex, dimInfo) {
+      return val;
+    },
+    'Q2': function (val, upstream, dataIndex, dimInfo) {
+      return val;
+    },
+    'Q3': function (val, upstream, dataIndex, dimInfo) {
+      return val;
+    }
+  };
 
-    var myTransform = exports.myTransform = exports.myTransform || {};
-    myTransform.id = transform;
+  function lineCreatorForQ(percent, dimInfo, groupByDimInfo, groupByVal) {
+    var gatheredValues = groupByDimInfo ? dimInfo.gatheredValuesByGroup[groupByVal + ''] : dimInfo.gatheredValuesNoGroup;
+    return quantile(gatheredValues, percent);
+  }
 
-})(this);
+  exports.aggregate = transform$1;
+  exports.id = transform;
+  Object.defineProperty(exports, '__esModule', {
+    value: true
+  });
+});
\ No newline at end of file
diff --git a/public/data/data-transform-aggregate.js b/public/data/data-transform-aggregate.js
new file mode 100644
index 0000000..4a8c467
--- /dev/null
+++ b/public/data/data-transform-aggregate.js
@@ -0,0 +1,80 @@
+/*
+title: Data Transform Simple Aggregate
+category: bar
+titleCN: 简单的数据聚合
+difficulty: 3
+*/
+
+$.when(
+    $.get(ROOT_PATH + '/data/asset/data/life-expectancy-table.json'),
+    $.getScript(ROOT_PATH + '/data/asset/js/myTransform.js')
+).done(function (res) {
+    run(res[0]);
+});
+
+function run(_rawData) {
+
+    echarts.registerTransform(window.myTransform.aggregate);
+
+    option = {
+        dataset: [{
+            id: 'raw',
+            source: _rawData
+        }, {
+            id: 'income_aggregate',
+            fromDatasetId: 'raw',
+            transform: [{
+                type: 'filter',
+                config: {
+                    dimension: 'Year', gte: 1950
+                }
+            }, {
+                type: 'myTransform:aggregate',
+                config: {
+                    resultDimensions: [
+                        { name: 'min', from: 'Income', method: 'min' },
+                        { name: 'Q1', from: 'Income', method: 'Q1' },
+                        { name: 'median', from: 'Income', method: 'median' },
+                        { name: 'Q3', from: 'Income', method: 'Q3' },
+                        { name: 'max', from: 'Income', method: 'max' },
+                        { name: 'Country', from: 'Country' }
+                    ],
+                    groupBy: 'Country'
+                }
+            }, {
+                type: 'sort',
+                config: {
+                    dimension: 'max',
+                    order: 'asc'
+                }
+            }]
+        }],
+        title: {
+            text: 'Income since 1950'
+        },
+        tooltip: {
+            trigger: 'axis'
+        },
+        xAxis: {
+            name: 'Income',
+            nameLocation: 'middle',
+            nameGap: 30
+        },
+        yAxis: {
+            type: 'category'
+        },
+        series: {
+            type: 'boxplot',
+            datasetId: 'income_aggregate',
+            encode: {
+                x: ['min', 'Q1', 'median', 'Q3', 'max'],
+                y: 'Country',
+                itemName: ['Country'],
+                tooltip: ['min', 'Q1', 'median', 'Q3', 'max']
+            }
+        }
+    };
+
+    myChart.setOption(option);
+
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org