-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
[WIP] Transforms [rebase of timelyportfolio's work] #936
Changes from 25 commits
9bb2b10
582d210
d0ef359
9574f4f
77e2b27
aa1f1d3
6015768
6daeac5
3e0f209
d735b64
a820b0c
2dd3646
c30f94e
e9bde33
c6355e8
5765f66
02742e8
b23d2ff
55f9e0c
462b2f0
9cafe1e
87de31f
61f3385
57d0c13
7085729
392844d
1dd93bb
1ea2fd7
59b741d
a5dad2a
79dcbc3
aa70e4c
523f61b
4efe6a9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
/** | ||
* Copyright 2012-2016, Plotly, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
module.exports = require('../src/transforms/filter'); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
/** | ||
* Copyright 2012-2016, Plotly, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
|
||
'use strict'; | ||
|
||
// returns true for a valid value object and false for tree nodes in the attribute hierarchy | ||
module.exports = function(obj) { | ||
return obj && obj.valType !== undefined; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
/** | ||
* Copyright 2012-2016, Plotly, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
|
||
'use strict'; | ||
|
||
var Lib = require('../lib'); | ||
|
||
var crawler = module.exports = {}; | ||
|
||
crawler.IS_SUBPLOT_OBJ = '_isSubplotObj'; | ||
crawler.IS_LINKED_TO_ARRAY = '_isLinkedToArray'; | ||
crawler.DEPRECATED = '_deprecated'; | ||
|
||
// list of underscore attributes to keep in schema as is | ||
crawler.UNDERSCORE_ATTRS = [crawler.IS_SUBPLOT_OBJ, crawler.IS_LINKED_TO_ARRAY, crawler.DEPRECATED]; | ||
|
||
crawler.crawl = function(attrs, callback, specifiedLevel) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here, I'd put this in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @etpinard same question here, how would it best fit, as a separate export or ... pls specify? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similarly here:
|
||
var level = specifiedLevel || 0; | ||
Object.keys(attrs).forEach(function(attrName) { | ||
var attr = attrs[attrName]; | ||
|
||
if(crawler.UNDERSCORE_ATTRS.indexOf(attrName) !== -1) return; | ||
|
||
callback(attr, attrName, attrs, level); | ||
|
||
if(Lib.isValObject(attr)) return; | ||
if(Lib.isPlainObject(attr)) crawler.crawl(attr, callback, level + 1); | ||
}); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,7 @@ | |
|
||
'use strict'; | ||
|
||
var crawler = require('./../plot_api/crawler'); | ||
var d3 = require('d3'); | ||
var isNumeric = require('fast-isnumeric'); | ||
|
||
|
@@ -786,6 +787,27 @@ function applyTransforms(fullTrace, fullData, layout) { | |
var container = fullTrace.transforms, | ||
dataOut = [fullTrace]; | ||
|
||
var attributeSets = dataOut.map(function(trace) { | ||
|
||
var arraySplitAttributes = []; | ||
|
||
var stack = []; | ||
|
||
function callback(attr, attrName, attrs, level) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Interesting! Thanks for the docs. This might be applicable in a few situations. |
||
|
||
stack = stack.slice(0, level).concat([attrName]); | ||
|
||
var splittableAttr = attr.valType === 'data_array' || attr.arrayOk === true; | ||
if(splittableAttr) { | ||
arraySplitAttributes.push(stack.slice()); | ||
} | ||
} | ||
|
||
crawler.crawl(trace._module.attributes, callback); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is the crawler able to catch nested attributes like If not, it's not a big deal. I'm not a big fan of the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know offhand, if it's not a big deal either way, I'll take a quick look and either cover it or reify it with a test case. |
||
|
||
return arraySplitAttributes; | ||
}); | ||
|
||
for(var i = 0; i < container.length; i++) { | ||
var transform = container[i], | ||
type = transform.type, | ||
|
@@ -796,6 +818,7 @@ function applyTransforms(fullTrace, fullData, layout) { | |
transform: transform, | ||
fullTrace: fullTrace, | ||
fullData: fullData, | ||
attributeSets: attributeSets, | ||
layout: layout | ||
}); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,20 @@ | ||
/** | ||
* Copyright 2012-2016, Plotly, Inc. | ||
* All rights reserved. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
*/ | ||
|
||
'use strict'; | ||
|
||
var isNumeric = require('fast-isnumeric'); | ||
|
||
// var Lib = require('@src/lib'); | ||
var Lib = require('../../../../src/lib'); | ||
var Lib = require('../lib'); | ||
|
||
/* eslint no-unused-vars: 0*/ | ||
|
||
|
||
// so that Plotly.register knows what to do with it | ||
exports.moduleType = 'transform'; | ||
|
||
|
@@ -16,17 +25,21 @@ exports.name = 'filter'; | |
exports.attributes = { | ||
operation: { | ||
valType: 'enumerated', | ||
values: ['=', '<', '>'], | ||
values: ['=', '<', '>', 'within', 'notwithin', 'in', 'notin'], | ||
dflt: '=' | ||
}, | ||
value: { | ||
valType: 'number', | ||
valType: 'any', | ||
dflt: 0 | ||
}, | ||
filtersrc: { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we add There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you mean There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you, yes. I was looking at the wrong branch. |
||
valType: 'enumerated', | ||
values: ['x', 'y'], | ||
dflt: 'x' | ||
dflt: 'x', | ||
ids: { | ||
valType: 'data_array', | ||
description: 'A list of keys for object constancy of data points during animation' | ||
} | ||
} | ||
}; | ||
|
||
|
@@ -54,6 +67,16 @@ exports.supplyDefaults = function(transformIn, fullData, layout) { | |
coerce('value'); | ||
coerce('filtersrc'); | ||
|
||
// numeric values as character should be converted to numeric | ||
if(Array.isArray(transformOut.value)) { | ||
transformOut.value = transformOut.value.map(function(v) { | ||
if(isNumeric(v)) v = +v; | ||
return v; | ||
}); | ||
} else { | ||
if(isNumeric(transformOut.value)) transformOut.value = +transformOut.value; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would prefer moving the array item type conversion down to the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FYI I haven't touched anything in |
||
} | ||
|
||
// or some more complex logic using fullData and layout | ||
|
||
return transformOut; | ||
|
@@ -121,6 +144,16 @@ function transformOne(trace, state) { | |
|
||
function getFilterFunc(opts) { | ||
var value = opts.value; | ||
// if value is not array then coerce to | ||
// an array of [value,value] so the | ||
// filter function will work | ||
// but perhaps should just error out | ||
var valueArr = []; | ||
if(!Array.isArray(value)) { | ||
valueArr = [value, value]; | ||
} else { | ||
valueArr = value; | ||
} | ||
|
||
switch(opts.operation) { | ||
case '=': | ||
|
@@ -129,6 +162,30 @@ function getFilterFunc(opts) { | |
return function(v) { return v < value; }; | ||
case '>': | ||
return function(v) { return v > value; }; | ||
case 'within': | ||
return function(v) { | ||
// if character then ignore with no side effect | ||
function notDateNumber(d) { | ||
return !(isNumeric(d) || Lib.isDateTime(d)); | ||
} | ||
if(valueArr.some(notDateNumber)) { | ||
return true; | ||
} | ||
|
||
// keep the = ? | ||
return v >= Math.min.apply(null, valueArr) && | ||
v <= Math.max.apply(null, valueArr); | ||
}; | ||
case 'notwithin': | ||
return function(v) { | ||
// keep the = ? | ||
return !(v >= Math.min.apply(null, valueArr) && | ||
v <= Math.max.apply(null, valueArr)); | ||
}; | ||
case 'in': | ||
return function(v) { return valueArr.indexOf(v) >= 0; }; | ||
case 'notin': | ||
return function(v) { return valueArr.indexOf(v) === -1; }; | ||
} | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice job, looking over circular dependencies.
I think this function would make more sense in the
src/lib/coerce.js
module. Thoughts?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes,
coerce.js
looks like the best home for it.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@etpinard Where do you specifically want to see it in
coerce.js
? Totally separate export (exports.isValObject
), or as an element insideexports.valObject
, e.g.object: {...}
in which case the actual function is incoerceFunction
, or something else?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be
exports.isValObject
incoerce.js
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I moved it to
coerce.js
and similarly to how othercoerce
constituents are handled, I directly reexport asLib.isValObject
. If it's desirable, I can phase outPlotSchema.isValObject
in favor ofLib.isValObject
, what do you think?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not yet as
Plotly.PlotSchema.isValObject
is currently exposed publicly.