使用 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};
                }));
        }
    };
}