mirror of https://github.com/buster-so/buster.git
trendline max and mins
This commit is contained in:
parent
e9a6c26415
commit
6f44c99e2d
|
@ -22,4 +22,5 @@ export interface Trendline {
|
||||||
| 'median'; //default is linear trend
|
| 'median'; //default is linear trend
|
||||||
trendLineColor?: string | null; //OPTIONAL: default is #000000
|
trendLineColor?: string | null; //OPTIONAL: default is #000000
|
||||||
columnId: string;
|
columnId: string;
|
||||||
|
id?: string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,8 @@ describe('useTrendlines', () => {
|
||||||
trendlines: [] as TrendlineDataset[],
|
trendlines: [] as TrendlineDataset[],
|
||||||
columnLabelFormats: {} as Record<string, IColumnLabelFormat | undefined>,
|
columnLabelFormats: {} as Record<string, IColumnLabelFormat | undefined>,
|
||||||
selectedChartType: 'line' as ChartType,
|
selectedChartType: 'line' as ChartType,
|
||||||
lineGroupType: null
|
lineGroupType: null,
|
||||||
|
barGroupType: null
|
||||||
};
|
};
|
||||||
|
|
||||||
it('returns the expected structure', () => {
|
it('returns the expected structure', () => {
|
||||||
|
@ -153,6 +154,7 @@ describe('useTrendlines', () => {
|
||||||
const columnId = 'col1';
|
const columnId = 'col1';
|
||||||
const props = {
|
const props = {
|
||||||
...defaultProps,
|
...defaultProps,
|
||||||
|
|
||||||
trendlines: [
|
trendlines: [
|
||||||
mockTrendlineDataset({
|
mockTrendlineDataset({
|
||||||
id: 'test-linear-slope',
|
id: 'test-linear-slope',
|
||||||
|
|
|
@ -282,14 +282,14 @@ export const trendlineDatasetCreator: Record<
|
||||||
},
|
},
|
||||||
|
|
||||||
average: (trendline, datasetsWithTicks) => {
|
average: (trendline, datasetsWithTicks) => {
|
||||||
const datasets = datasetsWithTicks.datasets;
|
const { validData, ticks, xAxisColumn, selectedDatasets } = getValidDataAndTicks(
|
||||||
const selectedDataset = datasets.find((dataset) => dataset.id === trendline.columnId);
|
datasetsWithTicks.datasets,
|
||||||
|
trendline
|
||||||
|
);
|
||||||
|
|
||||||
if (!selectedDataset?.data || selectedDataset.data.length === 0) return [];
|
if (!selectedDatasets || selectedDatasets.length === 0 || validData.length === 0) return [];
|
||||||
|
|
||||||
// Filter out null/undefined values
|
|
||||||
const validData = selectedDataset.data.filter((value) => value !== null && value !== undefined);
|
|
||||||
|
|
||||||
|
// Sum all valid values and divide by the count
|
||||||
if (validData.length === 0) return [];
|
if (validData.length === 0) return [];
|
||||||
|
|
||||||
// Sum all valid values and divide by the count
|
// Sum all valid values and divide by the count
|
||||||
|
@ -313,14 +313,12 @@ export const trendlineDatasetCreator: Record<
|
||||||
},
|
},
|
||||||
|
|
||||||
min: (trendline, datasetsWithTicks) => {
|
min: (trendline, datasetsWithTicks) => {
|
||||||
const datasets = datasetsWithTicks.datasets;
|
const { validData, ticks, xAxisColumn, selectedDatasets } = getValidDataAndTicks(
|
||||||
const selectedDataset = datasets.find((dataset) => dataset.id === trendline.columnId);
|
datasetsWithTicks.datasets,
|
||||||
|
trendline
|
||||||
|
);
|
||||||
|
|
||||||
if (!selectedDataset?.data || selectedDataset.data.length === 0) return [];
|
if (!selectedDatasets || selectedDatasets.length === 0 || validData.length === 0) return [];
|
||||||
|
|
||||||
// Filter out null/undefined values
|
|
||||||
const validData = selectedDataset.data.filter((value) => value !== null && value !== undefined);
|
|
||||||
if (validData.length === 0) return [];
|
|
||||||
|
|
||||||
// Use the first valid value as initial accumulator
|
// Use the first valid value as initial accumulator
|
||||||
const min = validData.reduce<number>((acc, datapoint) => {
|
const min = validData.reduce<number>((acc, datapoint) => {
|
||||||
|
@ -341,14 +339,12 @@ export const trendlineDatasetCreator: Record<
|
||||||
},
|
},
|
||||||
|
|
||||||
max: (trendline, datasetsWithTicks) => {
|
max: (trendline, datasetsWithTicks) => {
|
||||||
const datasets = datasetsWithTicks.datasets;
|
const { validData, ticks, xAxisColumn, selectedDatasets } = getValidDataAndTicks(
|
||||||
const selectedDataset = datasets.find((dataset) => dataset.id === trendline.columnId);
|
datasetsWithTicks.datasets,
|
||||||
|
trendline
|
||||||
|
);
|
||||||
|
|
||||||
if (!selectedDataset?.data || selectedDataset.data.length === 0) return [];
|
if (!selectedDatasets || selectedDatasets.length === 0 || validData.length === 0) return [];
|
||||||
|
|
||||||
// Filter out null/undefined values
|
|
||||||
const validData = selectedDataset.data.filter((value) => value !== null && value !== undefined);
|
|
||||||
if (validData.length === 0) return [];
|
|
||||||
|
|
||||||
// Use the first valid value as initial accumulator
|
// Use the first valid value as initial accumulator
|
||||||
const max = validData.reduce<number>((acc, datapoint) => {
|
const max = validData.reduce<number>((acc, datapoint) => {
|
||||||
|
@ -369,15 +365,15 @@ export const trendlineDatasetCreator: Record<
|
||||||
},
|
},
|
||||||
|
|
||||||
median: (trendline, datasetsWithTicks) => {
|
median: (trendline, datasetsWithTicks) => {
|
||||||
const datasets = datasetsWithTicks.datasets;
|
const { validData, ticks, xAxisColumn, selectedDatasets } = getValidDataAndTicks(
|
||||||
const selectedDataset = datasets.find((dataset) => dataset.id === trendline.columnId);
|
datasetsWithTicks.datasets,
|
||||||
|
trendline
|
||||||
|
);
|
||||||
|
|
||||||
if (!selectedDataset?.data || selectedDataset.data.length === 0) return [];
|
if (!selectedDatasets || selectedDatasets.length === 0 || validData.length === 0) return [];
|
||||||
|
|
||||||
// Sort the data and get the middle value
|
// Sort the data and get the middle value
|
||||||
const sortedData = [...selectedDataset.data]
|
const sortedData = [...validData].sort((a, b) => (a as number) - (b as number));
|
||||||
.filter((value) => value !== null && value !== undefined)
|
|
||||||
.sort((a, b) => (a as number) - (b as number));
|
|
||||||
|
|
||||||
let median: number;
|
let median: number;
|
||||||
const midIndex = Math.floor(sortedData.length / 2);
|
const midIndex = Math.floor(sortedData.length / 2);
|
||||||
|
|
|
@ -42,8 +42,9 @@ export const useDataTrendlineOptions = ({
|
||||||
!hasTrendlines ||
|
!hasTrendlines ||
|
||||||
!datasetOptions ||
|
!datasetOptions ||
|
||||||
!datasetOptions.datasets.length
|
!datasetOptions.datasets.length
|
||||||
)
|
) {
|
||||||
return [] as TrendlineDataset[];
|
return [] as TrendlineDataset[];
|
||||||
|
}
|
||||||
|
|
||||||
const trendlineDatasets: TrendlineDataset[] = [];
|
const trendlineDatasets: TrendlineDataset[] = [];
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@ import { EditTrendlineShowLine } from './EditTrendlineShowLine';
|
||||||
import { EditTrendlineOption } from './EditTrendlineOption';
|
import { EditTrendlineOption } from './EditTrendlineOption';
|
||||||
import { TypeToLabel } from './config';
|
import { TypeToLabel } from './config';
|
||||||
import { JOIN_CHARACTER } from '@/components/ui/charts/commonHelpers';
|
import { JOIN_CHARACTER } from '@/components/ui/charts/commonHelpers';
|
||||||
|
import isEqual from 'lodash/isEqual';
|
||||||
|
|
||||||
export interface LoopTrendline extends Trendline {
|
export interface LoopTrendline extends Trendline {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -40,7 +41,7 @@ export const EditTrendline: React.FC<{
|
||||||
selectedChartType
|
selectedChartType
|
||||||
}) => {
|
}) => {
|
||||||
const [trends, _setTrends] = useState<LoopTrendline[]>(
|
const [trends, _setTrends] = useState<LoopTrendline[]>(
|
||||||
trendlines.map((trend) => ({ ...trend, id: uuidv4() }))
|
trendlines.map((trend) => ({ ...trend, id: trend.id || uuidv4() }))
|
||||||
);
|
);
|
||||||
const [newTrendIds, { add: addNewTrendId }] = useSet<string>();
|
const [newTrendIds, { add: addNewTrendId }] = useSet<string>();
|
||||||
|
|
||||||
|
@ -60,13 +61,30 @@ export const EditTrendline: React.FC<{
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onAddTrendline = useMemoizedFn(() => {
|
const onAddTrendline = useMemoizedFn(() => {
|
||||||
|
const getNewType = () => {
|
||||||
|
const types = [
|
||||||
|
'linear_regression',
|
||||||
|
'polynomial_regression',
|
||||||
|
'exponential_regression',
|
||||||
|
'logarithmic_regression',
|
||||||
|
'average',
|
||||||
|
'min',
|
||||||
|
'max',
|
||||||
|
'median'
|
||||||
|
] as const;
|
||||||
|
return types[Math.floor(Math.random() * types.length)];
|
||||||
|
};
|
||||||
|
|
||||||
|
const hasLinearRegression = trends.some((trend) => trend.type === 'linear_regression');
|
||||||
|
const type = hasLinearRegression ? getNewType() : ('linear_regression' as const);
|
||||||
|
|
||||||
const newTrendline: Required<LoopTrendline> = {
|
const newTrendline: Required<LoopTrendline> = {
|
||||||
id: uuidv4(),
|
id: uuidv4(),
|
||||||
show: true,
|
show: true,
|
||||||
showTrendlineLabel: false,
|
showTrendlineLabel: false,
|
||||||
trendlineLabel: null,
|
trendlineLabel: null,
|
||||||
type: 'linear_regression',
|
type,
|
||||||
trendLineColor: null,
|
trendLineColor: '#FF0000',
|
||||||
columnId: selectedAxis.y[0] || ''
|
columnId: selectedAxis.y[0] || ''
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -77,12 +95,8 @@ export const EditTrendline: React.FC<{
|
||||||
});
|
});
|
||||||
|
|
||||||
const onUpdateTrendlines = useMemoizedFn((trends: LoopTrendline[]) => {
|
const onUpdateTrendlines = useMemoizedFn((trends: LoopTrendline[]) => {
|
||||||
const newTrends = trends.map(({ id, ...rest }) => ({
|
|
||||||
...rest
|
|
||||||
}));
|
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
onUpdateChartConfig({ trendlines: newTrends });
|
onUpdateChartConfig({ trendlines: trends });
|
||||||
}, 30);
|
}, 30);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -120,7 +134,13 @@ export const EditTrendline: React.FC<{
|
||||||
};
|
};
|
||||||
}, [trends]);
|
}, [trends]);
|
||||||
|
|
||||||
//TODO: fix the bug where we need to "reset" the trends when the reset button is clicked
|
useEffect(() => {
|
||||||
|
const updatedTrends = trendlines.map((trend) => ({ ...trend, id: trend.id || uuidv4() }));
|
||||||
|
|
||||||
|
if (!isEqual(updatedTrends, trends)) {
|
||||||
|
_setTrends(updatedTrends);
|
||||||
|
}
|
||||||
|
}, [trendlines]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col space-y-2.5">
|
<div className="flex flex-col space-y-2.5">
|
||||||
|
|
Loading…
Reference in New Issue