From be1c5e13d529719689bf017fe4b60a4fb4054a37 Mon Sep 17 00:00:00 2001 From: Leon Sorokin Date: Tue, 10 Jan 2023 17:42:45 -0600 Subject: [PATCH] DataFrame: Add explicit histogram frame type (panel & transforms) (#61195) --- .../panel-histogram/histogram_tests.json | 1188 +++++++++++------ .../transformers/histogram.test.ts | 10 +- .../transformations/transformers/histogram.ts | 94 +- .../grafana-data/src/types/dataFrameTypes.ts | 6 + .../app/plugins/panel/histogram/Histogram.tsx | 12 +- .../panel/histogram/HistogramPanel.tsx | 14 + public/app/plugins/panel/histogram/utils.ts | 8 +- 7 files changed, 865 insertions(+), 467 deletions(-) diff --git a/devenv/dev-dashboards/panel-histogram/histogram_tests.json b/devenv/dev-dashboards/panel-histogram/histogram_tests.json index 49caf47b446..1bb343f7088 100644 --- a/devenv/dev-dashboards/panel-histogram/histogram_tests.json +++ b/devenv/dev-dashboards/panel-histogram/histogram_tests.json @@ -1,434 +1,772 @@ { - "annotations": { - "list": [ - { - "builtIn": 1, - "datasource": "-- Grafana --", - "enable": true, - "hide": true, - "iconColor": "rgba(0, 211, 255, 1)", - "name": "Annotations & Alerts", - "type": "dashboard" - } - ] - }, - "editable": true, - "graphTooltip": 0, - "id": 632, - "links": [], - "panels": [ - { - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "fillOpacity": 80, - "gradientMode": "none", - "hideFrom": { - "viz": false, - "legend": false, - "tooltip": false - }, - "lineWidth": 1 - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 0 - }, - "id": 4, - "options": { - "bucketOffset": 0, - "combine": false, - "legend": { - "calcs": [], - "displayMode": "hidden", - "placement": "bottom" - } - }, - "targets": [ - { - "refId": "A", - "scenarioId": "random_walk", - "spread": 10 - } - ], - "title": "Time series + Auto buckets", - "type": "histogram" - }, + "annotations": { + "list": [ { + "builtIn": 1, "datasource": { "type": "datasource", - "uid": "-- Dashboard --" + "uid": "grafana" }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "fillOpacity": 80, - "gradientMode": "none", - "hideFrom": { - "viz": false, - "legend": false, - "tooltip": false - }, - "lineWidth": 1 - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "target": { + "limit": 100, + "matchAny": false, + "tags": [], + "type": "dashboard" }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 0 - }, - "id": 3, - "options": { - "bucketOffset": 0, - "bucketSize": 3, - "combine": false, - "legend": { - "calcs": [], - "displayMode": "hidden", - "placement": "bottom" - } - }, - "targets": [ - { - "panelId": 4, - "refId": "A" - } - ], - "title": "Time series + bucket size 3", - "type": "histogram" - }, - { - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "fillOpacity": 80, - "gradientMode": "none", - "hideFrom": { - "viz": false, - "legend": false, - "tooltip": false - }, - "lineWidth": 1 - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 8 - }, - "id": 5, - "options": { - "bucketOffset": 0, - "bucketSize": 1, - "combine": false, - "legend": { - "calcs": [], - "displayMode": "hidden", - "placement": "bottom" - } - }, - "targets": [ - { - "csvFileName": "weight_height.csv", - "refId": "A", - "scenarioId": "csv_file" - } - ], - "title": "People height distribution", - "transformations": [ - { - "id": "filterFieldsByName", - "options": { - "include": { - "names": [ - "Height" - ] - } - } - } - ], - "type": "histogram" - }, - { - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "fillOpacity": 80, - "gradientMode": "none", - "hideFrom": { - "viz": false, - "legend": false, - "tooltip": false - }, - "lineWidth": 1 - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 8 - }, - "id": 6, - "options": { - "bucketOffset": 0, - "bucketSize": 5, - "combine": false, - "legend": { - "calcs": [], - "displayMode": "hidden", - "placement": "bottom" - } - }, - "targets": [ - { - "csvFileName": "weight_height.csv", - "refId": "A", - "scenarioId": "csv_file" - } - ], - "title": "People weight distribution", - "transformations": [ - { - "id": "filterFieldsByName", - "options": { - "include": { - "names": [ - "Weight" - ] - } - } - } - ], - "type": "histogram" - }, - { - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "custom": { - "align": "auto", - "displayMode": "auto" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 9, - "w": 12, - "x": 0, - "y": 16 - }, - "id": 8, - "options": { - "showHeader": true - }, - "pluginVersion": "8.1.0-pre", - "targets": [ - { - "csvFileName": "weight_height.csv", - "refId": "A", - "scenarioId": "csv_file" - } - ], - "title": "Standalone transform - Height", - "transformations": [ - { - "id": "filterFieldsByName", - "options": { - "include": { - "names": [ - "Height" - ] - } - } - }, - { - "id": "histogram", - "options": { - "combine": true, - "fields": {} - } - } - ], - "type": "table" - }, - { - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "custom": { - "align": "auto", - "displayMode": "auto" - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green" - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 9, - "w": 12, - "x": 12, - "y": 16 - }, - "id": 9, - "options": { - "showHeader": true - }, - "pluginVersion": "8.1.0-pre", - "targets": [ - { - "csvFileName": "weight_height.csv", - "refId": "A", - "scenarioId": "csv_file" - } - ], - "title": "Standalone transform - Weight", - "transformations": [ - { - "id": "filterFieldsByName", - "options": { - "include": { - "names": [ - "Weight" - ] - } - } - }, - { - "id": "histogram", - "options": { - "combine": true, - "fields": {} - } - } - ], - "type": "table" + "type": "dashboard" } - ], - "schemaVersion": 33, - "style": "dark", - "tags": [ - "gdev", - "panel-tests", - "graph-ng" - ], - "templating": { - "list": [] + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 4, + "options": { + "bucketOffset": 0, + "combine": false, + "legend": { + "calcs": [ + "sum" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + } + }, + "targets": [ + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "A", + "scenarioId": "random_walk", + "spread": 10 + } + ], + "title": "Time series + Auto buckets", + "type": "histogram" }, - "time": { - "from": "now-6h", - "to": "now" + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 3, + "options": { + "bucketOffset": 0, + "bucketSize": 3, + "combine": false, + "legend": { + "calcs": [ + "sum" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + } + }, + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 4, + "refId": "A" + } + ], + "title": "Time series + bucket size 3", + "type": "histogram" }, - "timepicker": {}, - "timezone": "", - "title": "Panel Tests - Histogram", - "uid": "UTv--wqMk", - "version": 4 - } + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 5, + "options": { + "bucketOffset": 0, + "bucketSize": 1, + "combine": false, + "legend": { + "calcs": [ + "sum" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + } + }, + "targets": [ + { + "csvFileName": "weight_height.csv", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "A", + "scenarioId": "csv_file" + } + ], + "title": "People height distribution", + "transformations": [ + { + "id": "filterFieldsByName", + "options": { + "include": { + "names": [ + "Height" + ] + } + } + } + ], + "type": "histogram" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 8 + }, + "id": 6, + "options": { + "bucketOffset": 0, + "bucketSize": 5, + "combine": false, + "legend": { + "calcs": [ + "sum" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + } + }, + "targets": [ + { + "csvFileName": "weight_height.csv", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "A", + "scenarioId": "csv_file" + } + ], + "title": "People weight distribution", + "transformations": [ + { + "id": "filterFieldsByName", + "options": { + "include": { + "names": [ + "Weight" + ] + } + } + } + ], + "type": "histogram" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "displayMode": "auto", + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 0, + "y": 16 + }, + "id": 8, + "options": { + "footer": { + "countRows": false, + "fields": [], + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "9.4.0-pre", + "targets": [ + { + "csvFileName": "weight_height.csv", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "A", + "scenarioId": "csv_file" + } + ], + "title": "Standalone transform - Height", + "transformations": [ + { + "id": "filterFieldsByName", + "options": { + "include": { + "names": [ + "Height" + ] + } + } + }, + { + "id": "histogram", + "options": { + "combine": true, + "fields": {} + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "align": "auto", + "displayMode": "auto", + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 12, + "x": 12, + "y": 16 + }, + "id": 9, + "options": { + "footer": { + "countRows": false, + "fields": [], + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "9.4.0-pre", + "targets": [ + { + "csvFileName": "weight_height.csv", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "A", + "scenarioId": "csv_file" + } + ], + "title": "Standalone transform - Weight", + "transformations": [ + { + "id": "filterFieldsByName", + "options": { + "include": { + "names": [ + "Weight" + ] + } + } + }, + { + "id": "histogram", + "options": { + "combine": true, + "fields": {} + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "count1" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 25 + }, + "id": 11, + "options": { + "bucketOffset": 0, + "legend": { + "calcs": [ + "sum" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + } + }, + "targets": [ + { + "csvContent": "xMin,xMax,count1,abcd\n1,2,10,123\n2,3,20,265\n3,4,30,73\n4,5,10,24", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "A", + "scenarioId": "csv_content" + } + ], + "title": "Explicit xMin,xMax", + "type": "histogram" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "count1" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 25 + }, + "id": 12, + "options": { + "bucketOffset": 0, + "legend": { + "calcs": [ + "sum" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + } + }, + "targets": [ + { + "csvContent": "xMin,count1,abcd\n1,10,123\n2,20,265\n3,30,73\n4,10,24", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "A", + "scenarioId": "csv_content" + } + ], + "title": "Implict xMax", + "type": "histogram" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "thresholds" + }, + "custom": { + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1 + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "count1" + }, + "properties": [ + { + "id": "color", + "value": { + "fixedColor": "red", + "mode": "fixed" + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 25 + }, + "id": 13, + "options": { + "bucketOffset": 0, + "legend": { + "calcs": [ + "sum" + ], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + } + }, + "targets": [ + { + "csvContent": "xMax,count1,abcd\n1,10,123\n2,20,265\n3,30,73\n4,10,24", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "A", + "scenarioId": "csv_content" + } + ], + "title": "Implict xMin", + "type": "histogram" + } + ], + "revision": 1, + "schemaVersion": 37, + "style": "dark", + "tags": [ + "gdev", + "panel-tests", + "graph-ng" + ], + "templating": { + "list": [] + }, + "time": { + "from": "now-6h", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "Panel Tests - Histogram", + "uid": "UTv--wqMk", + "version": 7, + "weekStart": "" +} diff --git a/packages/grafana-data/src/transformations/transformers/histogram.test.ts b/packages/grafana-data/src/transformations/transformers/histogram.test.ts index 98e127ee2f1..dd1e24fb2d7 100644 --- a/packages/grafana-data/src/transformations/transformers/histogram.test.ts +++ b/packages/grafana-data/src/transformations/transformers/histogram.test.ts @@ -35,7 +35,7 @@ describe('histogram frames frames', () => { "config": { "unit": "mph", }, - "name": "BucketMin", + "name": "xMin", "values": [ 1, 2, @@ -52,7 +52,7 @@ describe('histogram frames frames', () => { "config": { "unit": "mph", }, - "name": "BucketMax", + "name": "xMax", "values": [ 2, 3, @@ -145,7 +145,7 @@ describe('histogram frames frames', () => { ).toMatchInlineSnapshot(` [ { - "name": "BucketMin", + "name": "xMin", "values": [ 1, 2, @@ -159,7 +159,7 @@ describe('histogram frames frames', () => { ], }, { - "name": "BucketMax", + "name": "xMax", "values": [ 2, 3, @@ -173,7 +173,7 @@ describe('histogram frames frames', () => { ], }, { - "name": "Count", + "name": "count", "values": [ 1, 1, diff --git a/packages/grafana-data/src/transformations/transformers/histogram.ts b/packages/grafana-data/src/transformations/transformers/histogram.ts index 943f46975d6..c0da943552a 100644 --- a/packages/grafana-data/src/transformations/transformers/histogram.ts +++ b/packages/grafana-data/src/transformations/transformers/histogram.ts @@ -2,8 +2,9 @@ import { map } from 'rxjs/operators'; import { getDisplayProcessor } from '../../field'; import { createTheme, GrafanaTheme2 } from '../../themes'; -import { SynchronousDataTransformerInfo } from '../../types'; +import { DataFrameType, SynchronousDataTransformerInfo } from '../../types'; import { DataFrame, Field, FieldConfig, FieldType } from '../../types/dataFrame'; +import { roundDecimals } from '../../utils'; import { ArrayVector } from '../../vector/ArrayVector'; import { DataTransformerID } from './ids'; @@ -100,19 +101,33 @@ export const histogramTransformer: SynchronousDataTransformerInfo 1) { + let vals = xMin.values.toArray(); + let bucketSize = roundDecimals(vals[1] - vals[0], 6); + + xMax = { + ...xMin, + name: histogramFrameBucketMaxFieldName, + values: new ArrayVector(vals.map((v) => v + bucketSize)), + }; + } + + if (!xMin && xMax && xMax?.values.length > 1) { + let vals = xMax.values.toArray(); + let bucketSize = roundDecimals(vals[1] - vals[0], 6); + + xMin = { + ...xMax, + name: histogramFrameBucketMinFieldName, + values: new ArrayVector(vals.map((v) => v - bucketSize)), + }; + } + + if (xMin && xMax && counts.length) { return { - bucketMin, - bucketMax, + xMin, + xMax, counts, }; } @@ -250,7 +289,7 @@ export function buildHistogram(frames: DataFrame[], options?: HistogramTransform } } - const bucketMin: Field = { + const xMin: Field = { name: histogramFrameBucketMinFieldName, values: new ArrayVector(joinedHists[0]), type: FieldType.number, @@ -263,8 +302,8 @@ export function buildHistogram(frames: DataFrame[], options?: HistogramTransform decimals: bucketDecimals, }, }; - const bucketMax = { - ...bucketMin, + const xMax = { + ...xMin, name: histogramFrameBucketMaxFieldName, values: new ArrayVector(joinedHists[0].map((v) => v + bucketSize!)), }; @@ -279,7 +318,7 @@ export function buildHistogram(frames: DataFrame[], options?: HistogramTransform counts = [ { ...counts[0], - name: 'Count', + name: 'count', values: new ArrayVector(vals), type: FieldType.number, state: undefined, @@ -292,8 +331,8 @@ export function buildHistogram(frames: DataFrame[], options?: HistogramTransform } return { - bucketMin, - bucketMax, + xMin, + xMax, counts, }; } @@ -364,13 +403,13 @@ function histogram( * @internal */ export function histogramFieldsToFrame(info: HistogramFields, theme?: GrafanaTheme2): DataFrame { - if (!info.bucketMin.display) { + if (!info.xMin.display) { const display = getDisplayProcessor({ - field: info.bucketMin, + field: info.xMin, theme: theme ?? createTheme(), }); - info.bucketMin.display = display; - info.bucketMax.display = display; + info.xMin.display = display; + info.xMax.display = display; } // ensure updated units are reflected on the count field used for y axis formatting @@ -380,7 +419,10 @@ export function histogramFieldsToFrame(info: HistogramFields, theme?: GrafanaThe }); return { - fields: [info.bucketMin, info.bucketMax, ...info.counts], - length: info.bucketMin.values.length, + length: info.xMin.values.length, + meta: { + type: DataFrameType.Histogram, + }, + fields: [info.xMin, info.xMax, ...info.counts], }; } diff --git a/packages/grafana-data/src/types/dataFrameTypes.ts b/packages/grafana-data/src/types/dataFrameTypes.ts index 17103d77fde..3b515b3f8a8 100644 --- a/packages/grafana-data/src/types/dataFrameTypes.ts +++ b/packages/grafana-data/src/types/dataFrameTypes.ts @@ -30,4 +30,10 @@ export enum DataFrameType { * If the y value is actually ordinal, use `meta.custom` to specify the bucket lookup values */ HeatmapCells = 'heatmap-cells', + + /** + * Explicit fields for: + * xMin, xMax, count + */ + Histogram = 'histogram', } diff --git a/public/app/plugins/panel/histogram/Histogram.tsx b/public/app/plugins/panel/histogram/Histogram.tsx index 85721e7d7d0..0616e914829 100644 --- a/public/app/plugins/panel/histogram/Histogram.tsx +++ b/public/app/plugins/panel/histogram/Histogram.tsx @@ -175,7 +175,7 @@ const prepConfig = (frame: DataFrame, theme: GrafanaTheme2) => { let seriesIndex = 0; - // assumes BucketMax is [1] + // assumes xMin is [0], xMax is [1] for (let i = 2; i < frame.fields.length; i++) { const field = frame.fields[i]; @@ -209,10 +209,7 @@ const prepConfig = (frame: DataFrame, theme: GrafanaTheme2) => { softMax: customConfig.axisSoftMax, // The following properties are not used in the uPlot config, but are utilized as transport for legend config - dataFrameFieldIndex: { - fieldIndex: 1, - frameIndex: i - 2, - }, + dataFrameFieldIndex: field.state.origin, }); } @@ -272,11 +269,12 @@ export class Histogram extends React.Component { renderLegend(config: UPlotConfigBuilder) { const { legend } = this.props; - if (!config || legend.showLegend === false || !this.props.rawSeries) { + + if (!config || legend.showLegend === false) { return null; } - return ; + return ; } componentDidUpdate(prevProps: HistogramProps) { diff --git a/public/app/plugins/panel/histogram/HistogramPanel.tsx b/public/app/plugins/panel/histogram/HistogramPanel.tsx index 81513102dd6..fba60c5c61d 100644 --- a/public/app/plugins/panel/histogram/HistogramPanel.tsx +++ b/public/app/plugins/panel/histogram/HistogramPanel.tsx @@ -16,6 +16,20 @@ export const HistogramPanel = ({ data, options, width, height }: Props) => { if (!data?.series?.length) { return undefined; } + + // stamp origins for legend's calcs (from raw values) + data.series.forEach((frame, frameIndex) => { + frame.fields.forEach((field, fieldIndex) => { + field.state = { + ...field.state, + origin: { + frameIndex, + fieldIndex, + }, + }; + }); + }); + if (data.series.length === 1) { const info = getHistogramFields(data.series[0]); if (info) { diff --git a/public/app/plugins/panel/histogram/utils.ts b/public/app/plugins/panel/histogram/utils.ts index a98e8768f3d..51d041050bf 100644 --- a/public/app/plugins/panel/histogram/utils.ts +++ b/public/app/plugins/panel/histogram/utils.ts @@ -1,7 +1,7 @@ import { DataFrame, FieldType } from '@grafana/data'; import { - histogramFrameBucketMinFieldName, - histogramFrameBucketMaxFieldName, + isHistogramFrameBucketMinFieldName, + isHistogramFrameBucketMaxFieldName, } from '@grafana/data/src/transformations/transformers/histogram'; export function originalDataHasHistogram(frames?: DataFrame[]): boolean { @@ -14,8 +14,8 @@ export function originalDataHasHistogram(frames?: DataFrame[]): boolean { } if ( - frame.fields[0].name !== histogramFrameBucketMinFieldName || - frame.fields[1].name !== histogramFrameBucketMaxFieldName + !isHistogramFrameBucketMinFieldName(frame.fields[0].name) || + !isHistogramFrameBucketMaxFieldName(frame.fields[1].name) ) { return false; }