diff --git a/packages/grafana-ui/src/components/uPlot/config/UPlotScaleBuilder.ts b/packages/grafana-ui/src/components/uPlot/config/UPlotScaleBuilder.ts index 9527e8b69b2..2d575064cbf 100644 --- a/packages/grafana-ui/src/components/uPlot/config/UPlotScaleBuilder.ts +++ b/packages/grafana-ui/src/components/uPlot/config/UPlotScaleBuilder.ts @@ -98,6 +98,8 @@ export class UPlotScaleBuilder extends PlotConfigBuilder { return minMax; } + let logBase = scale.log ?? 10; + if (scale.distr === 1 || scale.distr === 2 || scale.distr === 4) { if (centeredZero) { let absMin = Math.abs(dataMin!); @@ -110,18 +112,48 @@ export class UPlotScaleBuilder extends PlotConfigBuilder { if (scale.distr === 4) { // TODO: switch to `, true)` after updating uPlot to 1.6.23+ // see https://github.com/leeoniya/uPlot/issues/749 - minMax = uPlot.rangeAsinh(dataMin!, dataMax!, scale.log ?? 10, false); + minMax = uPlot.rangeAsinh(dataMin!, dataMax!, logBase, false); } else { // @ts-ignore here we may use hardMin / hardMax to make sure any extra padding is computed from a more accurate delta minMax = uPlot.rangeNum(hardMinOnly ? hardMin : dataMin, hardMaxOnly ? hardMax : dataMax, rangeConfig); } } else if (scale.distr === 3) { - minMax = uPlot.rangeLog(dataMin!, dataMax!, scale.log ?? 10, true); + minMax = uPlot.rangeLog(dataMin!, dataMax!, logBase, true); } if (decimals === 0) { - minMax[0] = incrRoundDn(minMax[0]!, 1); - minMax[1] = incrRoundUp(minMax[1]!, 1); + if (scale.distr === 1 || scale.distr === 2) { + minMax[0] = incrRoundDn(minMax[0]!, 1); + minMax[1] = incrRoundUp(minMax[1]!, 1); + } + // log2 or log10 scale min must be clamped to 1 + else if (scale.distr === 3) { + let logFn = scale.log === 2 ? Math.log2 : Math.log10; + + if (minMax[0]! <= 1) { + // clamp min + minMax[0] = 1; + } else { + // snap min to nearest mag below + let minExp = Math.floor(logFn(minMax[0]!)); + minMax[0] = logBase ** minExp; + } + + // snap max to nearest mag above + let maxExp = Math.ceil(logFn(minMax[1]!)); + minMax[1] = logBase ** maxExp; + + // inflate max by mag if same + if (minMax[0] === minMax[1]) { + minMax[1] *= logBase; + } + } + // TODO: this should be better. symlog values can be <= 0, but should also be snapped to log2 or log10 boundaries + // for now we just do same as linear snapping above, so may have non-neat range and ticks at edges + else if (scale.distr === 4) { + minMax[0] = incrRoundDn(minMax[0]!, 1); + minMax[1] = incrRoundUp(minMax[1]!, 1); + } } // if all we got were hard limits, treat them as static min/max @@ -135,7 +167,7 @@ export class UPlotScaleBuilder extends PlotConfigBuilder { // guard against invalid y ranges if (minMax[0]! >= minMax[1]!) { - minMax[0] = 0; + minMax[0] = scale.distr === 3 ? 1 : 0; minMax[1] = 100; }