【发布时间】:2020-03-09 19:38:58
【问题描述】:
我想创建一个多时间线图作为系列图。
我阅读了有关填充缺失数据的 Stack Overflow dc.js lineChart - fill missing dates and show zero where no data
问题:我在那里实现了代码,它非常适合单线图。对于系列图表,我需要对其进行一些调整。它可以工作,但是性能很糟糕。
这是我们使用的示例数据:
let data = [{description: "Walmart", location: "40.216403 -74.541296", timeReported: 1581710670184}
{description: "Target", location: "38.271996 -84.032575", timeReported: 1583524065011}
{description: "Wendys", location: "39.255831 -75.532763", timeReported: 1583524065011}
{description: "7-11", location: "34.925349 -78.463977", timeReported: 1583524065011}
{description: "WaWa", location: "35.716208 -77.741230", timeReported: 1583524065013}
{description: "7-11", location: "41.258950 -83.888060", timeReported: 1583524065013}
{description: "Shell", location: "37.879694 -79.836127", timeReported: 1583524065011}
{description: "Dominos", location: "35.890273 -80.700329", timeReported: 1583524065395}
{description: "Dominos", location: "39.268777 -78.743366", timeReported: 1583524065397}
{description: "Walgreens", location: "35.490215 -81.773863", timeReported: 1583524065399}
{description: "7-11", location: "37.974797 -81.393449", timeReported: 1583524065506}
{description: "Wendys", location: "40.859685 -76.963065", timeReported: 1583524065521}
{description: "CVS", location: "38.517910 -78.251419", timeReported: 1583524065553}
{description: "CVS", location: "35.947033 -81.616061", timeReported: 1583524142169}
{description: "Shell", location: "39.566535 -77.992499", timeReported: 1583524142176}
{description: "Target", location: "37.832142 -88.003151", timeReported: 1583524142170}
{description: "Wendys", location: "40.245397 -80.061998", timeReported: 1583524142223}
{description: "Macys", location: "39.631265 -75.157194", timeReported: 1583524142223}
{description: "Macys", location: "36.631458 -77.803286", timeReported: 1583524142213}
{description: "7-11", location: "36.249754 -79.830006", timeReported: 1583524142251}
{description: "7-11", location: "41.138285 -83.298142", timeReported: 1583524142249}
{description: "Wendys", location: "34.940485 -77.230388", timeReported: 1583524142249}
{description: "7-11", location: "39.605373 -77.448768", timeReported: 1583524142296}
{description: "Wendys", location: "35.609094 -79.455712", timeReported: 1583524142293}
{description: "WaWa", location: "37.130753 -78.076709", timeReported: 1583524142310}
{description: "Macys", location: "40.058482 -78.497258", timeReported: 1583524142338}
{description: "Wendys", location: "39.255831 -75.532763", timeReported: 1582058735883}
{description: "Macys", location: "39.631265 -75.157194", timeReported: 1582058735883}
{description: "7-11", location: "36.249754 -79.830006", timeReported: 1582058735883}
{description: "7-11", location: "39.605373 -77.448768", timeReported: 1582058735883}
{description: "Wendys", location: "35.609094 -79.455712", timeReported: 1582058735883}
{description: "WaWa", location: "37.130753 -78.076709", timeReported: 1582058735883}
{description: "Macys", location: "40.058482 -78.497258", timeReported: 1582058735883}
{description: "Kohls", location: "40.373533 -101.057470", timeReported: 1582838559493}]
这里是示例代码。顺便说一句,下面代码中的 curTimeInterval 只是 d3 timeIntervlas 的别名,可以由用户选择。 (d3.timeHour, d3.timeDay, d3.timeWeek, d3.timeMonth)。
cf = crossfilter(data);
dateDim = cf.dimension((d) => {
return curTimeInterval(d.timeReportedDate);
});
reportedGroup = dateDim.group().reduceSum((d) => 1);
let minDate = d3.min(reportedGroup.all(), (kv) => {
return kv.key;
});
let maxDate = d3.max(reportedGroup.all(), (kv) => {
return kv.key;
});
minDate = curTimeInterval.offset(minDate, -2);
maxDate = curTimeInterval.offset(maxDate, 2);
const runDimension = cf.dimension((d) => {
return [d.description, curTimeInterval(d.timeReportedDate)];
});
const runGroup = runDimension.group();
// Fills the missing data in the group
const filledSeries = fill_composite_intervals(runGroup, curTimeInterval);
const seriesChart = new dc.SeriesChart('#series');
seriesChart
.width(768)
.height(480)
.chart(function(c) {
return new dc.LineChart(c).curve(d3.curveCardinal);
})
.x(d3.scaleTime().domain([minDate, maxDate]))
.xUnits(curTimeInterval.range)
.brushOn(false)
.clipPadding(10)
.elasticY(true)
.dimension(runDimension)
.group(filledSeries)
.mouseZoomable(true)
.seriesAccessor((d) => {
return d.key[0];
})
.keyAccessor((d) => {
return d.key[1];
})
.valueAccessor((d) => {
return d.value;
})
.legend(dc.legend().x(350).y(350).itemHeight(13).gap(5).horizontal(1).legendWidth(140).itemWidth(70))
.yAxis()
.tickValues(d3.range(min > 0 ? min - 1 : min, max + 1));
seriesChart.margins().left += 40;
fill_composite_intervals = (group, interval) => {
return {
all: function() {
const retVal = [];
const allArray = group.all();
if (!allArray.length) {
return retVal;
}
allArray.sort((a, b) => {
if (a.key[1].getTime() < b.key[1].getTime()) {
return -1;
}
if (a.key[1].getTime() > b.key[1].getTime()) {
return 1;
}
// a must be equal to b
return 0;
});
const target = interval.range(allArray[0].key[1], allArray[allArray.length-1].key[1]);
const allMap = new Map();
allArray.forEach((obj) => {
let innerArray = allMap.get(obj.key[0]);
if (!innerArray) {
innerArray = [];
allMap.set(obj.key[0], innerArray);
}
innerArray.push({key: obj.key[1], value: obj.value});
});
allMap.forEach((value, key, map) => {
const orig = value.map((kv) => ({key: new Date(kv.key), value: kv.value}));
const result = [];
if (orig.length) {
let oi;
let ti;
for (oi = 0, ti = 0; oi < orig.length && ti < target.length;) {
if (orig[oi].key <= target[ti]) {
result.push(orig[oi]);
if (orig[oi++].key.valueOf() === target[ti].valueOf()) {
++ti;
}
} else {
result.push({key: target[ti], value: 0});
++ti;
}
}
if (oi<orig.length) {
Array.prototype.push.apply(result, orig.slice(oi));
}
if (ti<target.length) {
Array.prototype.push.apply(result, target.slice(ti).map((t) => ({key: t, value: 0})));
}
}
map.set(key, result);
});
allMap.forEach((value, key, map) => {
value.forEach((obj) => {
const newObj = {
key: [key, obj.key],
value: obj.value
};
retVal.push(newObj);
});
});
return retVal;
}
};
};
【问题讨论】:
-
你没有说你使用这个数据的间隔。我写了an example of choosing the appropriate interval,它演示了使用太细的间隔的问题。对于此数据,timeDay 产生 240 个 bin,timeHour 产生 5542 个 bin,timeMinute 产生 332482 个 bin。没有理由显示比像素宽度更多的点;我还在这个演示中关闭了
xyTipsOn,因为每个点都被隐藏了。希望尽快跟进一个彻底的答案。
标签: d3.js dc.js crossfilter