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 21 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
40 changes: 39 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,47 @@ axes.doTicks = function(gd, axid, skipTitle) {
}
}

function doAutoMargins() {
if(axLetter !== 'x' && axLetter !== 'y') { return; }
var pushKey = ax._name + '.automargin';
var sideLetter = ax.side[0];
var existingPush = fullLayout._pushmargin[pushKey];
var pushParams = {x: 0, y: 0, r: 0, l: 0, t: 0, b: 0};

if(!ax.automargin || ax.anchor === 'free' || !ax._anchorAxis) {
if(existingPush && !(
existingPush.r.size === 0 && existingPush.l.size === 0 &&
existingPush.b.size === 0 && existingPush.t.size === 0)) {
Plots.autoMargin(gd, pushKey, pushParams);
}
return;
}

var axisDim;
if(axLetter === 'x') {
pushParams.y = ax._anchorAxis.domain[sideLetter === 't' ? 1 : 0];
axisDim = ax._boundingBox.height;
}
else {
pushParams.x = ax._anchorAxis.domain[sideLetter === 'r' ? 1 : 0];
axisDim = ax._boundingBox.width;
}
var axisTitleDim = (ax.title !== fullLayout._dfltTitle[axLetter] ?
ax.titlefont.size : 0);
var marginPush = axisTitleDim + axisDim;

if(!fullLayout._replotting ||
!existingPush || existingPush[sideLetter].size < marginPush) {
pushParams[sideLetter] = marginPush;
Plots.autoMargin(gd, pushKey, pushParams);
}
}

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;
};
10 changes: 10 additions & 0 deletions src/plots/cartesian/layout_attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,16 @@ module.exports = {
editType: 'ticks',
description: 'Determines whether or not the tick labels are drawn.'
},
automargin: {
valType: 'boolean',
dflt: false,
role: 'style',
editType: 'ticks',
description: [
'Determines whether long tick labels automatically grow the figure',
'margins.'
].join(' ')
},
showspikes: {
valType: 'boolean',
dflt: false,
Expand Down
1 change: 1 addition & 0 deletions src/plots/cartesian/layout_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, fullData) {
data: fullData,
bgColor: bgColor,
calendar: layoutOut.calendar,
automargin: true,
cheateronly: axLetter === 'x' && xaCheater[axName] && !xaNonCheater[axName]
};

Expand Down
10 changes: 8 additions & 2 deletions src/plots/polar/polar.js
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,10 @@ proto.updateRadialAxis = function(fullLayout, polarLayout) {
position: 0,

// dummy truthy value to make Axes.doTicks draw the grid
_counteraxis: true
_counteraxis: true,

// don't use automargins routine for labels
automargin: false
Copy link
Collaborator

Choose a reason for hiding this comment

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

might be nice to let polar and ternary contribute to automargin in the future - but since this is an axis-level attribute I guess there's no problem ignoring that part for now.

});

setScale(ax, radialLayout, fullLayout);
Expand Down Expand Up @@ -410,7 +413,10 @@ proto.updateAngularAxis = function(fullLayout, polarLayout) {
position: 0,

// dummy truthy value to make Axes.doTicks draw the grid
_counteraxis: true
_counteraxis: true,

// don't use automargins routine for labels
automargin: false
});

// Set the angular range in degrees to make auto-tick computation cleaner,
Expand Down
9 changes: 6 additions & 3 deletions src/plots/ternary/ternary.js
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,8 @@ proto.adjustLayout = function(ternaryLayout, graphSize) {
_pos: 0, // _this.xaxis.domain[0] * graphSize.w,
_id: 'y',
_length: w,
_gridpath: 'M0,0l' + h + ',-' + (w / 2)
_gridpath: 'M0,0l' + h + ',-' + (w / 2),
automargin: false // don't use automargins routine for labels
});
setConvert(aaxis, _this.graphDiv._fullLayout);
aaxis.setScale();
Expand All @@ -280,7 +281,8 @@ proto.adjustLayout = function(ternaryLayout, graphSize) {
_pos: 0, // (1 - yDomain0) * graphSize.h,
_id: 'x',
_length: w,
_gridpath: 'M0,0l-' + (w / 2) + ',-' + h
_gridpath: 'M0,0l-' + (w / 2) + ',-' + h,
automargin: false // don't use automargins routine for labels
});
setConvert(baxis, _this.graphDiv._fullLayout);
baxis.setScale();
Expand All @@ -301,7 +303,8 @@ proto.adjustLayout = function(ternaryLayout, graphSize) {
_pos: 0, // _this.xaxis.domain[1] * graphSize.w,
_id: 'y',
_length: w,
_gridpath: 'M0,0l-' + h + ',' + (w / 2)
_gridpath: 'M0,0l-' + h + ',' + (w / 2),
automargin: false // don't use automargins routine for labels
});
setConvert(caxis, _this.graphDiv._fullLayout);
caxis.setScale();
Expand Down
Binary file added test/image/baselines/long_axis_labels.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
59 changes: 59 additions & 0 deletions test/image/mocks/long_axis_labels.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
{
"data": [
{
"type": "scatter",
"name": "loooooong x",
"x": [
"short label 1",
"loooooong label 1",
"short label 2",
"loooooong label 2",
"short label 3",
"loooooong label 3",
"short label 4",
"loooooongloooooongloooooong label 4",
"short label 5",
"loooooong label 5"
],
"y": [
"short label 1",
"loooooong label 1",
"short label 2",
"loooooong label 2",
"short label 3",
"loooooong label 3",
"short label 4",
"loooooong label 4",
"short label 5",
"loooooong label 5"
]
},
{
"yaxis": "y2",
"type": "scatter",
"name": "loooooong y",
"x": ["looooooooooooonger"],
"y": ["loooooooo"]
}
],
"layout": {
"xaxis": {
"title": "X Axis Title",
"titlefont": { "size": 80 },
"automargin": true
},
"yaxis": {
"title": "Y Axis Title",
"titlefont": { "size": 40 },
"ticklen": 50,
"automargin": true
},
"yaxis2": {
"title": "Y2 Axis Title",
"overlaying": "y",
"side": "right",
"titlefont": { "size": 40 },
"automargin": true
}
}
}
139 changes: 139 additions & 0 deletions test/jasmine/tests/axes_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2564,6 +2564,145 @@ describe('Test axes', function() {
});
});
});

