Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

automatic margins for long labels #2243

Merged
merged 22 commits into from
Mar 2, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
6797c9d
first cut at automatic margins for long labels
nicolaskruchten Jan 10, 2018
f83fb55
:hocho: test code
nicolaskruchten Jan 10, 2018
eda678d
proper fix for top/right axes
nicolaskruchten Jan 22, 2018
e86cfea
subplot-compatible generalization
nicolaskruchten Jan 22, 2018
8a5de93
Merge branch 'master' into label_automargin
nicolaskruchten Jan 29, 2018
0ef6009
creating default-false parameter
nicolaskruchten Jan 29, 2018
412941c
option guard
nicolaskruchten Jan 29, 2018
bc0cf06
removing package-lock.json
nicolaskruchten Jan 30, 2018
b2d49d5
Merge branch 'master' into label_automargin
nicolaskruchten Jan 30, 2018
25a36db
adding baseline, fixing coerce check
nicolaskruchten Jan 31, 2018
d89f23e
moving coercion around
nicolaskruchten Feb 1, 2018
8d0a5eb
Merge branch 'master' into label_automargin
nicolaskruchten Feb 1, 2018
67b04e9
ticklabelsautomargin -> automargin
nicolaskruchten Feb 1, 2018
05b909a
Merge branch 'master' into label_automargin
nicolaskruchten Feb 27, 2018
a05bd81
first relayout test
nicolaskruchten Feb 28, 2018
eeb1f65
make relayout test relative, add guards
nicolaskruchten Mar 1, 2018
c1f7df4
more guards
nicolaskruchten Mar 1, 2018
48da987
Merge branch 'master' into label_automargin
nicolaskruchten Mar 1, 2018
504d133
axes push according to the domain of their anchor
nicolaskruchten Mar 1, 2018
ae6ec95
formatting of mock
nicolaskruchten Mar 1, 2018
20bdefa
exclude polar and ternary from automargins
nicolaskruchten Mar 2, 2018
1df34bd
add editType to clear automargins from pushmargins
nicolaskruchten Mar 2, 2018
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
3 changes: 2 additions & 1 deletion src/plot_api/edit_types.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ var layoutOpts = {
valType: 'flaglist',
extras: ['none'],
flags: [
'calc', 'calcIfAutorange', 'plot', 'legend', 'ticks',
'calc', 'calcIfAutorange', 'plot', 'legend', 'ticks', 'margins',
'layoutstyle', 'modebar', 'camera', 'arraydraw'
],
description: [
Expand All @@ -47,6 +47,7 @@ var layoutOpts = {
'*plot* calls `Plotly.plot` but without first clearing `gd.calcdata`.',
'*legend* only redraws the legend.',
'*ticks* only redraws axis ticks, labels, and gridlines.',
'*margins* recomputes ticklabel automargins.',
Copy link
Collaborator

Choose a reason for hiding this comment

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

Ah yes, that's a much better solution 🎉

'*layoutstyle* reapplies global and SVG cartesian axis styles.',
'*modebar* just updates the modebar.',
'*camera* just updates the camera settings for gl3d scenes.',
Expand Down
9 changes: 9 additions & 0 deletions src/plot_api/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -561,3 +561,12 @@ exports.clearAxisTypes = function(gd, traces, layoutUpdate) {
}
}
};

exports.clearAxisAutomargins = function(gd) {
var keys = Object.keys(gd._fullLayout._pushmargin);
for(var i = 0; i < keys.length; i++) {
if(keys[i].indexOf('automargin') !== -1) {
delete gd._fullLayout._pushmargin[keys[i]];
}
}
};
3 changes: 3 additions & 0 deletions src/plot_api/plot_api.js
Original file line number Diff line number Diff line change
Expand Up @@ -1742,6 +1742,7 @@ Plotly.relayout = function relayout(gd, astr, val) {

// clear calcdata if required
if(flags.calc) gd.calcdata = undefined;
if(flags.margins) helpers.clearAxisAutomargins(gd);

// fill in redraw sequence

Expand Down Expand Up @@ -2182,6 +2183,7 @@ Plotly.update = function update(gd, traceUpdate, layoutUpdate, _traces) {
// clear calcdata and/or axis types if required
if(restyleFlags.clearCalc || relayoutFlags.calc) gd.calcdata = undefined;
if(restyleFlags.clearAxisTypes) helpers.clearAxisTypes(gd, traces, layoutUpdate);
if(relayoutFlags.margins) helpers.clearAxisAutomargins(gd);

// fill in redraw sequence
var seq = [];
Expand Down Expand Up @@ -2309,6 +2311,7 @@ Plotly.react = function(gd, data, layout, config) {

// clear calcdata if required
if(restyleFlags.calc || relayoutFlags.calc) gd.calcdata = undefined;
if(relayoutFlags.margins) helpers.clearAxisAutomargins(gd);

// Note: what restyle/relayout use impliedEdits and clearAxisTypes for
// must be handled by the user when using Plotly.react.
Expand Down
33 changes: 32 additions & 1 deletion src/plots/cartesian/axes.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

var d3 = require('d3');
var isNumeric = require('fast-isnumeric');
var Plots = require('../../plots/plots');

var Registry = require('../../registry');
var Lib = require('../../lib');
Expand Down Expand Up @@ -2217,10 +2218,40 @@ axes.doTicks = function(gd, axid, skipTitle) {
}
}

function doAutoMargins() {
if(!ax.automargin) { return; }
if(axLetter !== 'x' && axLetter !== 'y') { return; }

var s = ax.side[0];
var push = {x: 0, y: 0, r: 0, l: 0, t: 0, b: 0};

if(axLetter === 'x') {
push.y = (ax.anchor === 'free' ? ax.position :
ax._anchorAxis.domain[s === 't' ? 1 : 0]);
push[s] += ax._boundingBox.height;
}
else {
push.x = (ax.anchor === 'free' ? ax.position :
ax._anchorAxis.domain[s === 'r' ? 1 : 0]);
push[s] += ax._boundingBox.width;
}

if(ax.title !== fullLayout._dfltTitle[axLetter]) {
push[s] += ax.titlefont.size;
}

var pushKey = ax._name + '.automargin';
var prevPush = fullLayout._pushmargin[pushKey];
if(!prevPush || prevPush[s].size < push[s]) {
Plots.autoMargin(gd, pushKey, push);
}
}

var done = Lib.syncOrAsync([
allLabelsReady,
fixLabelOverlaps,
calcBoundingBox
calcBoundingBox,
doAutoMargins
]);
if(done && done.then) gd._promises.push(done);
return done;
Expand Down
2 changes: 2 additions & 0 deletions src/plots/cartesian/axis_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,5 +88,7 @@ module.exports = function handleAxisDefaults(containerIn, containerOut, coerce,

if(containerOut.showline || containerOut.ticks) coerce('mirror');

if(options.automargin) coerce('automargin');

return containerOut;
};
80 changes: 45 additions & 35 deletions src/plots/cartesian/layout_attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@ module.exports = {
title: {
valType: 'string',
role: 'info',
editType: 'ticks',
editType: 'ticks+margins',
description: 'Sets the title of this axis.'
},
titlefont: fontAttrs({
editType: 'ticks',
editType: 'ticks+margins',
description: [
'Sets this axis\' title font.'
].join(' ')
Expand Down Expand Up @@ -100,10 +100,10 @@ module.exports = {
valType: 'info_array',
role: 'info',
items: [
{valType: 'any', editType: 'plot', impliedEdits: {'^autorange': false}},
{valType: 'any', editType: 'plot', impliedEdits: {'^autorange': false}}
{valType: 'any', editType: 'plot+margins', impliedEdits: {'^autorange': false}},
{valType: 'any', editType: 'plot+margins', impliedEdits: {'^autorange': false}}
],
editType: 'plot',
editType: 'plot+margins',
impliedEdits: {'autorange': false},
description: [
'Sets the range of this axis.',
Expand Down Expand Up @@ -198,7 +198,7 @@ module.exports = {
valType: 'enumerated',
values: ['auto', 'linear', 'array'],
role: 'info',
editType: 'ticks',
editType: 'ticks+margins',
impliedEdits: {tick0: undefined, dtick: undefined},
description: [
'Sets the tick mode for this axis.',
Expand All @@ -216,7 +216,7 @@ module.exports = {
min: 0,
dflt: 0,
role: 'style',
editType: 'ticks',
editType: 'ticks+margins',
description: [
'Specifies the maximum number of ticks for the particular axis.',
'The actual number of ticks will be chosen automatically to be',
Expand All @@ -227,7 +227,7 @@ module.exports = {
tick0: {
valType: 'any',
role: 'style',
editType: 'ticks',
editType: 'ticks+margins',
impliedEdits: {tickmode: 'linear'},
description: [
'Sets the placement of the first tick on this axis.',
Expand All @@ -243,7 +243,7 @@ module.exports = {
dtick: {
valType: 'any',
role: 'style',
editType: 'ticks',
editType: 'ticks+margins',
impliedEdits: {tickmode: 'linear'},
description: [
'Sets the step in-between ticks on this axis. Use with `tick0`.',
Expand All @@ -269,7 +269,7 @@ module.exports = {
},
tickvals: {
valType: 'data_array',
editType: 'ticks',
editType: 'ticks+margins',
description: [
'Sets the values at which ticks on this axis appear.',
'Only has an effect if `tickmode` is set to *array*.',
Expand All @@ -278,7 +278,7 @@ module.exports = {
},
ticktext: {
valType: 'data_array',
editType: 'ticks',
editType: 'ticks+margins',
description: [
'Sets the text displayed at the ticks position via `tickvals`.',
'Only has an effect if `tickmode` is set to *array*.',
Expand All @@ -289,7 +289,7 @@ module.exports = {
valType: 'enumerated',
values: ['outside', 'inside', ''],
role: 'style',
editType: 'ticks',
editType: 'ticks+margins',
description: [
'Determines whether ticks are drawn or not.',
'If **, this axis\' ticks are not drawn.',
Expand Down Expand Up @@ -341,9 +341,19 @@ module.exports = {
valType: 'boolean',
dflt: true,
role: 'style',
editType: 'ticks',
editType: 'ticks+margins',
description: 'Determines whether or not the tick labels are drawn.'
},
automargin: {
valType: 'boolean',
dflt: false,
role: 'style',
editType: 'ticks+margins',
description: [
'Determines whether long tick labels automatically grow the figure',
'margins.'
].join(' ')
},
showspikes: {
valType: 'boolean',
dflt: false,
Expand Down Expand Up @@ -396,14 +406,14 @@ module.exports = {
description: 'Determines whether spikelines are stuck to the cursor or to the closest datapoints.'
},
tickfont: fontAttrs({
editType: 'ticks',
editType: 'ticks+margins',
description: 'Sets the tick font.'
}),
tickangle: {
valType: 'angle',
dflt: 'auto',
role: 'style',
editType: 'ticks',
editType: 'ticks+margins',
description: [
'Sets the angle of the tick labels with respect to the horizontal.',
'For example, a `tickangle` of -90 draws the tick labels',
Expand All @@ -414,15 +424,15 @@ module.exports = {
valType: 'string',
dflt: '',
role: 'style',
editType: 'ticks',
editType: 'ticks+margins',
description: 'Sets a tick label prefix.'
},
showtickprefix: {
valType: 'enumerated',
values: ['all', 'first', 'last', 'none'],
dflt: 'all',
role: 'style',
editType: 'ticks',
editType: 'ticks+margins',
description: [
'If *all*, all tick labels are displayed with a prefix.',
'If *first*, only the first tick is displayed with a prefix.',
Expand All @@ -434,23 +444,23 @@ module.exports = {
valType: 'string',
dflt: '',
role: 'style',
editType: 'ticks',
editType: 'ticks+margins',
description: 'Sets a tick label suffix.'
},
showticksuffix: {
valType: 'enumerated',
values: ['all', 'first', 'last', 'none'],
dflt: 'all',
role: 'style',
editType: 'ticks',
editType: 'ticks+margins',
description: 'Same as `showtickprefix` but for tick suffixes.'
},
showexponent: {
valType: 'enumerated',
values: ['all', 'first', 'last', 'none'],
dflt: 'all',
role: 'style',
editType: 'ticks',
editType: 'ticks+margins',
description: [
'If *all*, all exponents are shown besides their significands.',
'If *first*, only the exponent of the first tick is shown.',
Expand All @@ -463,7 +473,7 @@ module.exports = {
values: ['none', 'e', 'E', 'power', 'SI', 'B'],
dflt: 'B',
role: 'style',
editType: 'ticks',
editType: 'ticks+margins',
description: [
'Determines a formatting rule for the tick exponents.',
'For example, consider the number 1,000,000,000.',
Expand All @@ -479,7 +489,7 @@ module.exports = {
valType: 'boolean',
dflt: false,
role: 'style',
editType: 'ticks',
editType: 'ticks+margins',
description: [
'If "true", even 4-digit integers are separated'
].join(' ')
Expand All @@ -488,7 +498,7 @@ module.exports = {
valType: 'string',
dflt: '',
role: 'style',
editType: 'ticks',
editType: 'ticks+margins',
description: [
'Sets the tick label formatting rule using d3 formatting mini-languages',
'which are very similar to those in Python. For numbers, see:',
Expand All @@ -507,10 +517,10 @@ module.exports = {
valType: 'info_array',
role: 'info',
items: [
{valType: 'any', editType: 'ticks'},
{valType: 'any', editType: 'ticks'}
{valType: 'any', editType: 'ticks+margins'},
{valType: 'any', editType: 'ticks+margins'}
],
editType: 'ticks',
editType: 'ticks+margins',
description: [
'range [*min*, *max*], where *min*, *max* - dtick values',
'which describe some zoom level, it is possible to omit *min*',
Expand All @@ -521,12 +531,12 @@ module.exports = {
valType: 'string',
dflt: '',
role: 'style',
editType: 'ticks',
editType: 'ticks+margins',
description: [
'string - dtickformat for described zoom level, the same as *tickformat*'
].join(' ')
},
editType: 'ticks'
editType: 'ticks+margins'
},
hoverformat: {
valType: 'string',
Expand Down Expand Up @@ -628,7 +638,7 @@ module.exports = {
constants.idRegex.y.toString()
],
role: 'info',
editType: 'plot',
editType: 'plot+margins',
description: [
'If set to an opposite-letter axis id (e.g. `x2`, `y`), this axis is bound to',
'the corresponding opposite-letter axis.',
Expand All @@ -641,7 +651,7 @@ module.exports = {
valType: 'enumerated',
values: ['top', 'bottom', 'left', 'right'],
role: 'info',
editType: 'plot',
editType: 'plot+margins',
description: [
'Determines whether a x (y) axis is positioned',
'at the *bottom* (*left*) or *top* (*right*)',
Expand Down Expand Up @@ -685,11 +695,11 @@ module.exports = {
valType: 'info_array',
role: 'info',
items: [
{valType: 'number', min: 0, max: 1, editType: 'plot'},
{valType: 'number', min: 0, max: 1, editType: 'plot'}
{valType: 'number', min: 0, max: 1, editType: 'plot+margins'},
{valType: 'number', min: 0, max: 1, editType: 'plot+margins'}
],
dflt: [0, 1],
editType: 'plot',
editType: 'plot+margins',
description: [
'Sets the domain of this axis (in plot fraction).'
].join(' ')
Expand All @@ -700,7 +710,7 @@ module.exports = {
max: 1,
dflt: 0,
role: 'style',
editType: 'plot',
editType: 'plot+margins',
description: [
'Sets the position of this axis in the plotting space',
'(in normalized coordinates).',
Expand Down Expand Up @@ -744,7 +754,7 @@ module.exports = {
autotick: {
valType: 'boolean',
role: 'info',
editType: 'ticks',
editType: 'ticks+margins',
description: [
'Obsolete.',
'Set `tickmode` to *auto* for old `autotick` *true* behavior.',
Expand Down
Loading