D3 图表缺少数据

本文关键字:数据 D3 | 更新日期: 2023-09-27 18:36:08

我有一个 d3 折线图,效果很好。它映射了当月或当年收到的电话和电子邮件的数量。但是,唯一的问题是,如果仅在每月的某一天收到电话,则在该值处仅显示一个点。我想发生的是,对于每天没有值,则该值被视为 0。我环顾了一下谷歌,但我只能找到走另一条路的例子。有人能帮忙吗?

我的代码是:

function buildCommunicationLineChart(data, placeholder, callback, type) {
var margin = { top: 20, right: 30, bottom: 40, left: 50 },
    width = 960 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom,
    tooltipTextColour = "white";
var color = ["#FF9797", "#86BCFF", "#33FDC0", "#EFA9FE", "#7BCAE1", "#8C8CFF", "#80B584", "#C88E8E", "#DD597D", "#D8F0F8", "#DD597D", "#D6C485", "#990099", "#5B5BFF", "#1FCB4A", "#000000", "#00BFFF", "#BE81F7", "#BDBDBD", "#F79F81"];
if (type == "month") {
    var x = d3.scale.linear()
                    .domain([1, 31])
                    .range([0, width]);
    var tip = d3.tip()
      .attr('class', 'd3-tip')
      .offset([-10, 0])
      .html(function (d) {
          return "<strong>Value:</strong> <span style='color:" + tooltipTextColour + "'>" + d.Value + "</span><br /><strong>Day of Month:</strong><span style='color:white'>" + d.xValue + "</span>";
      });
}
else if (type == "year")
{
    var x = d3.scale.linear()
                    .domain([1, 12])
                    .range([0, width]);
    var tip = d3.tip()
      .attr('class', 'd3-tip')
      .offset([-10, 0])
      .html(function (d) {
          return "<strong>Value:</strong> <span style='color:" + tooltipTextColour + "'>" + d.Value + "</span><br /><strong>Month of Year:</strong><span style='color:white'>" + d.xValue + "</span>";
      });
}
var y = d3.scale.linear()
    .domain([0, 60])
    .range([height, 0]);
var xAxis = d3.svg.axis()
    .scale(x)
    .tickSize(-height)
    .tickPadding(10)
    .tickSubdivide(true)
    .orient("bottom");
var yAxis = d3.svg.axis()
    .scale(y)
    .tickPadding(10)
    .tickSize(-width)
    .tickSubdivide(true)
    .orient("left");
var line = d3.svg.line()
            .x(function (d) { var xTest = x(d.xValue); return x(d.xValue); })
            .y(function (d) { var yTest = y(d.Value); return y(d.Value); });
var svg = placeholder.append("svg")
    .attr("width", width + margin.left + margin.right + 50)
    .attr("height", height + margin.top + margin.bottom)
    .attr("class", "chart")
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + height + ")")
    .call(xAxis);
if (type == "year") {
    svg.append("g")
        .attr("class", "x axis")
        .append("text")
        .attr("class", "axis-label")
        .attr("transform", "none")
        .attr("y", (-margin.left) + 530)
        .attr("x", -height + 860)
        .text('Month');
}
else if (type == "month") {
    svg.append("g")
        .attr("class", "x axis")
        .append("text")
        .attr("class", "axis-label")
        .attr("transform", "none")
        .attr("y", (-margin.left) + 525)
        .attr("x", -height + 860)
        .text('Day');
}
var methods = d3.entries(data);
y.domain([
    d3.min(methods, function (c) { return d3.min(c.value.DataPoints, function (v) { return v.Value; }); }) -1,
    d3.max(methods, function (c) { return d3.max(c.value.DataPoints, function (v) { return v.Value; }); }) +1
]);
svg.call(tip);
svg.append("g")
    .attr("class", "y axis")
    .call(yAxis);
svg.append("g")
    .attr("class", "y axis")
    .append("text")
    .attr("class", "axis-label")
    .attr("transform", "rotate(-90)")
    .attr("y", (-margin.left) + 15)
    .attr("x", -height / 2)
    .text('Communications');
