Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Templates #2761

Merged
merged 24 commits into from Jul 3, 2018
Merged

Templates #2761

merged 24 commits into from Jul 3, 2018

Conversation

alexcjohnson
Copy link
Contributor

@alexcjohnson alexcjohnson commented Jun 27, 2018

For #2469

The first 6 commits - up through 3dee25c - are essentially prep work, mostly standardizing and simplifying our handling of container arrays.

Then there's one large commit 5cca8d3 that implements the coerce-level templating that I settled on, after first trying to merge templates into data and layout directly at the beginning of supplyDefaults, which failed for a variety of reasons.

After that are a bunch of cleanup commits, like 8e2a321 making array objects (which may not exist in layout if they came from named template items) work with GUI editing.

TODO:

  • Jasmine tests - the committed ones right now are still just the skeleton from @bpostlethwaite's initial work and don't actually apply.
  • Checking if the template is compatible with the plot it was applied to. This is a bit ill-defined, but I guess means mostly do all the trace types and layout containers fit what's in the template.

@etpinard anything here look problematic to you?

@etpinard
Copy link
Contributor

cc @nicolaskruchten this is happening 🎉

@etpinard etpinard added this to the v1.39.0 milestone Jun 27, 2018
Copy link
Contributor

@etpinard etpinard left a comment

Choose a reason for hiding this comment

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

I like the way this looks so far.

The coerce-level template logic appears pretty robust 💪

