I know there are a lot of questions on that specific subject on SO but none of the solutions seem to work in my case.
This is my data :
var theData = [{
"value": "190.79",
"age_days": "22",
"criteria": "FX"
}, {
"value": "18.43",
"age_days": "22",
"criteria": "FX"
}, {...}]
I put the data into buckets as such :
var getAge = (d) => {
if ((d.age_days) <= 7) {
return (["1w", "2w", "1m", "3m", "6m", "1y", "All"]);
} else if ((d.age_days) <= 14) {
return (["2w", "1m", "3m", "6m", "1y", "All"]);
} else if ((d.age_days) <= 30) {
return (["1m", "3m", "6m", "1y", "All"]);
} else if ((d.age_days) <= 90) {
return (["3m", "6m", "1y", "All"]);
} else if ((d.age_days) <= 180) {
return (["6m", "1y", "All"]);
} else if ((d.age_days) <= 360) {
return (["1y", "All"]);
} else {
return (["All"]);
}
};
var ndx = crossfilter(theData);
var dims = {};
var groups = {};
dims.age = ndx.dimension(getAge,true);
groups.age = {};
groups.age.valueSum = dims.age.group().reduceSum((d) => d.value);
I then try to order the group using the fake group approach :
var sort_group = (source_group, order) => {
return {
all: () => {
let g = source_group.all();
let map = {};
g.forEach(function (kv) {
map[kv.key] = kv.value;
});
return order
.filter((k) => map.hasOwnProperty(k))
.map((k) => {
return {key: k, value: map[k]}
});
}
};
};
var the_order = ["1w", "2w", "1m", "3m", "6m", "1y", "All"];
var the_sorted_age_group = sort_group(groups.age.valueSum, the_order);
then I create the barChart
using
theAgeChart
.height(200)
.width(400)
.dimension(dims.age)
.group(the_sorted_age_group)
.valueAccessor((d) => d.value)
.x(d3.scaleBand())
.xUnits(dc.units.ordinal);
But it still comes out using the default sort :
I've created a jsFiddle
here which contains everything.
How can I get my bars sorted as I want them to be sorted ?
When elasticX is true or the x scale domain is not set, the coordinate grid mixin will generate the X domain
if (_chart.elasticX() || _x.domain().length === 0) {
_x.domain(_chart._ordinalXDomain());
}
That totally makes sense, but it always sorts the domain when it generates it:
_chart._ordinalXDomain = function () {
var groups = _chart._computeOrderedGroups(_chart.data());
return groups.map(_chart.keyAccessor());
};
I guess we could consider not sorting the domain when ordering
is null.
Anyway, one workaround is to set the domain yourself:
.x(d3.scaleBand().domain(the_order))
You don't need to sort the group for a bar chart. (For a line chart, the group order must agree with the scale domain, but it doesn't matter for the bar chart.)
With the domain set, this also works:
.group(groups.age.valueSum)
I guess the moral of the story is that it's complicated to generate charts automatically. Most of the time one does want the X domain sorted, but what's the best way to allow the user to provide their own sort?
I would not say this is the best way, but there is a way to make it work.