-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Filter and groupby transforms in main bundle #978
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
Changes from 1 commit
6309837
96bcbfc
06c805d
f6eb2f4
0158f45
64dc72a
1238236
0e1e9a7
f722c5d
037fa5c
01f8595
8a29a89
ad5089e
7a98f15
c8a13b8
f4b9dcc
104123e
ba9b933
7fc7dfa
7cfa4ff
3e74c80
2a7738e
0aa4958
ad77818
4cd9edf
f5c64d2
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 |
---|---|---|
|
@@ -11,6 +11,10 @@ | |
var Lib = require('../lib'); | ||
var axisIds = require('../plots/cartesian/axis_ids'); | ||
|
||
var INEQUALITY_OPS = ['=', '<', '>=', '>', '<=']; | ||
var INTERVAL_OPS = ['[]', '()', '[)', '(]', '][', ')(', '](', ')[']; | ||
var SET_OPS = ['{}', '}{']; | ||
|
||
exports.moduleType = 'transform'; | ||
|
||
exports.name = 'filter'; | ||
|
@@ -33,10 +37,31 @@ exports.attributes = { | |
}, | ||
operation: { | ||
valType: 'enumerated', | ||
values: ['=', '<', '>', 'within', 'notwithin', 'in', 'notin'], | ||
values: [].concat(INEQUALITY_OPS).concat(INTERVAL_OPS).concat(SET_OPS), | ||
dflt: '=', | ||
description: [ | ||
'Sets the filter operation.' | ||
'Sets the filter operation.', | ||
|
||
'*=* filters items equal to `value`', | ||
|
||
'*<* filters items less than `value`', | ||
'*<=* filters items less than or equal to `value`', | ||
|
||
'*>* filters items greater than `value`', | ||
'*>=* filters items greater than or equal to `value`', | ||
|
||
'*[]* filters items inside `value[0]` to value[1]` including both bounds`', | ||
'*()* filters items inside `value[0]` to value[1]` excluding both bounds`', | ||
'*[)* filters items inside `value[0]` to value[1]` including `value[0]` but excluding `value[1]', | ||
'*(]* filters items inside `value[0]` to value[1]` including both bounds`', | ||
|
||
'*][* filters items outside `value[0]` to value[1]` and not equal to both bounds`', | ||
'*)(* filters items outside `value[0]` to value[1]`', | ||
'*](* filters items outside `value[0]` to value[1]` and not equal to `value[0]`', | ||
'*)[* filters items outside `value[0]` to value[1]` and not equal to `value[1]`', | ||
|
||
'*{}* filters items present in a set of values', | ||
'*}{* filters items not present in a set of values' | ||
].join(' ') | ||
}, | ||
value: { | ||
|
@@ -51,19 +76,6 @@ exports.attributes = { | |
'is the lower bound and the second item is the upper bound.', | ||
'When `operation`, is set to *in*, *notin* ' | ||
].join(' ') | ||
}, | ||
strictinterval: { | ||
valType: 'boolean', | ||
dflt: true, | ||
arrayOk: true, | ||
description: [ | ||
'Determines whether or not the filter operation includes data item value,', | ||
'equal to *value*.', | ||
'Has only an effect for `operation` *>*, *<*, *within* and *notwithin*', | ||
'When `operation` is set to *within* and *notwithin*,', | ||
'`strictinterval` is expected to be a 2-item array where the first (second)', | ||
'item determines strictness for the lower (second) bound.' | ||
].join(' ') | ||
} | ||
}; | ||
|
||
|
@@ -77,14 +89,9 @@ exports.supplyDefaults = function(transformIn) { | |
var enabled = coerce('enabled'); | ||
|
||
if(enabled) { | ||
var operation = coerce('operation'); | ||
|
||
coerce('operation'); | ||
coerce('value'); | ||
coerce('filtersrc'); | ||
|
||
if(['=', 'in', 'notin'].indexOf(operation) === -1) { | ||
coerce('strictinterval'); | ||
} | ||
} | ||
|
||
return transformOut; | ||
|
@@ -154,33 +161,23 @@ function getDataToCoordFunc(gd, filtersrc) { | |
function getFilterFunc(opts, d2c) { | ||
var operation = opts.operation, | ||
value = opts.value, | ||
hasArrayValue = Array.isArray(value), | ||
strict = opts.strictinterval, | ||
hasArrayStrict = Array.isArray(strict); | ||
hasArrayValue = Array.isArray(value); | ||
|
||
function isOperationIn(array) { | ||
return array.indexOf(operation) !== -1; | ||
} | ||
|
||
var coercedValue, coercedStrict; | ||
var coercedValue; | ||
|
||
if(isOperationIn(['=', '<', '>'])) { | ||
if(isOperationIn(INEQUALITY_OPS)) { | ||
coercedValue = hasArrayValue ? d2c(value[0]) : d2c(value); | ||
|
||
if(isOperationIn(['<', '>'])) { | ||
coercedStrict = hasArrayStrict ? strict[0] : strict; | ||
} | ||
} | ||
else if(isOperationIn(['within', 'notwithin'])) { | ||
else if(isOperationIn(INTERVAL_OPS)) { | ||
coercedValue = hasArrayValue ? | ||
[d2c(value[0]), d2c(value[1])] : | ||
[d2c(value), d2c(value)]; | ||
|
||
coercedStrict = hasArrayStrict ? | ||
[strict[0], strict[1]] : | ||
[strict, strict]; | ||
} | ||
else if(isOperationIn(['in', 'notin'])) { | ||
else if(isOperationIn(SET_OPS)) { | ||
coercedValue = hasArrayValue ? value.map(d2c) : [d2c(value)]; | ||
} | ||
|
||
|
@@ -190,85 +187,71 @@ function getFilterFunc(opts, d2c) { | |
return function(v) { return d2c(v) === coercedValue; }; | ||
|
||
case '<': | ||
if(coercedStrict) { | ||
return function(v) { return d2c(v) < coercedValue; }; | ||
} | ||
else { | ||
return function(v) { return d2c(v) <= coercedValue; }; | ||
} | ||
return function(v) { return d2c(v) < coercedValue; }; | ||
|
||
case '<=': | ||
return function(v) { return d2c(v) <= coercedValue; }; | ||
|
||
case '>': | ||
if(coercedStrict) { | ||
return function(v) { return d2c(v) > coercedValue; }; | ||
} | ||
else { | ||
return function(v) { return d2c(v) >= coercedValue; }; | ||
} | ||
|
||
case 'within': | ||
|
||
if(coercedStrict[0] && coercedStrict[1]) { | ||
return function(v) { | ||
var cv = d2c(v); | ||
return cv > coercedValue[0] && cv < coercedValue[1]; | ||
}; | ||
} | ||
else if(coercedStrict[0] && !coercedStrict[1]) { | ||
return function(v) { | ||
var cv = d2c(v); | ||
return cv > coercedValue[0] && cv <= coercedValue[1]; | ||
}; | ||
} | ||
else if(!coercedStrict[0] && coercedStrict[1]) { | ||
return function(v) { | ||
var cv = d2c(v); | ||
return cv >= coercedValue[0] && cv < coercedValue[1]; | ||
}; | ||
} | ||
else if(!coercedStrict[0] && !coercedStrict[1]) { | ||
return function(v) { | ||
var cv = d2c(v); | ||
return cv >= coercedValue[0] && cv <= coercedValue[1]; | ||
}; | ||
} | ||
|
||
break; | ||
|
||
case 'notwithin': | ||
|
||
if(coercedStrict[0] && coercedStrict[1]) { | ||
return function(v) { | ||
var cv = d2c(v); | ||
return cv < coercedValue[0] || cv > coercedValue[1]; | ||
}; | ||
} | ||
else if(coercedStrict[0] && !coercedStrict[1]) { | ||
return function(v) { | ||
var cv = d2c(v); | ||
return cv < coercedValue[0] || cv >= coercedValue[1]; | ||
}; | ||
} | ||
else if(!coercedStrict[0] && coercedStrict[1]) { | ||
return function(v) { | ||
var cv = d2c(v); | ||
return cv <= coercedValue[0] || cv > coercedValue[1]; | ||
}; | ||
} | ||
else if(!coercedStrict[0] && !coercedStrict[1]) { | ||
return function(v) { | ||
var cv = d2c(v); | ||
return cv <= coercedValue[0] || cv >= coercedValue[1]; | ||
}; | ||
} | ||
|
||
break; | ||
|
||
case 'in': | ||
return function(v) { return d2c(v) > coercedValue; }; | ||
|
||
case '>=': | ||
return function(v) { return d2c(v) >= coercedValue; }; | ||
|
||
case '[]': | ||
return function(v) { | ||
var cv = d2c(v); | ||
return cv >= coercedValue[0] && cv <= coercedValue[1]; | ||
}; | ||
|
||
case '()': | ||
return function(v) { | ||
var cv = d2c(v); | ||
return cv > coercedValue[0] && cv < coercedValue[1]; | ||
}; | ||
|
||
case '[)': | ||
return function(v) { | ||
var cv = d2c(v); | ||
return cv >= coercedValue[0] && cv < coercedValue[1]; | ||
}; | ||
|
||
case '(]': | ||
return function(v) { | ||
var cv = d2c(v); | ||
return cv > coercedValue[0] && cv <= coercedValue[1]; | ||
}; | ||
|
||
case '][': | ||
return function(v) { | ||
var cv = d2c(v); | ||
return cv < coercedValue[0] || cv > coercedValue[1]; | ||
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. this isn't what I thought 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. yeah, I guess that's easier to remember than 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. out of context, 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. fixed in 7cfa4ff 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. btw 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. "Some authors use ]a, b[ to denote the complement of the interval (a, b); namely, the set of all real numbers that are either less than or equal to a, or greater than or equal to b." - wiki I think it makes intuitive sense also, in that the retained part, i.e. the part outside the interval, has closed bounds 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 has already changed it per my suggestion (thanks!) so not to beat a dead horse but I find it much more persuasive to think of these as a combination of two independent operators ( 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. @alexcjohnson I'm not requesting anything one way or another, it just looked like @etpinard's original code was in line with the standard math notation which is why I mentioned this on my initial review. I may be mistaken or we may not want to follow it, I have less experience than you figuring out what's expected by users. 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. @monfera no problem - also somehow I didn't see your previous comment including "]a, b[" before writing mine - which I think ends up being exactly what we ended up with ⭐ 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. @alexcjohnson just to clarify myself, when I wrote 'complement' it's meant in the set operations sense, for example, the complement of |
||
}; | ||
|
||
case ')(': | ||
return function(v) { | ||
var cv = d2c(v); | ||
return cv <= coercedValue[0] || cv >= coercedValue[1]; | ||
}; | ||
|
||
case '](': | ||
return function(v) { | ||
var cv = d2c(v); | ||
return cv < coercedValue[0] || cv >= coercedValue[1]; | ||
}; | ||
|
||
case ')[': | ||
return function(v) { | ||
var cv = d2c(v); | ||
return cv <= coercedValue[0] || cv > coercedValue[1]; | ||
}; | ||
|
||
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. nice run of all combinations, and the notation looks good and math |
||
case '{}': | ||
return function(v) { | ||
return coercedValue.indexOf(d2c(v)) !== -1; | ||
}; | ||
|
||
case 'notin': | ||
case '}{': | ||
return function(v) { | ||
return coercedValue.indexOf(d2c(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.
the verb "filters" is a bit ambiguous - could be taken to mean "filters out" which is the opposite of what you mean. How about "keeps" or "shows"?
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.
good point - done in 7cfa4ff
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 I also like "keeps" or "retains"