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({