Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/components/colorbar/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ module.exports = {
tickfont: axesAttrs.tickfont,
tickangle: axesAttrs.tickangle,
tickformat: axesAttrs.tickformat,
tickformatstops: axesAttrs.tickformatstops,
tickprefix: axesAttrs.tickprefix,
showtickprefix: axesAttrs.showtickprefix,
ticksuffix: axesAttrs.ticksuffix,
Expand Down
91 changes: 87 additions & 4 deletions src/plots/cartesian/axes.js
Original file line number Diff line number Diff line change
Expand Up @@ -1241,7 +1241,7 @@ function tickTextObj(ax, x, text) {

function formatDate(ax, out, hover, extraPrecision) {
var tr = ax._tickround,
fmt = (hover && ax.hoverformat) || ax.tickformat;
fmt = (hover && ax.hoverformat) || axes.getTickFormat(ax);

if(extraPrecision) {
// second or sub-second precision: extra always shows max digits.
Expand Down Expand Up @@ -1297,7 +1297,8 @@ function formatDate(ax, out, hover, extraPrecision) {

function formatLog(ax, out, hover, extraPrecision, hideexp) {
var dtick = ax.dtick,
x = out.x;
x = out.x,
tickformat = ax.tickformat;

if(hideexp === 'never') {
// If this is a hover label, then we must *never* hide the exponent
Expand All @@ -1311,7 +1312,7 @@ function formatLog(ax, out, hover, extraPrecision, hideexp) {

if(extraPrecision && ((typeof dtick !== 'string') || dtick.charAt(0) !== 'L')) dtick = 'L3';

if(ax.tickformat || (typeof dtick === 'string' && dtick.charAt(0) === 'L')) {
if(tickformat || (typeof dtick === 'string' && dtick.charAt(0) === 'L')) {
out.text = numFormat(Math.pow(10, x), ax, hideexp, extraPrecision);
}
else if(isNumeric(dtick) || ((dtick.charAt(0) === 'D') && (Lib.mod(x + 0.01, 1) < 0.1))) {
Expand Down Expand Up @@ -1406,7 +1407,7 @@ function numFormat(v, ax, fmtoverride, hover) {
tickRound = ax._tickround,
exponentFormat = fmtoverride || ax.exponentformat || 'B',
exponent = ax._tickexponent,
tickformat = ax.tickformat,
tickformat = axes.getTickFormat(ax),
separatethousands = ax.separatethousands;

// special case for hover: set exponent just for this value, and
Expand Down Expand Up @@ -1507,6 +1508,88 @@ function numFormat(v, ax, fmtoverride, hover) {
return v;
}

axes.getTickFormat = function(ax) {
function convertToMs(dtick) {
return typeof dtick !== 'string' ? dtick : Number(dtick.replace('M', '') * ONEAVGMONTH);
}
function isProperStop(dtick, range, convert) {
var convertFn = convert || function(x) { return x;};
var leftDtick = range[0];
var rightDtick = range[1];
return (leftDtick === null || convertFn(leftDtick) <= convertFn(dtick)) &&
(rightDtick === null || convertFn(rightDtick) >= convertFn(dtick));
}
function getRangeWidth(range, convert) {
var convertFn = convert || function(x) { return x;};
var left = range[0] || 0;
var right = range[1] || 0;
return Math.abs(convertFn(right) - convertFn(left));
}
function compareLogTicks(left, right) {
var priority = ['L', 'D'];
if(typeof left === typeof right) {
if(typeof left === 'number') {
return left - right;
} else {
var leftPriority = priority.indexOf(left.charAt(0));
var rightPriority = priority.indexOf(right.charAt(0));
if(leftPriority === rightPriority) {
return Number(left.replace(/(L|D)/g, '')) - Number(right.replace(/(L|D)/g, ''));
} else {
return leftPriority - rightPriority;
}
}
} else {
return typeof left === 'number' ? 1 : -1;
}
}

var tickstop;
if(ax.tickformatstops && ax.tickformatstops.length > 0) {
switch(ax.type) {
case 'date': {
tickstop = ax.tickformatstops.reduce(function(acc, stop) {
if(!isProperStop(ax.dtick, stop.dtickrange, convertToMs)) {
return acc;
}
if(!acc) {
return stop;
} else {
return getRangeWidth(stop.dtickrange, convertToMs) > getRangeWidth(acc.dtickrange, convertToMs) ? stop : acc;
}
}, null);
break;
}
case 'linear': {
tickstop = ax.tickformatstops.reduce(function(acc, stop) {
if(!isProperStop(ax.dtick, stop.dtickrange)) {
return acc;
}
if(!acc) {
return stop;
} else {
return getRangeWidth(stop.dtickrange) > getRangeWidth(acc.dtickrange) ? stop : acc;
}
}, null);
break;
}
case 'log': {
tickstop = ax.tickformatstops.filter(function(stop) {
var left = stop.dtickrange[0], right = stop.dtickrange[1];
var isLeftDtickNull = left === null;
var isRightDtickNull = right === null;
var isDtickInRangeLeft = compareLogTicks(ax.dtick, left) >= 0;
var isDtickInRangeRight = compareLogTicks(ax.dtick, right) <= 0;
return (isLeftDtickNull || isDtickInRangeLeft) && (isRightDtickNull || isDtickInRangeRight);
})[0];
break;
}
default:
}
}
return tickstop ? tickstop.value : ax.tickformat;
};

axes.subplotMatch = /^x([0-9]*)y([0-9]*)$/;

// getSubplots - extract all combinations of axes we need to make plots for
Expand Down
20 changes: 20 additions & 0 deletions src/plots/cartesian/layout_attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,26 @@ module.exports = {
'*%H~%M~%S.%2f* would display *09~15~23.46*'
].join(' ')
},
tickformatstops: {
_isLinkedToArray: 'tickformatstop',

dtickrange: {
valType: 'data_array',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

info_array please.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... just like range

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed, thanks.

description: [
'range [*min*, *max*], where *min*, *max* - dtick values',
'which describe some zoom level, it is possible to omit *min*',
'or *max* value by passing *null*'
].join(' ')
},
value: {
valType: 'string',
dflt: '',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is axis.tickformat: '' a valid format? More precisely, could

tickformatstop: [{
  dtickrange: [/* */],
  value: ''
}]

be used to hide tick labels for some dtick range?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no, tickformat: '' gives our default formatting. I suppose we could imagine making our own "hide" tickformat (for date axes you can already hack this with tickformat: ' ' but that doesn't work for numbers) but it seems a bit of a kludgy way to handle a very esoteric edge case.

role: 'style',
description: [
'string - dtickformat for described zoom level, the same as *tickformat*'
].join(' ')
}
},
hoverformat: {
valType: 'string',
dflt: '',
Expand Down
26 changes: 25 additions & 1 deletion src/plots/cartesian/tick_label_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
'use strict';

var Lib = require('../../lib');

var layoutAttributes = require('./layout_attributes');

/**
* options: inherits font, outerTicks, noHover from axes.handleAxisDefaults
Expand Down Expand Up @@ -40,6 +40,7 @@ module.exports = function handleTickLabelDefaults(containerIn, containerOut, coe

if(axType !== 'category') {
var tickFormat = coerce('tickformat');
tickformatstopsDefaults(containerIn, containerOut);
if(!tickFormat && axType !== 'date') {
coerce('showexponent', showAttrDflt);
coerce('exponentformat');
Expand Down Expand Up @@ -80,3 +81,26 @@ function getShowAttrDflt(containerIn) {
return containerIn[showAttrs[0]];
}
}

function tickformatstopsDefaults(tickformatIn, tickformatOut) {
var valuesIn = tickformatIn.tickformatstops || [],
valuesOut = tickformatOut.tickformatstops = [];

var valueIn, valueOut;

function coerce(attr, dflt) {
return Lib.coerce(valueIn, valueOut, layoutAttributes.tickformatstops, attr, dflt);
}

for(var i = 0; i < valuesIn.length; i++) {
valueIn = valuesIn[i];
valueOut = {};

coerce('dtickrange');
coerce('value');

valuesOut.push(valueOut);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nicely done. Thanks!

🎉

}

return valuesOut;
}
1 change: 1 addition & 0 deletions src/plots/gl3d/layout/axis_attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ module.exports = {
exponentformat: axesAttrs.exponentformat,
separatethousands: axesAttrs.separatethousands,
tickformat: axesAttrs.tickformat,
tickformatstops: axesAttrs.tickformatstops,
hoverformat: axesAttrs.hoverformat,
// lines and grids
showline: axesAttrs.showline,
Expand Down
1 change: 1 addition & 0 deletions src/plots/ternary/layout/axis_attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ module.exports = {
tickfont: axesAttrs.tickfont,
tickangle: axesAttrs.tickangle,
tickformat: axesAttrs.tickformat,
tickformatstops: axesAttrs.tickformatstops,
hoverformat: axesAttrs.hoverformat,
// lines and grids
showline: extendFlat({}, axesAttrs.showline, {dflt: true}),
Expand Down
20 changes: 20 additions & 0 deletions src/traces/carpet/axis_attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,26 @@ module.exports = {
'*%H~%M~%S.%2f* would display *09~15~23.46*'
].join(' ')
},
tickformatstops: {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you mind DRYing this up by adding

var axesAttrs = require('../../plots/cartesian/layout_attributes')

// ....

     tickformatstops: axesAtttrs.tickformatstops, 

// ...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed, thanks.

_isLinkedToArray: 'tickformatstop',

dtickrange: {
valType: 'data_array',
description: [
'range [*min*, *max*], where *min*, *max* - dtick values',
'which describe some zoom level, it is possible to omit *min*',
'or *max* value by passing *null*'
].join(' ')
},
value: {
valType: 'string',
dflt: '',
role: 'style',
description: [
'string - dtickformat for described zoom level, the same as *tickformat*'
].join(' ')
}
},
categoryorder: {
valType: 'enumerated',
values: [
Expand Down
4 changes: 2 additions & 2 deletions tasks/util/strict_d3.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ var pathToStrictD3Module = path.join(
constants.pathToImageTest,
'strict-d3.js'
);

var normalizedpathToStrictD3Module = pathToStrictD3Module.replace(/\\/g, '/'); // fix npm-sripts for windows users
/**
* Transform `require('d3')` expressions to `require(/path/to/strict-d3.js)`
*/
Expand All @@ -18,7 +18,7 @@ module.exports = transformTools.makeRequireTransform('requireTransform',
var pathOut;

if(pathIn === 'd3' && opts.file !== pathToStrictD3Module) {
pathOut = 'require(\'' + pathToStrictD3Module + '\')';
pathOut = 'require(\'' + normalizedpathToStrictD3Module + '\')';
}

if(pathOut) return cb(null, pathOut);
Expand Down