Skip to content

Remove internal option layout.autosize='initial' (Fixes #537) - #577

Merged
etpinard merged 26 commits into
plotly:masterfrom
n-riesco:remove-autosize-initial
Jun 9, 2016
Merged

Remove internal option layout.autosize='initial' (Fixes #537)#577
etpinard merged 26 commits into
plotly:masterfrom
n-riesco:remove-autosize-initial

Conversation

@n-riesco

Copy link
Copy Markdown
Contributor
  • Moved initial call to plotAutoSize into Plots.supplyDefaults(gd).
  • Replaced { autosize: 'initial' } with the flag
    gd._fullLayout._initialAutoSizeIsDone.
  • { autosize: false } the values of width and height undefined in
    gd.layout will be autosized only once.
  • { autosize: true } only autosizes the values of width and height
    undefined in gd.layout.

Fixes#537

* Commit 5df675a (fix demo/outside legend bug and null data autoscale
bug) introduced a guard in plotAutoSize to avoid calling layoutStyles
while autosize is set to 'initial'.
* Commit ee974d9 (autosizing in shareplots, autosize aspect ratio
restrictions and ...) removed the call to layoutStyles but forgot to
remove the guard.
* This commit removes the guard.
* Checked that all the jasmine and image tests still pass.
* Moved initial call to `plotAutoSize` into `Plots.supplyDefaults(gd)`.
* Replaced `{ autosize: 'initial' }` with the flag
`gd._fullLayout._initialAutoSizeIsDone`.
* `{ autosize: false }` the values of width and height undefined in
`gd.layout` will be autosized only once.
* `{ autosize: true }` only autosizes the values of width and height
undefined in `gd.layout`.
Fixesplotly#537
* Previous image didn't honour the width and height set in the layout.
* Added test to check `Plotly.newPlot` respects `layout.width` and
`layout.height`.
Comment threadsrc/plots/plots.js Outdated
newWidth,
newHeight;

if(typeof gd.emit === 'function') gd.emit('plotly_autosize');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

why do we need this?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

i.e. that if(typeof gd.emit === 'function')

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Otherwise I get errors in the console (perhaps some test are mocking gd with something other than a DOM element?). I will come back to you on this tomorrow.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Good call. Plots.supplyDefaults should work with plain objects.

Could we make this check more robust? I'd vote for using Lib.isPlotDiv.

Comment threadtest/jasmine/tests/plot_api_test.js Outdated

Plotly.plot(gd, data).then(function() {
Plotly.newPlot(gd, data, { height: 50 }).then(function() {
expect(gd._fullLayout.height).toBe(50);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

we should also check to svg attributes too to make sure that it updated properly.

@etpinard

etpinard commented May 30, 2016

Copy link
Copy Markdown
Contributor

@n-riesco looks like you're on the right path.

Replaced { autosize: 'initial' } with the flag gd._fullLayout._initialAutoSizeIsDone

Yep. Great idea. 👍

{ autosize: false } the values of width and height undefined in gd.layout will be autosized only once.

Hmm. Is this the current behavior? Shouldn't { autosize: false } lead to layout.width: 700 and layout.height: 400 as per their defaults?

{ autosize: true } only autosizes the values of width and height undefined in gd.layout

Great.

Unfortunately, the plotly.js auto-size routine has very poor test coverage; I'm a little concerned with merging this PR. @n-riesco could make sure that all code paths in plotAutoSize are tested under Plotly.plot and Plotly.relayout?

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

On 30/05/16 17:32, Étienne Tétreault-Pinard wrote:

@n-riescohttps://github.com/n-riesco looks like you're on the right path.
{ autosize: false } the values of width and height undefined in gd.layout will be autosized only once.

Hmm. Is this the current behavior? Shouldn't |{ autosize: false }| lead to |layout.width: 700| and |layout.height: 400| as per their defaults?

The current behaviour is that if layout.width or layout.height are undefined, then layout.autosize is set to 'initial'.
When layout.autosize is set to 'initial' (and assuming config.fillFrame is false), plotAutosize gets the layout width and height using window.getComputedStyle(gd). Only if this fails, then the default width and height values are used.

Unfortunately, the plotly.js auto-size has very poor test coverage; I'm a little concerned with the PR. @n-riescohttps://github.com/n-riesco could make sure that all code paths in |plotAutoSize| https://github.com/plotly/plotly.js/pull/577/files#diff-ad4f76ccd6044ed16514297078e13b84R783 are tested under |Plotly.plot| and |Plotly.relayout|.

OK. I'll add more tests.

@alexcjohnson

Copy link
Copy Markdown
Collaborator

@n-riesco this is great, that's definitely where the autosize code belongs.

My only question (which goes along with @etpinard 's concern about test coverage - there are tons of cases to consider) is whether there are cases we'd like autosize to coerce to true - ie if width or height is missing? For example if someone is using element size to determine plot size, but has not explicitly set autosize: true - then something outside the plot (window resize or some event on their page) causes the element size to change, I would expect a simple redraw or relayout to resize the plot too.

This then begs the question (that we probably don't need to delve into now, might be a rabbit hole, but something to keep in mind for later) of whether we actually gain anything with the initial / redraw distinction. Either I'm missing something or it used to work differently, but I don't see that plotAutoSize does anything time-consuming, so what's to stop us from always running it if there's one or more missing dimensions or if autosize is explicitly true? There will be places (relayout?) where we need to track whether anything actually changed to decide how much to do next, but we already do that anyway.

@n-riesco

n-riesco commented May 31, 2016

Copy link
Copy Markdown
ContributorAuthor

Below are the tests I'm planning to add:

  • autosize:false, fillFrame:true
  • autosize:false, fillFrame:false and frameMargins
  • autosize:false, fillFrame:false and no frameMargins
  • autosize:true, fillFrame:true
  • autosize:true, fillFrame:false and frameMargins
  • autosize:true, fillFrame:false and no frameMargins

For each test, I'll check fullLayout width and height after plot and after relayout.

These tests should cover the main execution paths in plotAutoSize.


Additional tests (from comments):

  • check SVG properties in test 'should respect layout.width and layout.height'
  • test supplyDefaults(gd) can be called with mocked gd.

@etpinard

Copy link
Copy Markdown
Contributor

@n-riesco your plans sounds good!

* Fix bug in `plotAutoSize`, triggered when `autosize` and `frameMagins`
are both enabled and `gd` is a plain object.
* Ensure `autosize` doesn't set values of width and height smaller than
the minimum defined in the corresponding layout attribute.
* Do not do the initial autosize if both config.autosizable and
layout.autosize are false.
* Fix bug introduced in the commit for respecting `config.autosizable`.
@n-riesco

Copy link
Copy Markdown
ContributorAuthor

While writing the tests for this PR, I noticed that config accepts the attribute autosizable. In master, this attribute is only honoured by plotPolar. Its meaning in plotPolar is:

  • if config.autosizable: false and layout.autosize: false, then no initial autosize is carried out (if needed, the default values of width and height are used);
  • if config.autosizable: true, then an initial autosize is carried out (regardless of layout.autosize).

I've updated this PR so that autosizable is always honoured.

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

The PR is ready for review again.

Comment threadsrc/plots/plots.js Outdated
factor = 1 - 2 * frameMargins;

var gdBB;
try {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think we should avoid using try-catch as much as possible - because they are very slow.

Here too, I'd vote for using Lib.isPlotDiv. But, I'm open to other (possible more strict) suggestions.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

How about?

vargdBB=fullLayout._container&&fullLayout._container.node ?
fullLayout._container.node().getBoundingClientRect() : {width: fullLayout.width,height: fullLayout.height};

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

@etpinard About autosizable, I think it should be kept in Plotly v1, and removed in Plotly v2. The reason why I think it should be removed is that I don't think autosizable should be a global setting (different plots should be able to define different values of autosizable).

For Plotly v2, I would suggest to combine autosize and autosizable into a single setting. How about something like this?

{autosize: {valType: 'enumerated',role: 'info',values: ['never','initial','always'],description: ['Determines how a layout width or height','that has been left undefined by the user','is set.','If *never*, the default values of width and height will be used.','If *initial*, an undefined layout width or height','will be initialized on the first call to plot.''If *always*, an undefined layout width or height','will be set on the first call to plot and subsequent calls to relayout.'].join(' ')}}

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

PR ready for review again.

Comment threadsrc/plots/plots.js
} catch(err) {
gdBB = {
var gdBB = fullLayout._container && fullLayout._container.node ?
fullLayout._container.node().getBoundingClientRect() : {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Good. 👍

@etpinard

Copy link
Copy Markdown
Contributor

Thanks @n-riesco . you're almost there.

As mentioned previously, this PR was set uncover a lot of un-tested code. Commits 172d81d and 862578e were no exceptions.

Would you mind a few test cases (one per commit is fine) for the two commits above? To lock their behavior until v2.0.0.

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

I've added tests for the commits you suggested and this uncovered an issue with 862578e and another with Lib.isPlotDiv. Both are now fixed and tested.

The PR is ready for review again.

@etpinard

Copy link
Copy Markdown
Contributor

Great. I tested your branch and I couldn't find any edge cases that you might have missed. 🎉

This for sure wins the PR of the week 🏆

I'll make two minor comments on the line diff (nothing major) and then it'll be time to 💃 .

Comment threadsrc/plots/layout_attributes.js Outdated
role: 'info',
// TODO: better handling of 'initial'
values: [true, false, 'initial'],
values: [false, true],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

we should change the valType to 'boolean' and remove the values field.

@etpinard
etpinard merged commit 25a8d9c into plotly:masterJun 9, 2016
@n-riesco
n-riesco deleted the remove-autosize-initial branch June 10, 2016 08:04
gd = createGraphDiv();

Plotly.plot(gd, [{ x: [1, 2, 3], y: [2, 3, 4] }], {})
Plotly.plot(gd, [{ x: [1, 2, 3], y: [2, 3, 4] }], { autosize: true })

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@n-riesco , @chriddyp and I are testing the mapbox branch (which is rebased on top of the latest master) in the plot.ly workspace at the moment and we some issues.

Looks like this PR here is backward incompatible and the line ⏫ is a symptom.

More clearly,

Plotly.plot(gd,data);

should go through the plotAutoSize routine on the initial Plotly.plot call.

I believe changing the autosize attribute dflt to true would solve this. What are your thoughts on that?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

@etpinard An alternative that would be fully backwards-compatible is that Plot.resize(gd) deletes gd.layout.width and gd.layout.height and calls Plotly.relayout(gd, { autosize: true });. I'll prepare a PR so that you can check that it'd fix the issue in the mapbox branch.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

See #629

@etpinard

Copy link
Copy Markdown
Contributor

As per-slack conversation with @n-riesco , I'm reverting this PR and will spend more time testing in plot.ly's workspace before the next minor release - to make sure we handle all edge cases in a backward-compatible way.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugsomething broken

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@n-riesco@etpinard@alexcjohnson
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Remove internal option layout.autosize='initial' (Fixes #537) by n-riesco · Pull Request #577 · plotly/plotly.js · GitHub
Skip to content

Remove internal option layout.autosize='initial' (Fixes #537) - #577

Merged
etpinard merged 26 commits into
plotly:masterfrom
n-riesco:remove-autosize-initial
Jun 9, 2016
Merged

Remove internal option layout.autosize='initial' (Fixes #537)#577
etpinard merged 26 commits into
plotly:masterfrom
n-riesco:remove-autosize-initial

Conversation

@n-riesco

Copy link
Copy Markdown
Contributor
  • Moved initial call to plotAutoSize into Plots.supplyDefaults(gd).
  • Replaced { autosize: 'initial' } with the flag
    gd._fullLayout._initialAutoSizeIsDone.
  • { autosize: false } the values of width and height undefined in
    gd.layout will be autosized only once.
  • { autosize: true } only autosizes the values of width and height
    undefined in gd.layout.

Fixes#537

* Commit 5df675a (fix demo/outside legend bug and null data autoscale
bug) introduced a guard in plotAutoSize to avoid calling layoutStyles
while autosize is set to 'initial'.
* Commit ee974d9 (autosizing in shareplots, autosize aspect ratio
restrictions and ...) removed the call to layoutStyles but forgot to
remove the guard.
* This commit removes the guard.
* Checked that all the jasmine and image tests still pass.
* Moved initial call to `plotAutoSize` into `Plots.supplyDefaults(gd)`.
* Replaced `{ autosize: 'initial' }` with the flag
`gd._fullLayout._initialAutoSizeIsDone`.
* `{ autosize: false }` the values of width and height undefined in
`gd.layout` will be autosized only once.
* `{ autosize: true }` only autosizes the values of width and height
undefined in `gd.layout`.
Fixesplotly#537
* Previous image didn't honour the width and height set in the layout.
* Added test to check `Plotly.newPlot` respects `layout.width` and
`layout.height`.
Comment threadsrc/plots/plots.js Outdated
newWidth,
newHeight;

if(typeof gd.emit === 'function') gd.emit('plotly_autosize');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

why do we need this?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

i.e. that if(typeof gd.emit === 'function')

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Otherwise I get errors in the console (perhaps some test are mocking gd with something other than a DOM element?). I will come back to you on this tomorrow.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Good call. Plots.supplyDefaults should work with plain objects.

Could we make this check more robust? I'd vote for using Lib.isPlotDiv.

Comment threadtest/jasmine/tests/plot_api_test.js Outdated

Plotly.plot(gd, data).then(function() {
Plotly.newPlot(gd, data, { height: 50 }).then(function() {
expect(gd._fullLayout.height).toBe(50);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

we should also check to svg attributes too to make sure that it updated properly.

@etpinard

etpinard commented May 30, 2016

Copy link
Copy Markdown
Contributor

@n-riesco looks like you're on the right path.

Replaced { autosize: 'initial' } with the flag gd._fullLayout._initialAutoSizeIsDone

Yep. Great idea. 👍

{ autosize: false } the values of width and height undefined in gd.layout will be autosized only once.

Hmm. Is this the current behavior? Shouldn't { autosize: false } lead to layout.width: 700 and layout.height: 400 as per their defaults?

{ autosize: true } only autosizes the values of width and height undefined in gd.layout

Great.

Unfortunately, the plotly.js auto-size routine has very poor test coverage; I'm a little concerned with merging this PR. @n-riesco could make sure that all code paths in plotAutoSize are tested under Plotly.plot and Plotly.relayout?

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

On 30/05/16 17:32, Étienne Tétreault-Pinard wrote:

@n-riescohttps://github.com/n-riesco looks like you're on the right path.
{ autosize: false } the values of width and height undefined in gd.layout will be autosized only once.

Hmm. Is this the current behavior? Shouldn't |{ autosize: false }| lead to |layout.width: 700| and |layout.height: 400| as per their defaults?

The current behaviour is that if layout.width or layout.height are undefined, then layout.autosize is set to 'initial'.
When layout.autosize is set to 'initial' (and assuming config.fillFrame is false), plotAutosize gets the layout width and height using window.getComputedStyle(gd). Only if this fails, then the default width and height values are used.

Unfortunately, the plotly.js auto-size has very poor test coverage; I'm a little concerned with the PR. @n-riescohttps://github.com/n-riesco could make sure that all code paths in |plotAutoSize| https://github.com/plotly/plotly.js/pull/577/files#diff-ad4f76ccd6044ed16514297078e13b84R783 are tested under |Plotly.plot| and |Plotly.relayout|.

OK. I'll add more tests.

@alexcjohnson

Copy link
Copy Markdown
Collaborator

@n-riesco this is great, that's definitely where the autosize code belongs.

My only question (which goes along with @etpinard 's concern about test coverage - there are tons of cases to consider) is whether there are cases we'd like autosize to coerce to true - ie if width or height is missing? For example if someone is using element size to determine plot size, but has not explicitly set autosize: true - then something outside the plot (window resize or some event on their page) causes the element size to change, I would expect a simple redraw or relayout to resize the plot too.

This then begs the question (that we probably don't need to delve into now, might be a rabbit hole, but something to keep in mind for later) of whether we actually gain anything with the initial / redraw distinction. Either I'm missing something or it used to work differently, but I don't see that plotAutoSize does anything time-consuming, so what's to stop us from always running it if there's one or more missing dimensions or if autosize is explicitly true? There will be places (relayout?) where we need to track whether anything actually changed to decide how much to do next, but we already do that anyway.

@n-riesco

n-riesco commented May 31, 2016

Copy link
Copy Markdown
ContributorAuthor

Below are the tests I'm planning to add:

  • autosize:false, fillFrame:true
  • autosize:false, fillFrame:false and frameMargins
  • autosize:false, fillFrame:false and no frameMargins
  • autosize:true, fillFrame:true
  • autosize:true, fillFrame:false and frameMargins
  • autosize:true, fillFrame:false and no frameMargins

For each test, I'll check fullLayout width and height after plot and after relayout.

These tests should cover the main execution paths in plotAutoSize.


Additional tests (from comments):

  • check SVG properties in test 'should respect layout.width and layout.height'
  • test supplyDefaults(gd) can be called with mocked gd.

@etpinard

Copy link
Copy Markdown
Contributor

@n-riesco your plans sounds good!

* Fix bug in `plotAutoSize`, triggered when `autosize` and `frameMagins`
are both enabled and `gd` is a plain object.
* Ensure `autosize` doesn't set values of width and height smaller than
the minimum defined in the corresponding layout attribute.
* Do not do the initial autosize if both config.autosizable and
layout.autosize are false.
* Fix bug introduced in the commit for respecting `config.autosizable`.
@n-riesco

Copy link
Copy Markdown
ContributorAuthor

While writing the tests for this PR, I noticed that config accepts the attribute autosizable. In master, this attribute is only honoured by plotPolar. Its meaning in plotPolar is:

  • if config.autosizable: false and layout.autosize: false, then no initial autosize is carried out (if needed, the default values of width and height are used);
  • if config.autosizable: true, then an initial autosize is carried out (regardless of layout.autosize).

I've updated this PR so that autosizable is always honoured.

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

The PR is ready for review again.

Comment threadsrc/plots/plots.js Outdated
factor = 1 - 2 * frameMargins;

var gdBB;
try {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think we should avoid using try-catch as much as possible - because they are very slow.

Here too, I'd vote for using Lib.isPlotDiv. But, I'm open to other (possible more strict) suggestions.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

How about?

vargdBB=fullLayout._container&&fullLayout._container.node ?
fullLayout._container.node().getBoundingClientRect() : {width: fullLayout.width,height: fullLayout.height};

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

@etpinard About autosizable, I think it should be kept in Plotly v1, and removed in Plotly v2. The reason why I think it should be removed is that I don't think autosizable should be a global setting (different plots should be able to define different values of autosizable).

For Plotly v2, I would suggest to combine autosize and autosizable into a single setting. How about something like this?

{autosize: {valType: 'enumerated',role: 'info',values: ['never','initial','always'],description: ['Determines how a layout width or height','that has been left undefined by the user','is set.','If *never*, the default values of width and height will be used.','If *initial*, an undefined layout width or height','will be initialized on the first call to plot.''If *always*, an undefined layout width or height','will be set on the first call to plot and subsequent calls to relayout.'].join(' ')}}

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

PR ready for review again.

Comment threadsrc/plots/plots.js
} catch(err) {
gdBB = {
var gdBB = fullLayout._container && fullLayout._container.node ?
fullLayout._container.node().getBoundingClientRect() : {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Good. 👍

@etpinard

Copy link
Copy Markdown
Contributor

Thanks @n-riesco . you're almost there.

As mentioned previously, this PR was set uncover a lot of un-tested code. Commits 172d81d and 862578e were no exceptions.

Would you mind a few test cases (one per commit is fine) for the two commits above? To lock their behavior until v2.0.0.

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

I've added tests for the commits you suggested and this uncovered an issue with 862578e and another with Lib.isPlotDiv. Both are now fixed and tested.

The PR is ready for review again.

@etpinard

Copy link
Copy Markdown
Contributor

Great. I tested your branch and I couldn't find any edge cases that you might have missed. 🎉

This for sure wins the PR of the week 🏆

I'll make two minor comments on the line diff (nothing major) and then it'll be time to 💃 .

Comment threadsrc/plots/layout_attributes.js Outdated
role: 'info',
// TODO: better handling of 'initial'
values: [true, false, 'initial'],
values: [false, true],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

we should change the valType to 'boolean' and remove the values field.

@etpinard
etpinard merged commit 25a8d9c into plotly:masterJun 9, 2016
@n-riesco
n-riesco deleted the remove-autosize-initial branch June 10, 2016 08:04
gd = createGraphDiv();

Plotly.plot(gd, [{ x: [1, 2, 3], y: [2, 3, 4] }], {})
Plotly.plot(gd, [{ x: [1, 2, 3], y: [2, 3, 4] }], { autosize: true })

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@n-riesco , @chriddyp and I are testing the mapbox branch (which is rebased on top of the latest master) in the plot.ly workspace at the moment and we some issues.

Looks like this PR here is backward incompatible and the line ⏫ is a symptom.

More clearly,

Plotly.plot(gd,data);

should go through the plotAutoSize routine on the initial Plotly.plot call.

I believe changing the autosize attribute dflt to true would solve this. What are your thoughts on that?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

@etpinard An alternative that would be fully backwards-compatible is that Plot.resize(gd) deletes gd.layout.width and gd.layout.height and calls Plotly.relayout(gd, { autosize: true });. I'll prepare a PR so that you can check that it'd fix the issue in the mapbox branch.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

See #629

@etpinard

Copy link
Copy Markdown
Contributor

As per-slack conversation with @n-riesco , I'm reverting this PR and will spend more time testing in plot.ly's workspace before the next minor release - to make sure we handle all edge cases in a backward-compatible way.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugsomething broken

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@n-riesco@etpinard@alexcjohnson
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Remove internal option layout.autosize='initial' (Fixes #537) by n-riesco · Pull Request #577 · plotly/plotly.js · GitHub
Skip to content

Remove internal option layout.autosize='initial' (Fixes #537) - #577

Merged
etpinard merged 26 commits into
plotly:masterfrom
n-riesco:remove-autosize-initial
Jun 9, 2016
Merged

Remove internal option layout.autosize='initial' (Fixes #537)#577
etpinard merged 26 commits into
plotly:masterfrom
n-riesco:remove-autosize-initial

Conversation

@n-riesco

Copy link
Copy Markdown
Contributor
  • Moved initial call to plotAutoSize into Plots.supplyDefaults(gd).
  • Replaced { autosize: 'initial' } with the flag
    gd._fullLayout._initialAutoSizeIsDone.
  • { autosize: false } the values of width and height undefined in
    gd.layout will be autosized only once.
  • { autosize: true } only autosizes the values of width and height
    undefined in gd.layout.

Fixes#537

* Commit 5df675a (fix demo/outside legend bug and null data autoscale
bug) introduced a guard in plotAutoSize to avoid calling layoutStyles
while autosize is set to 'initial'.
* Commit ee974d9 (autosizing in shareplots, autosize aspect ratio
restrictions and ...) removed the call to layoutStyles but forgot to
remove the guard.
* This commit removes the guard.
* Checked that all the jasmine and image tests still pass.
* Moved initial call to `plotAutoSize` into `Plots.supplyDefaults(gd)`.
* Replaced `{ autosize: 'initial' }` with the flag
`gd._fullLayout._initialAutoSizeIsDone`.
* `{ autosize: false }` the values of width and height undefined in
`gd.layout` will be autosized only once.
* `{ autosize: true }` only autosizes the values of width and height
undefined in `gd.layout`.
Fixesplotly#537
* Previous image didn't honour the width and height set in the layout.
* Added test to check `Plotly.newPlot` respects `layout.width` and
`layout.height`.
Comment threadsrc/plots/plots.js Outdated
newWidth,
newHeight;

if(typeof gd.emit === 'function') gd.emit('plotly_autosize');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

why do we need this?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

i.e. that if(typeof gd.emit === 'function')

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Otherwise I get errors in the console (perhaps some test are mocking gd with something other than a DOM element?). I will come back to you on this tomorrow.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Good call. Plots.supplyDefaults should work with plain objects.

Could we make this check more robust? I'd vote for using Lib.isPlotDiv.

Comment threadtest/jasmine/tests/plot_api_test.js Outdated

Plotly.plot(gd, data).then(function() {
Plotly.newPlot(gd, data, { height: 50 }).then(function() {
expect(gd._fullLayout.height).toBe(50);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

we should also check to svg attributes too to make sure that it updated properly.

@etpinard

etpinard commented May 30, 2016

Copy link
Copy Markdown
Contributor

@n-riesco looks like you're on the right path.

Replaced { autosize: 'initial' } with the flag gd._fullLayout._initialAutoSizeIsDone

Yep. Great idea. 👍

{ autosize: false } the values of width and height undefined in gd.layout will be autosized only once.

Hmm. Is this the current behavior? Shouldn't { autosize: false } lead to layout.width: 700 and layout.height: 400 as per their defaults?

{ autosize: true } only autosizes the values of width and height undefined in gd.layout

Great.

Unfortunately, the plotly.js auto-size routine has very poor test coverage; I'm a little concerned with merging this PR. @n-riesco could make sure that all code paths in plotAutoSize are tested under Plotly.plot and Plotly.relayout?

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

On 30/05/16 17:32, Étienne Tétreault-Pinard wrote:

@n-riescohttps://github.com/n-riesco looks like you're on the right path.
{ autosize: false } the values of width and height undefined in gd.layout will be autosized only once.

Hmm. Is this the current behavior? Shouldn't |{ autosize: false }| lead to |layout.width: 700| and |layout.height: 400| as per their defaults?

The current behaviour is that if layout.width or layout.height are undefined, then layout.autosize is set to 'initial'.
When layout.autosize is set to 'initial' (and assuming config.fillFrame is false), plotAutosize gets the layout width and height using window.getComputedStyle(gd). Only if this fails, then the default width and height values are used.

Unfortunately, the plotly.js auto-size has very poor test coverage; I'm a little concerned with the PR. @n-riescohttps://github.com/n-riesco could make sure that all code paths in |plotAutoSize| https://github.com/plotly/plotly.js/pull/577/files#diff-ad4f76ccd6044ed16514297078e13b84R783 are tested under |Plotly.plot| and |Plotly.relayout|.

OK. I'll add more tests.

@alexcjohnson

Copy link
Copy Markdown
Collaborator

@n-riesco this is great, that's definitely where the autosize code belongs.

My only question (which goes along with @etpinard 's concern about test coverage - there are tons of cases to consider) is whether there are cases we'd like autosize to coerce to true - ie if width or height is missing? For example if someone is using element size to determine plot size, but has not explicitly set autosize: true - then something outside the plot (window resize or some event on their page) causes the element size to change, I would expect a simple redraw or relayout to resize the plot too.

This then begs the question (that we probably don't need to delve into now, might be a rabbit hole, but something to keep in mind for later) of whether we actually gain anything with the initial / redraw distinction. Either I'm missing something or it used to work differently, but I don't see that plotAutoSize does anything time-consuming, so what's to stop us from always running it if there's one or more missing dimensions or if autosize is explicitly true? There will be places (relayout?) where we need to track whether anything actually changed to decide how much to do next, but we already do that anyway.

@n-riesco

n-riesco commented May 31, 2016

Copy link
Copy Markdown
ContributorAuthor

Below are the tests I'm planning to add:

  • autosize:false, fillFrame:true
  • autosize:false, fillFrame:false and frameMargins
  • autosize:false, fillFrame:false and no frameMargins
  • autosize:true, fillFrame:true
  • autosize:true, fillFrame:false and frameMargins
  • autosize:true, fillFrame:false and no frameMargins

For each test, I'll check fullLayout width and height after plot and after relayout.

These tests should cover the main execution paths in plotAutoSize.


Additional tests (from comments):

  • check SVG properties in test 'should respect layout.width and layout.height'
  • test supplyDefaults(gd) can be called with mocked gd.

@etpinard

Copy link
Copy Markdown
Contributor

@n-riesco your plans sounds good!

* Fix bug in `plotAutoSize`, triggered when `autosize` and `frameMagins`
are both enabled and `gd` is a plain object.
* Ensure `autosize` doesn't set values of width and height smaller than
the minimum defined in the corresponding layout attribute.
* Do not do the initial autosize if both config.autosizable and
layout.autosize are false.
* Fix bug introduced in the commit for respecting `config.autosizable`.
@n-riesco

Copy link
Copy Markdown
ContributorAuthor

While writing the tests for this PR, I noticed that config accepts the attribute autosizable. In master, this attribute is only honoured by plotPolar. Its meaning in plotPolar is:

  • if config.autosizable: false and layout.autosize: false, then no initial autosize is carried out (if needed, the default values of width and height are used);
  • if config.autosizable: true, then an initial autosize is carried out (regardless of layout.autosize).

I've updated this PR so that autosizable is always honoured.

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

The PR is ready for review again.

Comment threadsrc/plots/plots.js Outdated
factor = 1 - 2 * frameMargins;

var gdBB;
try {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think we should avoid using try-catch as much as possible - because they are very slow.

Here too, I'd vote for using Lib.isPlotDiv. But, I'm open to other (possible more strict) suggestions.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

How about?

vargdBB=fullLayout._container&&fullLayout._container.node ?
fullLayout._container.node().getBoundingClientRect() : {width: fullLayout.width,height: fullLayout.height};

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

@etpinard About autosizable, I think it should be kept in Plotly v1, and removed in Plotly v2. The reason why I think it should be removed is that I don't think autosizable should be a global setting (different plots should be able to define different values of autosizable).

For Plotly v2, I would suggest to combine autosize and autosizable into a single setting. How about something like this?

{autosize: {valType: 'enumerated',role: 'info',values: ['never','initial','always'],description: ['Determines how a layout width or height','that has been left undefined by the user','is set.','If *never*, the default values of width and height will be used.','If *initial*, an undefined layout width or height','will be initialized on the first call to plot.''If *always*, an undefined layout width or height','will be set on the first call to plot and subsequent calls to relayout.'].join(' ')}}

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

PR ready for review again.

Comment threadsrc/plots/plots.js
} catch(err) {
gdBB = {
var gdBB = fullLayout._container && fullLayout._container.node ?
fullLayout._container.node().getBoundingClientRect() : {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Good. 👍

@etpinard

Copy link
Copy Markdown
Contributor

Thanks @n-riesco . you're almost there.

As mentioned previously, this PR was set uncover a lot of un-tested code. Commits 172d81d and 862578e were no exceptions.

Would you mind a few test cases (one per commit is fine) for the two commits above? To lock their behavior until v2.0.0.

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

I've added tests for the commits you suggested and this uncovered an issue with 862578e and another with Lib.isPlotDiv. Both are now fixed and tested.

The PR is ready for review again.

@etpinard

Copy link
Copy Markdown
Contributor

Great. I tested your branch and I couldn't find any edge cases that you might have missed. 🎉

This for sure wins the PR of the week 🏆

I'll make two minor comments on the line diff (nothing major) and then it'll be time to 💃 .

Comment threadsrc/plots/layout_attributes.js Outdated
role: 'info',
// TODO: better handling of 'initial'
values: [true, false, 'initial'],
values: [false, true],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

we should change the valType to 'boolean' and remove the values field.

@etpinard
etpinard merged commit 25a8d9c into plotly:masterJun 9, 2016
@n-riesco
n-riesco deleted the remove-autosize-initial branch June 10, 2016 08:04
gd = createGraphDiv();

Plotly.plot(gd, [{ x: [1, 2, 3], y: [2, 3, 4] }], {})
Plotly.plot(gd, [{ x: [1, 2, 3], y: [2, 3, 4] }], { autosize: true })

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@n-riesco , @chriddyp and I are testing the mapbox branch (which is rebased on top of the latest master) in the plot.ly workspace at the moment and we some issues.

Looks like this PR here is backward incompatible and the line ⏫ is a symptom.

More clearly,

Plotly.plot(gd,data);

should go through the plotAutoSize routine on the initial Plotly.plot call.

I believe changing the autosize attribute dflt to true would solve this. What are your thoughts on that?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

@etpinard An alternative that would be fully backwards-compatible is that Plot.resize(gd) deletes gd.layout.width and gd.layout.height and calls Plotly.relayout(gd, { autosize: true });. I'll prepare a PR so that you can check that it'd fix the issue in the mapbox branch.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

See #629

@etpinard

Copy link
Copy Markdown
Contributor

As per-slack conversation with @n-riesco , I'm reverting this PR and will spend more time testing in plot.ly's workspace before the next minor release - to make sure we handle all edge cases in a backward-compatible way.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugsomething broken

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@n-riesco@etpinard@alexcjohnson
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Remove internal option layout.autosize='initial' (Fixes #537) by n-riesco · Pull Request #577 · plotly/plotly.js · GitHub
Skip to content

Remove internal option layout.autosize='initial' (Fixes #537) - #577

Merged
etpinard merged 26 commits into
plotly:masterfrom
n-riesco:remove-autosize-initial
Jun 9, 2016
Merged

Remove internal option layout.autosize='initial' (Fixes #537)#577
etpinard merged 26 commits into
plotly:masterfrom
n-riesco:remove-autosize-initial

Conversation

@n-riesco

Copy link
Copy Markdown
Contributor
  • Moved initial call to plotAutoSize into Plots.supplyDefaults(gd).
  • Replaced { autosize: 'initial' } with the flag
    gd._fullLayout._initialAutoSizeIsDone.
  • { autosize: false } the values of width and height undefined in
    gd.layout will be autosized only once.
  • { autosize: true } only autosizes the values of width and height
    undefined in gd.layout.

Fixes#537

* Commit 5df675a (fix demo/outside legend bug and null data autoscale
bug) introduced a guard in plotAutoSize to avoid calling layoutStyles
while autosize is set to 'initial'.
* Commit ee974d9 (autosizing in shareplots, autosize aspect ratio
restrictions and ...) removed the call to layoutStyles but forgot to
remove the guard.
* This commit removes the guard.
* Checked that all the jasmine and image tests still pass.
* Moved initial call to `plotAutoSize` into `Plots.supplyDefaults(gd)`.
* Replaced `{ autosize: 'initial' }` with the flag
`gd._fullLayout._initialAutoSizeIsDone`.
* `{ autosize: false }` the values of width and height undefined in
`gd.layout` will be autosized only once.
* `{ autosize: true }` only autosizes the values of width and height
undefined in `gd.layout`.
Fixesplotly#537
* Previous image didn't honour the width and height set in the layout.
* Added test to check `Plotly.newPlot` respects `layout.width` and
`layout.height`.
Comment threadsrc/plots/plots.js Outdated
newWidth,
newHeight;

if(typeof gd.emit === 'function') gd.emit('plotly_autosize');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

why do we need this?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

i.e. that if(typeof gd.emit === 'function')

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Otherwise I get errors in the console (perhaps some test are mocking gd with something other than a DOM element?). I will come back to you on this tomorrow.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Good call. Plots.supplyDefaults should work with plain objects.

Could we make this check more robust? I'd vote for using Lib.isPlotDiv.

Comment threadtest/jasmine/tests/plot_api_test.js Outdated

Plotly.plot(gd, data).then(function() {
Plotly.newPlot(gd, data, { height: 50 }).then(function() {
expect(gd._fullLayout.height).toBe(50);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

we should also check to svg attributes too to make sure that it updated properly.

@etpinard

etpinard commented May 30, 2016

Copy link
Copy Markdown
Contributor

@n-riesco looks like you're on the right path.

Replaced { autosize: 'initial' } with the flag gd._fullLayout._initialAutoSizeIsDone

Yep. Great idea. 👍

{ autosize: false } the values of width and height undefined in gd.layout will be autosized only once.

Hmm. Is this the current behavior? Shouldn't { autosize: false } lead to layout.width: 700 and layout.height: 400 as per their defaults?

{ autosize: true } only autosizes the values of width and height undefined in gd.layout

Great.

Unfortunately, the plotly.js auto-size routine has very poor test coverage; I'm a little concerned with merging this PR. @n-riesco could make sure that all code paths in plotAutoSize are tested under Plotly.plot and Plotly.relayout?

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

On 30/05/16 17:32, Étienne Tétreault-Pinard wrote:

@n-riescohttps://github.com/n-riesco looks like you're on the right path.
{ autosize: false } the values of width and height undefined in gd.layout will be autosized only once.

Hmm. Is this the current behavior? Shouldn't |{ autosize: false }| lead to |layout.width: 700| and |layout.height: 400| as per their defaults?

The current behaviour is that if layout.width or layout.height are undefined, then layout.autosize is set to 'initial'.
When layout.autosize is set to 'initial' (and assuming config.fillFrame is false), plotAutosize gets the layout width and height using window.getComputedStyle(gd). Only if this fails, then the default width and height values are used.

Unfortunately, the plotly.js auto-size has very poor test coverage; I'm a little concerned with the PR. @n-riescohttps://github.com/n-riesco could make sure that all code paths in |plotAutoSize| https://github.com/plotly/plotly.js/pull/577/files#diff-ad4f76ccd6044ed16514297078e13b84R783 are tested under |Plotly.plot| and |Plotly.relayout|.

OK. I'll add more tests.

@alexcjohnson

Copy link
Copy Markdown
Collaborator

@n-riesco this is great, that's definitely where the autosize code belongs.

My only question (which goes along with @etpinard 's concern about test coverage - there are tons of cases to consider) is whether there are cases we'd like autosize to coerce to true - ie if width or height is missing? For example if someone is using element size to determine plot size, but has not explicitly set autosize: true - then something outside the plot (window resize or some event on their page) causes the element size to change, I would expect a simple redraw or relayout to resize the plot too.

This then begs the question (that we probably don't need to delve into now, might be a rabbit hole, but something to keep in mind for later) of whether we actually gain anything with the initial / redraw distinction. Either I'm missing something or it used to work differently, but I don't see that plotAutoSize does anything time-consuming, so what's to stop us from always running it if there's one or more missing dimensions or if autosize is explicitly true? There will be places (relayout?) where we need to track whether anything actually changed to decide how much to do next, but we already do that anyway.

@n-riesco

n-riesco commented May 31, 2016

Copy link
Copy Markdown
ContributorAuthor

Below are the tests I'm planning to add:

  • autosize:false, fillFrame:true
  • autosize:false, fillFrame:false and frameMargins
  • autosize:false, fillFrame:false and no frameMargins
  • autosize:true, fillFrame:true
  • autosize:true, fillFrame:false and frameMargins
  • autosize:true, fillFrame:false and no frameMargins

For each test, I'll check fullLayout width and height after plot and after relayout.

These tests should cover the main execution paths in plotAutoSize.


Additional tests (from comments):

  • check SVG properties in test 'should respect layout.width and layout.height'
  • test supplyDefaults(gd) can be called with mocked gd.

@etpinard

Copy link
Copy Markdown
Contributor

@n-riesco your plans sounds good!

* Fix bug in `plotAutoSize`, triggered when `autosize` and `frameMagins`
are both enabled and `gd` is a plain object.
* Ensure `autosize` doesn't set values of width and height smaller than
the minimum defined in the corresponding layout attribute.
* Do not do the initial autosize if both config.autosizable and
layout.autosize are false.
* Fix bug introduced in the commit for respecting `config.autosizable`.
@n-riesco

Copy link
Copy Markdown
ContributorAuthor

While writing the tests for this PR, I noticed that config accepts the attribute autosizable. In master, this attribute is only honoured by plotPolar. Its meaning in plotPolar is:

  • if config.autosizable: false and layout.autosize: false, then no initial autosize is carried out (if needed, the default values of width and height are used);
  • if config.autosizable: true, then an initial autosize is carried out (regardless of layout.autosize).

I've updated this PR so that autosizable is always honoured.

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

The PR is ready for review again.

Comment threadsrc/plots/plots.js Outdated
factor = 1 - 2 * frameMargins;

var gdBB;
try {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think we should avoid using try-catch as much as possible - because they are very slow.

Here too, I'd vote for using Lib.isPlotDiv. But, I'm open to other (possible more strict) suggestions.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

How about?

vargdBB=fullLayout._container&&fullLayout._container.node ?
fullLayout._container.node().getBoundingClientRect() : {width: fullLayout.width,height: fullLayout.height};

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

@etpinard About autosizable, I think it should be kept in Plotly v1, and removed in Plotly v2. The reason why I think it should be removed is that I don't think autosizable should be a global setting (different plots should be able to define different values of autosizable).

For Plotly v2, I would suggest to combine autosize and autosizable into a single setting. How about something like this?

{autosize: {valType: 'enumerated',role: 'info',values: ['never','initial','always'],description: ['Determines how a layout width or height','that has been left undefined by the user','is set.','If *never*, the default values of width and height will be used.','If *initial*, an undefined layout width or height','will be initialized on the first call to plot.''If *always*, an undefined layout width or height','will be set on the first call to plot and subsequent calls to relayout.'].join(' ')}}

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

PR ready for review again.

Comment threadsrc/plots/plots.js
} catch(err) {
gdBB = {
var gdBB = fullLayout._container && fullLayout._container.node ?
fullLayout._container.node().getBoundingClientRect() : {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Good. 👍

@etpinard

Copy link
Copy Markdown
Contributor

Thanks @n-riesco . you're almost there.

As mentioned previously, this PR was set uncover a lot of un-tested code. Commits 172d81d and 862578e were no exceptions.

Would you mind a few test cases (one per commit is fine) for the two commits above? To lock their behavior until v2.0.0.

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

I've added tests for the commits you suggested and this uncovered an issue with 862578e and another with Lib.isPlotDiv. Both are now fixed and tested.

The PR is ready for review again.

@etpinard

Copy link
Copy Markdown
Contributor

Great. I tested your branch and I couldn't find any edge cases that you might have missed. 🎉

This for sure wins the PR of the week 🏆

I'll make two minor comments on the line diff (nothing major) and then it'll be time to 💃 .

Comment threadsrc/plots/layout_attributes.js Outdated
role: 'info',
// TODO: better handling of 'initial'
values: [true, false, 'initial'],
values: [false, true],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

we should change the valType to 'boolean' and remove the values field.

@etpinard
etpinard merged commit 25a8d9c into plotly:masterJun 9, 2016
@n-riesco
n-riesco deleted the remove-autosize-initial branch June 10, 2016 08:04
gd = createGraphDiv();

Plotly.plot(gd, [{ x: [1, 2, 3], y: [2, 3, 4] }], {})
Plotly.plot(gd, [{ x: [1, 2, 3], y: [2, 3, 4] }], { autosize: true })

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@n-riesco , @chriddyp and I are testing the mapbox branch (which is rebased on top of the latest master) in the plot.ly workspace at the moment and we some issues.

Looks like this PR here is backward incompatible and the line ⏫ is a symptom.

More clearly,

Plotly.plot(gd,data);

should go through the plotAutoSize routine on the initial Plotly.plot call.

I believe changing the autosize attribute dflt to true would solve this. What are your thoughts on that?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

@etpinard An alternative that would be fully backwards-compatible is that Plot.resize(gd) deletes gd.layout.width and gd.layout.height and calls Plotly.relayout(gd, { autosize: true });. I'll prepare a PR so that you can check that it'd fix the issue in the mapbox branch.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

See #629

@etpinard

Copy link
Copy Markdown
Contributor

As per-slack conversation with @n-riesco , I'm reverting this PR and will spend more time testing in plot.ly's workspace before the next minor release - to make sure we handle all edge cases in a backward-compatible way.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugsomething broken

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@n-riesco@etpinard@alexcjohnson
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' Remove internal option layout.autosize='initial' (Fixes #537) by n-riesco · Pull Request #577 · plotly/plotly.js · GitHub
Skip to content

Remove internal option layout.autosize='initial' (Fixes #537) - #577

Merged
etpinard merged 26 commits into
plotly:masterfrom
n-riesco:remove-autosize-initial
Jun 9, 2016
Merged

Remove internal option layout.autosize='initial' (Fixes #537)#577
etpinard merged 26 commits into
plotly:masterfrom
n-riesco:remove-autosize-initial

Conversation

@n-riesco

Copy link
Copy Markdown
Contributor
  • Moved initial call to plotAutoSize into Plots.supplyDefaults(gd).
  • Replaced { autosize: 'initial' } with the flag
    gd._fullLayout._initialAutoSizeIsDone.
  • { autosize: false } the values of width and height undefined in
    gd.layout will be autosized only once.
  • { autosize: true } only autosizes the values of width and height
    undefined in gd.layout.

Fixes#537

* Commit 5df675a (fix demo/outside legend bug and null data autoscale
bug) introduced a guard in plotAutoSize to avoid calling layoutStyles
while autosize is set to 'initial'.
* Commit ee974d9 (autosizing in shareplots, autosize aspect ratio
restrictions and ...) removed the call to layoutStyles but forgot to
remove the guard.
* This commit removes the guard.
* Checked that all the jasmine and image tests still pass.
* Moved initial call to `plotAutoSize` into `Plots.supplyDefaults(gd)`.
* Replaced `{ autosize: 'initial' }` with the flag
`gd._fullLayout._initialAutoSizeIsDone`.
* `{ autosize: false }` the values of width and height undefined in
`gd.layout` will be autosized only once.
* `{ autosize: true }` only autosizes the values of width and height
undefined in `gd.layout`.
Fixesplotly#537
* Previous image didn't honour the width and height set in the layout.
* Added test to check `Plotly.newPlot` respects `layout.width` and
`layout.height`.
Comment threadsrc/plots/plots.js Outdated
newWidth,
newHeight;

if(typeof gd.emit === 'function') gd.emit('plotly_autosize');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

why do we need this?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

i.e. that if(typeof gd.emit === 'function')

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Otherwise I get errors in the console (perhaps some test are mocking gd with something other than a DOM element?). I will come back to you on this tomorrow.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Good call. Plots.supplyDefaults should work with plain objects.

Could we make this check more robust? I'd vote for using Lib.isPlotDiv.

Comment threadtest/jasmine/tests/plot_api_test.js Outdated

Plotly.plot(gd, data).then(function() {
Plotly.newPlot(gd, data, { height: 50 }).then(function() {
expect(gd._fullLayout.height).toBe(50);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

we should also check to svg attributes too to make sure that it updated properly.

@etpinard

etpinard commented May 30, 2016

Copy link
Copy Markdown
Contributor

@n-riesco looks like you're on the right path.

Replaced { autosize: 'initial' } with the flag gd._fullLayout._initialAutoSizeIsDone

Yep. Great idea. 👍

{ autosize: false } the values of width and height undefined in gd.layout will be autosized only once.

Hmm. Is this the current behavior? Shouldn't { autosize: false } lead to layout.width: 700 and layout.height: 400 as per their defaults?

{ autosize: true } only autosizes the values of width and height undefined in gd.layout

Great.

Unfortunately, the plotly.js auto-size routine has very poor test coverage; I'm a little concerned with merging this PR. @n-riesco could make sure that all code paths in plotAutoSize are tested under Plotly.plot and Plotly.relayout?

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

On 30/05/16 17:32, Étienne Tétreault-Pinard wrote:

@n-riescohttps://github.com/n-riesco looks like you're on the right path.
{ autosize: false } the values of width and height undefined in gd.layout will be autosized only once.

Hmm. Is this the current behavior? Shouldn't |{ autosize: false }| lead to |layout.width: 700| and |layout.height: 400| as per their defaults?

The current behaviour is that if layout.width or layout.height are undefined, then layout.autosize is set to 'initial'.
When layout.autosize is set to 'initial' (and assuming config.fillFrame is false), plotAutosize gets the layout width and height using window.getComputedStyle(gd). Only if this fails, then the default width and height values are used.

Unfortunately, the plotly.js auto-size has very poor test coverage; I'm a little concerned with the PR. @n-riescohttps://github.com/n-riesco could make sure that all code paths in |plotAutoSize| https://github.com/plotly/plotly.js/pull/577/files#diff-ad4f76ccd6044ed16514297078e13b84R783 are tested under |Plotly.plot| and |Plotly.relayout|.

OK. I'll add more tests.

@alexcjohnson

Copy link
Copy Markdown
Collaborator

@n-riesco this is great, that's definitely where the autosize code belongs.

My only question (which goes along with @etpinard 's concern about test coverage - there are tons of cases to consider) is whether there are cases we'd like autosize to coerce to true - ie if width or height is missing? For example if someone is using element size to determine plot size, but has not explicitly set autosize: true - then something outside the plot (window resize or some event on their page) causes the element size to change, I would expect a simple redraw or relayout to resize the plot too.

This then begs the question (that we probably don't need to delve into now, might be a rabbit hole, but something to keep in mind for later) of whether we actually gain anything with the initial / redraw distinction. Either I'm missing something or it used to work differently, but I don't see that plotAutoSize does anything time-consuming, so what's to stop us from always running it if there's one or more missing dimensions or if autosize is explicitly true? There will be places (relayout?) where we need to track whether anything actually changed to decide how much to do next, but we already do that anyway.

@n-riesco

n-riesco commented May 31, 2016

Copy link
Copy Markdown
ContributorAuthor

Below are the tests I'm planning to add:

  • autosize:false, fillFrame:true
  • autosize:false, fillFrame:false and frameMargins
  • autosize:false, fillFrame:false and no frameMargins
  • autosize:true, fillFrame:true
  • autosize:true, fillFrame:false and frameMargins
  • autosize:true, fillFrame:false and no frameMargins

For each test, I'll check fullLayout width and height after plot and after relayout.

These tests should cover the main execution paths in plotAutoSize.


Additional tests (from comments):

  • check SVG properties in test 'should respect layout.width and layout.height'
  • test supplyDefaults(gd) can be called with mocked gd.

@etpinard

Copy link
Copy Markdown
Contributor

@n-riesco your plans sounds good!

* Fix bug in `plotAutoSize`, triggered when `autosize` and `frameMagins`
are both enabled and `gd` is a plain object.
* Ensure `autosize` doesn't set values of width and height smaller than
the minimum defined in the corresponding layout attribute.
* Do not do the initial autosize if both config.autosizable and
layout.autosize are false.
* Fix bug introduced in the commit for respecting `config.autosizable`.
@n-riesco

Copy link
Copy Markdown
ContributorAuthor

While writing the tests for this PR, I noticed that config accepts the attribute autosizable. In master, this attribute is only honoured by plotPolar. Its meaning in plotPolar is:

  • if config.autosizable: false and layout.autosize: false, then no initial autosize is carried out (if needed, the default values of width and height are used);
  • if config.autosizable: true, then an initial autosize is carried out (regardless of layout.autosize).

I've updated this PR so that autosizable is always honoured.

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

The PR is ready for review again.

Comment threadsrc/plots/plots.js Outdated
factor = 1 - 2 * frameMargins;

var gdBB;
try {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think we should avoid using try-catch as much as possible - because they are very slow.

Here too, I'd vote for using Lib.isPlotDiv. But, I'm open to other (possible more strict) suggestions.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

How about?

vargdBB=fullLayout._container&&fullLayout._container.node ?
fullLayout._container.node().getBoundingClientRect() : {width: fullLayout.width,height: fullLayout.height};

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

@etpinard About autosizable, I think it should be kept in Plotly v1, and removed in Plotly v2. The reason why I think it should be removed is that I don't think autosizable should be a global setting (different plots should be able to define different values of autosizable).

For Plotly v2, I would suggest to combine autosize and autosizable into a single setting. How about something like this?

{autosize: {valType: 'enumerated',role: 'info',values: ['never','initial','always'],description: ['Determines how a layout width or height','that has been left undefined by the user','is set.','If *never*, the default values of width and height will be used.','If *initial*, an undefined layout width or height','will be initialized on the first call to plot.''If *always*, an undefined layout width or height','will be set on the first call to plot and subsequent calls to relayout.'].join(' ')}}

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

PR ready for review again.

Comment threadsrc/plots/plots.js
} catch(err) {
gdBB = {
var gdBB = fullLayout._container && fullLayout._container.node ?
fullLayout._container.node().getBoundingClientRect() : {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Good. 👍

@etpinard

Copy link
Copy Markdown
Contributor

Thanks @n-riesco . you're almost there.

As mentioned previously, this PR was set uncover a lot of un-tested code. Commits 172d81d and 862578e were no exceptions.

Would you mind a few test cases (one per commit is fine) for the two commits above? To lock their behavior until v2.0.0.

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

I've added tests for the commits you suggested and this uncovered an issue with 862578e and another with Lib.isPlotDiv. Both are now fixed and tested.

The PR is ready for review again.

@etpinard

Copy link
Copy Markdown
Contributor

Great. I tested your branch and I couldn't find any edge cases that you might have missed. 🎉

This for sure wins the PR of the week 🏆

I'll make two minor comments on the line diff (nothing major) and then it'll be time to 💃 .

Comment threadsrc/plots/layout_attributes.js Outdated
role: 'info',
// TODO: better handling of 'initial'
values: [true, false, 'initial'],
values: [false, true],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

we should change the valType to 'boolean' and remove the values field.

@etpinard
etpinard merged commit 25a8d9c into plotly:masterJun 9, 2016
@n-riesco
n-riesco deleted the remove-autosize-initial branch June 10, 2016 08:04
gd = createGraphDiv();

Plotly.plot(gd, [{ x: [1, 2, 3], y: [2, 3, 4] }], {})
Plotly.plot(gd, [{ x: [1, 2, 3], y: [2, 3, 4] }], { autosize: true })

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@n-riesco , @chriddyp and I are testing the mapbox branch (which is rebased on top of the latest master) in the plot.ly workspace at the moment and we some issues.

Looks like this PR here is backward incompatible and the line ⏫ is a symptom.

More clearly,

Plotly.plot(gd,data);

should go through the plotAutoSize routine on the initial Plotly.plot call.

I believe changing the autosize attribute dflt to true would solve this. What are your thoughts on that?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

@etpinard An alternative that would be fully backwards-compatible is that Plot.resize(gd) deletes gd.layout.width and gd.layout.height and calls Plotly.relayout(gd, { autosize: true });. I'll prepare a PR so that you can check that it'd fix the issue in the mapbox branch.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

See #629

@etpinard

Copy link
Copy Markdown
Contributor

As per-slack conversation with @n-riesco , I'm reverting this PR and will spend more time testing in plot.ly's workspace before the next minor release - to make sure we handle all edge cases in a backward-compatible way.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugsomething broken

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@n-riesco@etpinard@alexcjohnson
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Remove internal option layout.autosize='initial' (Fixes #537) by n-riesco · Pull Request #577 · plotly/plotly.js · GitHub
Skip to content

Remove internal option layout.autosize='initial' (Fixes #537) - #577

Merged
etpinard merged 26 commits into
plotly:masterfrom
n-riesco:remove-autosize-initial
Jun 9, 2016
Merged

Remove internal option layout.autosize='initial' (Fixes #537)#577
etpinard merged 26 commits into
plotly:masterfrom
n-riesco:remove-autosize-initial

Conversation

@n-riesco

Copy link
Copy Markdown
Contributor
  • Moved initial call to plotAutoSize into Plots.supplyDefaults(gd).
  • Replaced { autosize: 'initial' } with the flag
    gd._fullLayout._initialAutoSizeIsDone.
  • { autosize: false } the values of width and height undefined in
    gd.layout will be autosized only once.
  • { autosize: true } only autosizes the values of width and height
    undefined in gd.layout.

Fixes#537

* Commit 5df675a (fix demo/outside legend bug and null data autoscale
bug) introduced a guard in plotAutoSize to avoid calling layoutStyles
while autosize is set to 'initial'.
* Commit ee974d9 (autosizing in shareplots, autosize aspect ratio
restrictions and ...) removed the call to layoutStyles but forgot to
remove the guard.
* This commit removes the guard.
* Checked that all the jasmine and image tests still pass.
* Moved initial call to `plotAutoSize` into `Plots.supplyDefaults(gd)`.
* Replaced `{ autosize: 'initial' }` with the flag
`gd._fullLayout._initialAutoSizeIsDone`.
* `{ autosize: false }` the values of width and height undefined in
`gd.layout` will be autosized only once.
* `{ autosize: true }` only autosizes the values of width and height
undefined in `gd.layout`.
Fixesplotly#537
* Previous image didn't honour the width and height set in the layout.
* Added test to check `Plotly.newPlot` respects `layout.width` and
`layout.height`.
Comment threadsrc/plots/plots.js Outdated
newWidth,
newHeight;

if(typeof gd.emit === 'function') gd.emit('plotly_autosize');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

why do we need this?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

i.e. that if(typeof gd.emit === 'function')

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Otherwise I get errors in the console (perhaps some test are mocking gd with something other than a DOM element?). I will come back to you on this tomorrow.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Good call. Plots.supplyDefaults should work with plain objects.

Could we make this check more robust? I'd vote for using Lib.isPlotDiv.

Comment threadtest/jasmine/tests/plot_api_test.js Outdated

Plotly.plot(gd, data).then(function() {
Plotly.newPlot(gd, data, { height: 50 }).then(function() {
expect(gd._fullLayout.height).toBe(50);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

we should also check to svg attributes too to make sure that it updated properly.

@etpinard

etpinard commented May 30, 2016

Copy link
Copy Markdown
Contributor

@n-riesco looks like you're on the right path.

Replaced { autosize: 'initial' } with the flag gd._fullLayout._initialAutoSizeIsDone

Yep. Great idea. 👍

{ autosize: false } the values of width and height undefined in gd.layout will be autosized only once.

Hmm. Is this the current behavior? Shouldn't { autosize: false } lead to layout.width: 700 and layout.height: 400 as per their defaults?

{ autosize: true } only autosizes the values of width and height undefined in gd.layout

Great.

Unfortunately, the plotly.js auto-size routine has very poor test coverage; I'm a little concerned with merging this PR. @n-riesco could make sure that all code paths in plotAutoSize are tested under Plotly.plot and Plotly.relayout?

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

On 30/05/16 17:32, Étienne Tétreault-Pinard wrote:

@n-riescohttps://github.com/n-riesco looks like you're on the right path.
{ autosize: false } the values of width and height undefined in gd.layout will be autosized only once.

Hmm. Is this the current behavior? Shouldn't |{ autosize: false }| lead to |layout.width: 700| and |layout.height: 400| as per their defaults?

The current behaviour is that if layout.width or layout.height are undefined, then layout.autosize is set to 'initial'.
When layout.autosize is set to 'initial' (and assuming config.fillFrame is false), plotAutosize gets the layout width and height using window.getComputedStyle(gd). Only if this fails, then the default width and height values are used.

Unfortunately, the plotly.js auto-size has very poor test coverage; I'm a little concerned with the PR. @n-riescohttps://github.com/n-riesco could make sure that all code paths in |plotAutoSize| https://github.com/plotly/plotly.js/pull/577/files#diff-ad4f76ccd6044ed16514297078e13b84R783 are tested under |Plotly.plot| and |Plotly.relayout|.

OK. I'll add more tests.

@alexcjohnson

Copy link
Copy Markdown
Collaborator

@n-riesco this is great, that's definitely where the autosize code belongs.

My only question (which goes along with @etpinard 's concern about test coverage - there are tons of cases to consider) is whether there are cases we'd like autosize to coerce to true - ie if width or height is missing? For example if someone is using element size to determine plot size, but has not explicitly set autosize: true - then something outside the plot (window resize or some event on their page) causes the element size to change, I would expect a simple redraw or relayout to resize the plot too.

This then begs the question (that we probably don't need to delve into now, might be a rabbit hole, but something to keep in mind for later) of whether we actually gain anything with the initial / redraw distinction. Either I'm missing something or it used to work differently, but I don't see that plotAutoSize does anything time-consuming, so what's to stop us from always running it if there's one or more missing dimensions or if autosize is explicitly true? There will be places (relayout?) where we need to track whether anything actually changed to decide how much to do next, but we already do that anyway.

@n-riesco

n-riesco commented May 31, 2016

Copy link
Copy Markdown
ContributorAuthor

Below are the tests I'm planning to add:

  • autosize:false, fillFrame:true
  • autosize:false, fillFrame:false and frameMargins
  • autosize:false, fillFrame:false and no frameMargins
  • autosize:true, fillFrame:true
  • autosize:true, fillFrame:false and frameMargins
  • autosize:true, fillFrame:false and no frameMargins

For each test, I'll check fullLayout width and height after plot and after relayout.

These tests should cover the main execution paths in plotAutoSize.


Additional tests (from comments):

  • check SVG properties in test 'should respect layout.width and layout.height'
  • test supplyDefaults(gd) can be called with mocked gd.

@etpinard

Copy link
Copy Markdown
Contributor

@n-riesco your plans sounds good!

* Fix bug in `plotAutoSize`, triggered when `autosize` and `frameMagins`
are both enabled and `gd` is a plain object.
* Ensure `autosize` doesn't set values of width and height smaller than
the minimum defined in the corresponding layout attribute.
* Do not do the initial autosize if both config.autosizable and
layout.autosize are false.
* Fix bug introduced in the commit for respecting `config.autosizable`.
@n-riesco

Copy link
Copy Markdown
ContributorAuthor

While writing the tests for this PR, I noticed that config accepts the attribute autosizable. In master, this attribute is only honoured by plotPolar. Its meaning in plotPolar is:

  • if config.autosizable: false and layout.autosize: false, then no initial autosize is carried out (if needed, the default values of width and height are used);
  • if config.autosizable: true, then an initial autosize is carried out (regardless of layout.autosize).

I've updated this PR so that autosizable is always honoured.

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

The PR is ready for review again.

Comment threadsrc/plots/plots.js Outdated
factor = 1 - 2 * frameMargins;

var gdBB;
try {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think we should avoid using try-catch as much as possible - because they are very slow.

Here too, I'd vote for using Lib.isPlotDiv. But, I'm open to other (possible more strict) suggestions.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

How about?

vargdBB=fullLayout._container&&fullLayout._container.node ?
fullLayout._container.node().getBoundingClientRect() : {width: fullLayout.width,height: fullLayout.height};

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

@etpinard About autosizable, I think it should be kept in Plotly v1, and removed in Plotly v2. The reason why I think it should be removed is that I don't think autosizable should be a global setting (different plots should be able to define different values of autosizable).

For Plotly v2, I would suggest to combine autosize and autosizable into a single setting. How about something like this?

{autosize: {valType: 'enumerated',role: 'info',values: ['never','initial','always'],description: ['Determines how a layout width or height','that has been left undefined by the user','is set.','If *never*, the default values of width and height will be used.','If *initial*, an undefined layout width or height','will be initialized on the first call to plot.''If *always*, an undefined layout width or height','will be set on the first call to plot and subsequent calls to relayout.'].join(' ')}}

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

PR ready for review again.

Comment threadsrc/plots/plots.js
} catch(err) {
gdBB = {
var gdBB = fullLayout._container && fullLayout._container.node ?
fullLayout._container.node().getBoundingClientRect() : {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Good. 👍

@etpinard

Copy link
Copy Markdown
Contributor

Thanks @n-riesco . you're almost there.

As mentioned previously, this PR was set uncover a lot of un-tested code. Commits 172d81d and 862578e were no exceptions.

Would you mind a few test cases (one per commit is fine) for the two commits above? To lock their behavior until v2.0.0.

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

I've added tests for the commits you suggested and this uncovered an issue with 862578e and another with Lib.isPlotDiv. Both are now fixed and tested.

The PR is ready for review again.

@etpinard

Copy link
Copy Markdown
Contributor

Great. I tested your branch and I couldn't find any edge cases that you might have missed. 🎉

This for sure wins the PR of the week 🏆

I'll make two minor comments on the line diff (nothing major) and then it'll be time to 💃 .

Comment threadsrc/plots/layout_attributes.js Outdated
role: 'info',
// TODO: better handling of 'initial'
values: [true, false, 'initial'],
values: [false, true],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

we should change the valType to 'boolean' and remove the values field.

@etpinard
etpinard merged commit 25a8d9c into plotly:masterJun 9, 2016
@n-riesco
n-riesco deleted the remove-autosize-initial branch June 10, 2016 08:04
gd = createGraphDiv();

Plotly.plot(gd, [{ x: [1, 2, 3], y: [2, 3, 4] }], {})
Plotly.plot(gd, [{ x: [1, 2, 3], y: [2, 3, 4] }], { autosize: true })

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@n-riesco , @chriddyp and I are testing the mapbox branch (which is rebased on top of the latest master) in the plot.ly workspace at the moment and we some issues.

Looks like this PR here is backward incompatible and the line ⏫ is a symptom.

More clearly,

Plotly.plot(gd,data);

should go through the plotAutoSize routine on the initial Plotly.plot call.

I believe changing the autosize attribute dflt to true would solve this. What are your thoughts on that?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

@etpinard An alternative that would be fully backwards-compatible is that Plot.resize(gd) deletes gd.layout.width and gd.layout.height and calls Plotly.relayout(gd, { autosize: true });. I'll prepare a PR so that you can check that it'd fix the issue in the mapbox branch.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

See #629

@etpinard

Copy link
Copy Markdown
Contributor

As per-slack conversation with @n-riesco , I'm reverting this PR and will spend more time testing in plot.ly's workspace before the next minor release - to make sure we handle all edge cases in a backward-compatible way.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugsomething broken

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@n-riesco@etpinard@alexcjohnson
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Remove internal option layout.autosize='initial' (Fixes #537) by n-riesco · Pull Request #577 · plotly/plotly.js · GitHub
Skip to content

Remove internal option layout.autosize='initial' (Fixes #537) - #577

Merged
etpinard merged 26 commits into
plotly:masterfrom
n-riesco:remove-autosize-initial
Jun 9, 2016
Merged

Remove internal option layout.autosize='initial' (Fixes #537)#577
etpinard merged 26 commits into
plotly:masterfrom
n-riesco:remove-autosize-initial

Conversation

@n-riesco

Copy link
Copy Markdown
Contributor
  • Moved initial call to plotAutoSize into Plots.supplyDefaults(gd).
  • Replaced { autosize: 'initial' } with the flag
    gd._fullLayout._initialAutoSizeIsDone.
  • { autosize: false } the values of width and height undefined in
    gd.layout will be autosized only once.
  • { autosize: true } only autosizes the values of width and height
    undefined in gd.layout.

Fixes#537

* Commit 5df675a (fix demo/outside legend bug and null data autoscale
bug) introduced a guard in plotAutoSize to avoid calling layoutStyles
while autosize is set to 'initial'.
* Commit ee974d9 (autosizing in shareplots, autosize aspect ratio
restrictions and ...) removed the call to layoutStyles but forgot to
remove the guard.
* This commit removes the guard.
* Checked that all the jasmine and image tests still pass.
* Moved initial call to `plotAutoSize` into `Plots.supplyDefaults(gd)`.
* Replaced `{ autosize: 'initial' }` with the flag
`gd._fullLayout._initialAutoSizeIsDone`.
* `{ autosize: false }` the values of width and height undefined in
`gd.layout` will be autosized only once.
* `{ autosize: true }` only autosizes the values of width and height
undefined in `gd.layout`.
Fixesplotly#537
* Previous image didn't honour the width and height set in the layout.
* Added test to check `Plotly.newPlot` respects `layout.width` and
`layout.height`.
Comment threadsrc/plots/plots.js Outdated
newWidth,
newHeight;

if(typeof gd.emit === 'function') gd.emit('plotly_autosize');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

why do we need this?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

i.e. that if(typeof gd.emit === 'function')

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Otherwise I get errors in the console (perhaps some test are mocking gd with something other than a DOM element?). I will come back to you on this tomorrow.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Good call. Plots.supplyDefaults should work with plain objects.

Could we make this check more robust? I'd vote for using Lib.isPlotDiv.

Comment threadtest/jasmine/tests/plot_api_test.js Outdated

Plotly.plot(gd, data).then(function() {
Plotly.newPlot(gd, data, { height: 50 }).then(function() {
expect(gd._fullLayout.height).toBe(50);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

we should also check to svg attributes too to make sure that it updated properly.

@etpinard

etpinard commented May 30, 2016

Copy link
Copy Markdown
Contributor

@n-riesco looks like you're on the right path.

Replaced { autosize: 'initial' } with the flag gd._fullLayout._initialAutoSizeIsDone

Yep. Great idea. 👍

{ autosize: false } the values of width and height undefined in gd.layout will be autosized only once.

Hmm. Is this the current behavior? Shouldn't { autosize: false } lead to layout.width: 700 and layout.height: 400 as per their defaults?

{ autosize: true } only autosizes the values of width and height undefined in gd.layout

Great.

Unfortunately, the plotly.js auto-size routine has very poor test coverage; I'm a little concerned with merging this PR. @n-riesco could make sure that all code paths in plotAutoSize are tested under Plotly.plot and Plotly.relayout?

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

On 30/05/16 17:32, Étienne Tétreault-Pinard wrote:

@n-riescohttps://github.com/n-riesco looks like you're on the right path.
{ autosize: false } the values of width and height undefined in gd.layout will be autosized only once.

Hmm. Is this the current behavior? Shouldn't |{ autosize: false }| lead to |layout.width: 700| and |layout.height: 400| as per their defaults?

The current behaviour is that if layout.width or layout.height are undefined, then layout.autosize is set to 'initial'.
When layout.autosize is set to 'initial' (and assuming config.fillFrame is false), plotAutosize gets the layout width and height using window.getComputedStyle(gd). Only if this fails, then the default width and height values are used.

Unfortunately, the plotly.js auto-size has very poor test coverage; I'm a little concerned with the PR. @n-riescohttps://github.com/n-riesco could make sure that all code paths in |plotAutoSize| https://github.com/plotly/plotly.js/pull/577/files#diff-ad4f76ccd6044ed16514297078e13b84R783 are tested under |Plotly.plot| and |Plotly.relayout|.

OK. I'll add more tests.

@alexcjohnson

Copy link
Copy Markdown
Collaborator

@n-riesco this is great, that's definitely where the autosize code belongs.

My only question (which goes along with @etpinard 's concern about test coverage - there are tons of cases to consider) is whether there are cases we'd like autosize to coerce to true - ie if width or height is missing? For example if someone is using element size to determine plot size, but has not explicitly set autosize: true - then something outside the plot (window resize or some event on their page) causes the element size to change, I would expect a simple redraw or relayout to resize the plot too.

This then begs the question (that we probably don't need to delve into now, might be a rabbit hole, but something to keep in mind for later) of whether we actually gain anything with the initial / redraw distinction. Either I'm missing something or it used to work differently, but I don't see that plotAutoSize does anything time-consuming, so what's to stop us from always running it if there's one or more missing dimensions or if autosize is explicitly true? There will be places (relayout?) where we need to track whether anything actually changed to decide how much to do next, but we already do that anyway.

@n-riesco

n-riesco commented May 31, 2016

Copy link
Copy Markdown
ContributorAuthor

Below are the tests I'm planning to add:

  • autosize:false, fillFrame:true
  • autosize:false, fillFrame:false and frameMargins
  • autosize:false, fillFrame:false and no frameMargins
  • autosize:true, fillFrame:true
  • autosize:true, fillFrame:false and frameMargins
  • autosize:true, fillFrame:false and no frameMargins

For each test, I'll check fullLayout width and height after plot and after relayout.

These tests should cover the main execution paths in plotAutoSize.


Additional tests (from comments):

  • check SVG properties in test 'should respect layout.width and layout.height'
  • test supplyDefaults(gd) can be called with mocked gd.

@etpinard

Copy link
Copy Markdown
Contributor

@n-riesco your plans sounds good!

* Fix bug in `plotAutoSize`, triggered when `autosize` and `frameMagins`
are both enabled and `gd` is a plain object.
* Ensure `autosize` doesn't set values of width and height smaller than
the minimum defined in the corresponding layout attribute.
* Do not do the initial autosize if both config.autosizable and
layout.autosize are false.
* Fix bug introduced in the commit for respecting `config.autosizable`.
@n-riesco

Copy link
Copy Markdown
ContributorAuthor

While writing the tests for this PR, I noticed that config accepts the attribute autosizable. In master, this attribute is only honoured by plotPolar. Its meaning in plotPolar is:

  • if config.autosizable: false and layout.autosize: false, then no initial autosize is carried out (if needed, the default values of width and height are used);
  • if config.autosizable: true, then an initial autosize is carried out (regardless of layout.autosize).

I've updated this PR so that autosizable is always honoured.

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

The PR is ready for review again.

Comment threadsrc/plots/plots.js Outdated
factor = 1 - 2 * frameMargins;

var gdBB;
try {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think we should avoid using try-catch as much as possible - because they are very slow.

Here too, I'd vote for using Lib.isPlotDiv. But, I'm open to other (possible more strict) suggestions.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

How about?

vargdBB=fullLayout._container&&fullLayout._container.node ?
fullLayout._container.node().getBoundingClientRect() : {width: fullLayout.width,height: fullLayout.height};

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

@etpinard About autosizable, I think it should be kept in Plotly v1, and removed in Plotly v2. The reason why I think it should be removed is that I don't think autosizable should be a global setting (different plots should be able to define different values of autosizable).

For Plotly v2, I would suggest to combine autosize and autosizable into a single setting. How about something like this?

{autosize: {valType: 'enumerated',role: 'info',values: ['never','initial','always'],description: ['Determines how a layout width or height','that has been left undefined by the user','is set.','If *never*, the default values of width and height will be used.','If *initial*, an undefined layout width or height','will be initialized on the first call to plot.''If *always*, an undefined layout width or height','will be set on the first call to plot and subsequent calls to relayout.'].join(' ')}}

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

PR ready for review again.

Comment threadsrc/plots/plots.js
} catch(err) {
gdBB = {
var gdBB = fullLayout._container && fullLayout._container.node ?
fullLayout._container.node().getBoundingClientRect() : {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Good. 👍

@etpinard

Copy link
Copy Markdown
Contributor

Thanks @n-riesco . you're almost there.

As mentioned previously, this PR was set uncover a lot of un-tested code. Commits 172d81d and 862578e were no exceptions.

Would you mind a few test cases (one per commit is fine) for the two commits above? To lock their behavior until v2.0.0.

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

I've added tests for the commits you suggested and this uncovered an issue with 862578e and another with Lib.isPlotDiv. Both are now fixed and tested.

The PR is ready for review again.

@etpinard

Copy link
Copy Markdown
Contributor

Great. I tested your branch and I couldn't find any edge cases that you might have missed. 🎉

This for sure wins the PR of the week 🏆

I'll make two minor comments on the line diff (nothing major) and then it'll be time to 💃 .

Comment threadsrc/plots/layout_attributes.js Outdated
role: 'info',
// TODO: better handling of 'initial'
values: [true, false, 'initial'],
values: [false, true],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

we should change the valType to 'boolean' and remove the values field.

@etpinard
etpinard merged commit 25a8d9c into plotly:masterJun 9, 2016
@n-riesco
n-riesco deleted the remove-autosize-initial branch June 10, 2016 08:04
gd = createGraphDiv();

Plotly.plot(gd, [{ x: [1, 2, 3], y: [2, 3, 4] }], {})
Plotly.plot(gd, [{ x: [1, 2, 3], y: [2, 3, 4] }], { autosize: true })

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@n-riesco , @chriddyp and I are testing the mapbox branch (which is rebased on top of the latest master) in the plot.ly workspace at the moment and we some issues.

Looks like this PR here is backward incompatible and the line ⏫ is a symptom.

More clearly,

Plotly.plot(gd,data);

should go through the plotAutoSize routine on the initial Plotly.plot call.

I believe changing the autosize attribute dflt to true would solve this. What are your thoughts on that?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

@etpinard An alternative that would be fully backwards-compatible is that Plot.resize(gd) deletes gd.layout.width and gd.layout.height and calls Plotly.relayout(gd, { autosize: true });. I'll prepare a PR so that you can check that it'd fix the issue in the mapbox branch.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

See #629

@etpinard

Copy link
Copy Markdown
Contributor

As per-slack conversation with @n-riesco , I'm reverting this PR and will spend more time testing in plot.ly's workspace before the next minor release - to make sure we handle all edge cases in a backward-compatible way.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugsomething broken

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@n-riesco@etpinard@alexcjohnson
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); Remove internal option layout.autosize='initial' (Fixes #537) by n-riesco · Pull Request #577 · plotly/plotly.js · GitHub
Skip to content

Remove internal option layout.autosize='initial' (Fixes #537) - #577

Merged
etpinard merged 26 commits into
plotly:masterfrom
n-riesco:remove-autosize-initial
Jun 9, 2016
Merged

Remove internal option layout.autosize='initial' (Fixes #537)#577
etpinard merged 26 commits into
plotly:masterfrom
n-riesco:remove-autosize-initial

Conversation

@n-riesco

Copy link
Copy Markdown
Contributor
  • Moved initial call to plotAutoSize into Plots.supplyDefaults(gd).
  • Replaced { autosize: 'initial' } with the flag
    gd._fullLayout._initialAutoSizeIsDone.
  • { autosize: false } the values of width and height undefined in
    gd.layout will be autosized only once.
  • { autosize: true } only autosizes the values of width and height
    undefined in gd.layout.

Fixes#537

* Commit 5df675a (fix demo/outside legend bug and null data autoscale
bug) introduced a guard in plotAutoSize to avoid calling layoutStyles
while autosize is set to 'initial'.
* Commit ee974d9 (autosizing in shareplots, autosize aspect ratio
restrictions and ...) removed the call to layoutStyles but forgot to
remove the guard.
* This commit removes the guard.
* Checked that all the jasmine and image tests still pass.
* Moved initial call to `plotAutoSize` into `Plots.supplyDefaults(gd)`.
* Replaced `{ autosize: 'initial' }` with the flag
`gd._fullLayout._initialAutoSizeIsDone`.
* `{ autosize: false }` the values of width and height undefined in
`gd.layout` will be autosized only once.
* `{ autosize: true }` only autosizes the values of width and height
undefined in `gd.layout`.
Fixesplotly#537
* Previous image didn't honour the width and height set in the layout.
* Added test to check `Plotly.newPlot` respects `layout.width` and
`layout.height`.
Comment threadsrc/plots/plots.js Outdated
newWidth,
newHeight;

if(typeof gd.emit === 'function') gd.emit('plotly_autosize');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

why do we need this?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

i.e. that if(typeof gd.emit === 'function')

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Otherwise I get errors in the console (perhaps some test are mocking gd with something other than a DOM element?). I will come back to you on this tomorrow.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Good call. Plots.supplyDefaults should work with plain objects.

Could we make this check more robust? I'd vote for using Lib.isPlotDiv.

Comment threadtest/jasmine/tests/plot_api_test.js Outdated

Plotly.plot(gd, data).then(function() {
Plotly.newPlot(gd, data, { height: 50 }).then(function() {
expect(gd._fullLayout.height).toBe(50);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

we should also check to svg attributes too to make sure that it updated properly.

@etpinard

etpinard commented May 30, 2016

Copy link
Copy Markdown
Contributor

@n-riesco looks like you're on the right path.

Replaced { autosize: 'initial' } with the flag gd._fullLayout._initialAutoSizeIsDone

Yep. Great idea. 👍

{ autosize: false } the values of width and height undefined in gd.layout will be autosized only once.

Hmm. Is this the current behavior? Shouldn't { autosize: false } lead to layout.width: 700 and layout.height: 400 as per their defaults?

{ autosize: true } only autosizes the values of width and height undefined in gd.layout

Great.

Unfortunately, the plotly.js auto-size routine has very poor test coverage; I'm a little concerned with merging this PR. @n-riesco could make sure that all code paths in plotAutoSize are tested under Plotly.plot and Plotly.relayout?

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

On 30/05/16 17:32, Étienne Tétreault-Pinard wrote:

@n-riescohttps://github.com/n-riesco looks like you're on the right path.
{ autosize: false } the values of width and height undefined in gd.layout will be autosized only once.

Hmm. Is this the current behavior? Shouldn't |{ autosize: false }| lead to |layout.width: 700| and |layout.height: 400| as per their defaults?

The current behaviour is that if layout.width or layout.height are undefined, then layout.autosize is set to 'initial'.
When layout.autosize is set to 'initial' (and assuming config.fillFrame is false), plotAutosize gets the layout width and height using window.getComputedStyle(gd). Only if this fails, then the default width and height values are used.

Unfortunately, the plotly.js auto-size has very poor test coverage; I'm a little concerned with the PR. @n-riescohttps://github.com/n-riesco could make sure that all code paths in |plotAutoSize| https://github.com/plotly/plotly.js/pull/577/files#diff-ad4f76ccd6044ed16514297078e13b84R783 are tested under |Plotly.plot| and |Plotly.relayout|.

OK. I'll add more tests.

@alexcjohnson

Copy link
Copy Markdown
Collaborator

@n-riesco this is great, that's definitely where the autosize code belongs.

My only question (which goes along with @etpinard 's concern about test coverage - there are tons of cases to consider) is whether there are cases we'd like autosize to coerce to true - ie if width or height is missing? For example if someone is using element size to determine plot size, but has not explicitly set autosize: true - then something outside the plot (window resize or some event on their page) causes the element size to change, I would expect a simple redraw or relayout to resize the plot too.

This then begs the question (that we probably don't need to delve into now, might be a rabbit hole, but something to keep in mind for later) of whether we actually gain anything with the initial / redraw distinction. Either I'm missing something or it used to work differently, but I don't see that plotAutoSize does anything time-consuming, so what's to stop us from always running it if there's one or more missing dimensions or if autosize is explicitly true? There will be places (relayout?) where we need to track whether anything actually changed to decide how much to do next, but we already do that anyway.

@n-riesco

n-riesco commented May 31, 2016

Copy link
Copy Markdown
ContributorAuthor

Below are the tests I'm planning to add:

  • autosize:false, fillFrame:true
  • autosize:false, fillFrame:false and frameMargins
  • autosize:false, fillFrame:false and no frameMargins
  • autosize:true, fillFrame:true
  • autosize:true, fillFrame:false and frameMargins
  • autosize:true, fillFrame:false and no frameMargins

For each test, I'll check fullLayout width and height after plot and after relayout.

These tests should cover the main execution paths in plotAutoSize.


Additional tests (from comments):

  • check SVG properties in test 'should respect layout.width and layout.height'
  • test supplyDefaults(gd) can be called with mocked gd.

@etpinard

Copy link
Copy Markdown
Contributor

@n-riesco your plans sounds good!

* Fix bug in `plotAutoSize`, triggered when `autosize` and `frameMagins`
are both enabled and `gd` is a plain object.
* Ensure `autosize` doesn't set values of width and height smaller than
the minimum defined in the corresponding layout attribute.
* Do not do the initial autosize if both config.autosizable and
layout.autosize are false.
* Fix bug introduced in the commit for respecting `config.autosizable`.
@n-riesco

Copy link
Copy Markdown
ContributorAuthor

While writing the tests for this PR, I noticed that config accepts the attribute autosizable. In master, this attribute is only honoured by plotPolar. Its meaning in plotPolar is:

  • if config.autosizable: false and layout.autosize: false, then no initial autosize is carried out (if needed, the default values of width and height are used);
  • if config.autosizable: true, then an initial autosize is carried out (regardless of layout.autosize).

I've updated this PR so that autosizable is always honoured.

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

The PR is ready for review again.

Comment threadsrc/plots/plots.js Outdated
factor = 1 - 2 * frameMargins;

var gdBB;
try {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think we should avoid using try-catch as much as possible - because they are very slow.

Here too, I'd vote for using Lib.isPlotDiv. But, I'm open to other (possible more strict) suggestions.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

How about?

vargdBB=fullLayout._container&&fullLayout._container.node ?
fullLayout._container.node().getBoundingClientRect() : {width: fullLayout.width,height: fullLayout.height};

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

@etpinard About autosizable, I think it should be kept in Plotly v1, and removed in Plotly v2. The reason why I think it should be removed is that I don't think autosizable should be a global setting (different plots should be able to define different values of autosizable).

For Plotly v2, I would suggest to combine autosize and autosizable into a single setting. How about something like this?

{autosize: {valType: 'enumerated',role: 'info',values: ['never','initial','always'],description: ['Determines how a layout width or height','that has been left undefined by the user','is set.','If *never*, the default values of width and height will be used.','If *initial*, an undefined layout width or height','will be initialized on the first call to plot.''If *always*, an undefined layout width or height','will be set on the first call to plot and subsequent calls to relayout.'].join(' ')}}

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

PR ready for review again.

Comment threadsrc/plots/plots.js
} catch(err) {
gdBB = {
var gdBB = fullLayout._container && fullLayout._container.node ?
fullLayout._container.node().getBoundingClientRect() : {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Good. 👍

@etpinard

Copy link
Copy Markdown
Contributor

Thanks @n-riesco . you're almost there.

As mentioned previously, this PR was set uncover a lot of un-tested code. Commits 172d81d and 862578e were no exceptions.

Would you mind a few test cases (one per commit is fine) for the two commits above? To lock their behavior until v2.0.0.

@n-riesco

Copy link
Copy Markdown
ContributorAuthor

I've added tests for the commits you suggested and this uncovered an issue with 862578e and another with Lib.isPlotDiv. Both are now fixed and tested.

The PR is ready for review again.

@etpinard

Copy link
Copy Markdown
Contributor

Great. I tested your branch and I couldn't find any edge cases that you might have missed. 🎉

This for sure wins the PR of the week 🏆

I'll make two minor comments on the line diff (nothing major) and then it'll be time to 💃 .

Comment threadsrc/plots/layout_attributes.js Outdated
role: 'info',
// TODO: better handling of 'initial'
values: [true, false, 'initial'],
values: [false, true],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

we should change the valType to 'boolean' and remove the values field.

@etpinard
etpinard merged commit 25a8d9c into plotly:masterJun 9, 2016
@n-riesco
n-riesco deleted the remove-autosize-initial branch June 10, 2016 08:04
gd = createGraphDiv();

Plotly.plot(gd, [{ x: [1, 2, 3], y: [2, 3, 4] }], {})
Plotly.plot(gd, [{ x: [1, 2, 3], y: [2, 3, 4] }], { autosize: true })

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@n-riesco , @chriddyp and I are testing the mapbox branch (which is rebased on top of the latest master) in the plot.ly workspace at the moment and we some issues.

Looks like this PR here is backward incompatible and the line ⏫ is a symptom.

More clearly,

Plotly.plot(gd,data);

should go through the plotAutoSize routine on the initial Plotly.plot call.

I believe changing the autosize attribute dflt to true would solve this. What are your thoughts on that?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

@etpinard An alternative that would be fully backwards-compatible is that Plot.resize(gd) deletes gd.layout.width and gd.layout.height and calls Plotly.relayout(gd, { autosize: true });. I'll prepare a PR so that you can check that it'd fix the issue in the mapbox branch.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

See #629

@etpinard

Copy link
Copy Markdown
Contributor

As per-slack conversation with @n-riesco , I'm reverting this PR and will spend more time testing in plot.ly's workspace before the next minor release - to make sure we handle all edge cases in a backward-compatible way.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugsomething broken

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@n-riesco@etpinard@alexcjohnson