Histogram: move histogram from alpha to beta panel (#34246)

* add legend

* tooltip off-by-one

* units in x axis

* update function call

* remove tooltip
pull/34340/head^2
Ryan McKinley 5 years ago committed by GitHub
parent 348e76fc8e
commit 8147a65b5e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 9
      packages/grafana-data/src/transformations/transformers/histogram.ts
  2. 2
      packages/grafana-ui/src/components/uPlot/config/UPlotAxisBuilder.ts
  3. 39
      public/app/plugins/panel/histogram/Histogram.tsx
  4. 9
      public/app/plugins/panel/histogram/HistogramPanel.tsx
  5. 21
      public/app/plugins/panel/histogram/models.gen.ts
  6. 7
      public/app/plugins/panel/histogram/module.tsx
  7. 2
      public/app/plugins/panel/histogram/plugin.json

@ -203,16 +203,17 @@ export function buildHistogram(frames: DataFrame[], options?: HistogramTransform
} }
const bucketMin = { const bucketMin = {
...counts[0],
name: histogramFrameBucketMinFieldName, name: histogramFrameBucketMinFieldName,
values: new ArrayVector(joinedHists[0]), values: new ArrayVector(joinedHists[0]),
type: FieldType.number, type: FieldType.number,
config: {}, state: undefined,
}; };
const bucketMax = { const bucketMax = {
...bucketMin,
name: histogramFrameBucketMaxFieldName, name: histogramFrameBucketMaxFieldName,
values: new ArrayVector(joinedHists[0].map((v) => v + bucketSize!)), values: new ArrayVector(joinedHists[0].map((v) => v + bucketSize!)),
type: FieldType.number, state: undefined,
config: {},
}; };
if (options?.combine) { if (options?.combine) {
@ -227,6 +228,8 @@ export function buildHistogram(frames: DataFrame[], options?: HistogramTransform
...counts[0], ...counts[0],
name: 'Count', name: 'Count',
values: new ArrayVector(vals), values: new ArrayVector(vals),
type: FieldType.number,
state: undefined,
}, },
]; ];
} else { } else {

@ -93,7 +93,7 @@ export class UPlotAxisBuilder extends PlotConfigBuilder<AxisProps, Axis> {
} else if (isTime) { } else if (isTime) {
config.values = formatTime; config.values = formatTime;
} else if (formatValue) { } else if (formatValue) {
config.values = (u: uPlot, vals: any[]) => vals.map((v) => formatValue!(v)); config.values = (u: uPlot, vals: any[]) => vals.map(formatValue!);
} }
// store timezone // store timezone

