mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
TimeSeries: Support for log scale and negative numbers (#54812)
This commit is contained in:
parent
6a7e1caced
commit
eb90d0c4b5
@ -21,7 +21,7 @@ GraphTransform: "constant" | "negative-Y" @cue
|
||||
LineInterpolation: "linear" | "smooth" | "stepBefore" | "stepAfter" @cuetsy(kind="enum")
|
||||
|
||||
// TODO docs
|
||||
ScaleDistribution: "linear" | "log" | "ordinal" @cuetsy(kind="enum")
|
||||
ScaleDistribution: "linear" | "log" | "ordinal" | "symlog" @cuetsy(kind="enum")
|
||||
|
||||
// TODO docs
|
||||
GraphGradientMode: "none" | "opacity" | "hue" | "scheme" @cuetsy(kind="enum")
|
||||
@ -83,6 +83,7 @@ PointsConfig: {
|
||||
ScaleDistributionConfig: {
|
||||
type: ScaleDistribution
|
||||
log?: number
|
||||
linearThreshold?: number
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
// TODO docs
|
||||
|
@ -46,6 +46,7 @@ export enum ScaleDistribution {
|
||||
Linear = 'linear',
|
||||
Log = 'log',
|
||||
Ordinal = 'ordinal',
|
||||
Symlog = 'symlog',
|
||||
}
|
||||
|
||||
export enum GraphGradientMode {
|
||||
@ -116,6 +117,7 @@ export interface PointsConfig {
|
||||
}
|
||||
|
||||
export interface ScaleDistributionConfig {
|
||||
linearThreshold?: number;
|
||||
log?: number;
|
||||
type: ScaleDistribution;
|
||||
}
|
||||
|
@ -100,6 +100,7 @@ Object {
|
||||
],
|
||||
"scales": Object {
|
||||
"__fixed/na-na/na-na/auto/linear/na": Object {
|
||||
"asinh": undefined,
|
||||
"auto": true,
|
||||
"dir": 1,
|
||||
"distr": 1,
|
||||
|
@ -217,6 +217,7 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{
|
||||
direction: ScaleDirection.Up,
|
||||
distribution: customConfig.scaleDistribution?.type,
|
||||
log: customConfig.scaleDistribution?.log,
|
||||
linearThreshold: customConfig.scaleDistribution?.linearThreshold,
|
||||
min: field.config.min,
|
||||
max: field.config.max,
|
||||
softMin: customConfig.axisSoftMin,
|
||||
|
@ -124,6 +124,7 @@ describe('UPlotConfigBuilder', () => {
|
||||
"time": true,
|
||||
},
|
||||
"scale-y": Object {
|
||||
"asinh": undefined,
|
||||
"auto": true,
|
||||
"dir": 1,
|
||||
"distr": 1,
|
||||
@ -209,6 +210,7 @@ describe('UPlotConfigBuilder', () => {
|
||||
],
|
||||
"scales": Object {
|
||||
"scale-y": Object {
|
||||
"asinh": undefined,
|
||||
"auto": true,
|
||||
"dir": 1,
|
||||
"distr": 1,
|
||||
@ -274,6 +276,7 @@ describe('UPlotConfigBuilder', () => {
|
||||
],
|
||||
"scales": Object {
|
||||
"scale-y": Object {
|
||||
"asinh": undefined,
|
||||
"auto": true,
|
||||
"dir": 1,
|
||||
"distr": 1,
|
||||
@ -340,6 +343,7 @@ describe('UPlotConfigBuilder', () => {
|
||||
],
|
||||
"scales": Object {
|
||||
"scale-y": Object {
|
||||
"asinh": undefined,
|
||||
"auto": true,
|
||||
"dir": 1,
|
||||
"distr": 1,
|
||||
|
@ -17,6 +17,7 @@ export interface ScaleProps {
|
||||
orientation: ScaleOrientation;
|
||||
direction: ScaleDirection;
|
||||
log?: number;
|
||||
linearThreshold?: number;
|
||||
centeredZero?: boolean;
|
||||
decimals?: DecimalCount;
|
||||
}
|
||||
@ -41,15 +42,21 @@ export class UPlotScaleBuilder extends PlotConfigBuilder<ScaleProps, Scale> {
|
||||
centeredZero,
|
||||
decimals,
|
||||
} = this.props;
|
||||
|
||||
const distr = this.props.distribution;
|
||||
|
||||
const distribution = !isTime
|
||||
? {
|
||||
distr:
|
||||
this.props.distribution === ScaleDistribution.Log
|
||||
distr === ScaleDistribution.Symlog
|
||||
? 4
|
||||
: distr === ScaleDistribution.Log
|
||||
? 3
|
||||
: this.props.distribution === ScaleDistribution.Ordinal
|
||||
: distr === ScaleDistribution.Ordinal
|
||||
? 2
|
||||
: 1,
|
||||
log: this.props.distribution === ScaleDistribution.Log ? this.props.log || 2 : undefined,
|
||||
log: distr === ScaleDistribution.Log || distr === ScaleDistribution.Symlog ? this.props.log ?? 2 : undefined,
|
||||
asinh: distr === ScaleDistribution.Symlog ? this.props.linearThreshold ?? 1 : undefined,
|
||||
}
|
||||
: {};
|
||||
|
||||
@ -91,7 +98,7 @@ export class UPlotScaleBuilder extends PlotConfigBuilder<ScaleProps, Scale> {
|
||||
return minMax;
|
||||
}
|
||||
|
||||
if (scale.distr === 1 || scale.distr === 2) {
|
||||
if (scale.distr === 1 || scale.distr === 2 || scale.distr === 4) {
|
||||
if (centeredZero) {
|
||||
let absMin = Math.abs(dataMin!);
|
||||
let absMax = Math.abs(dataMax!);
|
||||
@ -100,8 +107,14 @@ export class UPlotScaleBuilder extends PlotConfigBuilder<ScaleProps, Scale> {
|
||||
dataMax = max;
|
||||
}
|
||||
|
||||
// @ts-ignore here we may use hardMin / hardMax to make sure any extra padding is computed from a more accurate delta
|
||||
minMax = uPlot.rangeNum(hardMinOnly ? hardMin : dataMin, hardMaxOnly ? hardMax : dataMax, rangeConfig);
|
||||
if (scale.distr === 4) {
|
||||
// TODO: switch to `, true)` after updating uPlot to 1.6.23+
|
||||
// see https://github.com/leeoniya/uPlot/issues/749
|
||||
minMax = uPlot.rangeAsinh(dataMin!, dataMax!, scale.log ?? 10, false);
|
||||
} else {
|
||||
// @ts-ignore here we may use hardMin / hardMax to make sure any extra padding is computed from a more accurate delta
|
||||
minMax = uPlot.rangeNum(hardMinOnly ? hardMin : dataMin, hardMaxOnly ? hardMax : dataMax, rangeConfig);
|
||||
}
|
||||
} else if (scale.distr === 3) {
|
||||
minMax = uPlot.rangeLog(dataMin!, dataMax!, scale.log ?? 10, true);
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ import {
|
||||
} from '@grafana/data';
|
||||
import { AxisColorMode, AxisConfig, AxisPlacement, ScaleDistribution, ScaleDistributionConfig } from '@grafana/schema';
|
||||
|
||||
import { graphFieldOptions, Select, HorizontalGroup, RadioButtonGroup } from '../../index';
|
||||
import { graphFieldOptions, Select, RadioButtonGroup, Input, Field } from '../../index';
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
@ -128,6 +128,10 @@ const DISTRIBUTION_OPTIONS: Array<SelectableValue<ScaleDistribution>> = [
|
||||
label: 'Logarithmic',
|
||||
value: ScaleDistribution.Log,
|
||||
},
|
||||
{
|
||||
label: 'Symlog',
|
||||
value: ScaleDistribution.Symlog,
|
||||
},
|
||||
];
|
||||
|
||||
const LOG_DISTRIBUTION_OPTIONS: Array<SelectableValue<number>> = [
|
||||
@ -147,32 +151,48 @@ const LOG_DISTRIBUTION_OPTIONS: Array<SelectableValue<number>> = [
|
||||
export const ScaleDistributionEditor = ({ value, onChange }: StandardEditorProps<ScaleDistributionConfig>) => {
|
||||
const type = value?.type ?? ScaleDistribution.Linear;
|
||||
return (
|
||||
<HorizontalGroup>
|
||||
<RadioButtonGroup
|
||||
value={type}
|
||||
options={DISTRIBUTION_OPTIONS}
|
||||
onChange={(v) => {
|
||||
onChange({
|
||||
...value,
|
||||
type: v!,
|
||||
log: v === ScaleDistribution.Linear ? undefined : 2,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
{type === ScaleDistribution.Log && (
|
||||
<Select
|
||||
options={LOG_DISTRIBUTION_OPTIONS}
|
||||
value={value.log || 2}
|
||||
prefix={'base'}
|
||||
width={12}
|
||||
<>
|
||||
<div style={{ marginBottom: 16 }}>
|
||||
<RadioButtonGroup
|
||||
value={type}
|
||||
options={DISTRIBUTION_OPTIONS}
|
||||
onChange={(v) => {
|
||||
onChange({
|
||||
...value,
|
||||
log: v.value!,
|
||||
type: v!,
|
||||
log: v === ScaleDistribution.Linear ? undefined : value.log ?? 2,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{(type === ScaleDistribution.Log || type === ScaleDistribution.Symlog) && (
|
||||
<Field label="Log base">
|
||||
<Select
|
||||
options={LOG_DISTRIBUTION_OPTIONS}
|
||||
value={value.log ?? 2}
|
||||
onChange={(v) => {
|
||||
onChange({
|
||||
...value,
|
||||
log: v.value!,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</Field>
|
||||
)}
|
||||
</HorizontalGroup>
|
||||
{type === ScaleDistribution.Symlog && (
|
||||
<Field label="Linear threshold">
|
||||
<Input
|
||||
placeholder="1"
|
||||
value={value.linearThreshold}
|
||||
onChange={(v) => {
|
||||
onChange({
|
||||
...value,
|
||||
linearThreshold: Number(v.currentTarget.value),
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</Field>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -105,6 +105,7 @@ Object {
|
||||
],
|
||||
"scales": Object {
|
||||
"m/s": Object {
|
||||
"asinh": undefined,
|
||||
"auto": true,
|
||||
"dir": 1,
|
||||
"distr": 1,
|
||||
@ -114,6 +115,7 @@ Object {
|
||||
"time": undefined,
|
||||
},
|
||||
"x": Object {
|
||||
"asinh": undefined,
|
||||
"auto": true,
|
||||
"dir": -1,
|
||||
"distr": 2,
|
||||
@ -256,6 +258,7 @@ Object {
|
||||
],
|
||||
"scales": Object {
|
||||
"m/s": Object {
|
||||
"asinh": undefined,
|
||||
"auto": true,
|
||||
"dir": 1,
|
||||
"distr": 1,
|
||||
@ -265,6 +268,7 @@ Object {
|
||||
"time": undefined,
|
||||
},
|
||||
"x": Object {
|
||||
"asinh": undefined,
|
||||
"auto": true,
|
||||
"dir": -1,
|
||||
"distr": 2,
|
||||
@ -407,6 +411,7 @@ Object {
|
||||
],
|
||||
"scales": Object {
|
||||
"m/s": Object {
|
||||
"asinh": undefined,
|
||||
"auto": true,
|
||||
"dir": 1,
|
||||
"distr": 1,
|
||||
@ -416,6 +421,7 @@ Object {
|
||||
"time": undefined,
|
||||
},
|
||||
"x": Object {
|
||||
"asinh": undefined,
|
||||
"auto": true,
|
||||
"dir": 1,
|
||||
"distr": 2,
|
||||
@ -558,6 +564,7 @@ Object {
|
||||
],
|
||||
"scales": Object {
|
||||
"m/s": Object {
|
||||
"asinh": undefined,
|
||||
"auto": true,
|
||||
"dir": 1,
|
||||
"distr": 1,
|
||||
@ -567,6 +574,7 @@ Object {
|
||||
"time": undefined,
|
||||
},
|
||||
"x": Object {
|
||||
"asinh": undefined,
|
||||
"auto": true,
|
||||
"dir": -1,
|
||||
"distr": 2,
|
||||
@ -709,6 +717,7 @@ Object {
|
||||
],
|
||||
"scales": Object {
|
||||
"m/s": Object {
|
||||
"asinh": undefined,
|
||||
"auto": true,
|
||||
"dir": 1,
|
||||
"distr": 1,
|
||||
@ -718,6 +727,7 @@ Object {
|
||||
"time": undefined,
|
||||
},
|
||||
"x": Object {
|
||||
"asinh": undefined,
|
||||
"auto": true,
|
||||
"dir": -1,
|
||||
"distr": 2,
|
||||
@ -860,6 +870,7 @@ Object {
|
||||
],
|
||||
"scales": Object {
|
||||
"m/s": Object {
|
||||
"asinh": undefined,
|
||||
"auto": true,
|
||||
"dir": 1,
|
||||
"distr": 1,
|
||||
@ -869,6 +880,7 @@ Object {
|
||||
"time": undefined,
|
||||
},
|
||||
"x": Object {
|
||||
"asinh": undefined,
|
||||
"auto": true,
|
||||
"dir": -1,
|
||||
"distr": 2,
|
||||
@ -1011,6 +1023,7 @@ Object {
|
||||
],
|
||||
"scales": Object {
|
||||
"m/s": Object {
|
||||
"asinh": undefined,
|
||||
"auto": true,
|
||||
"dir": 1,
|
||||
"distr": 1,
|
||||
@ -1020,6 +1033,7 @@ Object {
|
||||
"time": undefined,
|
||||
},
|
||||
"x": Object {
|
||||
"asinh": undefined,
|
||||
"auto": true,
|
||||
"dir": -1,
|
||||
"distr": 2,
|
||||
@ -1162,6 +1176,7 @@ Object {
|
||||
],
|
||||
"scales": Object {
|
||||
"m/s": Object {
|
||||
"asinh": undefined,
|
||||
"auto": true,
|
||||
"dir": 1,
|
||||
"distr": 1,
|
||||
@ -1171,6 +1186,7 @@ Object {
|
||||
"time": undefined,
|
||||
},
|
||||
"x": Object {
|
||||
"asinh": undefined,
|
||||
"auto": true,
|
||||
"dir": -1,
|
||||
"distr": 2,
|
||||
|
Loading…
Reference in New Issue
Block a user