Graph: Adds logarithmic scale option (log base 10), Closes #452

This commit is contained in:
Torkel Ödegaard 2015-03-18 18:51:29 -04:00
parent eb8b9c4ac3
commit d81d0c8c44
5 changed files with 106 additions and 43 deletions

View File

@ -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 #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 #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 #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** **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) - [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)

View File

@ -30,6 +30,12 @@
empty-to-null ng-model="panel.grid.leftMin" empty-to-null ng-model="panel.grid.leftMin"
ng-change="render()" ng-model-onblur> ng-change="render()" ng-model-onblur>
</li> </li>
<li class="tight-form-item">
Scale type
</li>
<li>
<select class="input-small tight-form-input" style="width: 113px" ng-model="panel.grid.leftScale" ng-options="v as k for (k, v) in scaleTypes" ng-change="render()"></select>
</li>
<li class="tight-form-item"> <li class="tight-form-item">
Label Label
</li> </li>
@ -69,6 +75,12 @@
empty-to-null ng-model="panel.grid.rightMin" empty-to-null ng-model="panel.grid.rightMin"
ng-change="render()" ng-model-onblur> ng-change="render()" ng-model-onblur>
</li> </li>
<li class="tight-form-item">
Scale type
</li>
<li>
<select class="input-small tight-form-input" style="width: 113px" ng-model="panel.grid.rightScale" ng-options="v as k for (k, v) in scaleTypes" ng-change="render()"></select>
</li>
<li class="tight-form-item"> <li class="tight-form-item">
Label Label
</li> </li>

View File

