mirror of
https://github.com/grafana/grafana.git
synced 2025-02-10 07:35:45 -06:00
StateTimeline: insert trailing null value at +interval (#45997)
This commit is contained in:
parent
016d9e14ed
commit
854f872b40
@ -116,7 +116,8 @@ export class GraphNG extends React.Component<GraphNGProps, GraphNGState> {
|
||||
fields || {
|
||||
x: fieldMatchers.get(FieldMatcherID.firstTimeField).get({}),
|
||||
y: fieldMatchers.get(FieldMatcherID.numeric).get({}),
|
||||
}
|
||||
},
|
||||
props.timeRange
|
||||
);
|
||||
pluginLog('GraphNG', false, 'data aligned', alignedFrame);
|
||||
|
||||
|
@ -97,6 +97,23 @@ describe('nullInsertThreshold Transformer', () => {
|
||||
expect(result.fields[2].values.toArray()).toStrictEqual(['a', null, 'b', null, 'c']);
|
||||
});
|
||||
|
||||
test('should insert trailing null at end +interval when timeRange.to.valueOf() exceeds threshold', () => {
|
||||
const df = new MutableDataFrame({
|
||||
refId: 'A',
|
||||
fields: [
|
||||
{ name: 'Time', type: FieldType.time, config: { interval: 1 }, values: [1, 3, 10] },
|
||||
{ name: 'One', type: FieldType.number, values: [4, 6, 8] },
|
||||
{ name: 'Two', type: FieldType.string, values: ['a', 'b', 'c'] },
|
||||
],
|
||||
});
|
||||
|
||||
const result = applyNullInsertThreshold(df, null, 13);
|
||||
|
||||
expect(result.fields[0].values.toArray()).toStrictEqual([1, 2, 3, 4, 10, 11]);
|
||||
expect(result.fields[1].values.toArray()).toStrictEqual([4, null, 6, null, 8, null]);
|
||||
expect(result.fields[2].values.toArray()).toStrictEqual(['a', null, 'b', null, 'c', null]);
|
||||
});
|
||||
|
||||
// TODO: make this work
|
||||
test.skip('should insert nulls at +threshold (when defined) instead of +interval', () => {
|
||||
const df = new MutableDataFrame({
|
||||
@ -115,23 +132,6 @@ describe('nullInsertThreshold Transformer', () => {
|
||||
expect(result.fields[2].values.toArray()).toStrictEqual(['a', null, 'b', null, 'c']);
|
||||
});
|
||||
|
||||
test('should insert nulls at midpoints between adjacent > interval: 2', () => {
|
||||
const df = new MutableDataFrame({
|
||||
refId: 'A',
|
||||
fields: [
|
||||
{ name: 'Time', type: FieldType.time, config: { interval: 2 }, values: [5, 7, 11] },
|
||||
{ name: 'One', type: FieldType.number, values: [4, 6, 8] },
|
||||
{ name: 'Two', type: FieldType.string, values: ['a', 'b', 'c'] },
|
||||
],
|
||||
});
|
||||
|
||||
const result = applyNullInsertThreshold(df);
|
||||
|
||||
expect(result.fields[0].values.toArray()).toStrictEqual([5, 7, 9, 11]);
|
||||
expect(result.fields[1].values.toArray()).toStrictEqual([4, 6, null, 8]);
|
||||
expect(result.fields[2].values.toArray()).toStrictEqual(['a', 'b', null, 'c']);
|
||||
});
|
||||
|
||||
test('should noop on fewer than two values', () => {
|
||||
const df = new MutableDataFrame({
|
||||
refId: 'A',
|
||||
|
@ -12,6 +12,7 @@ const INSERT_MODES = {
|
||||
export function applyNullInsertThreshold(
|
||||
frame: DataFrame,
|
||||
refFieldName?: string | null,
|
||||
refFieldPseudoMax: number | null = null,
|
||||
insertMode: InsertMode = INSERT_MODES.threshold
|
||||
): DataFrame {
|
||||
if (frame.length < 2) {
|
||||
@ -48,7 +49,7 @@ export function applyNullInsertThreshold(
|
||||
|
||||
const frameValues = frame.fields.map((field) => field.values.toArray());
|
||||
|
||||
const filledFieldValues = nullInsertThreshold(refValues, frameValues, threshold, insertMode);
|
||||
const filledFieldValues = nullInsertThreshold(refValues, frameValues, threshold, refFieldPseudoMax, insertMode);
|
||||
|
||||
if (filledFieldValues === frameValues) {
|
||||
return frame;
|
||||
@ -70,7 +71,14 @@ export function applyNullInsertThreshold(
|
||||
return frame;
|
||||
}
|
||||
|
||||
function nullInsertThreshold(refValues: number[], frameValues: any[][], threshold: number, getInsertValue: InsertMode) {
|
||||
function nullInsertThreshold(
|
||||
refValues: number[],
|
||||
frameValues: any[][],
|
||||
threshold: number,
|
||||
// will insert a trailing null when refFieldPseudoMax > last datapoint + threshold
|
||||
refFieldPseudoMax: number | null = null,
|
||||
getInsertValue: InsertMode
|
||||
) {
|
||||
const len = refValues.length;
|
||||
let prevValue: number = refValues[0];
|
||||
const refValuesNew: number[] = [prevValue];
|
||||
@ -87,6 +95,10 @@ function nullInsertThreshold(refValues: number[], frameValues: any[][], threshol
|
||||
prevValue = curValue;
|
||||
}
|
||||
|
||||
if (refFieldPseudoMax != null && prevValue + threshold <= refFieldPseudoMax) {
|
||||
refValuesNew.push(getInsertValue(prevValue, refFieldPseudoMax, threshold));
|
||||
}
|
||||
|
||||
const filledLen = refValuesNew.length;
|
||||
|
||||
if (filledLen === len) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { XYFieldMatchers } from './types';
|
||||
import { ArrayVector, DataFrame, FieldConfig, FieldType, outerJoinDataFrames } from '@grafana/data';
|
||||
import { ArrayVector, DataFrame, FieldConfig, FieldType, outerJoinDataFrames, TimeRange } from '@grafana/data';
|
||||
import { nullToUndefThreshold } from './nullToUndefThreshold';
|
||||
import { applyNullInsertThreshold } from './nullInsertThreshold';
|
||||
import { AxisPlacement, GraphFieldConfig, ScaleDistribution, ScaleDistributionConfig } from '@grafana/schema';
|
||||
@ -29,9 +29,9 @@ function applySpanNullsThresholds(frame: DataFrame) {
|
||||
return frame;
|
||||
}
|
||||
|
||||
export function preparePlotFrame(frames: DataFrame[], dimFields: XYFieldMatchers) {
|
||||
export function preparePlotFrame(frames: DataFrame[], dimFields: XYFieldMatchers, timeRange?: TimeRange | null) {
|
||||
let alignedFrame = outerJoinDataFrames({
|
||||
frames: frames.map((frame) => applyNullInsertThreshold(frame)),
|
||||
frames: frames.map((frame) => applyNullInsertThreshold(frame, null, timeRange?.to.valueOf())),
|
||||
joinBy: dimFields.x,
|
||||
keep: dimFields.y,
|
||||
keepOriginIndices: true,
|
||||
|
@ -1,5 +1,4 @@
|
||||
import React from 'react';
|
||||
import { XYFieldMatchers } from '@grafana/ui/src/components/GraphNG/types';
|
||||
import {
|
||||
ArrayVector,
|
||||
DataFrame,
|
||||
@ -19,7 +18,6 @@ import {
|
||||
getActiveThreshold,
|
||||
Threshold,
|
||||
getFieldConfigWithMinMax,
|
||||
outerJoinDataFrames,
|
||||
ThresholdsMode,
|
||||
} from '@grafana/data';
|
||||
import {
|
||||
@ -48,15 +46,6 @@ export function mapMouseEventToMode(event: React.MouseEvent): SeriesVisibilityCh
|
||||
return SeriesVisibilityChangeMode.ToggleSelection;
|
||||
}
|
||||
|
||||
export function preparePlotFrame(data: DataFrame[], dimFields: XYFieldMatchers) {
|
||||
return outerJoinDataFrames({
|
||||
frames: data,
|
||||
joinBy: dimFields.x,
|
||||
keep: dimFields.y,
|
||||
keepOriginIndices: true,
|
||||
});
|
||||
}
|
||||
|
||||
export const preparePlotConfigBuilder: UPlotConfigPrepFn<TimelineOptions> = ({
|
||||
frame,
|
||||
theme,
|
||||
|
Loading…
Reference in New Issue
Block a user