diff --git a/src/components/colorbar/attributes.js b/src/components/colorbar/attributes.js index 8c34b050b17..9246d98fa26 100644 --- a/src/components/colorbar/attributes.js +++ b/src/components/colorbar/attributes.js @@ -173,6 +173,7 @@ module.exports = overrideAll({ showticksuffix: axesAttrs.showticksuffix, separatethousands: axesAttrs.separatethousands, exponentformat: axesAttrs.exponentformat, + minexponent: axesAttrs.minexponent, showexponent: axesAttrs.showexponent, title: { text: { diff --git a/src/components/colorbar/draw.js b/src/components/colorbar/draw.js index a952f78340d..1cb4a8e68a4 100644 --- a/src/components/colorbar/draw.js +++ b/src/components/colorbar/draw.js @@ -683,6 +683,7 @@ function mockColorBarAxis(gd, opts, zrange) { tickangle: opts.tickangle, tickformat: opts.tickformat, exponentformat: opts.exponentformat, + minexponent: opts.minexponent, separatethousands: opts.separatethousands, showexponent: opts.showexponent, showtickprefix: opts.showtickprefix, diff --git a/src/plots/cartesian/axes.js b/src/plots/cartesian/axes.js index 26e73e7b0cf..6176147f8c1 100644 --- a/src/plots/cartesian/axes.js +++ b/src/plots/cartesian/axes.js @@ -1042,7 +1042,8 @@ function autoTickRound(ax) { var maxend = Math.max(Math.abs(rng[0]), Math.abs(rng[1])); var rangeexp = Math.floor(Math.log(maxend) / Math.LN10 + 0.01); - if(Math.abs(rangeexp) > 3) { + var minexponent = ax.minexponent === undefined ? 3 : ax.minexponent; + if(Math.abs(rangeexp) > minexponent) { if(isSIFormat(ax.exponentformat) && !beyondSI(rangeexp)) { ax._tickexponent = 3 * Math.round((rangeexp - 1) / 3); } else ax._tickexponent = rangeexp; @@ -1525,6 +1526,7 @@ function numFormat(v, ax, fmtoverride, hover) { // make a dummy axis obj to get the auto rounding and exponent var ah = { exponentformat: exponentFormat, + minexponent: ax.minexponent, dtick: ax.showexponent === 'none' ? ax.dtick : (isNumeric(v) ? Math.abs(v) || 1 : 1), // if not showing any exponents, don't change the exponent diff --git a/src/plots/cartesian/layout_attributes.js b/src/plots/cartesian/layout_attributes.js index 3e732dda964..d62b424256a 100644 --- a/src/plots/cartesian/layout_attributes.js +++ b/src/plots/cartesian/layout_attributes.js @@ -680,6 +680,17 @@ module.exports = { 'If *B*, 1B.' ].join(' ') }, + minexponent: { + valType: 'number', + dflt: 3, + min: 0, + role: 'style', + editType: 'ticks', + description: [ + 'Hide SI prefix for 10^n if |n| is below this number.', + 'This only has an effect when `tickformat` is *SI* or *B*.' + ].join(' ') + }, separatethousands: { valType: 'boolean', dflt: false, diff --git a/src/plots/cartesian/tick_label_defaults.js b/src/plots/cartesian/tick_label_defaults.js index ad3a1d166a1..959b200d828 100644 --- a/src/plots/cartesian/tick_label_defaults.js +++ b/src/plots/cartesian/tick_label_defaults.js @@ -72,6 +72,7 @@ function handleOtherDefaults(containerIn, containerOut, coerce, axType, options) if(!tickFormat && axType !== 'date') { coerce('showexponent', showAttrDflt); coerce('exponentformat'); + coerce('minexponent'); coerce('separatethousands'); } } diff --git a/src/plots/gl3d/layout/axis_attributes.js b/src/plots/gl3d/layout/axis_attributes.js index 4a805ff8dbb..76081cc764f 100644 --- a/src/plots/gl3d/layout/axis_attributes.js +++ b/src/plots/gl3d/layout/axis_attributes.js @@ -108,6 +108,7 @@ module.exports = overrideAll({ showticksuffix: axesAttrs.showticksuffix, showexponent: axesAttrs.showexponent, exponentformat: axesAttrs.exponentformat, + minexponent: axesAttrs.minexponent, separatethousands: axesAttrs.separatethousands, tickformat: axesAttrs.tickformat, tickformatstops: axesAttrs.tickformatstops, diff --git a/src/plots/polar/layout_attributes.js b/src/plots/polar/layout_attributes.js index fc296524e34..c9cf34ecf29 100644 --- a/src/plots/polar/layout_attributes.js +++ b/src/plots/polar/layout_attributes.js @@ -47,6 +47,7 @@ var axisTickAttrs = overrideAll({ ticksuffix: axesAttrs.ticksuffix, showexponent: axesAttrs.showexponent, exponentformat: axesAttrs.exponentformat, + minexponent: axesAttrs.minexponent, separatethousands: axesAttrs.separatethousands, tickfont: axesAttrs.tickfont, tickangle: axesAttrs.tickangle, diff --git a/src/plots/ternary/layout_attributes.js b/src/plots/ternary/layout_attributes.js index d451a6d729d..aa763b38b8e 100644 --- a/src/plots/ternary/layout_attributes.js +++ b/src/plots/ternary/layout_attributes.js @@ -40,6 +40,7 @@ var ternaryAxesAttrs = { ticksuffix: axesAttrs.ticksuffix, showexponent: axesAttrs.showexponent, exponentformat: axesAttrs.exponentformat, + minexponent: axesAttrs.minexponent, separatethousands: axesAttrs.separatethousands, tickfont: axesAttrs.tickfont, tickangle: axesAttrs.tickangle, diff --git a/src/traces/carpet/axis_attributes.js b/src/traces/carpet/axis_attributes.js index 16b03ee3c48..a6e1ea53cfb 100644 --- a/src/traces/carpet/axis_attributes.js +++ b/src/traces/carpet/axis_attributes.js @@ -284,6 +284,16 @@ module.exports = { 'If *B*, 1B.' ].join(' ') }, + minexponent: { + valType: 'number', + dflt: 3, + min: 0, + role: 'style', + editType: 'calc', + description: [ + 'Hide SI prefix for 10^n if |n| is below this number' + ].join(' ') + }, separatethousands: { valType: 'boolean', dflt: false, diff --git a/src/traces/carpet/axis_defaults.js b/src/traces/carpet/axis_defaults.js index 680a787a6c8..f6ae5e36344 100644 --- a/src/traces/carpet/axis_defaults.js +++ b/src/traces/carpet/axis_defaults.js @@ -78,6 +78,7 @@ module.exports = function handleAxisDefaults(containerIn, containerOut, options) coerce('separatethousands'); coerce('tickformat'); coerce('exponentformat'); + coerce('minexponent'); coerce('showexponent'); coerce('categoryorder'); @@ -186,6 +187,7 @@ module.exports = function handleAxisDefaults(containerIn, containerOut, options) delete containerOut.tickangle; delete containerOut.showexponent; delete containerOut.exponentformat; + delete containerOut.minexponent; delete containerOut.tickformat; delete containerOut.showticksuffix; delete containerOut.showtickprefix; diff --git a/src/traces/indicator/attributes.js b/src/traces/indicator/attributes.js index e9bd0ab5c92..452f9665f1a 100644 --- a/src/traces/indicator/attributes.js +++ b/src/traces/indicator/attributes.js @@ -355,6 +355,7 @@ module.exports = { showticksuffix: axesAttrs.showticksuffix, separatethousands: axesAttrs.separatethousands, exponentformat: axesAttrs.exponentformat, + minexponent: axesAttrs.minexponent, showexponent: axesAttrs.showexponent, editType: 'plot' }, 'plot'), diff --git a/test/jasmine/tests/axes_test.js b/test/jasmine/tests/axes_test.js index 1f9e9ca9781..a3682c8054c 100644 --- a/test/jasmine/tests/axes_test.js +++ b/test/jasmine/tests/axes_test.js @@ -2851,6 +2851,58 @@ describe('Test axes', function() { ]); }); + it('Does not use SI prefixes for 10^n with |n| < minexponent', function() { + var textOut = mockCalc({ + type: 'log', + tickmode: 'linear', + exponentformat: 'SI', + minexponent: 5, + showexponent: 'all', + tick0: 0, + dtick: 1, + range: [-18.5, 18.5] + }); + + expect(textOut).toEqual([ + '10\u221218', + '10\u221217', + '10\u221216', + '1f', '10f', '100f', '1p', '10p', '100p', '1n', '10n', '100n', + '1μ', '0.00001', '0.0001', '0.001', '0.01', '0.1', '1', '10', '100', + '1000', '10,000', '100,000', '1M', '10M', '100M', '1G', '10G', '100G', + '1T', '10T', '100T', + '1015', + '1016', + '1017', + '1018' + ]); + + textOut = mockCalc({ + type: 'log', + tickmode: 'linear', + exponentformat: 'SI', + minexponent: 0, + showexponent: 'all', + tick0: 0, + dtick: 1, + range: [-18.5, 18.5] + }); + + expect(textOut).toEqual([ + '10\u221218', + '10\u221217', + '10\u221216', + '1f', '10f', '100f', '1p', '10p', '100p', '1n', '10n', '100n', + '1μ', '10μ', '100μ', '1m', '10m', '100m', '1', '10', '100', + '1k', '10k', '100k', '1M', '10M', '100M', '1G', '10G', '100G', + '1T', '10T', '100T', + '1015', + '1016', + '1017', + '1018' + ]); + }); + it('supports e/E format on log axes', function() { ['e', 'E'].forEach(function(e) { var textOut = mockCalc({