@ -2,6 +2,7 @@ import React from 'react';
import uPlot, { AlignedData } from 'uplot'; import uPlot, { AlignedData } from 'uplot';
import { import {
DataFrame, DataFrame,
formattedValueToString,
getFieldColorModeForField, getFieldColorModeForField,
getFieldDisplayName, getFieldDisplayName,
getFieldSeriesColor, getFieldSeriesColor,
@ -16,6 +17,8 @@ import {
AxisPlacement, AxisPlacement,
ScaleDirection, ScaleDirection,
ScaleOrientation, ScaleOrientation,
LegendDisplayMode,
PlotLegend,
} from '@grafana/ui'; } from '@grafana/ui';
import { import {
@ -32,12 +35,7 @@ export interface HistogramProps extends Themeable2 {
height: number; height: number;
structureRev?: number; // a number that will change when the frames[] structure changes structureRev?: number; // a number that will change when the frames[] structure changes
legend: VizLegendOptions; legend: VizLegendOptions;
//onLegendClick?: (event: GraphNGLegendEvent) => void;
children?: (builder: UPlotConfigBuilder, frame: DataFrame) => React.ReactNode; children?: (builder: UPlotConfigBuilder, frame: DataFrame) => React.ReactNode;
//prepConfig: (frame: DataFrame) => UPlotConfigBuilder;
//propsToDiff?: string[];
//renderLegend: (config: UPlotConfigBuilder) => React.ReactElement;
} }
const prepConfig = (frame: DataFrame, theme: GrafanaTheme2) => { const prepConfig = (frame: DataFrame, theme: GrafanaTheme2) => {
@ -84,12 +82,18 @@ const prepConfig = (frame: DataFrame, theme: GrafanaTheme2) => {
direction: ScaleDirection.Up, direction: ScaleDirection.Up,
}); });
const fmt = frame.fields[0].display!;
const xAxisFormatter = (v: number) => {
return formattedValueToString(fmt(v));
};
builder.addAxis({ builder.addAxis({
scaleKey: 'x', scaleKey: 'x',
isTime: false, isTime: false,
placement: AxisPlacement.Bottom, placement: AxisPlacement.Bottom,
incrs: histogramBucketSizes, incrs: histogramBucketSizes,
splits: xSplits, splits: xSplits,
values: (u: uPlot, vals: any[]) => vals.map(xAxisFormatter),
//incrs: () => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((mult) => mult * bucketSize), //incrs: () => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((mult) => mult * bucketSize),
//splits: config.xSplits, //splits: config.xSplits,
//values: config.xValues, //values: config.xValues,
@ -138,15 +142,15 @@ const prepConfig = (frame: DataFrame, theme: GrafanaTheme2) => {
colorMode, colorMode,
pathBuilder, pathBuilder,
//pointsBuilder: config.drawPoints, //pointsBuilder: config.drawPoints,
show: !customConfig.hideFrom?.graph, show: !customConfig.hideFrom?.vis,
gradientMode: customConfig.gradientMode, gradientMode: customConfig.gradientMode,
thresholds: field.config.thresholds, thresholds: field.config.thresholds,
// The following properties are not used in the uPlot config, but are utilized as transport for legend config // The following properties are not used in the uPlot config, but are utilized as transport for legend config
// dataFrameFieldIndex: { dataFrameFieldIndex: {
// fieldIndex: i, fieldIndex: i,
// frameIndex: 0, frameIndex: 0,
// }, },
fieldName: getFieldDisplayName(field, frame), fieldName: getFieldDisplayName(field, frame),
hideInLegend: customConfig.hideFrom?.legend, hideInLegend: customConfig.hideFrom?.legend,
}); });
@ -178,10 +182,6 @@ const preparePlotData = (frame: DataFrame) => {
return data; return data;
}; };
const renderLegend = (config: UPlotConfigBuilder) => {
return null;
};
interface State { interface State {
alignedData: AlignedData; alignedData: AlignedData;
config?: UPlotConfigBuilder; config?: UPlotConfigBuilder;
@ -210,6 +210,15 @@ export class Histogram extends React.Component<HistogramProps, State> {
return state; return state;
} }
renderLegend(config: UPlotConfigBuilder) {
const { legend } = this.props;
if (!config || legend.displayMode === LegendDisplayMode.Hidden) {
return null;
}
return <PlotLegend data={[this.props.alignedFrame]} config={config} maxHeight="35%" maxWidth="60%" {...legend} />;
}
componentDidUpdate(prevProps: HistogramProps) { componentDidUpdate(prevProps: HistogramProps) {
const { structureRev, alignedFrame } = this.props; const { structureRev, alignedFrame } = this.props;
@ -241,7 +250,7 @@ export class Histogram extends React.Component<HistogramProps, State> {
} }
return ( return (
<VizLayout width={width} height={height} legend={renderLegend(config) as any}> <VizLayout width={width} height={height} legend={this.renderLegend(config)}>
{(vizWidth: number, vizHeight: number) => ( {(vizWidth: number, vizHeight: number) => (
<UPlotChart <UPlotChart
config={this.state.config!} config={this.state.config!}

@ -26,6 +26,7 @@ export const HistogramPanel: React.FC<Props> = ({ data, options, width, height }
if (!hist) { if (!hist) {
return undefined; return undefined;
} }
return histogramFieldsToFrame(hist); return histogramFieldsToFrame(hist);
}, [data.series, options]); }, [data.series, options]);
@ -41,11 +42,15 @@ export const HistogramPanel: React.FC<Props> = ({ data, options, width, height }
<Histogram <Histogram
options={options} options={options}
theme={theme} theme={theme}
legend={null as any} // TODO! legend={options.legend}
structureRev={data.structureRev} structureRev={data.structureRev}
width={width} width={width}
height={height} height={height}
alignedFrame={histogram} alignedFrame={histogram}
/> >
{(config, alignedFrame) => {
return null; // <TooltipPlugin data={alignedFrame} config={config} mode={options.tooltip.mode} timeZone={timeZone} />;
}}
</Histogram>
); );
}; };

@ -3,11 +3,18 @@
// It is currenty hand written but will serve as the target for cuetsy // It is currenty hand written but will serve as the target for cuetsy
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
import { GraphGradientMode } from '@grafana/ui'; import {
GraphGradientMode,
HideableFieldConfig,
LegendDisplayMode,
OptionsWithLegend,
OptionsWithTooltip,
TooltipDisplayMode,
} from '@grafana/ui';
export const modelVersion = Object.freeze([1, 0]); export const modelVersion = Object.freeze([1, 0]);
export interface PanelOptions { export interface PanelOptions extends OptionsWithLegend, OptionsWithTooltip {
bucketSize?: number; bucketSize?: number;
bucketOffset?: number; bucketOffset?: number;
combine?: boolean; combine?: boolean;
@ -15,12 +22,20 @@ export interface PanelOptions {
export const defaultPanelOptions: PanelOptions = { export const defaultPanelOptions: PanelOptions = {
bucketOffset: 0, bucketOffset: 0,
legend: {
displayMode: LegendDisplayMode.List,
placement: 'bottom',
calcs: [],
},
tooltip: {
mode: TooltipDisplayMode.Multi,
},
}; };
/** /**
* @alpha * @alpha
*/ */
export interface PanelFieldConfig { export interface PanelFieldConfig extends HideableFieldConfig {
lineWidth?: number; // 0 lineWidth?: number; // 0
fillOpacity?: number; // 100 fillOpacity?: number; // 100
gradientMode?: GraphGradientMode; gradientMode?: GraphGradientMode;

@ -1,6 +1,6 @@
import { FieldColorModeId, FieldConfigProperty, PanelPlugin } from '@grafana/data'; import { FieldColorModeId, FieldConfigProperty, PanelPlugin } from '@grafana/data';
import { HistogramPanel } from './HistogramPanel'; import { HistogramPanel } from './HistogramPanel';
import { graphFieldOptions } from '@grafana/ui'; import { commonOptionsBuilder, graphFieldOptions } from '@grafana/ui';
import { PanelFieldConfig, PanelOptions, defaultPanelFieldConfig, defaultPanelOptions } from './models.gen'; import { PanelFieldConfig, PanelOptions, defaultPanelFieldConfig, defaultPanelOptions } from './models.gen';
import { originalDataHasHistogram } from './utils'; import { originalDataHasHistogram } from './utils';
@ -44,6 +44,9 @@ export const plugin = new PanelPlugin<PanelOptions, PanelFieldConfig>(HistogramP
defaultValue: defaultPanelOptions.combine, defaultValue: defaultPanelOptions.combine,
showIf: (opts, data) => !originalDataHasHistogram(data), showIf: (opts, data) => !originalDataHasHistogram(data),
}); });
// commonOptionsBuilder.addTooltipOptions(builder);
commonOptionsBuilder.addLegendOptions(builder);
}) })
.useFieldConfig({ .useFieldConfig({
standardOptions: { standardOptions: {
@ -88,5 +91,7 @@ export const plugin = new PanelPlugin<PanelOptions, PanelFieldConfig>(HistogramP
options: graphFieldOptions.fillGradient, options: graphFieldOptions.fillGradient,
}, },
}); });
commonOptionsBuilder.addHideFrom(builder);
}, },
}); });

@ -3,7 +3,7 @@
"name": "Histogram", "name": "Histogram",
"id": "histogram", "id": "histogram",
"state": "alpha", "state": "beta",
"info": { "info": {
"author": { "author": {

Loading…
Cancel
Save