mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
TimeSeries: always try to detect & fix reverse-sorted time field (#47906)
This commit is contained in:
parent
89fa35a53f
commit
aa98123e72
@ -188,7 +188,7 @@ describe('align frames', () => {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
const out = outerJoinDataFrames({ frames: [series1], enforceSort: true, keepOriginIndices: true })!;
|
const out = outerJoinDataFrames({ frames: [series1], keepOriginIndices: true })!;
|
||||||
expect(
|
expect(
|
||||||
out.fields.map((f) => ({
|
out.fields.map((f) => ({
|
||||||
name: f.name,
|
name: f.name,
|
||||||
|
@ -48,13 +48,6 @@ export interface JoinOptions {
|
|||||||
*/
|
*/
|
||||||
keep?: FieldMatcher;
|
keep?: FieldMatcher;
|
||||||
|
|
||||||
/**
|
|
||||||
* When the result is a single frame, this will to a quick check to see if the values are sorted,
|
|
||||||
* and sort if necessary. If the first/last values are in order the whole vector is assumed to be
|
|
||||||
* sorted
|
|
||||||
*/
|
|
||||||
enforceSort?: boolean;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @internal -- used when we need to keep a reference to the original frame/field index
|
* @internal -- used when we need to keep a reference to the original frame/field index
|
||||||
*/
|
*/
|
||||||
@ -65,6 +58,21 @@ function getJoinMatcher(options: JoinOptions): FieldMatcher {
|
|||||||
return options.joinBy ?? pickBestJoinField(options.frames);
|
return options.joinBy ?? pickBestJoinField(options.frames);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
export function maybeSortFrame(frame: DataFrame, fieldIdx: number) {
|
||||||
|
if (fieldIdx >= 0) {
|
||||||
|
let sortByField = frame.fields[fieldIdx];
|
||||||
|
|
||||||
|
if (sortByField.type !== FieldType.string && !isLikelyAscendingVector(sortByField.values)) {
|
||||||
|
frame = sortDataFrame(frame, fieldIdx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This will return a single frame joined by the first matching field. When a join field is not specified,
|
* This will return a single frame joined by the first matching field. When a join field is not specified,
|
||||||
* the default will use the first time field
|
* the default will use the first time field
|
||||||
@ -109,12 +117,8 @@ export function outerJoinDataFrames(options: JoinOptions): DataFrame | undefined
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.enforceSort) {
|
if (joinIndex >= 0) {
|
||||||
if (joinIndex >= 0) {
|
frameCopy = maybeSortFrame(frameCopy, joinIndex);
|
||||||
if (!isLikelyAscendingVector(frameCopy.fields[joinIndex].values)) {
|
|
||||||
frameCopy = sortDataFrame(frameCopy, joinIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.keep) {
|
if (options.keep) {
|
||||||
|
@ -301,7 +301,6 @@ export const prepareTimeSeriesTransformer: SynchronousDataTransformerInfo<Prepar
|
|||||||
const frame = outerJoinDataFrames({
|
const frame = outerJoinDataFrames({
|
||||||
frames: data,
|
frames: data,
|
||||||
joinBy: fieldMatchers.get(FieldMatcherID.firstTimeField).get({}),
|
joinBy: fieldMatchers.get(FieldMatcherID.firstTimeField).get({}),
|
||||||
enforceSort: true,
|
|
||||||
keepOriginIndices: true,
|
keepOriginIndices: true,
|
||||||
});
|
});
|
||||||
return frame ? [frame] : [];
|
return frame ? [frame] : [];
|
||||||
|
@ -28,6 +28,7 @@ import {
|
|||||||
import { orderBy } from 'lodash';
|
import { orderBy } from 'lodash';
|
||||||
import { findField } from 'app/features/dimensions';
|
import { findField } from 'app/features/dimensions';
|
||||||
import { getStackingGroups } from '@grafana/ui/src/components/uPlot/utils';
|
import { getStackingGroups } from '@grafana/ui/src/components/uPlot/utils';
|
||||||
|
import { maybeSortFrame } from '@grafana/data/src/transformations/transformers/joinDataFrames';
|
||||||
|
|
||||||
function getBarCharScaleOrientation(orientation: VizOrientation) {
|
function getBarCharScaleOrientation(orientation: VizOrientation) {
|
||||||
if (orientation === VizOrientation.Vertical) {
|
if (orientation === VizOrientation.Vertical) {
|
||||||
@ -301,7 +302,13 @@ export function prepareBarChartDisplayValues(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Bar chart requires a single frame
|
// Bar chart requires a single frame
|
||||||
const frame = series.length === 1 ? series[0] : outerJoinDataFrames({ frames: series, enforceSort: false });
|
const frame =
|
||||||
|
series.length === 1
|
||||||
|
? maybeSortFrame(
|
||||||
|
series[0],
|
||||||
|
series[0].fields.findIndex((f) => f.type === FieldType.time)
|
||||||
|
)
|
||||||
|
: outerJoinDataFrames({ frames: series });
|
||||||
if (!frame) {
|
if (!frame) {
|
||||||
return { warn: 'Unable to join data' } as BarChartDisplayValues;
|
return { warn: 'Unable to join data' } as BarChartDisplayValues;
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import {
|
|||||||
GrafanaTheme2,
|
GrafanaTheme2,
|
||||||
outerJoinDataFrames,
|
outerJoinDataFrames,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
|
import { maybeSortFrame } from '@grafana/data/src/transformations/transformers/joinDataFrames';
|
||||||
import { findField } from 'app/features/dimensions';
|
import { findField } from 'app/features/dimensions';
|
||||||
import { prepareGraphableFields } from '../timeseries/utils';
|
import { prepareGraphableFields } from '../timeseries/utils';
|
||||||
import { CandlestickOptions, CandlestickFieldMap, VizDisplayMode } from './models.gen';
|
import { CandlestickOptions, CandlestickFieldMap, VizDisplayMode } from './models.gen';
|
||||||
@ -102,7 +103,13 @@ export function prepareCandlestickFields(
|
|||||||
|
|
||||||
// All fields
|
// All fields
|
||||||
const fieldMap = options.fields ?? {};
|
const fieldMap = options.fields ?? {};
|
||||||
const aligned = series.length === 1 ? series[0] : outerJoinDataFrames({ frames: series, enforceSort: true });
|
const aligned =
|
||||||
|
series.length === 1
|
||||||
|
? maybeSortFrame(
|
||||||
|
series[0],
|
||||||
|
series[0].fields.findIndex((f) => f.type === FieldType.time)
|
||||||
|
)
|
||||||
|
: outerJoinDataFrames({ frames: series });
|
||||||
if (!aligned?.length) {
|
if (!aligned?.length) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user