@ -27,6 +27,7 @@ function (angular, $, kbn, moment, _, GraphTooltip) {
var dashboard = scope.dashboard; var dashboard = scope.dashboard;
var data, annotations; var data, annotations;
var sortedSeries; var sortedSeries;
var graphHeight;
var legendSideLastValue = null; var legendSideLastValue = null;
scope.crosshairEmiter = false; scope.crosshairEmiter = false;
@ -64,19 +65,19 @@ function (angular, $, kbn, moment, _, GraphTooltip) {
function setElementHeight() { function setElementHeight() {
try { try {
var height = scope.height || scope.panel.height || scope.row.height; graphHeight = scope.height || scope.panel.height || scope.row.height;
if (_.isString(height)) { if (_.isString(graphHeight)) {
height = parseInt(height.replace('px', ''), 10); graphHeight = parseInt(graphHeight.replace('px', ''), 10);
} }
height -= 5; // padding graphHeight -= 5; // padding
height -= scope.panel.title ? 24 : 9; // subtract panel title bar graphHeight -= scope.panel.title ? 24 : 9; // subtract panel title bar
if (scope.panel.legend.show && !scope.panel.legend.rightSide) { 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; return true;
} catch(e) { // IE throws errors sometimes } catch(e) { // IE throws errors sometimes
@ -349,6 +350,8 @@ function (angular, $, kbn, moment, _, GraphTooltip) {
position: 'left', position: 'left',
show: scope.panel['y-axis'], show: scope.panel['y-axis'],
min: scope.panel.grid.leftMin, min: scope.panel.grid.leftMin,
index: 1,
scale: scope.panel.grid.leftScale,
max: scope.panel.percentage && scope.panel.stack ? 100 : scope.panel.grid.leftMax, 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})) { if (_.findWhere(data, {yaxis: 2})) {
var secondY = _.clone(defaults); var secondY = _.clone(defaults);
secondY.index = 2,
secondY.scale = scope.panel.grid.rightScale;
secondY.position = 'right'; secondY.position = 'right';
secondY.min = scope.panel.grid.rightMin; secondY.min = scope.panel.grid.rightMin;
secondY.max = scope.panel.percentage && scope.panel.stack ? 100 : scope.panel.grid.rightMax; secondY.max = scope.panel.percentage && scope.panel.stack ? 100 : scope.panel.grid.rightMax;
options.yaxes.push(secondY); options.yaxes.push(secondY);
applyLogScale(options.yaxes[1], data);
configureAxisMode(options.yaxes[1], scope.panel.y_formats[1]); configureAxisMode(options.yaxes[1], scope.panel.y_formats[1]);
} }
applyLogScale(options.yaxes[0], data);
configureAxisMode(options.yaxes[0], scope.panel.y_formats[0]); 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) { function configureAxisMode(axis, format) {
axis.tickFormatter = function(val, axis) { axis.tickFormatter = function(val, axis) {
return kbn.valueFormats[format](val, axis.tickDecimals, axis.scaledDecimals); 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'; url += scope.panel['y-axis'] ? '' : '&hideYAxis=true';
switch(scope.panel.y_formats[0]) { switch(scope.panel.y_formats[0]) {
case 'bytes': case 'bytes':
url += '&yUnitSystem=binary'; url += '&yUnitSystem=binary';
break; break;
case 'bits': case 'bits':
url += '&yUnitSystem=binary'; url += '&yUnitSystem=binary';
break; break;
case 'bps': case 'bps':
url += '&yUnitSystem=si'; url += '&yUnitSystem=si';
break; break;
case 'Bps': case 'Bps':
url += '&yUnitSystem=si'; url += '&yUnitSystem=si';
break; break;
case 'short': case 'short':
url += '&yUnitSystem=si'; url += '&yUnitSystem=si';
break; break;
case 'joule': case 'joule':
url += '&yUnitSystem=si'; url += '&yUnitSystem=si';
break; break;
case 'watt': case 'watt':
url += '&yUnitSystem=si'; url += '&yUnitSystem=si';
break; break;
case 'ev': case 'ev':
url += '&yUnitSystem=si'; url += '&yUnitSystem=si';
break; break;
case 'none': case 'none':
url += '&yUnitSystem=none'; url += '&yUnitSystem=none';
break; break;
} }
switch(scope.panel.nullPointMode) { switch(scope.panel.nullPointMode) {
case 'connected': case 'connected':
url += '&lineMode=connected'; url += '&lineMode=connected';
break; break;
case 'null': case 'null':
break; // graphite default lineMode break; // graphite default lineMode
case 'null as zero': case 'null as zero':
url += "&drawNullAsZero=true"; url += "&drawNullAsZero=true";
break; break;
} }
url += scope.panel.steppedLine ? '&lineMode=staircase' : ''; url += scope.panel.steppedLine ? '&lineMode=staircase' : '';

View File

@ -99,7 +99,7 @@ function ($) {
var group, value, timestamp, hoverInfo, i, series, seriesHtml; var group, value, timestamp, hoverInfo, i, series, seriesHtml;
if(dashboard.sharedCrosshair){ if(dashboard.sharedCrosshair){
scope.appEvent('setCrosshair', { pos: pos, scope: scope }); scope.appEvent('setCrosshair', { pos: pos, scope: scope });
} }
if (seriesList.length === 0) { if (seriesList.length === 0) {

View File

@ -53,10 +53,12 @@ function (angular, app, $, _, kbn, moment, TimeSeries, PanelMeta) {
y_formats : ['short', 'short'], y_formats : ['short', 'short'],
// grid options // grid options
grid : { grid : {
leftScale: 1,
leftMax: null, leftMax: null,
rightMax: null, rightMax: null,
leftMin: null, leftMin: null,
rightMin: null, rightMin: null,
rightScale: 1,
threshold1: null, threshold1: null,
threshold2: null, threshold2: null,
threshold1Color: 'rgba(216, 200, 27, 0.27)', 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.grid, _d.grid);
_.defaults($scope.panel.legend, _d.legend); _.defaults($scope.panel.legend, _d.legend);
$scope.scaleTypes = {'linear': 1, 'log (base 10)': 2};
$scope.hiddenSeries = {}; $scope.hiddenSeries = {};
$scope.seriesList = []; $scope.seriesList = [];
$scope.unitFormats = kbn.getUnitFormats(); $scope.unitFormats = kbn.getUnitFormats();