@@ -513,6 +513,16 @@ module.exports = {
tickformatstops: {
_isLinkedToArray: 'tickformatstop',

visible: {
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe enabled (similar to transforms) here would make more sense.

Copy link
Contributor

Choose a reason for hiding this comment

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

.... but maybe it isn't worth breaking symmetric with all other templated arrays 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right, enabled certainly makes more sense here. I thought about that but deferred to symmetry at the time. But the way this ended up working out, it would be easy to make visibilityAttr: 'enabled' or something an option to handleArrayContainerDefaults. I'll give that a try.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

switched to enabled in fb489aa

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm glad this wasn't too hard to implement 🎉

})
.then(function() {
expect(getLayerLength(gd)).toEqual(2);
expect(countVisibleLayers(gd)).toEqual(2);
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice tests. Thanks!

@@ -10,6 +10,12 @@


module.exports = {
visible: {
Copy link
Contributor

Choose a reason for hiding this comment

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

Brilliant commit ✨

* @param {string} dataAttr: the attribute of each dimension containing the data
* @param {integer} len: an already-existing length from other attributes
*/
module.exports = function(traceOut, dimensions, dataAttr, len) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Nicely done 🥇

var handleArrayContainerDefaults = require('../../plots/array_container_defaults');
var handleAnnotationDefaults = require('./annotation_defaults');
Copy link
Contributor

Choose a reason for hiding this comment

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

YES. Thanks for doing this 💯

// Note: does not need template propagation, since coerceAxis is still
// based on the subplot-wide coerce function. Though it may be more
// efficient to make a new coerce function, then we *would* need to
// propagate the template.
Copy link
Contributor

Choose a reason for hiding this comment

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

thanks for the note 📚

@@ -34,7 +34,6 @@ var Template = require('../plot_api/plot_template');
* - parentObj {object} (as in closure)
* - opts {object} (as in closure)
* - itemOpts {object}
* - itemIsNotPlainObject {boolean}
Copy link
Contributor

Choose a reason for hiding this comment

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

Nice cleanup!

@@ -12,7 +12,56 @@
var Lib = require('../lib');
var plotAttributes = require('../plots/attributes');

var TEMPLATEITEMNAME = exports.TEMPLATEITEMNAME = 'templateitemname';
var TEMPLATEITEMNAME = 'templateitemname';
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm usually not a fan of three-word attribute names, but I can't really think of a better alternative, so 👍

// value back to the input - so it doesn't make sense to template this.
// TODO: should we prohibit this in `coerce` as well, or honor it if
// someone enters it explicitly?
_noTemplating: true,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I prevented makeTemplate from pulling out axis.type with this flag, as it seems more likely to cause problems than fix them, but I did NOT prevent coerce from using it if someone makes a template of manually and includes it (to say "always make this axis categorical" for example). Seem reasonable?

Copy link
Contributor

Choose a reason for hiding this comment

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

Seem reasonable?

Very reasonable 👌

@@ -397,6 +397,8 @@ function isInSchema(schema, key) {
}

function getNestedSchema(schema, key) {
if(key in schema) return schema[key];

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not part of templating, just noticed it as there's similar logic in templates and I was looking to see how you handled it here 🙈

@@ -18,7 +18,7 @@
"yaxis2":{"title":"category","range":[0,1],"domain":[0.6,1],"anchor":"x2","type":"category","showgrid":false,"zeroline":false,"showticklabels":false},
"height":400,
"width":800,
"margin": {"l":20,"r":20,"top":10,"bottom":10,"pad":0},
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I didn't want to change the image so just deleted these bad attrs uncovered when testing this fix.

Perhaps we should make a test that validates all our mocks, to ensure we're not accidentally encouraging mistaken usage like this? Not in this PR of course...

Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps we should make a test that validates all our mocks, to ensure we're not accidentally encouraging mistaken usage like this?

That's a great idea 👍

@@ -203,6 +203,8 @@ exports.arrayTemplater = function(container, name, inclusionAttr) {
// it's explicitly marked visible - in which case it gets NO template,
// not even the default.
out[inclusionAttr] = itemIn[inclusionAttr] || false;
// special falsy value we can look for in validateTemplate
out._template = false;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This case is just special because we were told to look for a template by name and it wasn't found.

Otherwise _template can be null (no template was found but that's fine) or undefined (we don't need to propagate the template into this container).

@alexcjohnson alexcjohnson changed the title [WIP] Templates Templates Jul 3, 2018
@@ -38,7 +38,7 @@ var isArrayOrTypedArray = Lib.isArrayOrTypedArray;
* - {string} msg
* error message (shown in console in logger config argument is enable)
*/
module.exports = function valiate(data, layout) {
module.exports = function validate(data, layout) {
Copy link
Contributor

Choose a reason for hiding this comment

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

good 👁️

else {
// TODO: any need to look deeper than the first level of layout?
// I don't think so, that gets all the subplot types which should be
// sufficient.
Copy link
Contributor

Choose a reason for hiding this comment

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

What about xaxis.rangeslider.yaxis2 from #2364?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm, good point. You're right, though it's a lot of complication (for example for xaxis.rangeslider.yaxis we'd have to look for xaxis<N>.rangeslider.yaxis<M> for any combination of <N> and <M> and only generate an error if we don't find any of them. And the only time this would alert you that the template isn't appropriate is if the template has a xaxis<N>.rangeslider.yaxis<M> but does NOT have yaxis<M> - ie your template had opinions about how that y axis should work inside the rangeslider, but left the y axis itself untouched. This is of course possible, just seems very unlikely.

Copy link
Contributor

Choose a reason for hiding this comment

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

This is of course possible, just seems very unlikely.

Right. I don't this needs special handling. A comment about this would suffice.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

actually wasn't all that hard - recursed into layout in 15931cf

* to test. If omitted, we will look for a template already attached as the
* plot's `layout.template` attribute.
*
* @returns {array} array of error objects each containing:
Copy link
Contributor

@etpinard etpinard Jul 3, 2018

Choose a reason for hiding this comment

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

THanks for making this have a similar API as Plotly.validate !

Copy link
Contributor Author

Choose a reason for hiding this comment

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

One difference is I didn't make the object fields consistent - they all have code but each error, in fact even more specific than each code, includes whatever extra data it deems relevant. Given the nature of the issues (some apply to a specific trace, some to a path, some to a trace type but not a specific trace, etc... as opposed to Plotly.validate where you can basically always trace the issue back to a specific path) it seemed a bit to constraining to give them all the same fields.

// value back to the input - so it doesn't make sense to template this.
// Note: we do NOT prohibit this in `coerce`, so if someone enters a
// type in the template explicitly it will be honored as the default.
_noTemplating: true,
Copy link
Contributor

Choose a reason for hiding this comment

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

polar.angularaxis.type does not inherit from type in cartesian/layout_attributes.js. Should it also have _noTemplating: true?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good call - angularaxis.type gets _noTemplating in b1c6f0a

1);
});

it('catches missing template.data', function() {
Copy link
Contributor

Choose a reason for hiding this comment

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

🐄 catches missing template.layout.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

good catch! 818cac9

@etpinard
Copy link
Contributor

etpinard commented Jul 3, 2018

Fantastic. 💃

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants