mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
graph: better generation of y-axis ticks for log-scale
If there are too many ticks generated for the y-axis (which can occur for log scale 2, with a small y-min and a large max), then the ticks will be regenerated using larger jumps between the ticks. This also handles the case when y-min is set to 0. Previously, y-min of 0 was ignored as zero is not a valid value for log scale. Now the tick generator approximates zero by setting min to 0.1. Ref #8244 Ref #8516
This commit is contained in:
parent
1efdd92ae8
commit
1b79e17970
@ -506,6 +506,8 @@ coreModule.directive('grafanaGraph', function($rootScope, timeSrv, popoverSrv) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const minSetToZero = axis.min === 0;
|
||||||
|
|
||||||
if (axis.min < Number.MIN_VALUE) {
|
if (axis.min < Number.MIN_VALUE) {
|
||||||
axis.min = null;
|
axis.min = null;
|
||||||
}
|
}
|
||||||
@ -556,10 +558,17 @@ coreModule.directive('grafanaGraph', function($rootScope, timeSrv, popoverSrv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Number.isFinite(min) && Number.isFinite(max)) {
|
if (Number.isFinite(min) && Number.isFinite(max)) {
|
||||||
axis.ticks = [];
|
if (minSetToZero) {
|
||||||
var nextTick;
|
axis.min = 0.1;
|
||||||
for (nextTick = min; nextTick <= max; nextTick *= axis.logBase) {
|
min = 1;
|
||||||
axis.ticks.push(nextTick);
|
}
|
||||||
|
|
||||||
|
axis.ticks = generateTicksForLogScaleYAxis(min, max, axis.logBase);
|
||||||
|
if (minSetToZero) {
|
||||||
|
axis.ticks.unshift(0.1);
|
||||||
|
}
|
||||||
|
if (axis.ticks[axis.ticks.length - 1] > axis.max) {
|
||||||
|
axis.max = axis.ticks[axis.ticks.length - 1];
|
||||||
}
|
}
|
||||||
axis.tickDecimals = decimalPlaces(min);
|
axis.tickDecimals = decimalPlaces(min);
|
||||||
} else {
|
} else {
|
||||||
@ -567,7 +576,28 @@ coreModule.directive('grafanaGraph', function($rootScope, timeSrv, popoverSrv) {
|
|||||||
delete axis.min;
|
delete axis.min;
|
||||||
delete axis.max;
|
delete axis.max;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateTicksForLogScaleYAxis(min, max, logBase) {
|
||||||
|
let ticks = [];
|
||||||
|
|
||||||
|
var nextTick;
|
||||||
|
for (nextTick = min; nextTick <= max; nextTick *= logBase) {
|
||||||
|
ticks.push(nextTick);
|
||||||
|
}
|
||||||
|
|
||||||
|
const maxNumTicks = Math.ceil(ctrl.height/25);
|
||||||
|
const numTicks = ticks.length;
|
||||||
|
if (numTicks > maxNumTicks) {
|
||||||
|
const factor = Math.ceil(numTicks/maxNumTicks) * logBase;
|
||||||
|
ticks = [];
|
||||||
|
|
||||||
|
for (nextTick = min; nextTick <= (max * factor); nextTick *= factor) {
|
||||||
|
ticks.push(nextTick);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ticks;
|
||||||
}
|
}
|
||||||
|
|
||||||
function decimalPlaces(num) {
|
function decimalPlaces(num) {
|
||||||
|
@ -176,6 +176,60 @@ describe('grafanaGraph', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// y-min set 0 is a special case for log scale,
|
||||||
|
// this approximates it by setting min to 0.1
|
||||||
|
graphScenario('when logBase is log 10 and y-min is set to 0 and auto min is > 0.1', function(ctx) {
|
||||||
|
ctx.setup(function(ctrl, data) {
|
||||||
|
ctrl.panel.yaxes[0].logBase = 10;
|
||||||
|
ctrl.panel.yaxes[0].min = '0';
|
||||||
|
data[0] = new TimeSeries({
|
||||||
|
datapoints: [[2000,1],[4 ,2],[500,3],[3000,4]],
|
||||||
|
alias: 'seriesAutoscale',
|
||||||
|
});
|
||||||
|
data[0].yaxis = 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set min to 0.1 and add a tick for 0.1 and tickDecimals to be 0', function() {
|
||||||
|
var axisAutoscale = ctx.plotOptions.yaxes[0];
|
||||||
|
expect(axisAutoscale.transform(100)).to.be(2);
|
||||||
|
expect(axisAutoscale.inverseTransform(-3)).to.be(0.001);
|
||||||
|
expect(axisAutoscale.min).to.be(0.1);
|
||||||
|
expect(axisAutoscale.max).to.be(10000);
|
||||||
|
expect(axisAutoscale.ticks.length).to.be(6);
|
||||||
|
expect(axisAutoscale.ticks[0]).to.be(0.1);
|
||||||
|
expect(axisAutoscale.ticks[5]).to.be(10000);
|
||||||
|
expect(axisAutoscale.tickDecimals).to.be(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
graphScenario('when logBase is log 2 and y-min is set to 0 and num of ticks exceeds max', function(ctx) {
|
||||||
|
ctx.setup(function(ctrl, data) {
|
||||||
|
const heightForApprox5Ticks = 125;
|
||||||
|
ctrl.height = heightForApprox5Ticks;
|
||||||
|
ctrl.panel.yaxes[0].logBase = 2;
|
||||||
|
ctrl.panel.yaxes[0].min = '0';
|
||||||
|
data[0] = new TimeSeries({
|
||||||
|
datapoints: [[2000,1],[4 ,2],[500,3],[3000,4], [10000,5], [100000,6]],
|
||||||
|
alias: 'seriesAutoscale',
|
||||||
|
});
|
||||||
|
data[0].yaxis = 1;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should regenerate ticks so that if fits on the y-axis', function() {
|
||||||
|
var axisAutoscale = ctx.plotOptions.yaxes[0];
|
||||||
|
expect(axisAutoscale.min).to.be(0.1);
|
||||||
|
expect(axisAutoscale.ticks.length).to.be(8);
|
||||||
|
expect(axisAutoscale.ticks[0]).to.be(0.1);
|
||||||
|
expect(axisAutoscale.ticks[7]).to.be(262144);
|
||||||
|
expect(axisAutoscale.max).to.be(262144);
|
||||||
|
expect(axisAutoscale.tickDecimals).to.be(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set axis max to be max tick value', function() {
|
||||||
|
expect(ctx.plotOptions.yaxes[0].max).to.be(262144);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
graphScenario('dashed lines options', function(ctx) {
|
graphScenario('dashed lines options', function(ctx) {
|
||||||
ctx.setup(function(ctrl) {
|
ctx.setup(function(ctrl) {
|
||||||
ctrl.panel.lines = true;
|
ctrl.panel.lines = true;
|
||||||
|
Loading…
Reference in New Issue
Block a user