Przeglądaj źródła

heatmap: refactoring heatmap

Torkel Ödegaard 8 lat temu
rodzic
commit
dd5a426911

+ 2 - 9
docs/sources/features/datasources/testdata.md

@@ -11,26 +11,20 @@ weight = 20
 
 # Grafana TestData
 
-    > NOTE: This plugin is disable by default.
-
 The purpose of this data sources is to make it easier to create fake data for any panel.
 Using `Grafana TestData` you can build your own time series and have any panel render it.
 This make is much easier to verify functionally since the data can be shared very
 
 ## Enable
 
-`Grafana TestData` is not enabled by default. To enable it you have to go to `/plugins/testdata/edit` and click the enable button to enable it for each server.
+`Grafana TestData` is not enabled by default. To enable it you have to go to `/plugins/testdata/edit` and click the enable button to enable.
 
 ## Create mock data.
 
-Once `Grafana TestData` is enabled you use it as a datasource in the metric panel.
+Once `Grafana TestData` is enabled you can use it as a data source in any metric panel.
 
 ![](/img/docs/v41/test_data_add.png)
 
-## Scenarios
-
-You can now choose different scenario that you want rendered in the drop down menu. If you have scenarios that you think should be added, please add them to `` and submit a pull request.
-
 ## CSV
 
 The comma separated values scenario is the most powerful one since it lets you create any kind of graph you like.
@@ -38,7 +32,6 @@ Once you provided the numbers `Grafana TestData` will distribute them evenly bas
 
 ![](/img/docs/v41/test_data_csv_example.png)
 
-
 ## Dashboards
 
 `Grafana TestData` also contains some dashboards with example. `/plugins/testdata/edit`

+ 16 - 0
docs/sources/features/panels/heatmap.md

@@ -0,0 +1,16 @@
++++
+title = "Heatmap Panel"
+description = "Heatmap panel documentation"
+keywords = ["grafana", "heatmap", "panel", "documentation"]
+type = "docs"
+[menu.docs]
+parent = "panels"
+weight = 3
++++
+
+# Heatmap Panel
+
+> New panel only available in Grafana v4.3+
+
+![](/img/docs/v43/heatmap_panel.png)
+

+ 30 - 50
public/app/plugins/panel/heatmap/heatmap_data_converter.ts

@@ -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);
     });
   });
 

+ 6 - 6
public/app/plugins/panel/heatmap/partials/axes_editor.html

@@ -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>

+ 9 - 16
public/app/plugins/panel/heatmap/rendering.ts

@@ -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 max_value = d3.max(cardsData, card => {
-      return card.values.length;
-    });
+    let cardsData = convertToCards(data.buckets);
+    let maxValue = d3.max(cardsData, card => card.count);
 
-    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);
-}

+ 8 - 6
public/app/plugins/panel/heatmap/specs/heatmap_data_converter_specs.ts

@@ -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);
     });
   });
 });