mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
heatmap: refactoring heatmap
This commit is contained in:
@@ -16,56 +16,38 @@ interface YBucket {
|
||||
values: number[];
|
||||
}
|
||||
|
||||
function elasticHistogramToHeatmap(series) {
|
||||
let seriesBuckets = _.map(series, (s: TimeSeries) => {
|
||||
return convertEsSeriesToHeatmap(s);
|
||||
});
|
||||
let buckets = mergeBuckets(seriesBuckets);
|
||||
return buckets;
|
||||
}
|
||||
function elasticHistogramToHeatmap(seriesList) {
|
||||
let heatmap = {};
|
||||
|
||||
function convertEsSeriesToHeatmap(series: TimeSeries, saveZeroCounts = false) {
|
||||
let xBuckets: XBucket[] = [];
|
||||
|
||||
_.forEach(series.datapoints, point => {
|
||||
let bound = series.alias;
|
||||
let count = point[VALUE_INDEX];
|
||||
|
||||
if (!count) {
|
||||
for (let series of seriesList) {
|
||||
let bound = Number(series.alias);
|
||||
if (isNaN(bound)) {
|
||||
return;
|
||||
}
|
||||
|
||||
let values = new Array(Math.round(count));
|
||||
values.fill(Number(bound));
|
||||
for (let point of series.datapoints) {
|
||||
let count = point[VALUE_INDEX];
|
||||
let time = point[TIME_INDEX];
|
||||
|
||||
let valueBuckets = {};
|
||||
valueBuckets[bound] = {
|
||||
y: Number(bound),
|
||||
values: values
|
||||
};
|
||||
if (!_.isNumber(count)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let xBucket: XBucket = {
|
||||
x: point[TIME_INDEX],
|
||||
buckets: valueBuckets
|
||||
};
|
||||
let bucket = heatmap[time];
|
||||
if (!bucket) {
|
||||
bucket = heatmap[time] = {x: time, buckets: {}};
|
||||
}
|
||||
|
||||
// Don't push buckets with 0 count until saveZeroCounts flag is set
|
||||
if (count !== 0 || (count === 0 && saveZeroCounts)) {
|
||||
xBuckets.push(xBucket);
|
||||
bucket.buckets[bound] = {y: bound, count: count};
|
||||
}
|
||||
});
|
||||
|
||||
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:
|
||||
/**
|
||||
* Convert set of time series into heatmap buckets
|
||||
* @return {Object} Heatmap object:
|
||||
* {
|
||||
* xBucketBound_1: {
|
||||
* x: xBucketBound_1,
|
||||
@@ -109,18 +91,16 @@ function convertToHeatMap(series, yBucketSize, xBucketSize, logBase) {
|
||||
function convertToCards(buckets) {
|
||||
let cards = [];
|
||||
_.forEach(buckets, xBucket => {
|
||||
_.forEach(xBucket.buckets, (yBucket, key) => {
|
||||
if (yBucket.values.length) {
|
||||
let card = {
|
||||
x: Number(xBucket.x),
|
||||
y: Number(key),
|
||||
yBounds: yBucket.bounds,
|
||||
values: yBucket.values,
|
||||
seriesStat: getSeriesStat(yBucket.points)
|
||||
};
|
||||
|
||||
cards.push(card);
|
||||
}
|
||||
_.forEach(xBucket.buckets, yBucket=> {
|
||||
let card = {
|
||||
x: xBucket.x,
|
||||
y: yBucket.y,
|
||||
yBounds: yBucket.bounds,
|
||||
values: yBucket.values,
|
||||
count: yBucket.count,
|
||||
seriesStat: getSeriesStat(yBucket.points)
|
||||
};
|
||||
cards.push(card);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="section gf-form-group">
|
||||
<h5 class="section-heading">Y Axis</h5>
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-6">Unit</label>
|
||||
<label class="gf-form-label width-8">Unit</label>
|
||||
<div class="gf-form-dropdown-typeahead max-width-10"
|
||||
ng-model="ctrl.panel.yAxis.format"
|
||||
dropdown-typeahead2="editor.unitFormats"
|
||||
@@ -10,21 +10,21 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-6">Scale</label>
|
||||
<label class="gf-form-label width-8">Scale</label>
|
||||
<div class="gf-form-select-wrapper max-width-10">
|
||||
<select class="gf-form-input" ng-model="ctrl.panel.yAxis.logBase" ng-options="v as k for (k, v) in editor.logScales" ng-change="ctrl.refresh()"></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-6">Y-Min</label>
|
||||
<label class="gf-form-label width-8">Y-Min</label>
|
||||
<input type="text" class="gf-form-input width-10" placeholder="auto" empty-to-null ng-model="ctrl.panel.yAxis.min" ng-change="ctrl.render()" ng-model-onblur>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-6">Y-Max</label>
|
||||
<label class="gf-form-label width-8">Y-Max</label>
|
||||
<input type="text" class="gf-form-input width-10" placeholder="auto" empty-to-null ng-model="ctrl.panel.yAxis.max" ng-change="ctrl.render()" ng-model-onblur>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-6">Decimals</label>
|
||||
<label class="gf-form-label width-8">Decimals</label>
|
||||
<input type="number" class="gf-form-input width-10" placeholder="auto" data-placement="right"
|
||||
bs-tooltip="'Override automatic decimal precision for axis.'"
|
||||
ng-model="ctrl.panel.yAxis.decimals" ng-change="ctrl.render()" ng-model-onblur>
|
||||
@@ -55,7 +55,7 @@
|
||||
<label class="gf-form-label">Buckets</label>
|
||||
<input type="number" class="gf-form-input width-5" placeholder="auto" data-placement="right"
|
||||
bs-tooltip="'Number of buckets for Y axis.'"
|
||||
ng-model="ctrl.panel.yBucketNumber" ng-change="ctrl.refresh()" ng-model-onblur>
|
||||
ng-model="ctrl.panel.xBucketNumber" ng-change="ctrl.refresh()" ng-model-onblur>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label">Size</label>
|
||||
|
||||
@@ -366,14 +366,12 @@ export default function link(scope, elem, attrs, ctrl) {
|
||||
data.buckets = mergeZeroBuckets(data.buckets, _.min(tick_values));
|
||||
}
|
||||
}
|
||||
|
||||
let cardsData = convertToCards(data.buckets);
|
||||
let maxValue = d3.max(cardsData, card => card.count);
|
||||
|
||||
let max_value = d3.max(cardsData, card => {
|
||||
return card.values.length;
|
||||
});
|
||||
|
||||
colorScale = getColorScale(max_value);
|
||||
setOpacityScale(max_value);
|
||||
colorScale = getColorScale(maxValue);
|
||||
setOpacityScale(maxValue);
|
||||
setCardSize();
|
||||
|
||||
let cards = heatmap.selectAll(".heatmap-card").data(cardsData);
|
||||
@@ -431,14 +429,14 @@ export default function link(scope, elem, attrs, ctrl) {
|
||||
return d3.scaleSequential(colorInterpolator).domain([start, end]);
|
||||
}
|
||||
|
||||
function setOpacityScale(max_value) {
|
||||
function setOpacityScale(maxValue) {
|
||||
if (panel.color.colorScale === 'linear') {
|
||||
opacityScale = d3.scaleLinear()
|
||||
.domain([0, max_value])
|
||||
.domain([0, maxValue])
|
||||
.range([0, 1]);
|
||||
} else if (panel.color.colorScale === 'sqrt') {
|
||||
opacityScale = d3.scalePow().exponent(panel.color.exponent)
|
||||
.domain([0, max_value])
|
||||
.domain([0, maxValue])
|
||||
.range([0, 1]);
|
||||
}
|
||||
}
|
||||
@@ -529,13 +527,13 @@ export default function link(scope, elem, attrs, ctrl) {
|
||||
if (panel.color.mode === 'opacity') {
|
||||
return panel.color.cardColor;
|
||||
} else {
|
||||
return colorScale(d.values.length);
|
||||
return colorScale(d.count);
|
||||
}
|
||||
}
|
||||
|
||||
function getCardOpacity(d) {
|
||||
if (panel.color.mode === 'opacity') {
|
||||
return opacityScale(d.values.length);
|
||||
return opacityScale(d.count);
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
@@ -831,8 +829,3 @@ function getPrecision(num) {
|
||||
return str.length - dot_index - 1;
|
||||
}
|
||||
}
|
||||
|
||||
function getTicksPrecision(values) {
|
||||
let precisions = _.map(values, getPrecision);
|
||||
return _.max(precisions);
|
||||
}
|
||||
|
||||
@@ -200,7 +200,7 @@ describe('ES Histogram converter', () => {
|
||||
alias: '1', label: '1'
|
||||
}));
|
||||
ctx.series.push(new TimeSeries({
|
||||
datapoints: [[1, 1422774000000], [3, 1422774060000]],
|
||||
datapoints: [[5, 1422774000000], [3, 1422774060000]],
|
||||
alias: '2', label: '2'
|
||||
}));
|
||||
ctx.series.push(new TimeSeries({
|
||||
@@ -219,21 +219,23 @@ describe('ES Histogram converter', () => {
|
||||
'1422774000000': {
|
||||
x: 1422774000000,
|
||||
buckets: {
|
||||
'1': { y: 1, values: [1] },
|
||||
'2': { y: 2, values: [2] }
|
||||
'1': { y: 1, count: 1 },
|
||||
'2': { y: 2, count: 5 },
|
||||
'3': { y: 3, count: 0 }
|
||||
}
|
||||
},
|
||||
'1422774060000': {
|
||||
x: 1422774060000,
|
||||
buckets: {
|
||||
'2': { y: 2, values: [2, 2, 2] },
|
||||
'3': { y: 3, values: [3] }
|
||||
'1': { y: 1, count: 0 },
|
||||
'2': { y: 2, count: 3 },
|
||||
'3': { y: 3, count: 1 }
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
let heatmap = elasticHistogramToHeatmap(ctx.series);
|
||||
expect(isHeatmapDataEqual(heatmap, expectedHeatmap)).to.be(true);
|
||||
expect(heatmap).to.eql(expectedHeatmap);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user