You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@echarts.apache.org by sh...@apache.org on 2020/09/23 12:04:25 UTC

[incubator-echarts] branch pr/13317 updated: fix(sample): fix lttb downsample with dataZoom

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

shenyi pushed a commit to branch pr/13317
in repository https://gitbox.apache.org/repos/asf/incubator-echarts.git


The following commit(s) were added to refs/heads/pr/13317 by this push:
     new 255b019  fix(sample): fix lttb downsample with dataZoom
255b019 is described below

commit 255b019616445c40477d2a5515a69a6120d7e544
Author: pissang <bm...@gmail.com>
AuthorDate: Wed Sep 23 19:49:31 2020 +0800

    fix(sample): fix lttb downsample with dataZoom
---
 src/data/List.ts            | 121 +++++++++++++++++++++-----------------------
 src/processor/dataSample.ts |   2 +-
 2 files changed, 58 insertions(+), 65 deletions(-)

diff --git a/src/data/List.ts b/src/data/List.ts
index 84a50bc..cb4b3e0 100644
--- a/src/data/List.ts
+++ b/src/data/List.ts
@@ -1697,12 +1697,12 @@ class List<
      * Large data down sampling using largest-triangle-three-buckets
      * @param {string} baseDimension
      * @param {string} valueDimension
-     * @param {number} rate
+     * @param {number} targetCount
      */
     lttbDownSample(
         baseDimension: DimensionName,
         valueDimension: DimensionName,
-        rate: number
+        targetCount: number
     ) {
         const list = cloneListForMapAndSample(this, [baseDimension, valueDimension]);
         const targetStorage = list._storage;
@@ -1714,81 +1714,74 @@ class List<
 
         let sampledIndex = 0;
 
-        const frameSize = mathFloor(1 / rate);
+        const frameSize = (len - 2) / (targetCount - 2);
 
-        let currentSelectedIdx = 0;
+        let currentRawIndex = this.getRawIndex(0);
         let maxArea;
         let area;
-        let nextSelectedIdx;
-
-        for (let chunkIdx = 0; chunkIdx < this._chunkCount; chunkIdx++) {
-            const chunkOffset = chunkSize * chunkIdx;
-            const selfChunkSize = Math.min(len - chunkOffset, chunkSize);
-            const chunkFrameCount = Math.ceil((selfChunkSize - 2) / frameSize);
-            const baseDimChunk = baseDimStore[chunkIdx];
-            const valueDimChunk = valueDimStore[chunkIdx];
-
-            // The first frame is the first data.
-            newIndices[sampledIndex++] = currentSelectedIdx;
-
-            for (let frame = 0; frame < chunkFrameCount - 2; frame++) {
-                let avgX = 0;
-                let avgY = 0;
-                let avgRangeStart = (frame + 1) * frameSize + 1 + chunkOffset;
-                const avgRangeEnd = Math.min((frame + 2) * frameSize + 1, selfChunkSize) + chunkOffset;
-
-                const avgRangeLength = avgRangeEnd - avgRangeStart;
-
-                for (; avgRangeStart < avgRangeEnd; avgRangeStart++) {
-                    const x = baseDimChunk[avgRangeStart] as number;
-                    const y = valueDimChunk[avgRangeStart] as number;
-                    if (isNaN(x) || isNaN(y)) {
-                        continue;
-                    }
-                    avgX += x;
-                    avgY += y;
+        let nextRawIndex;
+
+        newIndices[sampledIndex++] = currentRawIndex;
+        for (let i = 0; i < targetCount - 2; i++) {
+            let avgX = 0;
+            let avgY = 0;
+            const avgRangeStart = mathFloor((i + 1) * frameSize) + 1;
+            const avgRangeEnd = Math.min(mathFloor((i + 2) * frameSize) + 1, len);
+
+            const avgRangeLength = avgRangeEnd - avgRangeStart;
+
+            for (let idx = avgRangeStart; idx < avgRangeEnd; idx++) {
+                const rawIndex = this.getRawIndex(idx);
+                const chunkIndex = mathFloor(rawIndex / chunkSize);
+                const chunkOffset = rawIndex % chunkSize;
+                const x = baseDimStore[chunkIndex][chunkOffset] as number;
+                const y = valueDimStore[chunkIndex][chunkOffset] as number;
+                if (isNaN(x) || isNaN(y)) {
+                    continue;
                 }
-                avgX /= avgRangeLength;
-                avgY /= avgRangeLength;
+                avgX += baseDimStore[chunkIndex][chunkOffset] as number;
+                avgY += valueDimStore[chunkIndex][chunkOffset] as number;
+            }
+            avgX /= avgRangeLength;
+            avgY /= avgRangeLength;
 
-                // Get the range for this bucket
-                let rangeOffs = (frame) * frameSize + 1 + chunkOffset;
-                const rangeTo = (frame + 1) * frameSize + 1 + chunkOffset;
+            const rangeOffs = mathFloor((i) * frameSize) + 1;
+            const rangeTo = mathFloor((i + 1) * frameSize) + 1;
 
-                // Point A
-                const pointAX = baseDimChunk[currentSelectedIdx] as number;
-                const pointAY = valueDimChunk[currentSelectedIdx] as number;
-                let allNaN = true;
+            const chunkIndex = mathFloor(currentRawIndex / chunkSize);
+            const chunkOffset = currentRawIndex % chunkSize;
+            const pointAX = baseDimStore[chunkIndex][chunkOffset] as number;
+            const pointAY = valueDimStore[chunkIndex][chunkOffset] as number;
 
-                maxArea = area = -1;
+            maxArea = area = -1;
 
-                for (; rangeOffs < rangeTo; rangeOffs++) {
-                    const y = valueDimChunk[rangeOffs] as number;
-                    const x = baseDimChunk[rangeOffs] as number;
-                    if (isNaN(x) || isNaN(y)) {
-                        continue;
-                    }
-                    allNaN = false;
-                    // Calculate triangle area over three buckets
-                    area = Math.abs((pointAX - avgX) * (y - pointAY)
-                                - (pointAX - x) * (avgY - pointAY)
-                            );
-                    if (area > maxArea) {
-                        maxArea = area;
-                        nextSelectedIdx = rangeOffs; // Next a is this b
-                    }
+            // Find a point from current frame that construct a triangel with largest area with previous selected point
+            // And the average of next frame.
+            for (let idx = rangeOffs; idx < rangeTo; idx++) {
+                const rawIndex = this.getRawIndex(idx);
+                const chunkIndex = mathFloor(rawIndex / chunkSize);
+                const chunkOffset = rawIndex % chunkSize;
+                const x = baseDimStore[chunkIndex][chunkOffset] as number;
+                const y = valueDimStore[chunkIndex][chunkOffset] as number;
+                if (isNaN(x) || isNaN(y)) {
+                    continue;
                 }
-
-                if (!allNaN) {
-                    newIndices[sampledIndex++] = nextSelectedIdx;
+                // Calculate triangle area over three buckets
+                area = Math.abs((pointAX - avgX) * (y - pointAY)
+                    - (pointAX - x) * (avgY - pointAY)
+                );
+                if (area > maxArea) {
+                    maxArea = area;
+                    nextRawIndex = rawIndex; // Next a is this b
                 }
-
-                currentSelectedIdx = nextSelectedIdx; // This a is the next a (chosen b)
             }
-            // The last frame is the last data.
-            newIndices[sampledIndex++] = selfChunkSize - 1;
+
+            newIndices[sampledIndex++] = nextRawIndex;
+
+            currentRawIndex = nextRawIndex; // This a is the next a (chosen b)
         }
 
+        newIndices[sampledIndex++] = this.getRawIndex(len - 1);
         list._count = sampledIndex;
         list._indices = newIndices;
 
diff --git a/src/processor/dataSample.ts b/src/processor/dataSample.ts
index 7d81fd6..485f6df 100644
--- a/src/processor/dataSample.ts
+++ b/src/processor/dataSample.ts
@@ -95,7 +95,7 @@ export default function (seriesType: string): StageHandler {
                 if (rate > 1) {
                     if (sampling === 'lttb') {
                         seriesModel.setData(data.lttbDownSample(
-                            data.mapDimension(baseAxis.dim), data.mapDimension(valueAxis.dim), 1 / rate
+                            data.mapDimension(baseAxis.dim), data.mapDimension(valueAxis.dim), size
                         ));
                     }
                     let sampler;


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