mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Histogram: reduce default bucket size, fix rendering (#35294)
This commit is contained in:
@@ -8,19 +8,31 @@ import { AlignedData, join } from './joinDataFrames';
|
||||
import { getDisplayProcessor } from '../../field';
|
||||
import { createTheme, GrafanaTheme2 } from '../../themes';
|
||||
|
||||
/* eslint-disable */
|
||||
// prettier-ignore
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
/* eslint-disable */
|
||||
// prettier-ignore
|
||||
export const histogramBucketSizes = [
|
||||
.001, .002, .0025, .005,
|
||||
.01, .02, .025, .05,
|
||||
.1, .2, .25, .5,
|
||||
1e-9, 2e-9, 2.5e-9, 4e-9, 5e-9,
|
||||
1e-8, 2e-8, 2.5e-8, 4e-8, 5e-8,
|
||||
1e-7, 2e-7, 2.5e-7, 4e-7, 5e-7,
|
||||
1e-6, 2e-6, 2.5e-6, 4e-6, 5e-6,
|
||||
1e-5, 2e-5, 2.5e-5, 4e-5, 5e-5,
|
||||
1e-4, 2e-4, 2.5e-4, 4e-4, 5e-4,
|
||||
1e-3, 2e-3, 2.5e-3, 4e-3, 5e-3,
|
||||
1e-2, 2e-2, 2.5e-2, 4e-2, 5e-2,
|
||||
1e-1, 2e-1, 2.5e-1, 4e-1, 5e-1,
|
||||
1, 2, 4, 5,
|
||||
10, 20, 25, 50,
|
||||
100, 200, 250, 500,
|
||||
1000, 2000, 2500, 5000,
|
||||
1e+1, 2e+1, 2.5e+1, 4e+1, 5e+1,
|
||||
1e+2, 2e+2, 2.5e+2, 4e+2, 5e+2,
|
||||
1e+3, 2e+3, 2.5e+3, 4e+3, 5e+3,
|
||||
1e+4, 2e+4, 2.5e+4, 4e+4, 5e+4,
|
||||
1e+5, 2e+5, 2.5e+5, 4e+5, 5e+5,
|
||||
1e+6, 2e+6, 2.5e+6, 4e+6, 5e+6,
|
||||
1e+7, 2e+7, 2.5e+7, 4e+7, 5e+7,
|
||||
1e+8, 2e+8, 2.5e+8, 4e+8, 5e+8,
|
||||
1e+9, 2e+9, 2.5e+9, 4e+9, 5e+9,
|
||||
];
|
||||
/* eslint-enable */
|
||||
|
||||
@@ -135,6 +147,8 @@ export function getHistogramFields(frame: DataFrame): HistogramFields | undefine
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const APPROX_BUCKETS = 20;
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
*/
|
||||
@@ -144,27 +158,47 @@ export function buildHistogram(frames: DataFrame[], options?: HistogramTransform
|
||||
|
||||
// if bucket size is auto, try to calc from all numeric fields
|
||||
if (!bucketSize) {
|
||||
let min = Infinity,
|
||||
max = -Infinity;
|
||||
let allValues: number[] = [];
|
||||
|
||||
// TODO: include field configs!
|
||||
for (const frame of frames) {
|
||||
for (const field of frame.fields) {
|
||||
if (field.type === FieldType.number) {
|
||||
for (const value of field.values.toArray()) {
|
||||
min = Math.min(min, value);
|
||||
max = Math.max(max, value);
|
||||
}
|
||||
allValues = allValues.concat(field.values.toArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let range = Math.abs(max - min);
|
||||
allValues.sort((a, b) => a - b);
|
||||
|
||||
let smallestDelta = Infinity;
|
||||
|
||||
// TODO: case of 1 value needs work
|
||||
if (allValues.length === 1) {
|
||||
smallestDelta = 1;
|
||||
} else {
|
||||
for (let i = 1; i < allValues.length; i++) {
|
||||
let delta = allValues[i] - allValues[i - 1];
|
||||
|
||||
if (delta !== 0) {
|
||||
smallestDelta = Math.min(smallestDelta, delta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let min = allValues[0];
|
||||
let max = allValues[allValues.length - 1];
|
||||
|
||||
let range = max - min;
|
||||
|
||||
const targetSize = range / APPROX_BUCKETS;
|
||||
|
||||
// choose bucket
|
||||
for (const size of histogramBucketSizes) {
|
||||
if (range / 10 < size) {
|
||||
bucketSize = size;
|
||||
for (let i = 0; i < histogramBucketSizes.length; i++) {
|
||||
let _bucketSize = histogramBucketSizes[i];
|
||||
|
||||
if (targetSize < _bucketSize && _bucketSize >= smallestDelta) {
|
||||
bucketSize = _bucketSize;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
"react-transition-group": "4.4.1",
|
||||
"slate": "0.47.8",
|
||||
"tinycolor2": "1.4.1",
|
||||
"uplot": "1.6.11"
|
||||
"uplot": "1.6.12"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-commonjs": "16.0.0",
|
||||
|
||||
@@ -38,6 +38,7 @@ function incrRoundUp(num: number, incr: number) {
|
||||
export interface HistogramProps extends Themeable2 {
|
||||
options: PanelOptions; // used for diff
|
||||
alignedFrame: DataFrame; // This could take HistogramFields
|
||||
bucketSize: number;
|
||||
width: number;
|
||||
height: number;
|
||||
structureRev?: number; // a number that will change when the frames[] structure changes
|
||||
@@ -45,13 +46,18 @@ export interface HistogramProps extends Themeable2 {
|
||||
children?: (builder: UPlotConfigBuilder, frame: DataFrame) => React.ReactNode;
|
||||
}
|
||||
|
||||
export function getBucketSize(frame: DataFrame) {
|
||||
// assumes BucketMin is fields[0] and BucktMax is fields[1]
|
||||
return frame.fields[1].values.get(0) - frame.fields[0].values.get(0);
|
||||
}
|
||||
|
||||
const prepConfig = (frame: DataFrame, theme: GrafanaTheme2) => {
|
||||
// todo: scan all values in BucketMin and BucketMax fields to assert if uniform bucketSize
|
||||
|
||||
let builder = new UPlotConfigBuilder();
|
||||
|
||||
// assumes BucketMin is fields[0] and BucktMax is fields[1]
|
||||
let bucketSize = frame.fields[1].values.get(0) - frame.fields[0].values.get(0);
|
||||
let bucketSize = getBucketSize(frame);
|
||||
|
||||
// splits shifter, to ensure splits always start at first bucket
|
||||
let xSplits: uPlot.Axis.Splits = (u, axisIdx, scaleMin, scaleMax, foundIncr, foundSpace) => {
|
||||
@@ -251,13 +257,14 @@ export class Histogram extends React.Component<HistogramProps, State> {
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: HistogramProps) {
|
||||
const { structureRev, alignedFrame } = this.props;
|
||||
const { structureRev, alignedFrame, bucketSize } = this.props;
|
||||
|
||||
if (alignedFrame !== prevProps.alignedFrame) {
|
||||
let newState = this.prepState(this.props, false);
|
||||
|
||||
if (newState) {
|
||||
const shouldReconfig =
|
||||
bucketSize !== prevProps.bucketSize ||
|
||||
this.props.options !== prevProps.options ||
|
||||
this.state.config === undefined ||
|
||||
structureRev !== prevProps.structureRev ||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import { PanelProps, buildHistogram, getHistogramFields } from '@grafana/data';
|
||||
|
||||
import { Histogram } from './Histogram';
|
||||
import { Histogram, getBucketSize } from './Histogram';
|
||||
import { PanelOptions } from './models.gen';
|
||||
import { useTheme2 } from '@grafana/ui';
|
||||
|
||||
@@ -38,6 +38,8 @@ export const HistogramPanel: React.FC<Props> = ({ data, options, width, height }
|
||||
);
|
||||
}
|
||||
|
||||
const bucketSize = getBucketSize(histogram);
|
||||
|
||||
return (
|
||||
<Histogram
|
||||
options={options}
|
||||
@@ -47,6 +49,7 @@ export const HistogramPanel: React.FC<Props> = ({ data, options, width, height }
|
||||
width={width}
|
||||
height={height}
|
||||
alignedFrame={histogram}
|
||||
bucketSize={bucketSize}
|
||||
>
|
||||
{(config, alignedFrame) => {
|
||||
return null; // <TooltipPlugin data={alignedFrame} config={config} mode={options.tooltip.mode} timeZone={timeZone} />;
|
||||
|
||||
@@ -22043,10 +22043,10 @@ update-notifier@^2.5.0:
|
||||
semver-diff "^2.0.0"
|
||||
xdg-basedir "^3.0.0"
|
||||
|
||||
uplot@1.6.11:
|
||||
version "1.6.11"
|
||||
resolved "https://registry.yarnpkg.com/uplot/-/uplot-1.6.11.tgz#2ade33071e4eb30c6504ad7c68eb4c05d9dd47eb"
|
||||
integrity sha512-DTA/wLLFSccSghZKM02hLgHoe8zDoCGFEkbbszXwkNRFgkkRKYc0gPNaJG76JFrwDlZNc7+u9noUHxt9fLu+lg==
|
||||
uplot@1.6.12:
|
||||
version "1.6.12"
|
||||
resolved "https://registry.yarnpkg.com/uplot/-/uplot-1.6.12.tgz#a2741f224c3d3b4f4f25a53797c1687ddfef2989"
|
||||
integrity sha512-afBjwy/9SM0E7w29Gen+wQ+UAe6ipiA2zE/s1dMCidMXQYvYkCpEgxLRkVA179/8eRJz+og2r7ZFS1HIzT75fQ==
|
||||
|
||||
upper-case@^1.1.1:
|
||||
version "1.1.3"
|
||||
|
||||
Reference in New Issue
Block a user