javascript - DC.js compositeChart 与两个 lineChart 都代表日期的平均值

标签 javascript d3.js dc.js crossfilter

我想用两条线来创建 DC.js 图表,每条线代表日期的平均值。

我相信这样做的方法是使用 DC.js compositeChart 并创建两个 lineCharts 放入其中,然后使用 reducio() group.reduce(add, remove, initial) 获取平均数量。

我的问题是条件逻辑去哪里了?我如何/在哪里有条件地使用它:

var group = dimension.group().reduce(reduceAdd, reduceRemove, reduceInitial);  

要计算带有d.PPCC === "PPCC" 的记录的平均值和带有d.PPCC === "Other" 的记录的另一个平均值?

我尝试了两种方法,但都不适合我。

这是第一次尝试:

var bounce30DaysPPCC = function(d) { if (d.PPCC === "PPCC") 
{ dateDim.group().reduce(reduceAdd, reduceRemove, reduceInitial); 
} else { dateDim.group().reduce(0); } };

var bounce30DaysOther = function(d) { if (d.PPCC === "Other") 
{ dateDim.group().reduce(reduceAdd, reduceRemove, reduceInitial); 
} else { dateDim.group().reduce(0); } };

产生这个错误:

dc.js:4017 Uncaught TypeError: layer.group.all is not a function

这是第二次尝试:

var bounce30DaysPPCC = dateDim.group().reduce( function(d) { if (d.PPCC === "PPCC") 
{ return reduceAdd, reduceRemove, reduceInitial; } else { return 0; }});

var bounce30DaysOther = dateDim.group().reduceSum( function(d) { if (d.PPCC === "Other") 
{ return reduceAdd, reduceRemove, reduceInitial; } else { return 0; } });

这也会产生错误:

Uncaught TypeError: reduceInitial is not a function 

这是我的完整 javascript 代码。

<script type="text/javascript">

    // get csv data 
    d3.csv("merged.csv", function(data) {

    // get csv data and format date
    var parseDate = d3.time.format("%Y-%m-%d").parse;

    data.forEach(function(d) {
        d.date = parseDate(d.date);
        d.sessions = +d.sessions;
        d.ad_requests = +d.ad_requests;
        d.bounceRate = +d.bounceRate;
        d.clicks = +d.clicks;
        d.earnings = +d.earnings;
        d.newUsers = +d.newUsers;
        d.sessionDuration = +d.sessionDuration;
        d.sessionsPerUser = +d.sessionsPerUser;
        d.twitterSessions = +d.twitterSessions;
        d.users = +d.users;
    });

    // setup crossfilter
    var ndx  = crossfilter(data);

    // create dimension
    var dateDim = ndx.dimension(function(d) { return d["date"]; });

    // create data groups
    var bounce30DaysPPCC = function(d) { if (d.PPCC === "PPCC") 
    { dateDim.group().reduce(reduceAdd, reduceRemove, reduceInitial); 
    } else { dateDim.group().reduce(0); } };

    var bounce30DaysOther = function(d) { if (d.PPCC === "Other") 
    { dateDim.group().reduce(reduceAdd, reduceRemove, reduceInitial); 
    } else { dateDim.group().reduce(0); } };

    // create min and max dates to limit chart x axis values
    var minDateTime = new Date(new Date().setDate(new Date().getDate()-30));

    var maxDateTime = new Date(new Date().setDate(new Date().getDate()+1));

    // create chart     
    BounceChart30Day = dc.compositeChart("#bounce-chart-30day");

    // create two line charts to put into composite chart
    var ppccLine = dc.lineChart(BounceChart30Day)
    .group(bounce30DaysPPCC)    

    var otherLine = dc.lineChart(BounceChart30Day)
    .group(bounce30DaysOther)

    // create composite chart
    BounceChart30Day
    .height(50)
    .width(450)
    .margins({top: 10, right: 10, bottom: 5, left: 35})
    .dimension(dateDim)
    .transitionDuration(500)
    .brushOn(false)
    .elasticY(true)
    .compose([ppccLine, otherLine])
    .x(d3.time.scale().domain([minDateTime, maxDateTime]))
    .yAxis().ticks(3);

    // create value accessor to calculate averages
    BounceChart30Day.valueAccessor(function(p) { 
    return p.value.count > 0 ? p.value.total / p.value.count : 0; });

    // create add, remove, initial reduce functions
    function reduceAdd(p, v) {
      ++p.count;
      p.total += v.bounceRate;
      return p;
    }

    function reduceRemove(p, v) {
      --p.count;
      p.total -= v.bounceRate;
      return p;
    }

    function reduceInitial() {
      return {count: 0, total: 0};
    }

    // render chart
    dc.renderAll();

</script>

最佳答案

您需要在 reduce 函数中评估数据。所以让你的 reduce 函数看起来像这样:

// create add, remove, initial reduce functions
function reduceAdd(p, v) {
  if (v.PPCC === "PPCC") {
    ++p.PPCCcount;
    p.PPCCtotal += v.bounceRate;
  } else if(v.PPCC === "Other") {
    ++p.Othercount;
    p.Othertotal += v.bounceRate;
  }
  return p;
}

function reduceRemove(p, v) {
  if (v.PPCC === "PPCC") {
    --p.PPCCcount;
    p.PPCCtotal -= v.bounceRate;
  } else if(v.PPCC === "Other") {
    --p.Othercount;
    p.Othertotal -= v.bounceRate;
  }
  return p;
}

function reduceInitial() {
  return { PPCCcount: 0, PPCCtotal: 0, Othercount: 0, Othertotal: 0};
}

然后像往常一样创建您的组:

var bounce30DaysPPCC = dateDim.group().reduce(reduceAdd, reduceRemove, reduceInitial);
var bounce30DaysOther = dateDim.group().reduceSum(reduceAdd, reduceRemove, reduceInitial);

乍一看,其他一切看起来都还不错。您只需更新 valueAccessor 函数即可获取组中的新属性名称。

关于javascript - DC.js compositeChart 与两个 lineChart 都代表日期的平均值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39300364/

相关文章:

javascript - 复杂数据如何使用散点图?

javascript - 使用 dc.js 创建一个简单的饼图

JavaScript:客户端与服务器端验证

javascript - 将输入中的值转换或提取为纯文本

javascript - 在字符串和 ArrayBuffers 之间转换

d3.js - 用单行重新创建矩形波动画

javascript - 防止动画期间单击事件

用于图形渲染的 Javascript 插件(树和节点)

javascript - 隐藏功能jquery不起作用

javascript - Dc.js 刷机滞后。与 dc.js 版本 1.3 不同,过滤多次