data map update for linear regressions

This commit is contained in:
Nate Kelley 2025-05-07 17:15:39 -06:00
parent 6f44c99e2d
commit 8c1d4d4762
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
3 changed files with 72 additions and 103 deletions

View File

@ -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]

View File

@ -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'
});

View File

@ -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]);