mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
heatmap: add ES histogram converter
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
///<reference path="../../../headers/common.d.ts" />
|
||||
|
||||
import _ from 'lodash';
|
||||
import TimeSeries from 'app/core/time_series2';
|
||||
|
||||
let VALUE_INDEX = 0;
|
||||
let TIME_INDEX = 1;
|
||||
@@ -15,6 +16,48 @@ interface YBucket {
|
||||
values: number[];
|
||||
}
|
||||
|
||||
function elasticHistogramToHeatmap(series) {
|
||||
let seriesBuckets = _.map(series, (s: TimeSeries) => {
|
||||
return convertEsSeriesToHeatmap(s);
|
||||
});
|
||||
let buckets = mergeBuckets(seriesBuckets);
|
||||
return buckets;
|
||||
}
|
||||
|
||||
function convertEsSeriesToHeatmap(series: TimeSeries, saveZeroCounts = false) {
|
||||
let xBuckets: XBucket[] = [];
|
||||
|
||||
_.forEach(series.datapoints, point => {
|
||||
let bound = series.alias;
|
||||
let count = point[VALUE_INDEX];
|
||||
let values = new Array(count);
|
||||
values.fill(Number(bound));
|
||||
|
||||
let valueBuckets = {};
|
||||
valueBuckets[bound] = {
|
||||
y: Number(bound),
|
||||
values: values
|
||||
};
|
||||
|
||||
let xBucket: XBucket = {
|
||||
x: point[TIME_INDEX],
|
||||
buckets: valueBuckets
|
||||
};
|
||||
|
||||
// Don't push buckets vith 0 count until saveZeroCounts flag is set
|
||||
if (count !== 0 || (count === 0 && saveZeroCounts)) {
|
||||
xBuckets.push(xBucket);
|
||||
}
|
||||
});
|
||||
|
||||
let heatmap: any = {};
|
||||
_.forEach(xBuckets, (bucket: XBucket) => {
|
||||
heatmap[bucket.x] = bucket;
|
||||
});
|
||||
|
||||
return heatmap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert set of time series into heatmap buckets
|
||||
* @return {Object} Heatmap object:
|
||||
@@ -321,20 +364,29 @@ function mergeBuckets(seriesBuckets) {
|
||||
} else {
|
||||
_.forEach(seriesBucket, (xBucket, xBound) => {
|
||||
if (mergedBuckets[xBound]) {
|
||||
mergedBuckets[xBound].points = xBucket.points.concat(mergedBuckets[xBound].points);
|
||||
mergedBuckets[xBound].values = xBucket.values.concat(mergedBuckets[xBound].values);
|
||||
if (xBucket.points) {
|
||||
mergedBuckets[xBound].points = xBucket.points.concat(mergedBuckets[xBound].points);
|
||||
}
|
||||
if (xBucket.values) {
|
||||
mergedBuckets[xBound].values = xBucket.values.concat(mergedBuckets[xBound].values);
|
||||
}
|
||||
|
||||
_.forEach(xBucket.buckets, (yBucket, yBound) => {
|
||||
let bucket = mergedBuckets[xBound].buckets[yBound];
|
||||
if (bucket && bucket.values) {
|
||||
mergedBuckets[xBound].buckets[yBound].values = bucket.values.concat(yBucket.values);
|
||||
mergedBuckets[xBound].buckets[yBound].points = bucket.points.concat(yBucket.points);
|
||||
|
||||
if (bucket.points) {
|
||||
mergedBuckets[xBound].buckets[yBound].points = bucket.points.concat(yBucket.points);
|
||||
}
|
||||
} else {
|
||||
mergedBuckets[xBound].buckets[yBound] = yBucket;
|
||||
}
|
||||
|
||||
let points = mergedBuckets[xBound].buckets[yBound].points;
|
||||
mergedBuckets[xBound].buckets[yBound].seriesStat = getSeriesStat(points);
|
||||
if (points) {
|
||||
mergedBuckets[xBound].buckets[yBound].seriesStat = getSeriesStat(points);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
mergedBuckets[xBound] = xBucket;
|
||||
@@ -363,10 +415,15 @@ function logp(value, base) {
|
||||
* @param objB
|
||||
*/
|
||||
function isHeatmapDataEqual(objA: any, objB: any): boolean {
|
||||
let is_eql = true;
|
||||
let is_eql = !emptyXOR(objA, objB);
|
||||
|
||||
_.forEach(objA, (xBucket: XBucket, x) => {
|
||||
if (objB[x]) {
|
||||
if (emptyXOR(xBucket.buckets, objB[x].buckets)) {
|
||||
is_eql = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
_.forEach(xBucket.buckets, (yBucket: YBucket, y) => {
|
||||
if (objB[x].buckets && objB[x].buckets[y]) {
|
||||
if (objB[x].buckets[y].values) {
|
||||
@@ -396,8 +453,13 @@ function isHeatmapDataEqual(objA: any, objB: any): boolean {
|
||||
return is_eql;
|
||||
}
|
||||
|
||||
function emptyXOR(foo: any, bar: any): boolean {
|
||||
return (_.isEmpty(foo) || _.isEmpty(bar)) && !(_.isEmpty(foo) && _.isEmpty(bar));
|
||||
}
|
||||
|
||||
export {
|
||||
convertToHeatMap,
|
||||
elasticHistogramToHeatmap,
|
||||
convertToCards,
|
||||
removeZeroBuckets,
|
||||
mergeZeroBuckets,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import _ from 'lodash';
|
||||
import { describe, beforeEach, it, sinon, expect, angularMocks } from '../../../../../test/lib/common';
|
||||
import TimeSeries from 'app/core/time_series2';
|
||||
import { convertToHeatMap, isHeatmapDataEqual } from '../heatmap_data_converter';
|
||||
import { convertToHeatMap, elasticHistogramToHeatmap, isHeatmapDataEqual } from '../heatmap_data_converter';
|
||||
|
||||
describe('isHeatmapDataEqual', () => {
|
||||
let ctx: any = {};
|
||||
@@ -40,10 +40,27 @@ describe('isHeatmapDataEqual', () => {
|
||||
let heatmapE = _.cloneDeep(ctx.heatmapA);
|
||||
heatmapE['1422774000000'].buckets['1'].values = [1, 1.6];
|
||||
|
||||
let empty = {};
|
||||
let emptyValues = _.cloneDeep(ctx.heatmapA);
|
||||
emptyValues['1422774000000'].buckets['1'].values = [];
|
||||
|
||||
expect(isHeatmapDataEqual(ctx.heatmapA, ctx.heatmapB)).to.be(true);
|
||||
expect(isHeatmapDataEqual(ctx.heatmapB, ctx.heatmapA)).to.be(true);
|
||||
|
||||
expect(isHeatmapDataEqual(ctx.heatmapA, heatmapC)).to.be(true);
|
||||
expect(isHeatmapDataEqual(heatmapC, ctx.heatmapA)).to.be(true);
|
||||
|
||||
expect(isHeatmapDataEqual(ctx.heatmapA, heatmapD)).to.be(false);
|
||||
expect(isHeatmapDataEqual(heatmapD, ctx.heatmapA)).to.be(false);
|
||||
|
||||
expect(isHeatmapDataEqual(ctx.heatmapA, heatmapE)).to.be(false);
|
||||
expect(isHeatmapDataEqual(heatmapE, ctx.heatmapA)).to.be(false);
|
||||
|
||||
expect(isHeatmapDataEqual(empty, ctx.heatmapA)).to.be(false);
|
||||
expect(isHeatmapDataEqual(ctx.heatmapA, empty)).to.be(false);
|
||||
|
||||
expect(isHeatmapDataEqual(emptyValues, ctx.heatmapA)).to.be(false);
|
||||
expect(isHeatmapDataEqual(ctx.heatmapA, emptyValues)).to.be(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -123,3 +140,53 @@ describe('HeatmapDataConverter', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('ES Histogram converter', () => {
|
||||
let ctx: any = {};
|
||||
|
||||
beforeEach(() => {
|
||||
ctx.series = [];
|
||||
ctx.series.push(new TimeSeries({
|
||||
datapoints: [[1, 1422774000000], [0, 1422774060000]],
|
||||
alias: '1', label: '1'
|
||||
}));
|
||||
ctx.series.push(new TimeSeries({
|
||||
datapoints: [[1, 1422774000000], [3, 1422774060000]],
|
||||
alias: '2', label: '2'
|
||||
}));
|
||||
ctx.series.push(new TimeSeries({
|
||||
datapoints: [[0, 1422774000000], [1, 1422774060000]],
|
||||
alias: '3', label: '3'
|
||||
}));
|
||||
});
|
||||
|
||||
describe('when converting ES histogram', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
});
|
||||
|
||||
it('should build proper heatmap data', () => {
|
||||
let expectedHeatmap = {
|
||||
'1422774000000': {
|
||||
x: 1422774000000,
|
||||
buckets: {
|
||||
'1': { y: 1, values: [1] },
|
||||
'2': { y: 2, values: [2] }
|
||||
}
|
||||
},
|
||||
'1422774060000': {
|
||||
x: 1422774060000,
|
||||
buckets: {
|
||||
'2': { y: 2, values: [2, 2, 2] },
|
||||
'3': { y: 3, values: [3] }
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
let heatmap = elasticHistogramToHeatmap(ctx.series);
|
||||
console.log(heatmap);
|
||||
expect(isHeatmapDataEqual(heatmap, expectedHeatmap)).to.be(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user