describe('automargin', function() {
var data = [{
x: [
'short label 1', 'loooooong label 1',
'short label 2', 'loooooong label 2',
'short label 3', 'loooooong label 3',
'short label 4', 'loooooongloooooongloooooong label 4',
'short label 5', 'loooooong label 5'
],
y: [
'short label 1', 'loooooong label 1',
'short label 2', 'loooooong label 2',
'short label 3', 'loooooong label 3',
'short label 4', 'loooooong label 4',
'short label 5', 'loooooong label 5'
]
}],
gd, initialSize, previousSize, savedBottom;

beforeEach(function() {
gd = createGraphDiv();
});

afterEach(destroyGraphDiv);

it('should grow and shrink margins', function(done) {

Plotly.plot(gd, data)
.then(function() {
initialSize = Lib.extendDeep({}, gd._fullLayout._size);
expect(gd._fullLayout.xaxis._lastangle).toBe(30);
})
.then(function() {
previousSize = Lib.extendDeep({}, gd._fullLayout._size);
return Plotly.relayout(gd, {'yaxis.automargin': true});
})
.then(function() {
var size = gd._fullLayout._size;
expect(size.l).toBeGreaterThan(previousSize.l);
expect(size.r).toBe(previousSize.r);
expect(size.b).toBe(previousSize.b);
expect(size.t).toBe(previousSize.t);
})
.then(function() {
previousSize = Lib.extendDeep({}, gd._fullLayout._size);
return Plotly.relayout(gd, {'xaxis.automargin': true});
})
.then(function() {
var size = gd._fullLayout._size;
expect(size.l).toBe(previousSize.l);
expect(size.r).toBe(previousSize.r);
expect(size.b).toBeGreaterThan(previousSize.b);
expect(size.t).toBe(previousSize.t);
})
.then(function() {
previousSize = Lib.extendDeep({}, gd._fullLayout._size);
savedBottom = previousSize.b;
return Plotly.relayout(gd, {'xaxis.tickangle': 45});
})
.then(function() {
var size = gd._fullLayout._size;
expect(size.l).toBe(previousSize.l);
expect(size.r).toBe(previousSize.r);
expect(size.b).toBeGreaterThan(previousSize.b);
expect(size.t).toBe(previousSize.t);
})
.then(function() {
previousSize = Lib.extendDeep({}, gd._fullLayout._size);
return Plotly.relayout(gd, {'xaxis.tickangle': 30});
})
.then(function() {
var size = gd._fullLayout._size;
expect(size.l).toBe(previousSize.l);
expect(size.r).toBe(previousSize.r);
expect(size.b).toBe(savedBottom);
expect(size.t).toBe(previousSize.t);
})
.then(function() {
previousSize = Lib.extendDeep({}, gd._fullLayout._size);
return Plotly.relayout(gd, {'yaxis.ticklen': 30});
})
.then(function() {
var size = gd._fullLayout._size;
expect(size.l).toBeGreaterThan(previousSize.l);
expect(size.r).toBe(previousSize.r);
expect(size.b).toBe(previousSize.b);
expect(size.t).toBe(previousSize.t);
})
.then(function() {
previousSize = Lib.extendDeep({}, gd._fullLayout._size);
return Plotly.relayout(gd, {'yaxis.titlefont.size': 30});
})
.then(function() {
var size = gd._fullLayout._size;
expect(size).toEqual(previousSize);
})
.then(function() {
previousSize = Lib.extendDeep({}, gd._fullLayout._size);
return Plotly.relayout(gd, {'yaxis.title': 'hello'});
})
.then(function() {
var size = gd._fullLayout._size;
expect(size.l).toBeGreaterThan(previousSize.l);
expect(size.r).toBe(previousSize.r);
expect(size.b).toBe(previousSize.b);
expect(size.t).toBe(previousSize.t);
})
.then(function() {
previousSize = Lib.extendDeep({}, gd._fullLayout._size);
return Plotly.relayout(gd, {
'yaxis.side': 'right',
'xaxis.side': 'top'
});
})
.then(function() {
var size = gd._fullLayout._size;
// left to right and bottom to top
expect(size.l).toBe(initialSize.r);
expect(size.r).toBe(previousSize.l);
expect(size.b).toBe(initialSize.b);
expect(size.t).toBe(previousSize.b);
})
.then(function() {
return Plotly.relayout(gd, {
'xaxis.automargin': false,
'yaxis.automargin': false
});
})
.then(function() {
var size = gd._fullLayout._size;
// back to the defaults
expect(size).toEqual(initialSize);
})
.catch(failTest)
.then(done);

});
});
});

function getZoomInButton(gd) {
Expand Down