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 <bm2736...@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-unsubscr...@echarts.apache.org For additional commands, e-mail: commits-h...@echarts.apache.org