mirror of https://github.com/buster-so/buster.git
data map update for linear regressions
This commit is contained in:
parent
6f44c99e2d
commit
8c1d4d4762
|
@ -1,20 +1,12 @@
|
|||
import { describe, it, expect } from '@jest/globals';
|
||||
import { dataMapper } from './dataMapper';
|
||||
import { DEFAULT_COLUMN_LABEL_FORMAT } from '@/api/asset_interfaces/metric';
|
||||
import type { DatasetOption } from '../interfaces';
|
||||
import type { IColumnLabelFormat } from '@/api/asset_interfaces/metric/charts';
|
||||
|
||||
describe('dataMapper', () => {
|
||||
it('should handle numeric x-axis values correctly', () => {
|
||||
const dataset: DatasetOption = {
|
||||
id: 'test',
|
||||
data: [10, 20, 30],
|
||||
dataKey: 'xAxis',
|
||||
axisType: 'y',
|
||||
tooltipData: [],
|
||||
label: []
|
||||
};
|
||||
|
||||
const data = [10, 20, 30];
|
||||
const xAxisColumn = 'xAxis';
|
||||
const ticks = {
|
||||
ticks: [['1'], ['2'], ['3']],
|
||||
ticksKey: [{ key: 'xAxis', value: '' }]
|
||||
|
@ -28,7 +20,7 @@ describe('dataMapper', () => {
|
|||
}
|
||||
};
|
||||
|
||||
const result = dataMapper(dataset, ticks, columnLabelFormats);
|
||||
const result = dataMapper(data, xAxisColumn, ticks, columnLabelFormats);
|
||||
expect(result).toEqual([
|
||||
[0, 10],
|
||||
[1, 20],
|
||||
|
@ -37,15 +29,8 @@ describe('dataMapper', () => {
|
|||
});
|
||||
|
||||
it('should handle date x-axis values correctly', () => {
|
||||
const dataset: DatasetOption = {
|
||||
id: 'test',
|
||||
data: [100, 200, 300],
|
||||
dataKey: 'date',
|
||||
axisType: 'y',
|
||||
tooltipData: [],
|
||||
label: []
|
||||
};
|
||||
|
||||
const data = [100, 200, 300];
|
||||
const xAxisColumn = 'date';
|
||||
const dates = ['2023-01-01', '2023-01-02', '2023-01-03'];
|
||||
const ticks = {
|
||||
ticks: dates.map((d) => [d]),
|
||||
|
@ -60,7 +45,7 @@ describe('dataMapper', () => {
|
|||
}
|
||||
};
|
||||
|
||||
const result = dataMapper(dataset, ticks, columnLabelFormats);
|
||||
const result = dataMapper(data, xAxisColumn, ticks, columnLabelFormats);
|
||||
|
||||
// Test that we have the right number of data points
|
||||
expect(result.length).toBe(3);
|
||||
|
@ -77,15 +62,8 @@ describe('dataMapper', () => {
|
|||
});
|
||||
|
||||
it('should handle categorical x-axis values by using indices', () => {
|
||||
const dataset: DatasetOption = {
|
||||
id: 'test',
|
||||
data: [15, 25, 35],
|
||||
dataKey: 'category',
|
||||
axisType: 'y',
|
||||
tooltipData: [],
|
||||
label: []
|
||||
};
|
||||
|
||||
const data = [15, 25, 35];
|
||||
const xAxisColumn = 'category';
|
||||
const ticks = {
|
||||
ticks: [['A'], ['B'], ['C']],
|
||||
ticksKey: [{ key: 'category', value: '' }]
|
||||
|
@ -99,7 +77,7 @@ describe('dataMapper', () => {
|
|||
}
|
||||
};
|
||||
|
||||
const result = dataMapper(dataset, ticks, columnLabelFormats);
|
||||
const result = dataMapper(data, xAxisColumn, ticks, columnLabelFormats);
|
||||
expect(result).toEqual([
|
||||
[0, 15],
|
||||
[1, 25],
|
||||
|
@ -108,15 +86,9 @@ describe('dataMapper', () => {
|
|||
});
|
||||
|
||||
it('should handle null/undefined values correctly', () => {
|
||||
const dataset: DatasetOption = {
|
||||
id: 'test',
|
||||
data: [10, null, 30, null, 50] as (number | null)[],
|
||||
dataKey: 'xAxis',
|
||||
axisType: 'y',
|
||||
tooltipData: [],
|
||||
label: []
|
||||
};
|
||||
|
||||
const rawData = [10, null, 30, null, 50] as (number | null)[];
|
||||
const data = rawData.map((val) => val ?? 0); // Convert null to 0
|
||||
const xAxisColumn = 'xAxis';
|
||||
const ticks = {
|
||||
ticks: [['1'], ['2'], ['3'], ['4'], ['5']],
|
||||
ticksKey: [{ key: 'xAxis', value: '' }]
|
||||
|
@ -130,7 +102,7 @@ describe('dataMapper', () => {
|
|||
}
|
||||
};
|
||||
|
||||
const result = dataMapper(dataset, ticks, columnLabelFormats);
|
||||
const result = dataMapper(data, xAxisColumn, ticks, columnLabelFormats);
|
||||
expect(result).toEqual([
|
||||
[0, 10],
|
||||
[1, 0],
|
||||
|
@ -141,15 +113,8 @@ describe('dataMapper', () => {
|
|||
});
|
||||
|
||||
it('should return empty array for empty dataset', () => {
|
||||
const dataset: DatasetOption = {
|
||||
id: 'test',
|
||||
data: [],
|
||||
dataKey: 'xAxis',
|
||||
axisType: 'y',
|
||||
tooltipData: [],
|
||||
label: []
|
||||
};
|
||||
|
||||
const data: number[] = [];
|
||||
const xAxisColumn = 'xAxis';
|
||||
const ticks = {
|
||||
ticks: [],
|
||||
ticksKey: [{ key: 'xAxis', value: '' }]
|
||||
|
@ -163,20 +128,13 @@ describe('dataMapper', () => {
|
|||
}
|
||||
};
|
||||
|
||||
const result = dataMapper(dataset, ticks, columnLabelFormats);
|
||||
const result = dataMapper(data, xAxisColumn, ticks, columnLabelFormats);
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
|
||||
it('should handle missing ticks correctly', () => {
|
||||
const dataset: DatasetOption = {
|
||||
id: 'test',
|
||||
data: [10, 20, 30],
|
||||
dataKey: 'xAxis',
|
||||
axisType: 'y',
|
||||
tooltipData: [],
|
||||
label: []
|
||||
};
|
||||
|
||||
const data = [10, 20, 30];
|
||||
const xAxisColumn = 'xAxis';
|
||||
const ticks = {
|
||||
ticks: [['1'], [], ['3']], // Missing tick in the middle
|
||||
ticksKey: [{ key: 'xAxis', value: '' }]
|
||||
|
@ -190,7 +148,7 @@ describe('dataMapper', () => {
|
|||
}
|
||||
};
|
||||
|
||||
const result = dataMapper(dataset, ticks, columnLabelFormats);
|
||||
const result = dataMapper(data, xAxisColumn, ticks, columnLabelFormats);
|
||||
expect(result).toEqual([
|
||||
[0, 10],
|
||||
[1, 30]
|
||||
|
|
|
@ -496,7 +496,7 @@ describe('trendlineDatasetCreator', () => {
|
|||
id: 'test-column-id',
|
||||
data: [2, 4, 6, 8, 10], // Perfect linear data
|
||||
label: [{ key: 'test-label', value: 'Test Label' }],
|
||||
dataKey: 'x-axis',
|
||||
dataKey: 'test-column-id',
|
||||
axisType: 'y',
|
||||
tooltipData: [[{ key: 'test-tooltip', value: 'Test Tooltip' }]]
|
||||
}
|
||||
|
@ -547,7 +547,7 @@ describe('trendlineDatasetCreator', () => {
|
|||
// Arrange
|
||||
const trendline: Trendline = {
|
||||
type: 'linear_regression',
|
||||
columnId: 'test-column-id',
|
||||
columnId: 'x-axis',
|
||||
show: true,
|
||||
showTrendlineLabel: true,
|
||||
trendlineLabel: 'Linear Regression'
|
||||
|
@ -587,8 +587,8 @@ describe('trendlineDatasetCreator', () => {
|
|||
// Assert
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0]).toMatchObject({
|
||||
id: DATASET_IDS.linearRegression('test-column-id'),
|
||||
dataKey: 'test-column-id',
|
||||
id: DATASET_IDS.linearRegression('x-axis'),
|
||||
dataKey: 'x-axis',
|
||||
axisType: 'y'
|
||||
});
|
||||
|
||||
|
@ -608,7 +608,7 @@ describe('trendlineDatasetCreator', () => {
|
|||
// Arrange
|
||||
const trendline: Trendline = {
|
||||
type: 'linear_regression',
|
||||
columnId: 'test-column-id',
|
||||
columnId: 'x-axis',
|
||||
show: true,
|
||||
showTrendlineLabel: true,
|
||||
trendlineLabel: 'Linear Regression'
|
||||
|
@ -648,8 +648,8 @@ describe('trendlineDatasetCreator', () => {
|
|||
// Assert
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0]).toMatchObject({
|
||||
id: DATASET_IDS.linearRegression('test-column-id'),
|
||||
dataKey: 'test-column-id',
|
||||
id: DATASET_IDS.linearRegression('x-axis'),
|
||||
dataKey: 'x-axis',
|
||||
axisType: 'y'
|
||||
});
|
||||
|
||||
|
@ -673,14 +673,14 @@ describe('trendlineDatasetCreator', () => {
|
|||
const approximateSlope = (lastPoint - firstPoint) / (data.length - 1);
|
||||
expect(approximateSlope).toBeCloseTo(1, 0);
|
||||
|
||||
expect(result[0].columnId).toEqual('test-column-id');
|
||||
expect(result[0].columnId).toEqual('x-axis');
|
||||
});
|
||||
|
||||
it('should calculate linear regression with date-based ticks', () => {
|
||||
// Arrange
|
||||
const trendline: Trendline = {
|
||||
type: 'linear_regression',
|
||||
columnId: 'test-column-id',
|
||||
columnId: 'x-axis',
|
||||
show: true,
|
||||
showTrendlineLabel: true,
|
||||
trendlineLabel: 'Linear Regression'
|
||||
|
@ -727,8 +727,8 @@ describe('trendlineDatasetCreator', () => {
|
|||
// Assert
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0]).toMatchObject({
|
||||
id: DATASET_IDS.linearRegression('test-column-id'),
|
||||
dataKey: 'test-column-id',
|
||||
id: DATASET_IDS.linearRegression('x-axis'),
|
||||
dataKey: 'x-axis',
|
||||
axisType: 'y'
|
||||
});
|
||||
|
||||
|
@ -748,7 +748,7 @@ describe('trendlineDatasetCreator', () => {
|
|||
expect(data[0] as number).toBeCloseTo(102, 0);
|
||||
expect(data[data.length - 1] as number).toBeCloseTo(155, 0);
|
||||
|
||||
expect(result[0].columnId).toEqual('test-column-id');
|
||||
expect(result[0].columnId).toEqual('x-axis');
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -757,7 +757,7 @@ describe('trendlineDatasetCreator', () => {
|
|||
// Arrange
|
||||
const trendline: Trendline = {
|
||||
type: 'exponential_regression',
|
||||
columnId: 'test-column-id',
|
||||
columnId: 'x-axis',
|
||||
show: true,
|
||||
showTrendlineLabel: true,
|
||||
trendlineLabel: 'Exponential Regression'
|
||||
|
@ -797,8 +797,8 @@ describe('trendlineDatasetCreator', () => {
|
|||
// Assert
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0]).toMatchObject({
|
||||
id: DATASET_IDS.exponentialRegression('test-column-id'),
|
||||
dataKey: 'test-column-id',
|
||||
id: DATASET_IDS.exponentialRegression('x-axis'),
|
||||
dataKey: 'x-axis',
|
||||
axisType: 'y'
|
||||
});
|
||||
|
||||
|
@ -815,7 +815,7 @@ describe('trendlineDatasetCreator', () => {
|
|||
// Arrange
|
||||
const trendline: Trendline = {
|
||||
type: 'exponential_regression',
|
||||
columnId: 'test-column-id',
|
||||
columnId: 'x-axis',
|
||||
show: true,
|
||||
showTrendlineLabel: true,
|
||||
trendlineLabel: 'Exponential Regression'
|
||||
|
@ -858,8 +858,8 @@ describe('trendlineDatasetCreator', () => {
|
|||
// Assert
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0]).toMatchObject({
|
||||
id: DATASET_IDS.exponentialRegression('test-column-id'),
|
||||
dataKey: 'test-column-id',
|
||||
id: DATASET_IDS.exponentialRegression('x-axis'),
|
||||
dataKey: 'x-axis',
|
||||
axisType: 'y'
|
||||
});
|
||||
|
||||
|
@ -872,7 +872,7 @@ describe('trendlineDatasetCreator', () => {
|
|||
// Arrange
|
||||
const trendline: Trendline = {
|
||||
type: 'exponential_regression',
|
||||
columnId: 'test-column-id',
|
||||
columnId: 'x-axis',
|
||||
show: true,
|
||||
showTrendlineLabel: true,
|
||||
trendlineLabel: 'Exponential Regression'
|
||||
|
@ -925,7 +925,7 @@ describe('trendlineDatasetCreator', () => {
|
|||
// Arrange
|
||||
const trendline: Trendline = {
|
||||
type: 'exponential_regression',
|
||||
columnId: 'test-column-id',
|
||||
columnId: 'x-axis',
|
||||
show: true,
|
||||
showTrendlineLabel: true,
|
||||
trendlineLabel: 'Exponential Regression'
|
||||
|
@ -972,7 +972,7 @@ describe('trendlineDatasetCreator', () => {
|
|||
// Arrange
|
||||
const trendline: Trendline = {
|
||||
type: 'logarithmic_regression',
|
||||
columnId: 'test-column-id',
|
||||
columnId: 'x-axis',
|
||||
show: true,
|
||||
showTrendlineLabel: true,
|
||||
trendlineLabel: 'Logarithmic Regression'
|
||||
|
@ -1013,8 +1013,8 @@ describe('trendlineDatasetCreator', () => {
|
|||
// Assert
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0]).toMatchObject({
|
||||
id: DATASET_IDS.logarithmicRegression('test-column-id'),
|
||||
dataKey: 'test-column-id',
|
||||
id: DATASET_IDS.logarithmicRegression('x-axis'),
|
||||
dataKey: 'x-axis',
|
||||
axisType: 'y'
|
||||
});
|
||||
|
||||
|
|
|
@ -22,7 +22,8 @@ export const trendlineDatasetCreator: Record<
|
|||
const datasets = datasetsWithTicks.datasets;
|
||||
const { validData, ticks, xAxisColumn, selectedDatasets } = getValidDataAndTicks(
|
||||
datasets,
|
||||
trendline
|
||||
trendline,
|
||||
datasetsWithTicks.ticks
|
||||
);
|
||||
|
||||
if (!selectedDatasets || selectedDatasets.length === 0 || validData.length === 0) return [];
|
||||
|
@ -86,7 +87,8 @@ export const trendlineDatasetCreator: Record<
|
|||
const datasets = datasetsWithTicks.datasets;
|
||||
const { validData, ticks, xAxisColumn, selectedDatasets } = getValidDataAndTicks(
|
||||
datasets,
|
||||
trendline
|
||||
trendline,
|
||||
datasetsWithTicks.ticks
|
||||
);
|
||||
|
||||
if (!selectedDatasets || selectedDatasets.length === 0 || validData.length === 0) return [];
|
||||
|
@ -153,7 +155,8 @@ export const trendlineDatasetCreator: Record<
|
|||
const datasets = datasetsWithTicks.datasets;
|
||||
const { validData, ticks, xAxisColumn, selectedDatasets } = getValidDataAndTicks(
|
||||
datasets,
|
||||
trendline
|
||||
trendline,
|
||||
datasetsWithTicks.ticks
|
||||
);
|
||||
|
||||
if (!selectedDatasets || selectedDatasets.length === 0 || validData.length === 0) return [];
|
||||
|
@ -221,7 +224,8 @@ export const trendlineDatasetCreator: Record<
|
|||
const datasets = datasetsWithTicks.datasets;
|
||||
const { validData, ticks, xAxisColumn, selectedDatasets } = getValidDataAndTicks(
|
||||
datasets,
|
||||
trendline
|
||||
trendline,
|
||||
datasetsWithTicks.ticks
|
||||
);
|
||||
|
||||
if (!selectedDatasets || selectedDatasets.length === 0 || validData.length === 0) return [];
|
||||
|
@ -282,9 +286,10 @@ export const trendlineDatasetCreator: Record<
|
|||
},
|
||||
|
||||
average: (trendline, datasetsWithTicks) => {
|
||||
const { validData, ticks, xAxisColumn, selectedDatasets } = getValidDataAndTicks(
|
||||
const { validData, selectedDatasets } = getValidDataAndTicks(
|
||||
datasetsWithTicks.datasets,
|
||||
trendline
|
||||
trendline,
|
||||
datasetsWithTicks.ticks
|
||||
);
|
||||
|
||||
if (!selectedDatasets || selectedDatasets.length === 0 || validData.length === 0) return [];
|
||||
|
@ -313,9 +318,10 @@ export const trendlineDatasetCreator: Record<
|
|||
},
|
||||
|
||||
min: (trendline, datasetsWithTicks) => {
|
||||
const { validData, ticks, xAxisColumn, selectedDatasets } = getValidDataAndTicks(
|
||||
const { validData, selectedDatasets } = getValidDataAndTicks(
|
||||
datasetsWithTicks.datasets,
|
||||
trendline
|
||||
trendline,
|
||||
datasetsWithTicks.ticks
|
||||
);
|
||||
|
||||
if (!selectedDatasets || selectedDatasets.length === 0 || validData.length === 0) return [];
|
||||
|
@ -339,9 +345,10 @@ export const trendlineDatasetCreator: Record<
|
|||
},
|
||||
|
||||
max: (trendline, datasetsWithTicks) => {
|
||||
const { validData, ticks, xAxisColumn, selectedDatasets } = getValidDataAndTicks(
|
||||
const { validData, selectedDatasets } = getValidDataAndTicks(
|
||||
datasetsWithTicks.datasets,
|
||||
trendline
|
||||
trendline,
|
||||
datasetsWithTicks.ticks
|
||||
);
|
||||
|
||||
if (!selectedDatasets || selectedDatasets.length === 0 || validData.length === 0) return [];
|
||||
|
@ -365,9 +372,10 @@ export const trendlineDatasetCreator: Record<
|
|||
},
|
||||
|
||||
median: (trendline, datasetsWithTicks) => {
|
||||
const { validData, ticks, xAxisColumn, selectedDatasets } = getValidDataAndTicks(
|
||||
const { validData, selectedDatasets } = getValidDataAndTicks(
|
||||
datasetsWithTicks.datasets,
|
||||
trendline
|
||||
trendline,
|
||||
datasetsWithTicks.ticks
|
||||
);
|
||||
|
||||
if (!selectedDatasets || selectedDatasets.length === 0 || validData.length === 0) return [];
|
||||
|
@ -404,10 +412,12 @@ export const trendlineDatasetCreator: Record<
|
|||
|
||||
const getValidDataAndTicks = (
|
||||
datasets: DatasetOptionsWithTicks['datasets'],
|
||||
trendline: Trendline
|
||||
trendline: Trendline,
|
||||
datasetTicks: DatasetOptionsWithTicks['ticks']
|
||||
) => {
|
||||
const selectedDatasets = datasets.filter((dataset) => dataset.dataKey === trendline.columnId);
|
||||
const xAxisColumn = selectedDatasets[0].dataKey;
|
||||
const selectedDatasets =
|
||||
datasets?.filter((dataset) => dataset.dataKey === trendline.columnId) || [];
|
||||
const xAxisColumn = selectedDatasets[0]?.dataKey;
|
||||
|
||||
// If there's only one dataset, we can skip sorting
|
||||
if (selectedDatasets.length === 1) {
|
||||
|
@ -417,11 +427,12 @@ const getValidDataAndTicks = (
|
|||
|
||||
dataset.data.forEach((value, index) => {
|
||||
const isValidData = value !== null && value !== undefined;
|
||||
const associatedTick = dataset.ticksForScatter?.[index];
|
||||
|
||||
if (isValidData && associatedTick !== undefined) {
|
||||
const associatedTick = dataset.ticksForScatter?.[index] || datasetTicks?.[index];
|
||||
|
||||
if (isValidData) {
|
||||
validData.push(value as number);
|
||||
ticks.push(associatedTick);
|
||||
if (associatedTick !== undefined) ticks.push(associatedTick);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -432,7 +443,7 @@ const getValidDataAndTicks = (
|
|||
const pairs = selectedDatasets.reduce<Array<[(string | number)[], number]>>((acc, dataset) => {
|
||||
dataset.data.forEach((value, index) => {
|
||||
const isValidData = value !== null && value !== undefined;
|
||||
const associatedTick = dataset.ticksForScatter?.[index];
|
||||
const associatedTick = dataset.ticksForScatter?.[index] || datasetTicks?.[index];
|
||||
|
||||
if (isValidData && associatedTick !== undefined) {
|
||||
acc.push([associatedTick, value as number]);
|
||||
|
|
Loading…
Reference in New Issue