diff --git a/devenv/dev-dashboards/panel-graph/graph-ng-stacking2.json b/devenv/dev-dashboards/panel-graph/graph-ng-stacking2.json new file mode 100644 index 00000000000..29bda45b50f --- /dev/null +++ b/devenv/dev-dashboards/panel-graph/graph-ng-stacking2.json @@ -0,0 +1,2957 @@ +{ + "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, + "links": [], + "liveNow": false, + "panels": [ + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 4, + "x": 0, + "y": 0 + }, + "id": 6, + "maxDataPoints": 100, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "A", + "scenarioId": "csv_metric_values", + "stringInput": "0,2,2,3,4,5" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "B", + "scenarioId": "csv_metric_values", + "stringInput": "5,4,3,2,2,0" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "C", + "scenarioId": "csv_metric_values", + "stringInput": "1,20,10,25,5,0" + } + ], + "title": "Pos Only", + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 4, + "x": 4, + "y": 0 + }, + "id": 7, + "maxDataPoints": 100, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 6, + "refId": "A" + } + ], + "title": "Stack Normal", + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "percent" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 4, + "x": 8, + "y": 0 + }, + "id": 8, + "maxDataPoints": 100, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 6, + "refId": "A" + } + ], + "title": "Stack 100%", + "type": "timeseries" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 4, + "x": 12, + "y": 0 + }, + "id": 3, + "maxDataPoints": 100, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "alias": "+100", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "hide": false, + "refId": "A", + "scenarioId": "csv_metric_values", + "stringInput": "100,100,100,100,100,100,100,100" + }, + { + "alias": "+50", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "B", + "scenarioId": "csv_metric_values", + "stringInput": "50,50,50,50,50,50,50,50" + }, + { + "alias": "+25", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "C", + "scenarioId": "csv_metric_values", + "stringInput": "25,25,25,25,25,25,25,25" + }, + { + "alias": "-50", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "D", + "scenarioId": "csv_metric_values", + "stringInput": "-50,-50,-50,-50,-50,-50,-50,-50" + }, + { + "alias": "-100", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "E", + "scenarioId": "csv_metric_values", + "stringInput": "-100,-100,-100,-100,-100,-100,-100,-100" + } + ], + "title": "Pos & Neg", + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 4, + "x": 16, + "y": 0 + }, + "id": 4, + "maxDataPoints": 100, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 3, + "refId": "A" + } + ], + "title": "Stack Normal", + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "percent" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 4, + "x": 20, + "y": 0 + }, + "id": 12, + "maxDataPoints": 100, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 3, + "refId": "A" + } + ], + "title": "Stacked 100%", + "type": "timeseries" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "NegY" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 9, + "w": 4, + "x": 0, + "y": 9 + }, + "id": 9, + "maxDataPoints": 100, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "alias": "NegY", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "C", + "scenarioId": "csv_metric_values", + "stringInput": "1,20,10,25,5,0" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "A", + "scenarioId": "csv_metric_values", + "stringInput": "0,2,2,3,4,5" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "B", + "scenarioId": "csv_metric_values", + "stringInput": "5,4,3,2,2,0" + }, + { + "alias": "Neg", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "D", + "scenarioId": "csv_metric_values", + "stringInput": "-15,-5,-15,-5,-15,-5" + } + ], + "title": "Pos & Neg & NegY", + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "NegY" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 9, + "w": 4, + "x": 4, + "y": 9 + }, + "id": 10, + "maxDataPoints": 100, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 9, + "refId": "A" + } + ], + "title": "Stack Normal", + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "percent" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "NegY" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 9, + "w": 4, + "x": 8, + "y": 9 + }, + "id": 11, + "maxDataPoints": 100, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 9, + "refId": "A" + } + ], + "title": "Stack 100%", + "type": "timeseries" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 0, + "scaleDistribution": { + "type": "linear" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 4, + "x": 12, + "y": 9 + }, + "id": 17, + "options": { + "barRadius": 0, + "barWidth": 1, + "groupWidth": 0.89, + "legend": { + "calcs": [ + "max" + ], + "displayMode": "hidden", + "placement": "right" + }, + "orientation": "auto", + "showValue": "auto", + "stacking": "none", + "text": {}, + "tooltip": { + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 0 + }, + "targets": [ + { + "csvContent": "Name,Stat1,Stat2,Stat3,Stat4,Stat5,Stat6,Stat7,Stat8\nA, 10, 15,8,3,4,12,14,1\nB, 19, 5,8,3,4,12,14,6\nC, 15, 5,8,3,4,10,4,6\n", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "A", + "scenarioId": "csv_content" + } + ], + "title": "Barchart", + "type": "barchart" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 0, + "scaleDistribution": { + "type": "linear" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 4, + "x": 16, + "y": 9 + }, + "id": 18, + "options": { + "barRadius": 0, + "barWidth": 1, + "groupWidth": 0.89, + "legend": { + "calcs": [ + "max" + ], + "displayMode": "hidden", + "placement": "right" + }, + "orientation": "auto", + "showValue": "auto", + "stacking": "normal", + "text": {}, + "tooltip": { + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 0 + }, + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 17, + "refId": "A" + } + ], + "title": "Stack Normal", + "type": "barchart" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "axisSoftMin": 0, + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 0, + "scaleDistribution": { + "type": "linear" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 4, + "x": 20, + "y": 9 + }, + "id": 19, + "options": { + "barRadius": 0, + "barWidth": 1, + "groupWidth": 0.89, + "legend": { + "calcs": [ + "max" + ], + "displayMode": "hidden", + "placement": "right" + }, + "orientation": "auto", + "showValue": "auto", + "stacking": "percent", + "text": {}, + "tooltip": { + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 0 + }, + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 17, + "refId": "A" + } + ], + "title": "Stack 100%", + "type": "barchart" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "bars", + "fillOpacity": 50, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 0, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "NegY" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 9, + "w": 4, + "x": 0, + "y": 18 + }, + "id": 13, + "maxDataPoints": 100, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 9, + "refId": "A" + } + ], + "title": "Neg & NegY Bars", + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "bars", + "fillOpacity": 50, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 0, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "NegY" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 9, + "w": 4, + "x": 4, + "y": 18 + }, + "id": 14, + "maxDataPoints": 100, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 9, + "refId": "A" + } + ], + "title": "Stack Normal", + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "bars", + "fillOpacity": 50, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 0, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "percent" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "NegY" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 9, + "w": 4, + "x": 8, + "y": 18 + }, + "id": 15, + "maxDataPoints": 100, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 9, + "refId": "A" + } + ], + "title": "Stack 100%", + "type": "timeseries" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "(A|B)-series.*" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "bars" + }, + { + "id": "custom.lineWidth", + "value": 0 + }, + { + "id": "custom.fillOpacity", + "value": 100 + } + ] + } + ] + }, + "gridPos": { + "h": 9, + "w": 4, + "x": 12, + "y": 18 + }, + "id": 21, + "maxDataPoints": 20, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "A", + "scenarioId": "csv_metric_values", + "stringInput": "18,25,43,11,5" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "B", + "scenarioId": "csv_metric_values", + "stringInput": "41,29,20,23,27" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "C", + "scenarioId": "csv_metric_values", + "stringInput": "169,109,170,150,116" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "D", + "scenarioId": "csv_metric_values", + "stringInput": "160,131,117,134,139" + } + ], + "title": "Mixed Styles", + "transformations": [], + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "(A|B)-series.*" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "bars" + }, + { + "id": "custom.lineWidth", + "value": 0 + }, + { + "id": "custom.fillOpacity", + "value": 100 + } + ] + } + ] + }, + "gridPos": { + "h": 9, + "w": 4, + "x": 16, + "y": 18 + }, + "id": 22, + "maxDataPoints": 20, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 21, + "refId": "A" + } + ], + "title": "Stack Normal Auto-grouped", + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 40, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "percent" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "(A|B)-series.*" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "bars" + }, + { + "id": "custom.lineWidth", + "value": 0 + }, + { + "id": "custom.fillOpacity", + "value": 100 + } + ] + } + ] + }, + "gridPos": { + "h": 9, + "w": 4, + "x": 20, + "y": 18 + }, + "id": 23, + "maxDataPoints": 20, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 21, + "refId": "A" + } + ], + "title": "Stack 100% Auto-grouped", + "type": "timeseries" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 4, + "x": 0, + "y": 27 + }, + "id": 24, + "maxDataPoints": 100, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "alias": "+100", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "hide": false, + "refId": "A", + "scenarioId": "csv_metric_values", + "stringInput": "100,100,100,100,100,null,100,100" + }, + { + "alias": "+50", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "B", + "scenarioId": "csv_metric_values", + "stringInput": "50,50,50,50,50,null,50,50" + }, + { + "alias": "+25", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "C", + "scenarioId": "csv_metric_values", + "stringInput": "25,25,25,25,25,null,25,25" + }, + { + "alias": "-50", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "D", + "scenarioId": "csv_metric_values", + "stringInput": "-50,-50,null,-50,-50,-50,-50,-50" + }, + { + "alias": "-100", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "E", + "scenarioId": "csv_metric_values", + "stringInput": "-100,-100,null,-100,-100,-100,-100,-100" + } + ], + "title": "Null through all", + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 20, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 4, + "x": 4, + "y": 27 + }, + "id": 25, + "maxDataPoints": 100, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 24, + "refId": "A" + } + ], + "title": "Stack Normal", + "type": "timeseries" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "description": "", + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byName", + "options": "NegY" + }, + "properties": [ + { + "id": "custom.transform", + "value": "negative-Y" + } + ] + } + ] + }, + "gridPos": { + "h": 9, + "w": 4, + "x": 8, + "y": 27 + }, + "id": 2, + "maxDataPoints": 100, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "hide": false, + "refId": "A", + "scenarioId": "csv_metric_values", + "stringInput": "50,50,50,null,50,50,50,50" + }, + { + "alias": "NegY", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "B", + "scenarioId": "csv_metric_values", + "stringInput": "50,50,50,50,null,50,50" + } + ], + "title": "NegY nulls", + "type": "timeseries" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 8, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 9, + "w": 4, + "x": 12, + "y": 27 + }, + "id": 26, + "maxDataPoints": 20, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "A", + "scenarioId": "csv_metric_values", + "stringInput": "1,2,1,2,1" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "B", + "scenarioId": "csv_metric_values", + "stringInput": "3,3,3,3,3" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "C", + "scenarioId": "csv_metric_values", + "stringInput": "2,2,2,2,2" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "refId": "D", + "scenarioId": "csv_metric_values", + "stringInput": "4,4,4,4,4" + } + ], + "title": "1,2,3,4 Unstacked", + "transformations": [], + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 8, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "normal" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "(A|B)-series.*" + }, + "properties": [ + { + "id": "custom.stacking", + "value": { + "group": "B", + "mode": "normal" + } + } + ] + } + ] + }, + "gridPos": { + "h": 9, + "w": 4, + "x": 16, + "y": 27 + }, + "id": 27, + "maxDataPoints": 20, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 26, + "refId": "A" + } + ], + "title": "Stack Normal Groups A + B / C + D", + "transformations": [], + "type": "timeseries" + }, + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 8, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "percent" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byRegexp", + "options": "(A|B)-series.*" + }, + "properties": [ + { + "id": "custom.stacking", + "value": { + "group": "B", + "mode": "percent" + } + } + ] + } + ] + }, + "gridPos": { + "h": 9, + "w": 4, + "x": 20, + "y": 27 + }, + "id": 28, + "maxDataPoints": 20, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "datasource": { + "type": "datasource", + "uid": "-- Dashboard --" + }, + "panelId": 26, + "refId": "A" + } + ], + "title": "Stack 100% Groups A + B / C + D", + "transformations": [], + "type": "timeseries" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "bars" + }, + { + "id": "color", + "value": { + "mode": "palette-classic" + } + }, + { + "id": "custom.gradientMode", + "value": "none" + }, + { + "id": "custom.barAlignment", + "value": 1 + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "normal" + } + }, + { + "id": "custom.spanNulls", + "value": 3600000 + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 0, + "y": 36 + }, + "id": 30, + "options": { + "legend": { + "calcs": [], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "csvContent": "\"Time\",\"Sum daily.cost_per_kwh\"\n1639612800000,\n1639872000000,0\n1639958400000,272\n1640044800000,272\n1640131200000,327\n1640217600000,290\n1640304000000,286\n1640390400000,256\n1640476800000,397\n1640563200000,295\n1640649600000,310\n1640736000000,224\n1640822400000,291\n1640908800000,265\n1640995200000,256\n1641081600000,399\n1641168000000,471\n1641254400000,325\n1641340800000,363\n1641427200000,375\n1641513600000,365\n1641600000000,492\n1641686400000,409\n1641772800000,371\n1641859200000,448\n1641945600000,372\n1642032000000,0\n1642118400000,0\n1642204800000,0\n1642291200000,0\n1642377600000,0\n1642464000000,0\n\n", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "hide": false, + "refId": "A", + "scenarioId": "csv_content" + }, + { + "csvContent": "\"Time\",\"Sum morning.cost_per_kwh\",\"Sum afternoon.cost_per_kwh\",\"Sum evening.cost_per_kwh\",\"Sum night.cost_per_kwh\",\"Sum late.cost_per_kwh\"\n1639612800000,0,0,0,0,0\n1639872000000,,,,,\n1639958400000,,,,,\n1640044800000,,,,,\n1640131200000,,,,,\n1640217600000,32,28,62,63,32\n1640304000000,,,,,\n1640390400000,,,,,\n1640476800000,,,,,\n1640563200000,,,,,\n1640649600000,,,,,\n1640736000000,,,,,\n1640822400000,47,53,68,96,45\n1640908800000,,,,,\n1640995200000,,,,,\n1641081600000,,,,,\n1641168000000,,,,,\n1641254400000,,,,,\n1641340800000,,,,,\n1641427200000,112,130,147,152,115\n1641513600000,,,,,\n1641600000000,,,,,\n1641686400000,,,,,\n1641772800000,,,,,\n1641859200000,,,,,\n1641945600000,,,,,\n1642032000000,0,0,0,0,0\n1642118400000,,,,,\n1642204800000,,,,,\n1642291200000,,,,,\n1642377600000,,,,,\n1642464000000,,,,,\n\n", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "hide": false, + "refId": "B", + "scenarioId": "csv_content" + } + ], + "title": "https://github.com/grafana/grafana/pull/44359", + "transformations": [], + "type": "timeseries" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "line" + }, + { + "id": "color", + "value": { + "mode": "palette-classic" + } + }, + { + "id": "custom.gradientMode", + "value": "none" + }, + { + "id": "custom.barAlignment", + "value": 1 + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "normal" + } + }, + { + "id": "custom.spanNulls", + "value": true + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 8, + "y": 36 + }, + "id": 32, + "options": { + "legend": { + "calcs": [], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "csvContent": "\"Time\",\"Sum daily.cost_per_kwh\"\n1639612800000,\n1639872000000,0\n1639958400000,272\n1640044800000,272\n1640131200000,327\n1640217600000,290\n1640304000000,286\n1640390400000,256\n1640476800000,397\n1640563200000,295\n1640649600000,310\n1640736000000,224\n1640822400000,291\n1640908800000,265\n1640995200000,256\n1641081600000,399\n1641168000000,471\n1641254400000,325\n1641340800000,363\n1641427200000,375\n1641513600000,365\n1641600000000,492\n1641686400000,409\n1641772800000,371\n1641859200000,448\n1641945600000,372\n1642032000000,0\n1642118400000,0\n1642204800000,0\n1642291200000,0\n1642377600000,0\n1642464000000,0\n\n", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "hide": false, + "refId": "A", + "scenarioId": "csv_content" + }, + { + "csvContent": "\"Time\",\"Sum morning.cost_per_kwh\",\"Sum afternoon.cost_per_kwh\",\"Sum evening.cost_per_kwh\",\"Sum night.cost_per_kwh\",\"Sum late.cost_per_kwh\"\n1639612800000,0,0,0,0,0\n1639872000000,,,,,\n1639958400000,,,,,\n1640044800000,,,,,\n1640131200000,,,,,\n1640217600000,32,28,62,63,32\n1640304000000,,,,,\n1640390400000,,,,,\n1640476800000,,,,,\n1640563200000,,,,,\n1640649600000,,,,,\n1640736000000,,,,,\n1640822400000,47,53,68,96,45\n1640908800000,,,,,\n1640995200000,,,,,\n1641081600000,,,,,\n1641168000000,,,,,\n1641254400000,,,,,\n1641340800000,,,,,\n1641427200000,112,130,147,152,115\n1641513600000,,,,,\n1641600000000,,,,,\n1641686400000,,,,,\n1641772800000,,,,,\n1641859200000,,,,,\n1641945600000,,,,,\n1642032000000,0,0,0,0,0\n1642118400000,,,,,\n1642204800000,,,,,\n1642291200000,,,,,\n1642377600000,,,,,\n1642464000000,,,,,\n\n", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "hide": false, + "refId": "B", + "scenarioId": "csv_content" + } + ], + "title": "Connect null values = always", + "transformations": [], + "type": "timeseries" + }, + { + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [ + { + "matcher": { + "id": "byFrameRefID", + "options": "B" + }, + "properties": [ + { + "id": "custom.drawStyle", + "value": "line" + }, + { + "id": "color", + "value": { + "mode": "palette-classic" + } + }, + { + "id": "custom.gradientMode", + "value": "none" + }, + { + "id": "custom.barAlignment", + "value": 1 + }, + { + "id": "custom.stacking", + "value": { + "group": "A", + "mode": "normal" + } + }, + { + "id": "custom.spanNulls", + "value": false + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 8, + "x": 16, + "y": 36 + }, + "id": 34, + "options": { + "legend": { + "calcs": [], + "displayMode": "hidden", + "placement": "bottom" + }, + "tooltip": { + "mode": "multi", + "sort": "none" + } + }, + "targets": [ + { + "csvContent": "\"Time\",\"Sum daily.cost_per_kwh\"\n1639612800000,\n1639872000000,0\n1639958400000,272\n1640044800000,272\n1640131200000,327\n1640217600000,290\n1640304000000,286\n1640390400000,256\n1640476800000,397\n1640563200000,295\n1640649600000,310\n1640736000000,224\n1640822400000,291\n1640908800000,265\n1640995200000,256\n1641081600000,399\n1641168000000,471\n1641254400000,325\n1641340800000,363\n1641427200000,375\n1641513600000,365\n1641600000000,492\n1641686400000,409\n1641772800000,371\n1641859200000,448\n1641945600000,372\n1642032000000,0\n1642118400000,0\n1642204800000,0\n1642291200000,0\n1642377600000,0\n1642464000000,0\n\n", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "hide": false, + "refId": "A", + "scenarioId": "csv_content" + }, + { + "csvContent": "\"Time\",\"Sum morning.cost_per_kwh\",\"Sum afternoon.cost_per_kwh\",\"Sum evening.cost_per_kwh\",\"Sum night.cost_per_kwh\",\"Sum late.cost_per_kwh\"\n1639612800000,0,0,0,0,0\n1639872000000,,,,,\n1639958400000,,,,,\n1640044800000,,,,,\n1640131200000,,,,,\n1640217600000,32,28,62,63,32\n1640304000000,,,,,\n1640390400000,,,,,\n1640476800000,,,,,\n1640563200000,,,,,\n1640649600000,,,,,\n1640736000000,,,,,\n1640822400000,47,53,68,96,45\n1640908800000,,,,,\n1640995200000,,,,,\n1641081600000,,,,,\n1641168000000,,,,,\n1641254400000,,,,,\n1641340800000,,,,,\n1641427200000,112,130,147,152,115\n1641513600000,,,,,\n1641600000000,,,,,\n1641686400000,,,,,\n1641772800000,,,,,\n1641859200000,,,,,\n1641945600000,,,,,\n1642032000000,0,0,0,0,0\n1642118400000,,,,,\n1642204800000,,,,,\n1642291200000,,,,,\n1642377600000,,,,,\n1642464000000,,,,,\n\n", + "datasource": { + "type": "testdata", + "uid": "PD8C576611E62080A" + }, + "hide": false, + "refId": "B", + "scenarioId": "csv_content" + } + ], + "title": "Connect null values = never", + "transformations": [], + "type": "timeseries" + } + ], + "refresh": false, + "schemaVersion": 32, + "style": "dark", + "tags": [ + "gdev", + "panel-tests", + "graph-ng" + ], + "templating": { + "list": [] + }, + "time": { + "from": "2021-12-14T04:26:06.000Z", + "to": "2022-01-19T08:44:05.000Z" + }, + "timepicker": {}, + "timezone": "", + "title": "TimeSeries & BarChart Stacking", + "uid": "1KxMUdE7k", + "version": 1, + "weekStart": "" +} \ No newline at end of file diff --git a/packages/grafana-ui/src/components/GraphNG/GraphNG.tsx b/packages/grafana-ui/src/components/GraphNG/GraphNG.tsx index 9758bfcb61a..e02a291226a 100755 --- a/packages/grafana-ui/src/components/GraphNG/GraphNG.tsx +++ b/packages/grafana-ui/src/components/GraphNG/GraphNG.tsx @@ -82,7 +82,7 @@ function sameProps(prevProps: any, nextProps: any, propsToDiff: Array { constructor(props: GraphNGProps) { super(props); - this.state = this.prepState(props); + let state = this.prepState(props); + state.alignedData = state.config!.prepData!([state.alignedFrame]) as AlignedData; + this.state = state; this.plotInstance = React.createRef(); } @@ -131,7 +133,6 @@ export class GraphNG extends React.Component { state = { alignedFrame, - alignedData: config!.prepData!([alignedFrame]) as AlignedData, config, }; @@ -229,12 +230,13 @@ export class GraphNG extends React.Component { if (shouldReconfig) { newState.config = this.props.prepConfig(newState.alignedFrame, this.props.frames, this.getTimeRange); - newState.alignedData = newState.config.prepData!([newState.alignedFrame]) as AlignedData; pluginLog('GraphNG', false, 'config recreated', newState.config); } - } - newState && this.setState(newState); + newState.alignedData = newState.config!.prepData!([newState.alignedFrame]) as AlignedData; + + this.setState(newState); + } } } @@ -255,7 +257,7 @@ export class GraphNG extends React.Component { {(vizWidth: number, vizHeight: number) => ( { const alignedDataFrame = preparePlotFrame(props.sparkline, props.config); this.state = { - data: preparePlotData([alignedDataFrame]), + data: preparePlotData2(alignedDataFrame, getStackingGroups(alignedDataFrame)), alignedDataFrame, configBuilder: this.prepareConfig(alignedDataFrame), }; @@ -65,7 +65,7 @@ export class Sparkline extends PureComponent { return { ...state, - data: preparePlotData([frame]), + data: preparePlotData2(frame, getStackingGroups(frame)), alignedDataFrame: frame, }; } diff --git a/packages/grafana-ui/src/components/TimeSeries/TimeSeries.tsx b/packages/grafana-ui/src/components/TimeSeries/TimeSeries.tsx index 2b0813d2ee4..e3d54e93ce5 100644 --- a/packages/grafana-ui/src/components/TimeSeries/TimeSeries.tsx +++ b/packages/grafana-ui/src/components/TimeSeries/TimeSeries.tsx @@ -19,7 +19,7 @@ export class UnthemedTimeSeries extends React.Component { prepConfig = (alignedFrame: DataFrame, allFrames: DataFrame[], getTimeRange: () => TimeRange) => { const { eventBus, sync } = this.context as PanelContext; - const { theme, timeZone, legend, renderers, tweakAxis, tweakScale } = this.props; + const { theme, timeZone, renderers, tweakAxis, tweakScale } = this.props; return preparePlotConfigBuilder({ frame: alignedFrame, @@ -29,7 +29,6 @@ export class UnthemedTimeSeries extends React.Component { eventBus, sync, allFrames, - legend, renderers, tweakScale, tweakAxis, diff --git a/packages/grafana-ui/src/components/TimeSeries/utils.ts b/packages/grafana-ui/src/components/TimeSeries/utils.ts index d812a8dc93d..ed9e084759e 100644 --- a/packages/grafana-ui/src/components/TimeSeries/utils.ts +++ b/packages/grafana-ui/src/components/TimeSeries/utils.ts @@ -23,10 +23,9 @@ import { VisibilityMode, ScaleDirection, ScaleOrientation, - VizLegendOptions, StackingMode, } from '@grafana/schema'; -import { collectStackingGroups, INTERNAL_NEGATIVE_Y_PREFIX, orderIdsByCalcs, preparePlotData } from '../uPlot/utils'; +import { getStackingGroups, preparePlotData2 } from '../uPlot/utils'; import uPlot from 'uplot'; import { buildScaleKey } from '../GraphNG/utils'; @@ -40,7 +39,6 @@ const defaultConfig: GraphFieldConfig = { export const preparePlotConfigBuilder: UPlotConfigPrepFn<{ sync?: () => DashboardCursorSync; - legend?: VizLegendOptions; }> = ({ frame, theme, @@ -50,13 +48,12 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{ sync, allFrames, renderers, - legend, tweakScale = (opts) => opts, tweakAxis = (opts) => opts, }) => { const builder = new UPlotConfigBuilder(timeZone); - builder.setPrepData((prepData) => preparePlotData(prepData, undefined, legend)); + builder.setPrepData((frames) => preparePlotData2(frames[0], builder.getStackingGroups())); // X is the first field in the aligned frame const xField = frame.fields[0]; @@ -122,8 +119,6 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{ let customRenderedFields = renderers?.flatMap((r) => Object.values(r.fieldMap).filter((name) => r.indicesOnly.indexOf(name) === -1)) ?? []; - const stackingGroups: Map = new Map(); - let indexByName: Map | undefined; for (let i = 1; i < frame.fields.length; i++) { @@ -328,20 +323,11 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn<{ }); } } - collectStackingGroups(field, stackingGroups, seriesIndex); } - if (stackingGroups.size !== 0) { - for (const [group, seriesIds] of stackingGroups.entries()) { - const seriesIdxs = orderIdsByCalcs({ ids: seriesIds, legend, frame }); - for (let j = seriesIdxs.length - 1; j > 0; j--) { - builder.addBand({ - series: [seriesIdxs[j], seriesIdxs[j - 1]], - dir: group.startsWith(INTERNAL_NEGATIVE_Y_PREFIX) ? 1 : -1, - }); - } - } - } + let stackingGroups = getStackingGroups(frame); + + builder.setStackingGroups(stackingGroups); // hook up custom/composite renderers renderers?.forEach((r) => { diff --git a/packages/grafana-ui/src/components/uPlot/Plot.test.tsx b/packages/grafana-ui/src/components/uPlot/Plot.test.tsx index 26640d5b532..7505c6cb26f 100644 --- a/packages/grafana-ui/src/components/uPlot/Plot.test.tsx +++ b/packages/grafana-ui/src/components/uPlot/Plot.test.tsx @@ -6,7 +6,7 @@ import { GraphFieldConfig, GraphDrawStyle } from '@grafana/schema'; import uPlot from 'uplot'; import createMockRaf from 'mock-raf'; import { UPlotConfigBuilder } from './config/UPlotConfigBuilder'; -import { preparePlotData } from './utils'; +import { preparePlotData2, getStackingGroups } from './utils'; import { SeriesProps } from './config/UPlotSeriesBuilder'; const mockRaf = createMockRaf(); @@ -55,7 +55,7 @@ const mockData = () => { const config = new UPlotConfigBuilder(); config.addSeries({} as SeriesProps); - return { data: [data], timeRange, config }; + return { data: data, timeRange, config }; }; describe('UPlotChart', () => { @@ -75,7 +75,7 @@ describe('UPlotChart', () => { const { unmount } = render( { const { rerender } = render( { expect(uPlot).toBeCalledTimes(1); - data[0].fields[1].values.set(0, 1); + data.fields[1].values.set(0, 1); rerender( { it('skips uPlot intialization for width and height equal 0', async () => { const { data, timeRange, config } = mockData(); const { queryAllByTestId } = render( - + ); expect(queryAllByTestId('uplot-main-div')).toHaveLength(1); @@ -136,7 +142,7 @@ describe('UPlotChart', () => { const { rerender } = render( { nextConfig.addSeries({} as SeriesProps); rerender( - + ); expect(destroyMock).toBeCalledTimes(1); @@ -162,7 +174,7 @@ describe('UPlotChart', () => { const { rerender } = render( { // we wait 1 frame for plugins initialisation logic to finish rerender( AlignedData | FacetedData; +type PreDataStacked = (frames: DataFrame[], stackingGroups: StackingGroup[]) => AlignedData | FacetedData; export class UPlotConfigBuilder { private series: UPlotSeriesBuilder[] = []; private axes: Record = {}; private scales: UPlotScaleBuilder[] = []; private bands: Band[] = []; + private stackingGroups: StackingGroup[] = []; private cursor: Cursor | undefined; private select: uPlot.Select | undefined; private hasLeftAxis = false; @@ -143,6 +145,14 @@ export class UPlotConfigBuilder { this.bands.push(band); } + setStackingGroups(groups: StackingGroup[]) { + this.stackingGroups = groups; + } + + getStackingGroups() { + return this.stackingGroups; + } + setTooltipInterpolator(interpolator: PlotTooltipInterpolator) { this.tooltipInterpolator = interpolator; } @@ -151,10 +161,10 @@ export class UPlotConfigBuilder { return this.tooltipInterpolator; } - setPrepData(prepData: PrepData) { + setPrepData(prepData: PreDataStacked) { this.prepData = (frames) => { this.frames = frames; - return prepData(frames); + return prepData(frames, this.getStackingGroups()); }; } @@ -221,6 +231,14 @@ export class UPlotConfigBuilder { config.tzDate = this.tzDate; config.padding = this.padding; + if (this.stackingGroups.length) { + this.stackingGroups.forEach((group) => { + getStackingBands(group).forEach((band) => { + this.addBand(band); + }); + }); + } + if (this.bands.length) { config.bands = this.bands; } diff --git a/packages/grafana-ui/src/components/uPlot/utils.test.ts b/packages/grafana-ui/src/components/uPlot/utils.test.ts index 8cf0e7c1445..3ccb288de24 100644 --- a/packages/grafana-ui/src/components/uPlot/utils.test.ts +++ b/packages/grafana-ui/src/components/uPlot/utils.test.ts @@ -1,6 +1,7 @@ -import { orderIdsByCalcs, preparePlotData, timeFormatToTemplate } from './utils'; +import { getStackingGroups, preparePlotData2, timeFormatToTemplate } from './utils'; import { FieldType, MutableDataFrame } from '@grafana/data'; -import { GraphTransform, StackingMode } from '@grafana/schema'; +import { BarAlignment, GraphDrawStyle, GraphTransform, LineInterpolation, StackingMode } from '@grafana/schema'; +import Units from 'ol/proj/Units'; describe('timeFormatToTemplate', () => { it.each` @@ -16,7 +17,7 @@ describe('timeFormatToTemplate', () => { }); }); -describe('preparePlotData', () => { +describe('preparePlotData2', () => { const df = new MutableDataFrame({ fields: [ { name: 'time', type: FieldType.time, values: [9997, 9998, 9999] }, @@ -27,7 +28,7 @@ describe('preparePlotData', () => { }); it('creates array from DataFrame', () => { - expect(preparePlotData([df])).toMatchInlineSnapshot(` + expect(preparePlotData2(df, getStackingGroups(df))).toMatchInlineSnapshot(` Array [ Array [ 9997, @@ -63,7 +64,7 @@ describe('preparePlotData', () => { { name: 'c', values: [20, 20, 20], config: { custom: { transform: GraphTransform.NegativeY } } }, ], }); - expect(preparePlotData([df])).toMatchInlineSnapshot(` + expect(preparePlotData2(df, getStackingGroups(df))).toMatchInlineSnapshot(` Array [ Array [ 9997, @@ -104,7 +105,7 @@ describe('preparePlotData', () => { { name: 'i', values: [20, undefined, 20, 20], config: { custom: { transform: GraphTransform.NegativeY } } }, ], }); - expect(preparePlotData([df])).toMatchInlineSnapshot(` + expect(preparePlotData2(df, getStackingGroups(df))).toMatchInlineSnapshot(` Array [ Array [ 9997, @@ -178,7 +179,7 @@ describe('preparePlotData', () => { { name: 'c', values: [20, 20, 20] }, ], }); - expect(preparePlotData([df])).toMatchInlineSnapshot(` + expect(preparePlotData2(df, getStackingGroups(df))).toMatchInlineSnapshot(` Array [ Array [ 9997, @@ -226,7 +227,7 @@ describe('preparePlotData', () => { }, ], }); - expect(preparePlotData([df])).toMatchInlineSnapshot(` + expect(preparePlotData2(df, getStackingGroups(df))).toMatchInlineSnapshot(` Array [ Array [ 9997, @@ -273,7 +274,7 @@ describe('preparePlotData', () => { }, ], }); - expect(preparePlotData([df])).toMatchInlineSnapshot(` + expect(preparePlotData2(df, getStackingGroups(df))).toMatchInlineSnapshot(` Array [ Array [ 9997, @@ -329,7 +330,7 @@ describe('preparePlotData', () => { }, ], }); - expect(preparePlotData([df])).toMatchInlineSnapshot(` + expect(preparePlotData2(df, getStackingGroups(df))).toMatchInlineSnapshot(` Array [ Array [ 9997, @@ -397,7 +398,7 @@ describe('preparePlotData', () => { ], }); - expect(preparePlotData([df])).toMatchInlineSnapshot(` + expect(preparePlotData2(df, getStackingGroups(df))).toMatchInlineSnapshot(` Array [ Array [ 9997, @@ -472,7 +473,7 @@ describe('preparePlotData', () => { ], }); - expect(preparePlotData([df])).toMatchInlineSnapshot(` + expect(preparePlotData2(df, getStackingGroups(df))).toMatchInlineSnapshot(` Array [ Array [ 9997, @@ -507,239 +508,330 @@ describe('preparePlotData', () => { ] `); }); - - describe('ignores nullish-only stacks', () => { - test('single stacking group', () => { - const df = new MutableDataFrame({ - fields: [ - { name: 'time', type: FieldType.time, values: [9997, 9998, 9999] }, - { - name: 'a', - values: [-10, null, 10], - config: { custom: { stacking: { mode: StackingMode.Normal, group: 'stackA' } } }, - }, - { - name: 'b', - values: [10, null, null], - config: { custom: { stacking: { mode: StackingMode.Normal, group: 'stackA' } } }, - }, - { - name: 'c', - values: [20, undefined, 20], - config: { custom: { stacking: { mode: StackingMode.Normal, group: 'stackA' } } }, - }, - ], - }); - - expect(preparePlotData([df])).toMatchInlineSnapshot(` - Array [ - Array [ - 9997, - 9998, - 9999, - ], - Array [ - -10, - null, - 10, - ], - Array [ - 0, - null, - 10, - ], - Array [ - 20, - null, - 30, - ], - ] - `); - }); - test('multiple stacking groups', () => { - const df = new MutableDataFrame({ - fields: [ - { name: 'time', type: FieldType.time, values: [9997, 9998, 9999] }, - { - name: 'a', - values: [-10, undefined, 10], - config: { custom: { stacking: { mode: StackingMode.Normal, group: 'stackA' } } }, - }, - { - name: 'b', - values: [10, undefined, 10], - config: { custom: { stacking: { mode: StackingMode.Normal, group: 'stackA' } } }, - }, - { - name: 'c', - values: [20, undefined, 20], - config: { custom: { stacking: { mode: StackingMode.Normal, group: 'stackA' } } }, - }, - { - name: 'd', - values: [1, 2, null], - config: { custom: { stacking: { mode: StackingMode.Normal, group: 'stackB' } } }, - }, - { - name: 'e', - values: [1, 2, null], - config: { custom: { stacking: { mode: StackingMode.Normal, group: 'stackB' } } }, - }, - { - name: 'f', - values: [1, 2, null], - config: { custom: { stacking: { mode: StackingMode.Normal, group: 'stackB' } } }, - }, - ], - }); - - expect(preparePlotData([df])).toMatchInlineSnapshot(` - Array [ - Array [ - 9997, - 9998, - 9999, - ], - Array [ - -10, - null, - 10, - ], - Array [ - 0, - null, - 20, - ], - Array [ - 20, - null, - 40, - ], - Array [ - 1, - 2, - null, - ], - Array [ - 2, - 4, - null, - ], - Array [ - 3, - 6, - null, - ], - ] - `); - }); - }); - describe('with legend sorted', () => { - it('should affect when single group', () => { - const df = new MutableDataFrame({ - fields: [ - { name: 'time', type: FieldType.time, values: [9997, 9998, 9999] }, - { - name: 'a', - values: [-10, 20, 10], - state: { calcs: { max: 20 } }, - config: { custom: { stacking: { mode: StackingMode.Normal, group: 'stackA' } } }, - }, - { - name: 'b', - values: [10, 10, 10], - state: { calcs: { max: 10 } }, - config: { custom: { stacking: { mode: StackingMode.Normal, group: 'stackA' } } }, - }, - { - name: 'c', - values: [20, 20, 20], - state: { calcs: { max: 20 } }, - config: { custom: { stacking: { mode: StackingMode.Normal, group: 'stackA' } } }, - }, - ], - }); - - expect(preparePlotData([df], undefined, { sortBy: 'Max', sortDesc: false } as any)).toMatchInlineSnapshot(` - Array [ - Array [ - 9997, - 9998, - 9999, - ], - Array [ - 0, - 30, - 20, - ], - Array [ - 10, - 10, - 10, - ], - Array [ - 20, - 50, - 40, - ], - ] - `); - expect(preparePlotData([df], undefined, { sortBy: 'Max', sortDesc: true } as any)).toMatchInlineSnapshot(` - Array [ - Array [ - 9997, - 9998, - 9999, - ], - Array [ - -10, - 20, - 10, - ], - Array [ - 20, - 50, - 40, - ], - Array [ - 10, - 40, - 30, - ], - ] - `); - }); - }); }); }); -describe('orderIdsByCalcs', () => { - const ids = [1, 2, 3, 4]; - const frame = new MutableDataFrame({ - fields: [ - { name: 'time', type: FieldType.time, values: [9997, 9998, 9999] }, - { name: 'a', values: [-10, 20, 10], state: { calcs: { min: -10 } } }, - { name: 'b', values: [20, 20, 20], state: { calcs: { min: 20 } } }, - { name: 'c', values: [10, 10, 10], state: { calcs: { min: 10 } } }, - { name: 'd', values: [30, 30, 30] }, - ], +describe('auto stacking groups', () => { + test('split on stacking mode', () => { + const df = new MutableDataFrame({ + fields: [ + { name: 'time', type: FieldType.time, values: [0, 1, 2] }, + { + name: 'b', + values: [1, 2, 3], + config: { custom: { stacking: { mode: StackingMode.Percent } } }, + }, + { + name: 'c', + values: [4, 5, 6], + config: { custom: { stacking: { mode: StackingMode.Normal } } }, + }, + ], + }); + + expect(getStackingGroups(df)).toMatchInlineSnapshot(` + Array [ + Object { + "dir": 1, + "series": Array [ + 1, + ], + }, + Object { + "dir": 1, + "series": Array [ + 2, + ], + }, + ] + `); }); - it.each([ - { legend: undefined }, - { legend: { sortBy: 'Min' } }, - { legend: { sortDesc: false } }, - { legend: {} }, - { sortBy: 'Mik', sortDesc: true }, - ])('should return without ordering if legend option is %o', (legend: any) => { - const result = orderIdsByCalcs({ ids, frame, legend }); - expect(result).toEqual([1, 2, 3, 4]); + test('split pos/neg', () => { + // since we expect most series to be Pos, we try to bail early when scanning all values + // as soon as we find a value >= 0, it's assumed Pos, else Neg + + const df = new MutableDataFrame({ + fields: [ + { name: 'time', type: FieldType.time, values: [0, 1, 2] }, + { + name: 'a', + values: [-1, null, -3], + config: { custom: { stacking: { mode: StackingMode.Normal } } }, + }, + { + name: 'b', + values: [1, 2, 3], + config: { custom: { stacking: { mode: StackingMode.Normal } } }, + }, + { + name: 'c', + values: [0, 0, 0], + config: { custom: { stacking: { mode: StackingMode.Normal } } }, + }, + ], + }); + + expect(getStackingGroups(df)).toMatchInlineSnapshot(` + Array [ + Object { + "dir": -1, + "series": Array [ + 1, + 3, + ], + }, + Object { + "dir": 1, + "series": Array [ + 2, + ], + }, + ] + `); }); - it('should order the ids based on the frame stat', () => { - const resultDesc = orderIdsByCalcs({ ids, frame, legend: { sortBy: 'Min', sortDesc: true } as any }); - expect(resultDesc).toEqual([4, 2, 3, 1]); - const resultAsc = orderIdsByCalcs({ ids, frame, legend: { sortBy: 'Min', sortDesc: false } as any }); - expect(resultAsc).toEqual([1, 3, 2, 4]); + test('split pos/neg with NegY', () => { + const df = new MutableDataFrame({ + fields: [ + { name: 'time', type: FieldType.time, values: [0, 1, 2] }, + { + name: 'a', + values: [-1, null, -3], + config: { custom: { stacking: { mode: StackingMode.Normal }, transform: GraphTransform.NegativeY } }, + }, + { + name: 'b', + values: [1, 2, 3], + config: { custom: { stacking: { mode: StackingMode.Normal } } }, + }, + { + name: 'c', + values: [0, 0, 0], + config: { custom: { stacking: { mode: StackingMode.Normal } } }, + }, + ], + }); + + expect(getStackingGroups(df)).toMatchInlineSnapshot(` + Array [ + Object { + "dir": 1, + "series": Array [ + 1, + 2, + ], + }, + Object { + "dir": -1, + "series": Array [ + 3, + ], + }, + ] + `); + }); + + test('split on drawStyle, lineInterpolation, barAlignment', () => { + const df = new MutableDataFrame({ + fields: [ + { name: 'time', type: FieldType.time, values: [0, 1, 2] }, + { + name: 'a', + values: [1, 2, 3], + config: { + custom: { + drawStyle: GraphDrawStyle.Bars, + barAlignment: BarAlignment.After, + stacking: { mode: StackingMode.Normal }, + }, + }, + }, + { + name: 'b', + values: [1, 2, 3], + config: { + custom: { + drawStyle: GraphDrawStyle.Bars, + barAlignment: BarAlignment.Before, + stacking: { mode: StackingMode.Normal }, + }, + }, + }, + { + name: 'c', + values: [1, 2, 3], + config: { + custom: { + drawStyle: GraphDrawStyle.Line, + lineInterpolation: LineInterpolation.Linear, + stacking: { mode: StackingMode.Normal }, + }, + }, + }, + { + name: 'd', + values: [1, 2, 3], + config: { + custom: { + drawStyle: GraphDrawStyle.Line, + lineInterpolation: LineInterpolation.Smooth, + stacking: { mode: StackingMode.Normal }, + }, + }, + }, + { + name: 'e', + values: [1, 2, 3], + config: { custom: { drawStyle: GraphDrawStyle.Points, stacking: { mode: StackingMode.Normal } } }, + }, + ], + }); + + expect(getStackingGroups(df)).toMatchInlineSnapshot(` + Array [ + Object { + "dir": 1, + "series": Array [ + 1, + ], + }, + Object { + "dir": 1, + "series": Array [ + 2, + ], + }, + Object { + "dir": 1, + "series": Array [ + 3, + ], + }, + Object { + "dir": 1, + "series": Array [ + 4, + ], + }, + Object { + "dir": 1, + "series": Array [ + 5, + ], + }, + ] + `); + }); + + test('split on axis & units (scaleKey)', () => { + const df = new MutableDataFrame({ + fields: [ + { name: 'time', type: FieldType.time, values: [0, 1, 2] }, + { + name: 'a', + values: [1, 2, 3], + config: { custom: { stacking: { mode: StackingMode.Normal } }, unit: Units.FEET }, + }, + { + name: 'b', + values: [1, 2, 3], + config: { custom: { stacking: { mode: StackingMode.Normal } }, unit: Units.DEGREES }, + }, + ], + }); + + expect(getStackingGroups(df)).toMatchInlineSnapshot(` + Array [ + Object { + "dir": 1, + "series": Array [ + 1, + ], + }, + Object { + "dir": 1, + "series": Array [ + 2, + ], + }, + ] + `); + }); + + test('split on explicit stacking group & mode & pos/neg w/NegY', () => { + const df = new MutableDataFrame({ + fields: [ + { name: 'time', type: FieldType.time, values: [0, 1, 2] }, + { + name: 'a', + values: [1, 2, 3], + config: { custom: { stacking: { mode: StackingMode.Normal, group: 'A' } } }, + }, + { + name: 'b', + values: [1, 2, 3], + config: { custom: { stacking: { mode: StackingMode.Normal, group: 'A' } } }, + }, + { + name: 'c', + values: [1, 2, 3], + config: { custom: { stacking: { mode: StackingMode.Percent, group: 'A' } } }, + }, + { + name: 'd', + values: [1, 2, 3], + config: { custom: { stacking: { mode: StackingMode.Normal, group: 'B' } } }, + }, + { + name: 'e', + values: [1, 2, 3], + config: { custom: { stacking: { mode: StackingMode.Percent, group: 'B' } } }, + }, + { + name: 'e', + values: [1, 2, 3], + config: { + custom: { stacking: { mode: StackingMode.Percent, group: 'B' }, transform: GraphTransform.NegativeY }, + }, + }, + ], + }); + + expect(getStackingGroups(df)).toMatchInlineSnapshot(` + Array [ + Object { + "dir": 1, + "series": Array [ + 1, + 2, + ], + }, + Object { + "dir": 1, + "series": Array [ + 3, + ], + }, + Object { + "dir": 1, + "series": Array [ + 4, + ], + }, + Object { + "dir": 1, + "series": Array [ + 5, + ], + }, + Object { + "dir": -1, + "series": Array [ + 6, + ], + }, + ] + `); }); }); diff --git a/packages/grafana-ui/src/components/uPlot/utils.ts b/packages/grafana-ui/src/components/uPlot/utils.ts index 96ceaf2eb5d..4bdaadc8b8d 100755 --- a/packages/grafana-ui/src/components/uPlot/utils.ts +++ b/packages/grafana-ui/src/components/uPlot/utils.ts @@ -1,12 +1,11 @@ -import { DataFrame, ensureTimeField, Field, FieldType } from '@grafana/data'; -import { GraphFieldConfig, GraphTransform, StackingMode, VizLegendOptions } from '@grafana/schema'; -import { orderBy } from 'lodash'; +import { DataFrame, ensureTimeField, FieldType } from '@grafana/data'; +import { BarAlignment, GraphDrawStyle, GraphTransform, LineInterpolation, StackingMode } from '@grafana/schema'; import uPlot, { AlignedData, Options, PaddingSide } from 'uplot'; import { attachDebugger } from '../../utils'; import { createLogger } from '../../utils/logger'; +import { buildScaleKey } from '../GraphNG/utils'; const ALLOWED_FORMAT_STRINGS_REGEX = /\b(YYYY|YY|MMMM|MMM|MM|M|DD|D|WWWW|WWW|HH|H|h|AA|aa|a|mm|m|ss|s|fff)\b/g; -export const INTERNAL_NEGATIVE_Y_PREFIX = '__internalNegY'; export function timeFormatToTemplate(f: string) { return f.replace(ALLOWED_FORMAT_STRINGS_REGEX, (match) => `{${match}}`); @@ -41,115 +40,225 @@ interface StackMeta { } /** @internal */ -export function preparePlotData( - frames: DataFrame[], - onStackMeta?: (meta: StackMeta) => void, - legend?: VizLegendOptions -): AlignedData { - const frame = frames[0]; - const result: any[] = []; - const stackingGroups: Map = new Map(); - let seriesIndex = 0; - - for (let i = 0; i < frame.fields.length; i++) { - const f = frame.fields[i]; - - if (f.type === FieldType.time) { - result.push(ensureTimeField(f).values.toArray()); - seriesIndex++; - continue; - } - - collectStackingGroups(f, stackingGroups, seriesIndex); - const customConfig: GraphFieldConfig = f.config.custom || {}; - - const values = f.values.toArray(); - - if (customConfig.transform === GraphTransform.NegativeY) { - result.push(values.map((v) => (v == null ? v : v * -1))); - } else if (customConfig.transform === GraphTransform.Constant) { - result.push(new Array(values.length).fill(values[0])); - } else { - result.push(values); - } - seriesIndex++; - } - - // Stacking - if (stackingGroups.size !== 0) { - const byPct = frame.fields[1].config.custom?.stacking?.mode === StackingMode.Percent; - const dataLength = result[0].length; - const alignedTotals = Array(stackingGroups.size); - alignedTotals[0] = null; - - // array or stacking groups - for (const [_, seriesIds] of stackingGroups.entries()) { - const seriesIdxs = orderIdsByCalcs({ ids: seriesIds, legend, frame }); - const noValueStack = Array(dataLength).fill(true); - const groupTotals = byPct ? Array(dataLength).fill(0) : null; - - if (byPct) { - for (let j = 0; j < seriesIdxs.length; j++) { - const currentlyStacking = result[seriesIdxs[j]]; - - for (let k = 0; k < dataLength; k++) { - const v = currentlyStacking[k]; - groupTotals![k] += v == null ? 0 : +v; - } - } - } - - const acc = Array(dataLength).fill(0); - - for (let j = 0; j < seriesIdxs.length; j++) { - let seriesIdx = seriesIdxs[j]; - - alignedTotals[seriesIdx] = groupTotals; - - const currentlyStacking = result[seriesIdx]; - - for (let k = 0; k < dataLength; k++) { - const v = currentlyStacking[k]; - if (v != null && noValueStack[k]) { - noValueStack[k] = false; - } - acc[k] += v == null ? 0 : v / (byPct ? groupTotals![k] : 1); - } - - result[seriesIdx] = acc.slice().map((v, i) => (noValueStack[i] ? null : v)); - } - } - - onStackMeta && - onStackMeta({ - totals: alignedTotals as AlignedData, - }); - } - - return result as AlignedData; +export interface StackingGroup { + series: number[]; + dir: StackDirection; } -export function collectStackingGroups(f: Field, groups: Map, seriesIdx: number) { - const customConfig = f.config.custom; - if (!customConfig) { - return; - } - if ( - customConfig.stacking?.mode !== StackingMode.None && - customConfig.stacking?.group && - !customConfig.hideFrom?.viz - ) { - const group = - customConfig.transform === GraphTransform.NegativeY - ? `${INTERNAL_NEGATIVE_Y_PREFIX}-${customConfig.stacking.group}` - : customConfig.stacking.group; +/** @internal */ +const enum StackDirection { + Pos = 1, + Neg = -1, +} - if (!groups.has(group)) { - groups.set(group, [seriesIdx]); - } else { - groups.set(group, groups.get(group)!.concat(seriesIdx)); +// generates bands between adjacent group series +/** @internal */ +export function getStackingBands(group: StackingGroup) { + let bands: uPlot.Band[] = []; + let { series, dir } = group; + let lastIdx = series.length - 1; + + let rSeries = series.slice().reverse(); + + rSeries.forEach((si, i) => { + if (i !== lastIdx) { + let nextIdx = rSeries[i + 1]; + bands.push({ + series: [si, nextIdx], + // fill direction is inverted from stack direction + dir: (-1 * dir) as 1 | -1, + }); } + }); + + return bands; +} + +// expects an AlignedFrame +/** @internal */ +export function getStackingGroups(frame: DataFrame) { + let groups: Map = new Map(); + + frame.fields.forEach(({ config, values }, i) => { + // skip x or time field + if (i === 0) { + return; + } + + let { custom } = config; + + if (custom == null) { + return; + } + + // TODO: currently all AlignedFrame fields end up in uplot series & data, even custom.hideFrom?.viz + // ideally hideFrom.viz fields would be excluded so we can remove this + if (custom.hideFrom?.viz) { + return; + } + + let { stacking } = custom; + + if (stacking == null) { + return; + } + + let { mode: stackingMode, group: stackingGroup } = stacking; + + // not stacking + if (stackingMode === StackingMode.None) { + return; + } + + // will this be stacked up or down after any transforms applied + let vals = values.toArray(); + let transform = custom.transform; + let stackDir = + transform === GraphTransform.Constant + ? vals[0] > 0 + ? StackDirection.Pos + : StackDirection.Neg + : transform === GraphTransform.NegativeY + ? vals.some((v) => v > 0) + ? StackDirection.Neg + : StackDirection.Pos + : vals.some((v) => v > 0) + ? StackDirection.Pos + : StackDirection.Neg; + + let drawStyle = custom.drawStyle as GraphDrawStyle; + let drawStyle2 = + drawStyle === GraphDrawStyle.Bars + ? (custom.barAlignment as BarAlignment) + : drawStyle === GraphDrawStyle.Line + ? (custom.lineInterpolation as LineInterpolation) + : null; + + let stackKey = `${stackDir}|${stackingMode}|${stackingGroup}|${buildScaleKey(config)}|${drawStyle}|${drawStyle2}`; + + let group = groups.get(stackKey); + + if (group == null) { + group = { + series: [], + dir: stackDir, + }; + + groups.set(stackKey, group); + } + + group.series.push(i); + }); + + return [...groups.values()]; +} + +/** @internal */ +export function preparePlotData2( + frame: DataFrame, + stackingGroups: StackingGroup[], + onStackMeta?: (meta: StackMeta) => void +) { + let data = Array(frame.fields.length) as AlignedData; + + let dataLen = frame.length; + let zeroArr = Array(dataLen).fill(0); + let accums = Array.from({ length: stackingGroups.length }, () => zeroArr.slice()); + + frame.fields.forEach((field, i) => { + let vals = field.values.toArray(); + + if (i === 0) { + if (field.type === FieldType.time) { + data[i] = ensureTimeField(field).values.toArray(); + } else { + data[i] = vals; + } + return; + } + + let { custom } = field.config; + + if (!custom || custom.hideFrom?.viz) { + data[i] = vals; + return; + } + + // apply transforms + if (custom.transform === GraphTransform.Constant) { + vals = Array(vals.length).fill(vals[0]); + } else { + vals = vals.slice(); + + if (custom.transform === GraphTransform.NegativeY) { + for (let i = 0; i < vals.length; i++) { + if (vals[i] != null) { + vals[i] *= -1; + } + } + } + } + + let stackingMode = custom.stacking?.mode; + + if (!stackingMode || stackingMode === StackingMode.None) { + data[i] = vals; + } else { + let stackIdx = stackingGroups.findIndex((group) => group.series.indexOf(i) > -1); + + let accum = accums[stackIdx]; + let stacked = (data[i] = Array(dataLen)); + + for (let i = 0; i < dataLen; i++) { + let v = vals[i]; + + if (v != null) { + stacked[i] = accum[i] += v; + } else { + stacked[i] = v; // we may want to coerce to 0 here + } + } + } + }); + + if (onStackMeta) { + let accumsBySeriesIdx = data.map((vals, i) => { + let stackIdx = stackingGroups.findIndex((group) => group.series.indexOf(i) > -1); + return stackIdx !== -1 ? accums[stackIdx] : vals; + }); + + onStackMeta({ + totals: accumsBySeriesIdx as AlignedData, + }); } + + // re-compute by percent + frame.fields.forEach((field, i) => { + if (i === 0 || field.config.custom?.hideFrom?.viz) { + return; + } + + let stackingMode = field.config.custom?.stacking?.mode; + + if (stackingMode === StackingMode.Percent) { + let stackIdx = stackingGroups.findIndex((group) => group.series.indexOf(i) > -1); + let accum = accums[stackIdx]; + let group = stackingGroups[stackIdx]; + + let stacked = data[i]; + + for (let i = 0; i < dataLen; i++) { + let v = stacked[i]; + + if (v != null) { + // v / accum will always be pos, so properly (re)sign by group stacking dir + stacked[i] = group.dir * (v / accum[i]); + } + } + } + }); + + return data; } /** @@ -215,23 +324,3 @@ export const pluginLogger = createLogger('uPlot'); export const pluginLog = pluginLogger.logger; // pluginLogger.enable(); attachDebugger('graphng', undefined, pluginLogger); - -type OrderIdsByCalcsOptions = { - legend?: VizLegendOptions; - ids: number[]; - frame: DataFrame; -}; -export function orderIdsByCalcs({ legend, ids, frame }: OrderIdsByCalcsOptions) { - if (!legend?.sortBy || legend.sortDesc == null) { - return ids; - } - const orderedIds = orderBy( - ids, - (id) => { - return frame.fields[id].state?.calcs?.[legend.sortBy!.toLowerCase()]; - }, - legend.sortDesc ? 'desc' : 'asc' - ); - - return orderedIds; -} diff --git a/public/app/plugins/panel/barchart/bars.ts b/public/app/plugins/panel/barchart/bars.ts index ef7cc7f6336..316baf93ecb 100644 --- a/public/app/plugins/panel/barchart/bars.ts +++ b/public/app/plugins/panel/barchart/bars.ts @@ -11,7 +11,7 @@ import { VizTextDisplayOptions, VizLegendOptions, } from '@grafana/schema'; -import { preparePlotData } from '../../../../../packages/grafana-ui/src/components/uPlot/utils'; +import { preparePlotData2, StackingGroup } from '../../../../../packages/grafana-ui/src/components/uPlot/utils'; import { alpha } from '@grafana/data/src/themes/colorManipulator'; import { formatTime } from '@grafana/ui/src/components/uPlot/config/UPlotAxisBuilder'; @@ -564,16 +564,11 @@ export function getConfig(opts: BarsOptions, theme: GrafanaTheme2) { let alignedTotals: AlignedData | null = null; - function prepData(frames: DataFrame[]) { + function prepData(frames: DataFrame[], stackingGroups: StackingGroup[]) { alignedTotals = null; - - return preparePlotData( - frames, - ({ totals }) => { - alignedTotals = totals; - }, - opts.legend - ); + return preparePlotData2(frames[0], stackingGroups, ({ totals }) => { + alignedTotals = totals; + }); } return { diff --git a/public/app/plugins/panel/barchart/utils.ts b/public/app/plugins/panel/barchart/utils.ts index 992138a0753..9cb28a986c1 100644 --- a/public/app/plugins/panel/barchart/utils.ts +++ b/public/app/plugins/panel/barchart/utils.ts @@ -25,9 +25,9 @@ import { StackingMode, VizLegendOptions, } from '@grafana/schema'; -import { collectStackingGroups, orderIdsByCalcs } from '../../../../../packages/grafana-ui/src/components/uPlot/utils'; import { orderBy } from 'lodash'; import { findField } from 'app/features/dimensions'; +import { getStackingGroups } from '@grafana/ui/src/components/uPlot/utils'; function getBarCharScaleOrientation(orientation: VizOrientation) { if (orientation === VizOrientation.Vertical) { @@ -156,7 +156,6 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn = ({ let seriesIndex = 0; const legendOrdered = isLegendOrdered(legend); - const stackingGroups: Map = new Map(); // iterate the y values for (let i = 1; i < frame.fields.length; i++) { @@ -237,20 +236,11 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn = ({ grid: { show: customConfig.axisGridShow }, }); } - - collectStackingGroups(field, stackingGroups, seriesIndex); } - if (stackingGroups.size !== 0) { - for (const [_, seriesIds] of stackingGroups.entries()) { - const seriesIdxs = orderIdsByCalcs({ ids: seriesIds, legend, frame }); - for (let j = seriesIdxs.length - 1; j > 0; j--) { - builder.addBand({ - series: [seriesIdxs[j], seriesIdxs[j - 1]], - }); - } - } - } + let stackingGroups = getStackingGroups(frame); + + builder.setStackingGroups(stackingGroups); return builder; }; diff --git a/public/app/plugins/panel/state-timeline/utils.ts b/public/app/plugins/panel/state-timeline/utils.ts index 0bf27bd90ba..e84b6a87fbb 100644 --- a/public/app/plugins/panel/state-timeline/utils.ts +++ b/public/app/plugins/panel/state-timeline/utils.ts @@ -31,7 +31,7 @@ import { getConfig, TimelineCoreOptions } from './timeline'; import { VizLegendOptions, AxisPlacement, ScaleDirection, ScaleOrientation } from '@grafana/schema'; import { TimelineFieldConfig, TimelineOptions } from './types'; import { PlotTooltipInterpolator } from '@grafana/ui/src/components/uPlot/types'; -import { preparePlotData } from '../../../../../packages/grafana-ui/src/components/uPlot/utils'; +import { preparePlotData2, getStackingGroups } from '../../../../../packages/grafana-ui/src/components/uPlot/utils'; import uPlot from 'uplot'; const defaultConfig: TimelineFieldConfig = { @@ -153,7 +153,7 @@ export const preparePlotConfigBuilder: UPlotConfigPrepFn = ({ builder.setTooltipInterpolator(interpolateTooltip); - builder.setPrepData(preparePlotData); + builder.setPrepData((frames) => preparePlotData2(frames[0], getStackingGroups(frames[0]))); builder.setCursor(coreConfig.cursor);