You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@echarts.apache.org by GitBox <gi...@apache.org> on 2021/08/03 08:17:28 UTC

[GitHub] [echarts] 100pah commented on a change in pull request #15355: dataset: fix dataset performance drops signifcantly on high dimensions data.

100pah commented on a change in pull request #15355:
URL: https://github.com/apache/echarts/pull/15355#discussion_r681539646



##########
File path: src/data/helper/createDimensions.ts
##########
@@ -44,33 +51,350 @@ export type CoordDimensionDefinitionLoose = CoordDimensionDefinition['name'] | C
 
 export type CreateDimensionsParams = {
     coordDimensions?: CoordDimensionDefinitionLoose[],
+    /**
+     * Will use `source.dimensionsDefine` if not given.
+     */
     dimensionsDefine?: DimensionDefinitionLoose[],
+    /**
+     * Will use `source.encodeDefine` if not given.
+     */
     encodeDefine?: HashMap<OptionEncodeValue, DimensionName> | OptionEncode,
     dimensionsCount?: number,
+    /**
+     * Make default encode if user not specified.
+     */
     encodeDefaulter?: EncodeDefaulter,
     generateCoord?: string,
-    generateCoordCount?: number
+    generateCoordCount?: number,
+
+    /**
+     * If omit unused dimension
+     * Used to improve the performance on high dimension data.
+     */
+    omitUnusedDimensions?: boolean
 };
 
 /**
- * @param opt.coordDimensions
- * @param opt.dimensionsDefine By default `source.dimensionsDefine` Overwrite source define.
- * @param opt.encodeDefine By default `source.encodeDefine` Overwrite source define.
- * @param opt.encodeDefaulter Make default encode if user not specified.
+ * This method builds the relationship between:
+ * + "what the coord sys or series requires (see `coordDimensions`)",
+ * + "what the user defines (in `encode` and `dimensions`, see `opt.dimensionsDefine` and `opt.encodeDefine`)"
+ * + "what the data source provids (see `source`)".
+ *
+ * Some guess strategy will be adapted if user does not define something.
+ * If no 'value' dimension specified, the first no-named dimension will be
+ * named as 'value'.
  */
 export default function createDimensions(
     // TODO: TYPE completeDimensions type
-    source: Source | List | OptionSourceData,
+    source: Source | SeriesData | OptionSourceData | DataStorage,
     opt?: CreateDimensionsParams
 ): DataDimensionInfo[] {
+    if (source instanceof DataStorage) {
+        source = source.getSource();
+    }
+    else if (source instanceof SeriesData) {
+        source = source.getStorage().getSource();
+    }
+    else if (!isSourceInstance(source)) {
+        source = createSourceFromSeriesDataOption(source as OptionSourceData);
+    }
+
     opt = opt || {};
-    return completeDimensions(opt.coordDimensions || [], source, {
-        // FIXME:TS detect whether source then call `.dimensionsDefine` and `.encodeDefine`?
-        dimsDef: opt.dimensionsDefine || (source as Source).dimensionsDefine,
-        encodeDef: opt.encodeDefine || (source as Source).encodeDefine,
-        dimCount: opt.dimensionsCount,
-        encodeDefaulter: opt.encodeDefaulter,
-        generateCoord: opt.generateCoord,
-        generateCoordCount: opt.generateCoordCount
+
+    const sysDims = opt.coordDimensions || [];
+    const dimsDef = opt.dimensionsDefine || source.dimensionsDefine || [];
+    const coordDimNameMap = createHashMap<true, DimensionName>();
+    const result: DataDimensionInfo[] = [];
+    const omitUnusedDimensions = opt.omitUnusedDimensions;
+    const isUsingSourceDimensionsDef = dimsDef === source.dimensionsDefine;
+    // Try to cache the dimNameMap if the dimensionsDefine is from source.
+    const canCacheDimNameMap = (isUsingSourceDimensionsDef && omitUnusedDimensions);
+    let dataDimNameMap = canCacheDimNameMap && inner(source).dimNameMap;
+    let needsUpdateDataDimNameMap = false;
+    if (!dataDimNameMap) {
+        needsUpdateDataDimNameMap = true;
+        dataDimNameMap = createHashMap<DimensionIndex, DimensionName>();
+    }
+
+    const dimCount = getDimCount(source, sysDims, dimsDef, opt.dimensionsCount);
+
+    let encodeDef = opt.encodeDefine;
+    if (!encodeDef && opt.encodeDefaulter) {
+        encodeDef = opt.encodeDefaulter(source, dimCount);
+    }
+    const encodeDefMap = createHashMap<DimensionIndex[] | false, DimensionName>(encodeDef as any);
+
+    const indicesMap = new CtorInt32Array(dimCount);
+    for (let i = 0; i < indicesMap.length; i++) {
+        indicesMap[i] = -1;
+    }
+    function getResultItem(dimIdx: number) {
+        const idx = indicesMap[dimIdx];
+        if (idx < 0) {
+            const dimDefItemRaw = dimsDef[dimIdx];
+            const dimDefItem = isObject(dimDefItemRaw) ? dimDefItemRaw : { name: dimDefItemRaw };
+            const resultItem = new DataDimensionInfo();
+            const userDimName = dimDefItem.name;
+            if (dataDimNameMap.get(userDimName) != null) {
+                resultItem.name = resultItem.displayName = userDimName;
+            }
+            dimDefItem.type != null && (resultItem.type = dimDefItem.type);
+            dimDefItem.displayName != null && (resultItem.displayName = dimDefItem.displayName);
+            const newIdx = result.length;
+            indicesMap[dimIdx] = newIdx;
+            result.push(resultItem);
+            return resultItem;
+        }
+        return result[idx];
+    }
+
+    if (needsUpdateDataDimNameMap) {
+        for (let i = 0; i < dimCount; i++) {
+            const dimDefItemRaw = dimsDef[i];
+            const userDimName = isObject(dimDefItemRaw) ? dimDefItemRaw.name : dimDefItemRaw;
+            // Name will be applied later for avoiding duplication.
+            if (userDimName != null && dataDimNameMap.get(userDimName) == null) {
+                // Only if `series.dimensions` is defined in option
+                // displayName, will be set, and dimension will be diplayed vertically in
+                // tooltip by default.
+                dataDimNameMap.set(userDimName, i);
+            }
+        }
+        if (canCacheDimNameMap) {
+            inner(source).dimNameMap = dataDimNameMap;
+        }
+    }
+    if (!omitUnusedDimensions) {
+        for (let i = 0; i < dimCount; i++) {
+            getResultItem(i);
+        }
+    }
+
+    // Set `coordDim` and `coordDimIndex` by `encodeDefMap` and normalize `encodeDefMap`.
+    encodeDefMap.each(function (dataDimsRaw, coordDim) {
+        const dataDims = normalizeToArray(dataDimsRaw as []).slice();
+
+        // Note: It is allowed that `dataDims.length` is `0`, e.g., options is
+        // `{encode: {x: -1, y: 1}}`. Should not filter anything in
+        // this case.
+        if (dataDims.length === 1 && !isString(dataDims[0]) && dataDims[0] < 0) {
+            encodeDefMap.set(coordDim, false);
+            return;
+        }
+
+        const validDataDims = encodeDefMap.set(coordDim, []) as DimensionIndex[];
+        each(dataDims, function (resultDimIdxOrName, idx) {
+            // The input resultDimIdx can be dim name or index.
+            const resultDimIdx = isString(resultDimIdxOrName)
+                ? dataDimNameMap.get(resultDimIdxOrName)
+                : resultDimIdxOrName;
+            if (resultDimIdx != null && resultDimIdx < dimCount) {
+                validDataDims[idx] = resultDimIdx;
+                applyDim(getResultItem(resultDimIdx), coordDim, idx);
+            }
+        });
+    });
+
+    // Apply templetes and default order from `sysDims`.
+    let availDimIdx = 0;
+    each(sysDims, function (sysDimItemRaw) {
+        let coordDim: DimensionName;
+        let sysDimItemDimsDef: CoordDimensionDefinition['dimsDef'];
+        let sysDimItemOtherDims: CoordDimensionDefinition['otherDims'];
+        let sysDimItem: CoordDimensionDefinition;
+        if (isString(sysDimItemRaw)) {
+            coordDim = sysDimItemRaw;
+            sysDimItem = {} as CoordDimensionDefinition;
+        }
+        else {
+            sysDimItem = sysDimItemRaw;
+            coordDim = sysDimItem.name;
+            const ordinalMeta = sysDimItem.ordinalMeta;
+            sysDimItem.ordinalMeta = null;
+            sysDimItem = extend({}, sysDimItem);
+            sysDimItem.ordinalMeta = ordinalMeta;
+            // `coordDimIndex` should not be set directly.
+            sysDimItemDimsDef = sysDimItem.dimsDef;
+            sysDimItemOtherDims = sysDimItem.otherDims;
+            sysDimItem.name = sysDimItem.coordDim = sysDimItem.coordDimIndex =
+                sysDimItem.dimsDef = sysDimItem.otherDims = null;
+        }
+
+        let dataDims = encodeDefMap.get(coordDim);
+
+        // negative resultDimIdx means no need to mapping.
+        if (dataDims === false) {
+            return;
+        }
+
+        dataDims = normalizeToArray(dataDims);
+
+        // dimensions provides default dim sequences.
+        if (!dataDims.length) {
+            for (let i = 0; i < (sysDimItemDimsDef && sysDimItemDimsDef.length || 1); i++) {
+                while (availDimIdx < dimCount && getResultItem(availDimIdx).coordDim != null) {
+                    availDimIdx++;
+                }
+                availDimIdx < dimCount && dataDims.push(availDimIdx++);
+            }
+        }
+
+        // Apply templates.
+        each(dataDims, function (resultDimIdx, coordDimIndex) {
+            const resultItem = getResultItem(resultDimIdx);
+            // Coordinate system has a higher priority on dim type than source.
+            if (isUsingSourceDimensionsDef && sysDimItem.type != null) {
+                resultItem.type = sysDimItem.type;
+            }
+            applyDim(defaults(resultItem, sysDimItem), coordDim, coordDimIndex);
+            if (resultItem.name == null && sysDimItemDimsDef) {
+                let sysDimItemDimsDefItem = sysDimItemDimsDef[coordDimIndex];
+                !isObject(sysDimItemDimsDefItem) && (sysDimItemDimsDefItem = {name: sysDimItemDimsDefItem});
+                resultItem.name = resultItem.displayName = sysDimItemDimsDefItem.name;
+                resultItem.defaultTooltip = sysDimItemDimsDefItem.defaultTooltip;
+            }
+            // FIXME refactor, currently only used in case: {otherDims: {tooltip: false}}
+            sysDimItemOtherDims && defaults(resultItem.otherDims, sysDimItemOtherDims);
+        });
     });
+
+    function applyDim(resultItem: DataDimensionInfo, coordDim: DimensionName, coordDimIndex: DimensionIndex) {
+        if (VISUAL_DIMENSIONS.get(coordDim as keyof DataVisualDimensions) != null) {
+            resultItem.otherDims[coordDim as keyof DataVisualDimensions] = coordDimIndex;
+        }
+        else {
+            resultItem.coordDim = coordDim;
+            resultItem.coordDimIndex = coordDimIndex;
+            coordDimNameMap.set(coordDim, true);
+        }
+    }
+
+    // Make sure the first extra dim is 'value'.
+    const generateCoord = opt.generateCoord;
+    let generateCoordCount = opt.generateCoordCount;
+    const fromZero = generateCoordCount != null;
+    generateCoordCount = generateCoord ? (generateCoordCount || 1) : 0;
+    const extra = generateCoord || 'value';
+    let coordDimNameAutoIdx = 0;
+    let dataDimNameAutoIdx = 0;
+
+    // Set dim `name` and other `coordDim` and other props.
+    if (!omitUnusedDimensions) {
+        for (let resultDimIdx = 0; resultDimIdx < dimCount; resultDimIdx++) {
+            const resultItem = getResultItem(resultDimIdx);
+            const coordDim = resultItem.coordDim;
+
+            if (coordDim == null) {
+                const res = genName(
+                    extra, coordDimNameMap, coordDimNameAutoIdx, fromZero
+                );
+                coordDimNameAutoIdx = res.autoIdx;
+                resultItem.coordDim = res.name;
+                resultItem.coordDimIndex = 0;
+                // Series specified generateCoord is using out.
+                if (!generateCoord || generateCoordCount <= 0) {
+                    resultItem.isExtraCoord = true;
+                }
+                generateCoordCount--;
+            }
+
+            if (resultItem.name == null) {
+                const res = genName(
+                    resultItem.coordDim, dataDimNameMap, dataDimNameAutoIdx, false
+                );
+                resultItem.name = res.name;
+                dataDimNameAutoIdx = res.autoIdx;
+            }
+
+            if (resultItem.type == null
+                && (
+                    guessOrdinal(source, resultDimIdx) === BE_ORDINAL.Must
+                    // Consider the case:
+                    // {
+                    //    dataset: {source: [
+                    //        ['2001', 123],
+                    //        ['2002', 456],
+                    //        ...
+                    //        ['The others', 987],
+                    //    ]},
+                    //    series: {type: 'pie'}
+                    // }
+                    // The first colum should better be treated as a "ordinal" although it
+                    // might not able to be detected as an "ordinal" by `guessOrdinal`.
+                    || (resultItem.isExtraCoord
+                        && (resultItem.otherDims.itemName != null
+                            || resultItem.otherDims.seriesName != null
+                        )
+                    )
+                )
+            ) {
+                resultItem.type = 'ordinal';
+            }
+        }
+        return result;
+    }
+    else {
+        // Sort dimensions
+        const toSort = [];
+        for (let i = 0; i < indicesMap.length; i++) {
+            if (indicesMap[i] >= 0) {
+                toSort.push({ i, o: result[indicesMap[i]]});
+            }
+        }
+        toSort.sort((a, b) => a.i - b.i);

Review comment:
       With the same option above, 
   
   In 5.1.2: 
   <img width="301" alt="Screen Shot 2021-08-03 at 4 14 20 PM" src="https://user-images.githubusercontent.com/1956569/127981913-1f307c09-a3a9-49db-820d-915625c86bb8.png">
   
   But in the newest commit 
   ae9226ecc01eb60e5662f34c8bcf275dbece17d8 [ae9226ecc]
   July 27, 2021 at 5:16:25 PM GMT+8
   
   <img width="235" alt="Screen Shot 2021-08-03 at 4 16 21 PM" src="https://user-images.githubusercontent.com/1956569/127982144-e472f27a-ac12-4d35-8936-c68eacf9c280.png">
   
   

##########
File path: src/data/helper/createDimensions.ts
##########
@@ -44,33 +51,350 @@ export type CoordDimensionDefinitionLoose = CoordDimensionDefinition['name'] | C
 
 export type CreateDimensionsParams = {
     coordDimensions?: CoordDimensionDefinitionLoose[],
+    /**
+     * Will use `source.dimensionsDefine` if not given.
+     */
     dimensionsDefine?: DimensionDefinitionLoose[],
+    /**
+     * Will use `source.encodeDefine` if not given.
+     */
     encodeDefine?: HashMap<OptionEncodeValue, DimensionName> | OptionEncode,
     dimensionsCount?: number,
+    /**
+     * Make default encode if user not specified.
+     */
     encodeDefaulter?: EncodeDefaulter,
     generateCoord?: string,
-    generateCoordCount?: number
+    generateCoordCount?: number,
+
+    /**
+     * If omit unused dimension
+     * Used to improve the performance on high dimension data.
+     */
+    omitUnusedDimensions?: boolean
 };
 
 /**
- * @param opt.coordDimensions
- * @param opt.dimensionsDefine By default `source.dimensionsDefine` Overwrite source define.
- * @param opt.encodeDefine By default `source.encodeDefine` Overwrite source define.
- * @param opt.encodeDefaulter Make default encode if user not specified.
+ * This method builds the relationship between:
+ * + "what the coord sys or series requires (see `coordDimensions`)",
+ * + "what the user defines (in `encode` and `dimensions`, see `opt.dimensionsDefine` and `opt.encodeDefine`)"
+ * + "what the data source provids (see `source`)".
+ *
+ * Some guess strategy will be adapted if user does not define something.
+ * If no 'value' dimension specified, the first no-named dimension will be
+ * named as 'value'.
  */
 export default function createDimensions(
     // TODO: TYPE completeDimensions type
-    source: Source | List | OptionSourceData,
+    source: Source | SeriesData | OptionSourceData | DataStorage,
     opt?: CreateDimensionsParams
 ): DataDimensionInfo[] {
+    if (source instanceof DataStorage) {
+        source = source.getSource();
+    }
+    else if (source instanceof SeriesData) {
+        source = source.getStorage().getSource();
+    }
+    else if (!isSourceInstance(source)) {
+        source = createSourceFromSeriesDataOption(source as OptionSourceData);
+    }
+
     opt = opt || {};
-    return completeDimensions(opt.coordDimensions || [], source, {
-        // FIXME:TS detect whether source then call `.dimensionsDefine` and `.encodeDefine`?
-        dimsDef: opt.dimensionsDefine || (source as Source).dimensionsDefine,
-        encodeDef: opt.encodeDefine || (source as Source).encodeDefine,
-        dimCount: opt.dimensionsCount,
-        encodeDefaulter: opt.encodeDefaulter,
-        generateCoord: opt.generateCoord,
-        generateCoordCount: opt.generateCoordCount
+
+    const sysDims = opt.coordDimensions || [];
+    const dimsDef = opt.dimensionsDefine || source.dimensionsDefine || [];
+    const coordDimNameMap = createHashMap<true, DimensionName>();
+    const result: DataDimensionInfo[] = [];
+    const omitUnusedDimensions = opt.omitUnusedDimensions;
+    const isUsingSourceDimensionsDef = dimsDef === source.dimensionsDefine;
+    // Try to cache the dimNameMap if the dimensionsDefine is from source.
+    const canCacheDimNameMap = (isUsingSourceDimensionsDef && omitUnusedDimensions);
+    let dataDimNameMap = canCacheDimNameMap && inner(source).dimNameMap;
+    let needsUpdateDataDimNameMap = false;
+    if (!dataDimNameMap) {
+        needsUpdateDataDimNameMap = true;
+        dataDimNameMap = createHashMap<DimensionIndex, DimensionName>();
+    }
+
+    const dimCount = getDimCount(source, sysDims, dimsDef, opt.dimensionsCount);
+
+    let encodeDef = opt.encodeDefine;
+    if (!encodeDef && opt.encodeDefaulter) {
+        encodeDef = opt.encodeDefaulter(source, dimCount);
+    }
+    const encodeDefMap = createHashMap<DimensionIndex[] | false, DimensionName>(encodeDef as any);
+
+    const indicesMap = new CtorInt32Array(dimCount);
+    for (let i = 0; i < indicesMap.length; i++) {
+        indicesMap[i] = -1;
+    }
+    function getResultItem(dimIdx: number) {
+        const idx = indicesMap[dimIdx];
+        if (idx < 0) {
+            const dimDefItemRaw = dimsDef[dimIdx];
+            const dimDefItem = isObject(dimDefItemRaw) ? dimDefItemRaw : { name: dimDefItemRaw };
+            const resultItem = new DataDimensionInfo();
+            const userDimName = dimDefItem.name;
+            if (dataDimNameMap.get(userDimName) != null) {
+                resultItem.name = resultItem.displayName = userDimName;
+            }
+            dimDefItem.type != null && (resultItem.type = dimDefItem.type);
+            dimDefItem.displayName != null && (resultItem.displayName = dimDefItem.displayName);
+            const newIdx = result.length;
+            indicesMap[dimIdx] = newIdx;
+            result.push(resultItem);
+            return resultItem;
+        }
+        return result[idx];
+    }
+
+    if (needsUpdateDataDimNameMap) {
+        for (let i = 0; i < dimCount; i++) {
+            const dimDefItemRaw = dimsDef[i];
+            const userDimName = isObject(dimDefItemRaw) ? dimDefItemRaw.name : dimDefItemRaw;
+            // Name will be applied later for avoiding duplication.
+            if (userDimName != null && dataDimNameMap.get(userDimName) == null) {
+                // Only if `series.dimensions` is defined in option
+                // displayName, will be set, and dimension will be diplayed vertically in
+                // tooltip by default.
+                dataDimNameMap.set(userDimName, i);
+            }
+        }
+        if (canCacheDimNameMap) {
+            inner(source).dimNameMap = dataDimNameMap;
+        }
+    }
+    if (!omitUnusedDimensions) {
+        for (let i = 0; i < dimCount; i++) {
+            getResultItem(i);
+        }
+    }
+
+    // Set `coordDim` and `coordDimIndex` by `encodeDefMap` and normalize `encodeDefMap`.
+    encodeDefMap.each(function (dataDimsRaw, coordDim) {
+        const dataDims = normalizeToArray(dataDimsRaw as []).slice();
+
+        // Note: It is allowed that `dataDims.length` is `0`, e.g., options is
+        // `{encode: {x: -1, y: 1}}`. Should not filter anything in
+        // this case.
+        if (dataDims.length === 1 && !isString(dataDims[0]) && dataDims[0] < 0) {
+            encodeDefMap.set(coordDim, false);
+            return;
+        }
+
+        const validDataDims = encodeDefMap.set(coordDim, []) as DimensionIndex[];
+        each(dataDims, function (resultDimIdxOrName, idx) {
+            // The input resultDimIdx can be dim name or index.
+            const resultDimIdx = isString(resultDimIdxOrName)
+                ? dataDimNameMap.get(resultDimIdxOrName)
+                : resultDimIdxOrName;
+            if (resultDimIdx != null && resultDimIdx < dimCount) {
+                validDataDims[idx] = resultDimIdx;
+                applyDim(getResultItem(resultDimIdx), coordDim, idx);
+            }
+        });
+    });
+
+    // Apply templetes and default order from `sysDims`.
+    let availDimIdx = 0;
+    each(sysDims, function (sysDimItemRaw) {
+        let coordDim: DimensionName;
+        let sysDimItemDimsDef: CoordDimensionDefinition['dimsDef'];
+        let sysDimItemOtherDims: CoordDimensionDefinition['otherDims'];
+        let sysDimItem: CoordDimensionDefinition;
+        if (isString(sysDimItemRaw)) {
+            coordDim = sysDimItemRaw;
+            sysDimItem = {} as CoordDimensionDefinition;
+        }
+        else {
+            sysDimItem = sysDimItemRaw;
+            coordDim = sysDimItem.name;
+            const ordinalMeta = sysDimItem.ordinalMeta;
+            sysDimItem.ordinalMeta = null;
+            sysDimItem = extend({}, sysDimItem);
+            sysDimItem.ordinalMeta = ordinalMeta;
+            // `coordDimIndex` should not be set directly.
+            sysDimItemDimsDef = sysDimItem.dimsDef;
+            sysDimItemOtherDims = sysDimItem.otherDims;
+            sysDimItem.name = sysDimItem.coordDim = sysDimItem.coordDimIndex =
+                sysDimItem.dimsDef = sysDimItem.otherDims = null;
+        }
+
+        let dataDims = encodeDefMap.get(coordDim);
+
+        // negative resultDimIdx means no need to mapping.
+        if (dataDims === false) {
+            return;
+        }
+
+        dataDims = normalizeToArray(dataDims);
+
+        // dimensions provides default dim sequences.
+        if (!dataDims.length) {
+            for (let i = 0; i < (sysDimItemDimsDef && sysDimItemDimsDef.length || 1); i++) {
+                while (availDimIdx < dimCount && getResultItem(availDimIdx).coordDim != null) {
+                    availDimIdx++;
+                }
+                availDimIdx < dimCount && dataDims.push(availDimIdx++);
+            }
+        }
+
+        // Apply templates.
+        each(dataDims, function (resultDimIdx, coordDimIndex) {
+            const resultItem = getResultItem(resultDimIdx);
+            // Coordinate system has a higher priority on dim type than source.
+            if (isUsingSourceDimensionsDef && sysDimItem.type != null) {
+                resultItem.type = sysDimItem.type;
+            }
+            applyDim(defaults(resultItem, sysDimItem), coordDim, coordDimIndex);
+            if (resultItem.name == null && sysDimItemDimsDef) {
+                let sysDimItemDimsDefItem = sysDimItemDimsDef[coordDimIndex];
+                !isObject(sysDimItemDimsDefItem) && (sysDimItemDimsDefItem = {name: sysDimItemDimsDefItem});
+                resultItem.name = resultItem.displayName = sysDimItemDimsDefItem.name;
+                resultItem.defaultTooltip = sysDimItemDimsDefItem.defaultTooltip;
+            }
+            // FIXME refactor, currently only used in case: {otherDims: {tooltip: false}}
+            sysDimItemOtherDims && defaults(resultItem.otherDims, sysDimItemOtherDims);
+        });
     });
+
+    function applyDim(resultItem: DataDimensionInfo, coordDim: DimensionName, coordDimIndex: DimensionIndex) {
+        if (VISUAL_DIMENSIONS.get(coordDim as keyof DataVisualDimensions) != null) {
+            resultItem.otherDims[coordDim as keyof DataVisualDimensions] = coordDimIndex;
+        }
+        else {
+            resultItem.coordDim = coordDim;
+            resultItem.coordDimIndex = coordDimIndex;
+            coordDimNameMap.set(coordDim, true);
+        }
+    }
+
+    // Make sure the first extra dim is 'value'.
+    const generateCoord = opt.generateCoord;
+    let generateCoordCount = opt.generateCoordCount;
+    const fromZero = generateCoordCount != null;
+    generateCoordCount = generateCoord ? (generateCoordCount || 1) : 0;
+    const extra = generateCoord || 'value';
+    let coordDimNameAutoIdx = 0;
+    let dataDimNameAutoIdx = 0;
+
+    // Set dim `name` and other `coordDim` and other props.
+    if (!omitUnusedDimensions) {
+        for (let resultDimIdx = 0; resultDimIdx < dimCount; resultDimIdx++) {
+            const resultItem = getResultItem(resultDimIdx);
+            const coordDim = resultItem.coordDim;
+
+            if (coordDim == null) {
+                const res = genName(
+                    extra, coordDimNameMap, coordDimNameAutoIdx, fromZero
+                );
+                coordDimNameAutoIdx = res.autoIdx;
+                resultItem.coordDim = res.name;
+                resultItem.coordDimIndex = 0;
+                // Series specified generateCoord is using out.
+                if (!generateCoord || generateCoordCount <= 0) {
+                    resultItem.isExtraCoord = true;
+                }
+                generateCoordCount--;
+            }
+
+            if (resultItem.name == null) {
+                const res = genName(
+                    resultItem.coordDim, dataDimNameMap, dataDimNameAutoIdx, false
+                );
+                resultItem.name = res.name;
+                dataDimNameAutoIdx = res.autoIdx;
+            }
+
+            if (resultItem.type == null
+                && (
+                    guessOrdinal(source, resultDimIdx) === BE_ORDINAL.Must
+                    // Consider the case:
+                    // {
+                    //    dataset: {source: [
+                    //        ['2001', 123],
+                    //        ['2002', 456],
+                    //        ...
+                    //        ['The others', 987],
+                    //    ]},
+                    //    series: {type: 'pie'}
+                    // }
+                    // The first colum should better be treated as a "ordinal" although it
+                    // might not able to be detected as an "ordinal" by `guessOrdinal`.
+                    || (resultItem.isExtraCoord
+                        && (resultItem.otherDims.itemName != null
+                            || resultItem.otherDims.seriesName != null
+                        )
+                    )
+                )
+            ) {
+                resultItem.type = 'ordinal';
+            }
+        }
+        return result;
+    }
+    else {
+        // Sort dimensions
+        const toSort = [];
+        for (let i = 0; i < indicesMap.length; i++) {
+            if (indicesMap[i] >= 0) {
+                toSort.push({ i, o: result[indicesMap[i]]});
+            }
+        }
+        toSort.sort((a, b) => a.i - b.i);

Review comment:
       With the same option above, 
   
   In 5.1.2: 
   <img width="301" alt="Screen Shot 2021-08-03 at 4 14 20 PM" src="https://user-images.githubusercontent.com/1956569/127981913-1f307c09-a3a9-49db-820d-915625c86bb8.png">
   
   But in the newest commit 
   ae9226ecc01eb60e5662f34c8bcf275dbece17d8 
   July 27, 2021 at 5:16:25 PM GMT+8
   
   <img width="235" alt="Screen Shot 2021-08-03 at 4 16 21 PM" src="https://user-images.githubusercontent.com/1956569/127982144-e472f27a-ac12-4d35-8936-c68eacf9c280.png">
   
   




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



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