使用 dc.js 和交叉过滤器制作显示人口衰减的折线图
making a linegraph that shows population decay with dc.js and crossfilter
我正在 DC.js 中创建仪表板。其中一个可视化是生存曲线,显示 y 轴上的生存百分比和 x 轴上的时间(以周为单位)
数据集中的每条记录都包含一个名为 recidiefNa
的 deathAfter 列。这显示死亡发生后的周数,并显示 -99 表示存活。
查看示例数据集和所需图表形式的草图:
我创建此代码是为了创建维度和组并绘制所需的图表。
var recDim = cf1.dimension(dc.pluck('recidiefNa'));//sets dimension
var recGroup = recDim.group().reduceCount();
var resDim = cf1.dimension(dc.pluck('residuNa'));
var resGroup = resDim.group().reduceCount();
var scChart = dc.compositeChart("#scStepChart");
scChart
.width(600)
.height(400)
.x(d3.scale.linear().domain([0,52]))
.y(d3.scale.linear().domain([0,100]))
.clipPadding(10)
.brushOn(false)
.xAxisLabel("tijd in weken")
.yAxisLabel("percentage vrij van residu/recidief")
.compose([
dc.lineChart(scChart)
.dimension(recDim)
.group(recGroup)
.interpolate("step-after")
.renderDataPoints(true)
.renderTitle(true)
.keyAccessor(function(d){return d.key;})
.valueAccessor(function(d){return (d.value/cf1.groupAll().reduceCount().value()*100);}),
dc.lineChart(scChart)
.dimension(resDim)
.group(resGroup)
.interpolate("step-after")
.renderDataPoints(true)
.colors(['orange'])
.renderTitle(true)
.keyAccessor(function(d){return d.key;})
.valueAccessor(function(d){return (d.value/cf1.groupAll().reduceCount().value()*100 );})
])
.xAxis().ticks(4);
scChart.render();
结果如下:
如您所见,我的第一个问题是我需要延长线直到 y 轴显示 x=0weeks 和 y=100% 作为第一个数据点。
所以这是第一个问题:有没有办法让这条线看起来更像我的草图(从 y 轴的 100% 开始?
我的第二个 更大的问题 是它显示的是我需要的百分比的倒数(例如 38 而不是 62)。这是因为数据的结构方式(这是我不想改变的)
首先,我尝试将值访问器更改为 100-* 计算值。这显然是解决此问题的正常方法。但是我的结果是这样的:
正如您现在看到的那样,生存曲线是一个正斜率,这在生存曲线中是不可能的。这是我的第二个问题。有什么解决办法吗?
啊,从特定示例中不清楚每个数据点应基于最后一个数据点,但您的评论清楚地表明了这一点。听起来您正在寻找的是一种累积和 - 在您的情况下,是累积减法。
There is an entry in the FAQ for this.
根据您的用例调整该代码:
function accumulate_subtract_from_100_group(source_group) {
return {
all:function () {
var cumulate = 100;
return source_group.all().map(function(d) {
cumulate -= d.value;
return {key:d.key, value:cumulate};
});
}
};
}
这样使用:
var decayRecGroup = accumulate_subtract_from_100_group(recGroup)
// ...
dc.lineChart(scChart)
// ...
.group(decayRecGroup)
和 resGroup
类似
在此期间,我们可以将数据连接到初始点,以回答您的第一个问题:
function accumulate_subtract_from_100_and_prepend_start_point_group(source_group) {
return {
all:function () {
var cumulate = 100;
return [{key: 0, value: cumulate}]
.concat(source_group.all().map(function(d) {
cumulate -= d.value;
return {key:d.key, value:cumulate};
}));
}
};
}
(荒谬的函数名,仅供说明!)
编辑:这是@Erik 的最终改编答案,内置百分比转换,以及一些性能改进:
function fakeGrouper(source_group) {
var groupAll = cf1.groupAll().reduceCount();
return {
all:function () {
var cumulate = 100;
var total = groupAll.value();
return [{key: 0, value: cumulate}]
.concat(source_group.all().map(function(d) {
if(d.key > 0) {
cumulate -= (d.value/total*100).toFixed(0);
}
return {key:d.key, value:cumulate};
}));
}
};
}
我正在 DC.js 中创建仪表板。其中一个可视化是生存曲线,显示 y 轴上的生存百分比和 x 轴上的时间(以周为单位)
数据集中的每条记录都包含一个名为 recidiefNa
的 deathAfter 列。这显示死亡发生后的周数,并显示 -99 表示存活。
查看示例数据集和所需图表形式的草图:
我创建此代码是为了创建维度和组并绘制所需的图表。
var recDim = cf1.dimension(dc.pluck('recidiefNa'));//sets dimension
var recGroup = recDim.group().reduceCount();
var resDim = cf1.dimension(dc.pluck('residuNa'));
var resGroup = resDim.group().reduceCount();
var scChart = dc.compositeChart("#scStepChart");
scChart
.width(600)
.height(400)
.x(d3.scale.linear().domain([0,52]))
.y(d3.scale.linear().domain([0,100]))
.clipPadding(10)
.brushOn(false)
.xAxisLabel("tijd in weken")
.yAxisLabel("percentage vrij van residu/recidief")
.compose([
dc.lineChart(scChart)
.dimension(recDim)
.group(recGroup)
.interpolate("step-after")
.renderDataPoints(true)
.renderTitle(true)
.keyAccessor(function(d){return d.key;})
.valueAccessor(function(d){return (d.value/cf1.groupAll().reduceCount().value()*100);}),
dc.lineChart(scChart)
.dimension(resDim)
.group(resGroup)
.interpolate("step-after")
.renderDataPoints(true)
.colors(['orange'])
.renderTitle(true)
.keyAccessor(function(d){return d.key;})
.valueAccessor(function(d){return (d.value/cf1.groupAll().reduceCount().value()*100 );})
])
.xAxis().ticks(4);
scChart.render();
结果如下:
如您所见,我的第一个问题是我需要延长线直到 y 轴显示 x=0weeks 和 y=100% 作为第一个数据点。
所以这是第一个问题:有没有办法让这条线看起来更像我的草图(从 y 轴的 100% 开始?
我的第二个 更大的问题 是它显示的是我需要的百分比的倒数(例如 38 而不是 62)。这是因为数据的结构方式(这是我不想改变的)
首先,我尝试将值访问器更改为 100-* 计算值。这显然是解决此问题的正常方法。但是我的结果是这样的:
正如您现在看到的那样,生存曲线是一个正斜率,这在生存曲线中是不可能的。这是我的第二个问题。有什么解决办法吗?
啊,从特定示例中不清楚每个数据点应基于最后一个数据点,但您的评论清楚地表明了这一点。听起来您正在寻找的是一种累积和 - 在您的情况下,是累积减法。
There is an entry in the FAQ for this.
根据您的用例调整该代码:
function accumulate_subtract_from_100_group(source_group) {
return {
all:function () {
var cumulate = 100;
return source_group.all().map(function(d) {
cumulate -= d.value;
return {key:d.key, value:cumulate};
});
}
};
}
这样使用:
var decayRecGroup = accumulate_subtract_from_100_group(recGroup)
// ...
dc.lineChart(scChart)
// ...
.group(decayRecGroup)
和 resGroup
在此期间,我们可以将数据连接到初始点,以回答您的第一个问题:
function accumulate_subtract_from_100_and_prepend_start_point_group(source_group) {
return {
all:function () {
var cumulate = 100;
return [{key: 0, value: cumulate}]
.concat(source_group.all().map(function(d) {
cumulate -= d.value;
return {key:d.key, value:cumulate};
}));
}
};
}
(荒谬的函数名,仅供说明!)
编辑:这是@Erik 的最终改编答案,内置百分比转换,以及一些性能改进:
function fakeGrouper(source_group) {
var groupAll = cf1.groupAll().reduceCount();
return {
all:function () {
var cumulate = 100;
var total = groupAll.value();
return [{key: 0, value: cumulate}]
.concat(source_group.all().map(function(d) {
if(d.key > 0) {
cumulate -= (d.value/total*100).toFixed(0);
}
return {key:d.key, value:cumulate};
}));
}
};
}