Here's what I ended up hacking together. It works perfectly well, although I'm sure it's ludicrously inefficient because all the dimensions have to be created from scratch:
var _xfilter = crossfilter({x:1, y:2},{x:3, y:4}),
_dimensions = [];
_dimensions.push(_xfilter.dimension(function(d) { return d.x; });
// Unfilters all the given dimensions, removes all data
// from xf and adds newData to xf.
var _xfilter_reset = function(xf, dimensions, newData) {
var i;
for (i = 0; i < dimensions.length; i++) {
// Clear all filters from this dimension.
// Necessary because xf.remove only removes records
// matching the current filter.
dimensions[i].filter(null);
}
xf.remove(); // Remove all data from the crossfilter
xf.add(newData);
return xf;
}
// Resets the global crossfilter object and reapplies all
// current dc.js chart filters.
var _refresh_data = function(data) {
var i, j,
chart, oldFilters,
allCharts = dc.chartRegistry.list();
_xfilter = _xfilter_reset(_xfilter, _dimensions, data);
// Reset all filters using dc.js
for (i = 0; i < allCharts.length; i++) {
chart = allCharts[i];
oldFilters = chart.filters(); // Get current filters
chart.filter(null); // Reset all filters on current chart
for (j = 0; j < oldFilters.length; j++) {
// Set all the oldFilters back onto the chart
chart.filter(oldFilters[j]);
}
}
dc.redrawAll();
}