var method = svg.selectAll('.method')
                    .data(methods)
                    .enter().append('g')
                    .attr('class', 'method')
                    .style('fill',function(d,i){
                        return color[i];
                    })
                    .style('stroke', function (d, i) {
                        return color[i];
                    });
var m = method.append('path')
        .attr('class', function (d, i) { return 'line line-' + i; })
        .attr('d', function (d) { return line(d.value.DataPoints); });
method.selectAll('circle')
        .data(function (d) { return d.value.DataPoints; })
         .enter().append("circle")
        .attr('class', function (d, i) { return 'circle circle-' + i; })
         .attr("cx", function (dd) { return x(dd.xValue); })
         .attr("cy", function (dd) { return y(dd.Value); })
         .attr("r", 3.5)
         .on('mouseover', tip.show)
         .on('mouseout', tip.hide);
method.append('text')
        .datum(function (d) { return { commType: d.value.Type, value: d.value.DataPoints[d.value.DataPoints.length - 1] }; })
        .attr("transform", function (d) { return "translate(" + x(d.value.xValue) + "," + y(d.value.Value) + ")"; })
        .attr('x', 5)
        .attr('class',function(d,i){return 'text text-'+i;})
        .attr('dy', '.15em')
        .style('stroke','none')
        .text(function (d) { return d.commType; });
if (callback) {
    callback();
}
}

非常感谢:)

编辑

xVal 是月份编号的日期数:

[{
    "Type": "Email",
    "DataPoints": [{
        "xValue": 1,
        "Value": 17
    },
    {
        "xValue": 2,
        "Value": 59
    }]
},
{
    "Type": "Phone",
    "DataPoints": [{
        "xValue": 1,
        "Value": 1
    }]
}]

D3 图表缺少数据

我将假设一些要点:

您正在从数据源接收月份数组的年份数组(如果您逐月接收,则必须为每个月发出 Get 请求,这很容易,但我希望您有一条路线为您提供年份数据,对于此结果做 12 http get 并不酷)数据,例如:

[
    {
        month: "January",
        data: [{
        "Type": "Email",
        "DataPoints": 
            [{
                "xValue": 1,
                "Value": 17
            },
            {
                "xValue": 2,
                "Value": 59
            }]
        },
        {
            "Type": "Phone",
            "DataPoints": [{
                "xValue": 1,
                "Value": 1
            }]
        }]
    }
    },{
    month: "February",
    data: [...]
    },
    ...
]

我将在 Js 中执行客户端操作:

假设每个月是 31 天,我懒得考虑确切地做这件事,但这并不难,xValue 是月份中的一天。

function completeMonths(data){
    _.each(data, function(month){
        _.each(month.data, function(typeSource){
            for(var i = 1; i < 32; i++){
                var dayOnList = _.some(typeSource.DataPoints, function(day){
                    return day.xValue == i;
                });
                if(!dayOnList)
                    typeSource.DataPoints.push({xValue: i, Value: 0});
            }
            typeSource.DataPoints = _.sortBy(typeSource.DataPoints, function(ite){
                return ite.xValue;
            });
        });
    });
    return data;
}

可能不是更优化的代码,但我已经尝试过并且它正在工作。实际上,我认为最好将月份的天数映射到现在,并从 1 到 31 数组中拒绝它们。顺便说一句,您的 JSON 格式不正确,您缺少结束"]"。

JSON 结构如下:

[{
    "Type": "Email",
    "DataPoints": [{
        "xValue": 1,
        "Value": 17
    },
    {
        "xValue": 2,
        "Value": 59
    }]
},
{
    "Type": "Phone",
    "DataPoints": [{
        "xValue": 1,
        "Value": 1
    }]
}]

假设您的DataPoints数组按当月xValue和 31 天排序:

var maxDaysInMonth = 31;
// for each dataset
dataset.forEach(function(d){
  // loop our month
  for (var i = 1; i <= maxDaysInMonth; i++){
    // if there's no xValue at that location
    if (!d.DataPoints.some(function(v){ return (v.xValue === i) })){
      // add a zero in place
      d.values.splice((i - 1), 0, {xValue: i, Value: 0});
    }
  }
});