mirror of
https://github.com/grafana/grafana.git
synced 2024-12-26 00:41:20 -06:00
Heatmap: Support heatmap rows with non-timeseries X axis (#60929)
Co-authored-by: Leon Sorokin <leeoniya@gmail.com>
This commit is contained in:
parent
d4f4a83574
commit
4a8763d7b6
326
devenv/dev-dashboards/panel-heatmap/heatmap-x.json
Normal file
326
devenv/dev-dashboards/panel-heatmap/heatmap-x.json
Normal file
@ -0,0 +1,326 @@
|
||||
{
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
"builtIn": 1,
|
||||
"datasource": {
|
||||
"type": "grafana",
|
||||
"uid": "-- Grafana --"
|
||||
},
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations & Alerts",
|
||||
"target": {
|
||||
"limit": 100,
|
||||
"matchAny": false,
|
||||
"tags": [],
|
||||
"type": "dashboard"
|
||||
},
|
||||
"type": "dashboard"
|
||||
}
|
||||
]
|
||||
},
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 0,
|
||||
"id": 116,
|
||||
"links": [],
|
||||
"liveNow": false,
|
||||
"panels": [
|
||||
{
|
||||
"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": 10,
|
||||
"x": 0,
|
||||
"y": 0
|
||||
},
|
||||
"id": 2,
|
||||
"options": {
|
||||
"footer": {
|
||||
"countRows": false,
|
||||
"fields": "",
|
||||
"reducer": [
|
||||
"sum"
|
||||
],
|
||||
"show": false
|
||||
},
|
||||
"showHeader": true
|
||||
},
|
||||
"pluginVersion": "9.4.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"csvContent": "x,y1,y2\n1,8,12\n2,6,13\n3,7,9\n5,9,7\n6,5,9",
|
||||
"datasource": {
|
||||
"type": "testdata",
|
||||
"uid": "PD8C576611E62080A"
|
||||
},
|
||||
"refId": "A",
|
||||
"scenarioId": "csv_content"
|
||||
}
|
||||
],
|
||||
"title": "Raw heatmap rows",
|
||||
"type": "table"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "datasource",
|
||||
"uid": "-- Dashboard --"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"custom": {
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
}
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 9,
|
||||
"w": 14,
|
||||
"x": 10,
|
||||
"y": 0
|
||||
},
|
||||
"id": 4,
|
||||
"options": {
|
||||
"calculate": false,
|
||||
"cellGap": 1,
|
||||
"color": {
|
||||
"exponent": 0.5,
|
||||
"fill": "dark-orange",
|
||||
"mode": "scheme",
|
||||
"reverse": false,
|
||||
"scale": "exponential",
|
||||
"scheme": "Oranges",
|
||||
"steps": 64
|
||||
},
|
||||
"exemplars": {
|
||||
"color": "rgba(255,0,255,0.7)"
|
||||
},
|
||||
"filterValues": {
|
||||
"le": 1e-9
|
||||
},
|
||||
"legend": {
|
||||
"show": true
|
||||
},
|
||||
"rowsFrame": {
|
||||
"layout": "auto"
|
||||
},
|
||||
"tooltip": {
|
||||
"show": true,
|
||||
"yHistogram": false
|
||||
},
|
||||
"yAxis": {
|
||||
"axisPlacement": "left",
|
||||
"reverse": false
|
||||
}
|
||||
},
|
||||
"pluginVersion": "9.4.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "datasource",
|
||||
"uid": "-- Dashboard --"
|
||||
},
|
||||
"panelId": 2,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Row heatmap",
|
||||
"type": "heatmap"
|
||||
},
|
||||
{
|
||||
"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": 8,
|
||||
"w": 10,
|
||||
"x": 0,
|
||||
"y": 9
|
||||
},
|
||||
"id": 5,
|
||||
"options": {
|
||||
"footer": {
|
||||
"countRows": false,
|
||||
"fields": "",
|
||||
"reducer": [
|
||||
"sum"
|
||||
],
|
||||
"show": false
|
||||
},
|
||||
"showHeader": true
|
||||
},
|
||||
"pluginVersion": "9.4.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"csvContent": "x,y,count\n1,4,10\n1,6,11\n2,5,30\n2,4,22\n3,6,17",
|
||||
"datasource": {
|
||||
"type": "testdata",
|
||||
"uid": "PD8C576611E62080A"
|
||||
},
|
||||
"refId": "A",
|
||||
"scenarioId": "csv_content"
|
||||
}
|
||||
],
|
||||
"title": "Raw heatmap cells",
|
||||
"type": "table"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "datasource",
|
||||
"uid": "-- Dashboard --"
|
||||
},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"custom": {
|
||||
"hideFrom": {
|
||||
"legend": false,
|
||||
"tooltip": false,
|
||||
"viz": false
|
||||
},
|
||||
"scaleDistribution": {
|
||||
"type": "linear"
|
||||
}
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"gridPos": {
|
||||
"h": 8,
|
||||
"w": 14,
|
||||
"x": 10,
|
||||
"y": 9
|
||||
},
|
||||
"id": 6,
|
||||
"options": {
|
||||
"calculate": false,
|
||||
"cellGap": 1,
|
||||
"color": {
|
||||
"exponent": 0.5,
|
||||
"fill": "dark-orange",
|
||||
"mode": "scheme",
|
||||
"reverse": false,
|
||||
"scale": "exponential",
|
||||
"scheme": "Oranges",
|
||||
"steps": 64
|
||||
},
|
||||
"exemplars": {
|
||||
"color": "rgba(255,0,255,0.7)"
|
||||
},
|
||||
"filterValues": {
|
||||
"le": 1e-9
|
||||
},
|
||||
"legend": {
|
||||
"show": true
|
||||
},
|
||||
"rowsFrame": {
|
||||
"layout": "auto"
|
||||
},
|
||||
"tooltip": {
|
||||
"show": true,
|
||||
"yHistogram": false
|
||||
},
|
||||
"yAxis": {
|
||||
"axisPlacement": "left",
|
||||
"reverse": false
|
||||
}
|
||||
},
|
||||
"pluginVersion": "9.4.0-pre",
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "datasource",
|
||||
"uid": "-- Dashboard --"
|
||||
},
|
||||
"panelId": 5,
|
||||
"refId": "A"
|
||||
}
|
||||
],
|
||||
"title": "Cells heatmap",
|
||||
"type": "heatmap"
|
||||
}
|
||||
],
|
||||
"revision": 1,
|
||||
"schemaVersion": 37,
|
||||
"style": "dark",
|
||||
"tags": [],
|
||||
"templating": {
|
||||
"list": []
|
||||
},
|
||||
"time": {
|
||||
"from": "now-6h",
|
||||
"to": "now"
|
||||
},
|
||||
"timepicker": {},
|
||||
"timezone": "",
|
||||
"title": "Heatmap X axis",
|
||||
"uid": "5Y0jv6pVz",
|
||||
"version": 3,
|
||||
"weekStart": ""
|
||||
}
|
||||
|
@ -303,6 +303,13 @@ local dashboard = grafana.dashboard;
|
||||
id: 0,
|
||||
}
|
||||
},
|
||||
dashboard.new('heatmap-x', import '../dev-dashboards/panel-heatmap/heatmap-x.json') +
|
||||
resource.addMetadata('folder', 'dev-dashboards') +
|
||||
{
|
||||
spec+: {
|
||||
id: 0,
|
||||
}
|
||||
},
|
||||
dashboard.new('histogram_tests', import '../dev-dashboards/panel-histogram/histogram_tests.json') +
|
||||
resource.addMetadata('folder', 'dev-dashboards') +
|
||||
{
|
||||
|
@ -191,7 +191,7 @@ export function rowsToCellsHeatmap(opts: RowsHeatmapOptions): DataFrame {
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'xMax',
|
||||
name: xField.type === FieldType.time ? 'xMax' : 'x',
|
||||
type: xField.type,
|
||||
values: new ArrayVector(xs),
|
||||
config: xField.config,
|
||||
|
@ -237,7 +237,7 @@ const HeatmapHoverCell = ({ data, hover, showHistogram }: Props) => {
|
||||
<>
|
||||
<div>
|
||||
<div>{xDisp(xBucketMin)}</div>
|
||||
<div>{xDisp(xBucketMax)}</div>
|
||||
{data.xLayout !== HeatmapCellLayout.unknown && <div>{xDisp(xBucketMax)}</div>}
|
||||
</div>
|
||||
{showHistogram && (
|
||||
<canvas
|
||||
|
@ -14,6 +14,7 @@ import {
|
||||
incrRoundDn,
|
||||
incrRoundUp,
|
||||
TimeRange,
|
||||
FieldType,
|
||||
} from '@grafana/data';
|
||||
import { AxisPlacement, ScaleDirection, ScaleDistribution, ScaleOrientation } from '@grafana/schema';
|
||||
import { UPlotConfigBuilder } from '@grafana/ui';
|
||||
@ -98,7 +99,13 @@ export function prepConfig(opts: PrepConfigOpts) {
|
||||
} = opts;
|
||||
|
||||
const xScaleKey = 'x';
|
||||
const xScaleUnit = 'time';
|
||||
let xScaleUnit = 'time';
|
||||
let isTime = true;
|
||||
|
||||
if (dataRef.current?.heatmap?.fields[0].type !== FieldType.time) {
|
||||
xScaleUnit = dataRef.current?.heatmap?.fields[0].config?.unit ?? 'x';
|
||||
isTime = false;
|
||||
}
|
||||
|
||||
const pxRatio = devicePixelRatio;
|
||||
|
||||
@ -145,22 +152,24 @@ export function prepConfig(opts: PrepConfigOpts) {
|
||||
u.setSelect({ left: 0, top: 0, width: 0, height: 0 }, false);
|
||||
});
|
||||
|
||||
// this is a tmp hack because in mode: 2, uplot does not currently call scales.x.range() for setData() calls
|
||||
// scales.x.range() typically reads back from drilled-down panelProps.timeRange via getTimeRange()
|
||||
builder.addHook('setData', (u) => {
|
||||
//let [min, max] = (u.scales!.x!.range! as uPlot.Range.Function)(u, 0, 100, xScaleKey);
|
||||
if (isTime) {
|
||||
// this is a tmp hack because in mode: 2, uplot does not currently call scales.x.range() for setData() calls
|
||||
// scales.x.range() typically reads back from drilled-down panelProps.timeRange via getTimeRange()
|
||||
builder.addHook('setData', (u) => {
|
||||
//let [min, max] = (u.scales!.x!.range! as uPlot.Range.Function)(u, 0, 100, xScaleKey);
|
||||
|
||||
let { min: xMin, max: xMax } = u.scales!.x;
|
||||
let { min: xMin, max: xMax } = u.scales!.x;
|
||||
|
||||
let min = getTimeRange().from.valueOf();
|
||||
let max = getTimeRange().to.valueOf();
|
||||
let min = getTimeRange().from.valueOf();
|
||||
let max = getTimeRange().to.valueOf();
|
||||
|
||||
if (xMin !== min || xMax !== max) {
|
||||
queueMicrotask(() => {
|
||||
u.setScale(xScaleKey, { min, max });
|
||||
});
|
||||
}
|
||||
});
|
||||
if (xMin !== min || xMax !== max) {
|
||||
queueMicrotask(() => {
|
||||
u.setScale(xScaleKey, { min, max });
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// rect of .u-over (grid area)
|
||||
builder.addHook('syncRect', (u, r) => {
|
||||
@ -236,19 +245,42 @@ export function prepConfig(opts: PrepConfigOpts) {
|
||||
|
||||
builder.addScale({
|
||||
scaleKey: xScaleKey,
|
||||
isTime: true,
|
||||
isTime,
|
||||
orientation: ScaleOrientation.Horizontal,
|
||||
direction: ScaleDirection.Right,
|
||||
// TODO: expand by x bucket size and layout
|
||||
range: () => {
|
||||
return [getTimeRange().from.valueOf(), getTimeRange().to.valueOf()];
|
||||
range: (u, dataMin, dataMax) => {
|
||||
if (isTime) {
|
||||
return [getTimeRange().from.valueOf(), getTimeRange().to.valueOf()];
|
||||
} else {
|
||||
if (dataRef.current?.xLayout === HeatmapCellLayout.le) {
|
||||
return [dataMin - dataRef.current?.xBucketSize!, dataMax];
|
||||
} else if (dataRef.current?.xLayout === HeatmapCellLayout.ge) {
|
||||
return [dataMin, dataMax + dataRef.current?.xBucketSize!];
|
||||
} else {
|
||||
let offset = dataRef.current?.xBucketSize! / 2;
|
||||
|
||||
return [dataMin - offset, dataMax + offset];
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
let incrs;
|
||||
|
||||
if (!isTime) {
|
||||
incrs = [];
|
||||
|
||||
for (let i = 0; i < 10; i++) {
|
||||
incrs.push(i * dataRef.current?.xBucketSize!);
|
||||
}
|
||||
}
|
||||
|
||||
builder.addAxis({
|
||||
scaleKey: xScaleKey,
|
||||
placement: AxisPlacement.Bottom,
|
||||
isTime: true,
|
||||
incrs,
|
||||
isTime,
|
||||
theme: theme,
|
||||
timeZone,
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user