Skip to content

Commit

Permalink
Merge pull request #20315 from ribeirompl/ribeirompl-fix-minmax-sampling
Browse files Browse the repository at this point in the history
fix(sample): fix minmax sampling behaviour
  • Loading branch information
Ovilia authored Oct 28, 2024
2 parents ecebf65 + e928a4c commit ffdd017
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 18 deletions.
69 changes: 69 additions & 0 deletions src/data/DataStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1013,6 +1013,75 @@ class DataStore {
return target;
}

/**
* Large data down sampling using min-max
* @param {string} valueDimension
* @param {number} rate
*/
minmaxDownSample(
valueDimension: DimensionIndex,
rate: number
): DataStore {
const target = this.clone([valueDimension], true);
const targetStorage = target._chunks;

const frameSize = Math.floor(1 / rate);

const dimStore = targetStorage[valueDimension];
const len = this.count();

// Each frame results in 2 data points, one for min and one for max
const newIndices = new (getIndicesCtor(this._rawCount))(Math.ceil(len / frameSize) * 2);

let offset = 0;
for (let i = 0; i < len; i += frameSize) {
let minIndex = i;
let minValue = dimStore[this.getRawIndex(minIndex)];
let maxIndex = i;
let maxValue = dimStore[this.getRawIndex(maxIndex)];

let thisFrameSize = frameSize;
// Handle final smaller frame
if (i + frameSize > len) {
thisFrameSize = len - i;
}
// Determine min and max within the current frame
for (let k = 0; k < thisFrameSize; k++) {
const rawIndex = this.getRawIndex(i + k);
const value = dimStore[rawIndex];

if (value < minValue) {
minValue = value;
minIndex = i + k;
}
if (value > maxValue) {
maxValue = value;
maxIndex = i + k;
}
}

const rawMinIndex = this.getRawIndex(minIndex);
const rawMaxIndex = this.getRawIndex(maxIndex);

// Set the order of the min and max values, based on their ordering in the frame
if (minIndex < maxIndex) {
newIndices[offset++] = rawMinIndex;
newIndices[offset++] = rawMaxIndex;
}
else {
newIndices[offset++] = rawMaxIndex;
newIndices[offset++] = rawMinIndex;
}
}

target._count = offset;
target._indices = newIndices;

target._updateGetRawIdx();

return target;
}


/**
* Large data down sampling on given dimension
Expand Down
21 changes: 19 additions & 2 deletions src/data/SeriesData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,10 +254,10 @@ class SeriesData<

// Methods that create a new list based on this list should be listed here.
// Notice that those method should `RETURN` the new list.
TRANSFERABLE_METHODS = ['cloneShallow', 'downSample', 'lttbDownSample', 'map'] as const;
TRANSFERABLE_METHODS = ['cloneShallow', 'downSample', 'minmaxDownSample', 'lttbDownSample', 'map'] as const;
// Methods that change indices of this list should be listed here.
CHANGABLE_METHODS = ['filterSelf', 'selectRange'] as const;
DOWNSAMPLE_METHODS = ['downSample', 'lttbDownSample'] as const;
DOWNSAMPLE_METHODS = ['downSample', 'minmaxDownSample', 'lttbDownSample'] as const;

/**
* @param dimensionsInput.dimensions
Expand Down Expand Up @@ -1098,6 +1098,23 @@ class SeriesData<
return list as SeriesData<HostModel>;
}

/**
* Large data down sampling using min-max
* @param {string} valueDimension
* @param {number} rate
*/
minmaxDownSample(
valueDimension: DimensionLoose,
rate: number
): SeriesData<HostModel> {
const list = cloneListForMapAndSample(this);
list._store = this._store.minmaxDownSample(
this._getStoreDimIndex(valueDimension),
rate
);
return list as SeriesData<HostModel>;
}

/**
* Large data down sampling using largest-triangle-three-buckets
* @param {string} valueDimension
Expand Down
19 changes: 3 additions & 16 deletions src/processor/dataSample.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,22 +61,6 @@ const samplers: Dictionary<Sampler> = {
// NaN will cause illegal axis extent.
return isFinite(min) ? min : NaN;
},
minmax: function (frame) {
let turningPointAbsoluteValue = -Infinity;
let turningPointOriginalValue = -Infinity;

for (let i = 0; i < frame.length; i++) {
const originalValue = frame[i];
const absoluteValue = Math.abs(originalValue);

if (absoluteValue > turningPointAbsoluteValue) {
turningPointAbsoluteValue = absoluteValue;
turningPointOriginalValue = originalValue;
}
}

return isFinite(turningPointOriginalValue) ? turningPointOriginalValue : NaN;
},
// TODO
// Median
nearest: function (frame) {
Expand Down Expand Up @@ -115,6 +99,9 @@ export default function dataSample(seriesType: string): StageHandler {
if (sampling === 'lttb') {
seriesModel.setData(data.lttbDownSample(data.mapDimension(valueAxis.dim), 1 / rate));
}
else if (sampling === 'minmax') {
seriesModel.setData(data.minmaxDownSample(data.mapDimension(valueAxis.dim), 1 / rate));
}
let sampler;
if (isString(sampling)) {
sampler = samplers[sampling];
Expand Down

0 comments on commit ffdd017

Please sign in to comment.