From d81d0c8c44d1424c9df568d432335bac25dc46fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 18 Mar 2015 18:51:29 -0400 Subject: [PATCH] Graph: Adds logarithmic scale option (log base 10), Closes #452 --- CHANGELOG.md | 1 + src/app/panels/graph/axisEditor.html | 12 +++ src/app/panels/graph/graph.js | 130 +++++++++++++++++--------- src/app/panels/graph/graph.tooltip.js | 2 +- src/app/panels/graph/module.js | 4 + 5 files changed, 106 insertions(+), 43 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 23cc05810eb..0ade6b78d33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - [Issue #171](https://github.com/grafana/grafana/issues/171). Panel: Different time periods, panels can override dashboard relative time and/or add a time shift - [Issue #1488](https://github.com/grafana/grafana/issues/1488). Dashboard: Clone dashboard / Save as - [Issue #1458](https://github.com/grafana/grafana/issues/1458). User: persisted user option for dark or light theme (no longer an option on a dashboard) +- [Issue #452](https://github.com/grafana/grafana/issues/452). Graph: Adds logarithmic scale option (log base 10) **Enhancements** - [Issue #1366](https://github.com/grafana/grafana/issues/1366). Graph & Singlestat: Support for additional units, Fahrenheit (°F) and Celsius (°C), Humidity (%H), kW, watt-hour (Wh), kilowatt-hour (kWh), velocities (m/s, km/h, mpg, knot) diff --git a/src/app/panels/graph/axisEditor.html b/src/app/panels/graph/axisEditor.html index edf61a04cd3..40391995fc4 100644 --- a/src/app/panels/graph/axisEditor.html +++ b/src/app/panels/graph/axisEditor.html @@ -30,6 +30,12 @@ empty-to-null ng-model="panel.grid.leftMin" ng-change="render()" ng-model-onblur> +
  • + Scale type +
  • +
  • + +
  • Label
  • @@ -69,6 +75,12 @@ empty-to-null ng-model="panel.grid.rightMin" ng-change="render()" ng-model-onblur> +
  • + Scale type +
  • +
  • + +
  • Label
  • diff --git a/src/app/panels/graph/graph.js b/src/app/panels/graph/graph.js index 967991e5da8..5e2066466ca 100755 --- a/src/app/panels/graph/graph.js +++ b/src/app/panels/graph/graph.js @@ -27,6 +27,7 @@ function (angular, $, kbn, moment, _, GraphTooltip) { var dashboard = scope.dashboard; var data, annotations; var sortedSeries; + var graphHeight; var legendSideLastValue = null; scope.crosshairEmiter = false; @@ -64,19 +65,19 @@ function (angular, $, kbn, moment, _, GraphTooltip) { function setElementHeight() { try { - var height = scope.height || scope.panel.height || scope.row.height; - if (_.isString(height)) { - height = parseInt(height.replace('px', ''), 10); + graphHeight = scope.height || scope.panel.height || scope.row.height; + if (_.isString(graphHeight)) { + graphHeight = parseInt(graphHeight.replace('px', ''), 10); } - height -= 5; // padding - height -= scope.panel.title ? 24 : 9; // subtract panel title bar + graphHeight -= 5; // padding + graphHeight -= scope.panel.title ? 24 : 9; // subtract panel title bar if (scope.panel.legend.show && !scope.panel.legend.rightSide) { - height = height - 26; // subtract one line legend + graphHeight = graphHeight - 26; // subtract one line legend } - elem.css('height', height + 'px'); + elem.css('height', graphHeight + 'px'); return true; } catch(e) { // IE throws errors sometimes @@ -349,6 +350,8 @@ function (angular, $, kbn, moment, _, GraphTooltip) { position: 'left', show: scope.panel['y-axis'], min: scope.panel.grid.leftMin, + index: 1, + scale: scope.panel.grid.leftScale, max: scope.panel.percentage && scope.panel.stack ? 100 : scope.panel.grid.leftMax, }; @@ -356,16 +359,59 @@ function (angular, $, kbn, moment, _, GraphTooltip) { if (_.findWhere(data, {yaxis: 2})) { var secondY = _.clone(defaults); + secondY.index = 2, + secondY.scale = scope.panel.grid.rightScale; secondY.position = 'right'; secondY.min = scope.panel.grid.rightMin; secondY.max = scope.panel.percentage && scope.panel.stack ? 100 : scope.panel.grid.rightMax; options.yaxes.push(secondY); + + applyLogScale(options.yaxes[1], data); configureAxisMode(options.yaxes[1], scope.panel.y_formats[1]); } + applyLogScale(options.yaxes[0], data); configureAxisMode(options.yaxes[0], scope.panel.y_formats[0]); } + function applyLogScale(axis, data) { + if (axis.scale !== 2) { + return; + } + + var series, i; + var max = axis.max; + + if (max === null) { + for (i = 0; i < data.length; i++) { + series = data[i]; + if (series.yaxis === axis.index) { + if (max < series.stats.max) { + max = series.stats.max; + } + } + } + + if (max === null) { + max = 10000000000; + } + } + + axis.ticks = [0, 1]; + var tick = 1; + + while (true) { + tick = tick*10; + axis.ticks.push(tick); + if (tick > max) { + break; + } + } + + axis.transform = function(v) { return Math.log(v+0.1); }; + axis.inverseTransform = function (v) { return Math.pow(10,v); }; + } + function configureAxisMode(axis, format) { axis.tickFormatter = function(val, axis) { return kbn.valueFormats[format](val, axis.tickDecimals, axis.scaledDecimals); @@ -411,44 +457,44 @@ function (angular, $, kbn, moment, _, GraphTooltip) { url += scope.panel['y-axis'] ? '' : '&hideYAxis=true'; switch(scope.panel.y_formats[0]) { - case 'bytes': - url += '&yUnitSystem=binary'; - break; - case 'bits': - url += '&yUnitSystem=binary'; - break; - case 'bps': - url += '&yUnitSystem=si'; - break; - case 'Bps': - url += '&yUnitSystem=si'; - break; - case 'short': - url += '&yUnitSystem=si'; - break; - case 'joule': - url += '&yUnitSystem=si'; - break; - case 'watt': - url += '&yUnitSystem=si'; - break; - case 'ev': - url += '&yUnitSystem=si'; - break; - case 'none': - url += '&yUnitSystem=none'; - break; + case 'bytes': + url += '&yUnitSystem=binary'; + break; + case 'bits': + url += '&yUnitSystem=binary'; + break; + case 'bps': + url += '&yUnitSystem=si'; + break; + case 'Bps': + url += '&yUnitSystem=si'; + break; + case 'short': + url += '&yUnitSystem=si'; + break; + case 'joule': + url += '&yUnitSystem=si'; + break; + case 'watt': + url += '&yUnitSystem=si'; + break; + case 'ev': + url += '&yUnitSystem=si'; + break; + case 'none': + url += '&yUnitSystem=none'; + break; } switch(scope.panel.nullPointMode) { - case 'connected': - url += '&lineMode=connected'; - break; - case 'null': - break; // graphite default lineMode - case 'null as zero': - url += "&drawNullAsZero=true"; - break; + case 'connected': + url += '&lineMode=connected'; + break; + case 'null': + break; // graphite default lineMode + case 'null as zero': + url += "&drawNullAsZero=true"; + break; } url += scope.panel.steppedLine ? '&lineMode=staircase' : ''; diff --git a/src/app/panels/graph/graph.tooltip.js b/src/app/panels/graph/graph.tooltip.js index d4690bea96d..724588c4fd5 100644 --- a/src/app/panels/graph/graph.tooltip.js +++ b/src/app/panels/graph/graph.tooltip.js @@ -99,7 +99,7 @@ function ($) { var group, value, timestamp, hoverInfo, i, series, seriesHtml; if(dashboard.sharedCrosshair){ - scope.appEvent('setCrosshair', { pos: pos, scope: scope }); + scope.appEvent('setCrosshair', { pos: pos, scope: scope }); } if (seriesList.length === 0) { diff --git a/src/app/panels/graph/module.js b/src/app/panels/graph/module.js index 1a554f600c9..485e7593b73 100644 --- a/src/app/panels/graph/module.js +++ b/src/app/panels/graph/module.js @@ -53,10 +53,12 @@ function (angular, app, $, _, kbn, moment, TimeSeries, PanelMeta) { y_formats : ['short', 'short'], // grid options grid : { + leftScale: 1, leftMax: null, rightMax: null, leftMin: null, rightMin: null, + rightScale: 1, threshold1: null, threshold2: null, threshold1Color: 'rgba(216, 200, 27, 0.27)', @@ -114,6 +116,8 @@ function (angular, app, $, _, kbn, moment, TimeSeries, PanelMeta) { _.defaults($scope.panel.grid, _d.grid); _.defaults($scope.panel.legend, _d.legend); + $scope.scaleTypes = {'linear': 1, 'log (base 10)': 2}; + $scope.hiddenSeries = {}; $scope.seriesList = []; $scope.unitFormats = kbn.getUnitFormats();