Skip to content

Commit

Permalink
feat: xBoxPlot has an option to calculate outliers (#256)
Browse files Browse the repository at this point in the history
  • Loading branch information
lpatiny authored Aug 12, 2024
1 parent ddf8fb9 commit 69cb82c
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 1 deletion.
31 changes: 31 additions & 0 deletions src/x/__tests__/xBoxPlot.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ test('test xBoxPlot even', () => {
q3: 8.5,
min: 0,
max: 11,
outliers: [],
});
});

Expand All @@ -21,6 +22,7 @@ test('test xBoxPlot even small', () => {
q3: 4,
min: 0,
max: 5,
outliers: [],
});
});

Expand All @@ -32,6 +34,7 @@ test('test xBoxPlot odd', () => {
q3: 8,
min: 0,
max: 10,
outliers: [],
});
});

Expand All @@ -43,6 +46,7 @@ test('test xBoxPlot odd small', () => {
q3: 3.5,
min: 0,
max: 4,
outliers: [],
});
});

Expand All @@ -69,6 +73,7 @@ test('test xBoxPlot with one element', () => {
q3: 42,
min: 42,
max: 42,
outliers: [],
});
});

Expand All @@ -81,6 +86,7 @@ test('test xBoxPlot with 2 elements', () => {
q3: 44,
min: 40,
max: 44,
outliers: [],
});
});

Expand All @@ -93,5 +99,30 @@ test('test xBoxPlot with 3 elements', () => {
q3: 44,
min: 40,
max: 44,
outliers: [],
});
});

test('outliers', () => {
const array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 100];
expect(xBoxPlot(array)).toStrictEqual({
q1: 2,
median: 5,
q3: 8,
min: 0,
max: 100,
outliers: [],
});
});

test('outliers', () => {
const array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 100];
expect(xBoxPlot(array, { calculateOutliers: true })).toStrictEqual({
q1: 2,
median: 5,
q3: 8,
min: 0,
max: 9,
outliers: [100],
});
});
27 changes: 26 additions & 1 deletion src/x/xBoxPlot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ export interface XBoxPlotOptions {
* @default false
*/
allowSmallArray?: boolean;

/**
* Calculate outliers (value < min-1.5IQR or value > max+1.5IQR). The min and max are recalculated without the outliers.
* @default false
*/
calculateOutliers?: boolean;
}

export interface XBoxPlot {
Expand All @@ -14,6 +20,7 @@ export interface XBoxPlot {
q3: number;
min: number;
max: number;
outliers: number[];
}

/**
Expand All @@ -25,7 +32,7 @@ export function xBoxPlot(
array: NumberArray,
options: XBoxPlotOptions = {},
): XBoxPlot {
const { allowSmallArray = false } = options;
const { allowSmallArray = false, calculateOutliers = false } = options;
if (array.length < 5) {
if (allowSmallArray) {
if (array.length === 0) {
Expand All @@ -46,6 +53,7 @@ export function xBoxPlot(
q3: 0,
min: array[0],
max: array.at(-1) as number,
outliers: [],
};
let q1max, q3min;
if (array.length % 2 === 1) {
Expand All @@ -68,5 +76,22 @@ export function xBoxPlot(
const middleOver = (array.length + q3min) / 2;
info.q3 = (array[middleOver] + array[middleOver - 1]) / 2;
}

if (calculateOutliers) {
const iqr = info.q3 - info.q1;
const min = info.q1 - 1.5 * iqr;
const max = info.q3 + 1.5 * iqr;
// we need to recalculate the min and the max because they could be outliers
info.min = info.median;
info.max = info.median;
for (const value of array) {
if (value < min || value > max) {
info.outliers.push(value);
} else {
if (value < info.min) info.min = value;
if (value > info.max) info.max = value;
}
}
}
return info;
}

0 comments on commit 69cb82c

Please sign in to comment.