I'd like to do some fast filtering in the browser and have been recommended crossfilter, but having looked at it I'm not entirely sure it suits my data. So, my data has just 3 variables:
{group: "A", value: 39.8, variable: "ABC"}
{group: "B", value: 26.8, variable: "ABC"}
{group: "C", value: 27.4, variable: "ABC"}
{group: "D", value: 26.9, variable: "ABC"}
{group: "E", value: 22.9, variable: "ABC"}
{group: "A", value: 48.9, variable: "ALL"}
{group: "B", value: 32.2, variable: "ALL"}
{group: "C", value: 16.2, variable: "ALL"}
{group: "D", value: 13.2, variable: "ALL"}
{group: "A", value: 42.3, variable: "ALL1"}
{group: "B", value: 50.1, variable: "ALL1"}
{group: "C", value: 19.3, variable: "ALL1"}
etc
I'd like to be able to filter where the values limits vary for each group:
(group = 'A' & 10 <= value <=20) or (group = 'B' & 15 <= value <=95) or
(group = 'C' & 10 <= value <=20) or (group = 'D' & 25 <= value <=45) or
(group = 'E' & 10 <= value <=20)
Is this possible without reorganising the data or are there better options?
So, this is what I've tried:
{group: "B", value: 26.8, variable: "ABC"},
{group: "C", value: 27.4, variable: "ABC"},
{group: "D", value: 26.9, variable: "ABC"},
{group: "E", value: 22.9, variable: "ABC"},
{group: "A", value: 48.9, variable: "ALL"},
{group: "B", value: 32.2, variable: "ALL"},
{group: "C", value: 16.2, variable: "ALL"},
{group: "D", value: 13.2, variable: "ALL"},
{group: "A", value: 42.3, variable: "ALL1"},
{group: "B", value: 50.1, variable: "ALL1"},
{group: "C", value: 19.3, variable: "ALL1"}]
var testcf = crossfilter(test)
const valueDimT = testcf.dimension(({group, value}) => ({group, value}));
valueDimT.filterFunction(({group, value}) => ((group = 'B' && value <= 30) || (group = 'C' && value <= 18)))
valueDimT.top(100)
Which gives the following result:
[{group: "C", value: 19.3, variable: "ALL1"},
{group: "D", value: 13.2, variable: "ALL"},
{group: "C", value: 16.2, variable: "ALL"},
{group: "E", value: 22.9, variable: "ABC"},
{group: "D", value: 26.9, variable: "ABC"},
{group: "C", value: 27.4, variable: "ABC"},
{group: "B", value: 26.8, variable: "ABC"}] (7) = $3
Which isn't what I would expect. Primarily I would expect only group values of B & C with values below the respective equalities given that's all that was in the filter:
[{group: "B", value: 26.8, variable: "ABC"},
{group: "C", value: 16.2, variable: "ALL"}]
Obviously I'm missing something - I'm just not sure what it is.
filterFunction
You can filter using a function
const valueDim = cf.dimension(({group, value}) => ([group, value]));
valueDim.filterFunction(([group, value]) => /* as above */)
Note we are creating a composite key here. In an earlier draft I spelled the key {group, value}
but that doesn't work because the dimension and group keys must be naturally ordered. An object won't work, because it coerces to the useless string [object Object]
but an array will, because it coerces to a comma-delimited string with the values.
Complete code:
const valueDimT = testcf.dimension(({group, value}) => ([group, value]));
valueDimT.filterFunction(([group, value]) =>
((group == 'B' && value <= 30) || (group == 'C' && value <= 18)))
console.log(valueDimT.top(100))
It is probably more efficient to derive a key from the data:
const condDim = cf.dimension(({group, value}) => /* as above */);
condDim.filterExact(true)
Careful with double comparisons:
3 <= 2 <= 9
evaluates to
false <= 9
or true in JavaScript, since false
coerces to 0
.
You will need to do
10 <= value && value <= 20
Also be careful about =
vs ==
- the former is assignment and the latter tests equality.