From bb09a0fb6825cb3a8c61fea87230dbb746a4b66a Mon Sep 17 00:00:00 2001 From: cnathe Date: Thu, 20 Aug 2026 16:00:02 -0500 Subject: [PATCH 1/2] GitHub Issue #1434: Charting update to add 5% padding on auto-computed domain bounds for x/y axis --- core/webapp/vis/src/plot.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/core/webapp/vis/src/plot.js b/core/webapp/vis/src/plot.js index 924b723b66e..e4ec50ba062 100644 --- a/core/webapp/vis/src/plot.js +++ b/core/webapp/vis/src/plot.js @@ -471,6 +471,8 @@ boxPlot.render(); var getContinuousDomain = function(aesName, userScale, data, acc, errorAes) { var userMin, userMax, min, max, minAcc, maxAcc; + var minFromUser = false, maxFromUser = false; + var PADDING = 0.05; // GitHub Issue #1434: 5% padding on auto-computed domain bounds if (userScale && userScale.domain) { userMin = userScale.domain[0]; @@ -479,6 +481,7 @@ boxPlot.render(); if (LABKEY.vis.isValid(userMin)) { min = userMin; + minFromUser = true; } else { if ((aesName == 'yLeft' || aesName == 'yRight') && errorAes) { minAcc = function(d) { @@ -498,6 +501,7 @@ boxPlot.render(); if (LABKEY.vis.isValid(userMax)) { max = userMax; + maxFromUser = true; } else { if ((aesName == 'yLeft' || aesName == 'yRight') && errorAes) { maxAcc = function(d) { @@ -520,6 +524,23 @@ boxPlot.render(); min = min - 1; } } + else if (LABKEY.vis.isValid(min) && LABKEY.vis.isValid(max) + && (!minFromUser || !maxFromUser)) { + // Add padding so data points don't sit on the plot edges. Only pad + // bounds that were auto-computed; respect any user-specified bound exactly. + if (userScale && userScale.trans && userScale.trans === 'log' && min > 0) { + // Pad in log space so proportions are preserved and values stay > 0. + var logRange = (Math.log(max) - Math.log(min)) * PADDING; + if (!minFromUser) min = Math.exp(Math.log(min) - logRange); + if (!maxFromUser) max = Math.exp(Math.log(max) + logRange); + } + else { + var range = (max - min) * PADDING; + // Don't push a non-negative min below zero (e.g. bar/count data). + if (!minFromUser) min = (min >= 0) ? Math.max(0, min - range) : min - range; + if (!maxFromUser) max = max + range; + } + } // Keep time charts from getting in a bad state. // They currently rely on us rendering an empty grid when there is an invalid x-axis. From 5a492c8c526b136dabe0fa0f9d3eebca618b508c Mon Sep 17 00:00:00 2001 From: cnathe Date: Fri, 21 Aug 2026 10:42:10 -0500 Subject: [PATCH 2/2] Claude CR - restrict padding to axis aes --- core/webapp/vis/src/plot.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/core/webapp/vis/src/plot.js b/core/webapp/vis/src/plot.js index e4ec50ba062..a48872d6db9 100644 --- a/core/webapp/vis/src/plot.js +++ b/core/webapp/vis/src/plot.js @@ -469,6 +469,11 @@ boxPlot.render(); return domain; }; + // size/color scales map data onto an aesthetic range rather than a visible axis, so they are never domain-padded. + var isAxisAes = function(aesName) { + return aesName == 'x' || aesName == 'xTop' || aesName == 'xSub' || aesName == 'yLeft' || aesName == 'yRight'; + }; + var getContinuousDomain = function(aesName, userScale, data, acc, errorAes) { var userMin, userMax, min, max, minAcc, maxAcc; var minFromUser = false, maxFromUser = false; @@ -524,7 +529,7 @@ boxPlot.render(); min = min - 1; } } - else if (LABKEY.vis.isValid(min) && LABKEY.vis.isValid(max) + else if (isAxisAes(aesName) && LABKEY.vis.isValid(min) && LABKEY.vis.isValid(max) && (!minFromUser || !maxFromUser)) { // Add padding so data points don't sit on the plot edges. Only pad // bounds that were auto-computed; respect any user-specified bound exactly. @@ -536,7 +541,7 @@ boxPlot.render(); } else { var range = (max - min) * PADDING; - // Don't push a non-negative min below zero (e.g. bar/count data). + // Don't push a non-negative min below zero (zero-anchored data reads better flush) if (!minFromUser) min = (min >= 0) ? Math.max(0, min - range) : min - range; if (!maxFromUser) max = max + range; }