数据加入D3旭日形图

时间:2016-08-15 19:54:24

标签: javascript d3.js charts

我正在尝试创建下面的图表:

enter image description here

每个'fin'代表一项研究,每一行都是该研究中的品牌。

我收到了以下代码以添加转换(请参阅this question),但意识到这是在不使用数据连接的情况下构建的(这使得更新数据变得困难)。

Array.prototype.max = function() { return Math.max.apply(null, this); };

Array.prototype.min = function() { return Math.min.apply(null, this); };

Number.prototype.map = function (in_min, in_max, out_min, out_max) {
  return (this - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

var colors = {
  'rank1' : '#3FA548',
  'rank2' : '#00B09E',
  'rank3' : '#8971B3',
  'rank4' : '#DFC423',
  'rank5' : '#E74341'
};

var angleSize;

d3.text('text.csv', ready);

var study = null;

function ready(err, text) {
  if (err) console.warn('Error', err);

  var csv = d3.csv.parse(text);

  function selectStudy(d) {
    study = $(this).attr('study');
    updateChart(study);
  } 

  function updateChart(study) {
    //Remove and replace with transition
    d3.select('#chart svg')
      .remove();

    if (study) {
      csv = csv.filter(function(d) { 
         return d.study_name === study; 
      });
    } else {
      csv = d3.csv.parse(text);
    }

    var svg = d3.select('#chart')
                .append('svg')
                .attr({
                  'width' : 1000,
                  'height' : 1000,
                  'id' : 'container'
                })
                .append('g')
                .attr('transform', 'translate(500, 500)');

    angleSize = (2 * Math.PI) / csv.length

    var group1Array = [],
        group2Array = [],
        group3Array = [],
        group4Array = [];

    for ( var i = 0; i < csv.length; i++ ) {
      group1Array[i] = Number(csv[i].group1_score);
      group2Array[i] = Number(csv[i].group2_score);
      group3Array[i] = Number(csv[i].group3_score);
      group4Array[i] = Number(csv[i].group4_score);
    }

    //Loop through every row of data
    for ( var i = 0; i < csv.length; i++ ) {
      var startRadius = 140,
          endRadius = startRadius;

      for ( var x = 0; x < 4; x++ ) {
        //Increment endRadius based on the data
        if ( x == 0 ) {
          endRadius += Number(csv[i].group1_score) * 4;
        } else if ( x == 1 ) {
          endRadius += Number(csv[i].group2_score) * 4;
        } else if ( x == 2 ) {
          endRadius += Number(csv[i].group3_score) * 4;
        } else {
          endRadius += Number(csv[i].group4_score) * 4;
        }

        //Create svg element (arc) with the calculated values
        var arc = d3.svg.arc()
                    .innerRadius(startRadius)
                    .outerRadius(endRadius)
                    .startAngle(angleSize * i)
                    .endAngle(angleSize * (i + 1));

        var className,
            ratingClass,
            studyName;

        if ( x == 0 ) {
          className = csv[i].group1_class;
          ratingClass = 'Group1';
        } else if ( x == 1 ) {
          className = csv[i].group2_class;
          ratingClass = 'Group2';
        } else if ( x == 2 ) {
          className = csv[i].group3_class;
          ratingClass = 'Group3';
        } else {
          className = csv[i].group4_class;
          ratingClass = 'Group4';
        }

        studyName = csv[i].study_name;

        var path = svg.append('path')
                      .attr({
                        'class' : className,
                        'd' : arc,
                        'company' : csv[i].brand_name,
                        'cat' : ratingClass,
                        'study' : studyName,
                        'startradius' : startRadius,
                        'endradius' : endRadius,
                        'startangle' : angleSize * i,
                        'endangle' : angleSize * (i + 1),
                        'companyid' : i
                      })
                     .on('click', selectStudy);

        startRadius = endRadius + 0.3;
      }
    }
  }
}

以下是我对具有数据连接的重构版本的尝试,但到目前为止我无法使其正常工作(我收到以下错误:<path> attribute d: Expected moveto path command ('M' or 'm'), "function n(){var…")。

var colors = {
  'rank1' : '#3FA548',
  'rank2' : '#00B09E',
  'rank3' : '#8971B3',
  'rank4' : '#DFC423',
  'rank5' : '#E74341'
};

var $container = $('.chart'),
    m = 40,
    width = $container.width() - m,
    height = $container.height() - m,
    r = Math.min(width, height) / 2;

var angleSize,
    study = null;

d3.csv('text.csv', ready);

function ready(err, data) {
  if (err) console.warn('Error', err);

  angleSize = (2 * Math.PI) / data.length;

  var dataByStudy = d3.nest()
                      .key(function(d) { return d.study_name; })
                      .entries(data); 

  var svg = d3.select('.chart')
              .append('svg')
              .attr({
                'width' : (r + m) * 2,
                'height' : (r + m) * 2,
                'class' : 'container'
              })
              .append('g')
              .attr('transform', 'translate(' + (width / 4) + ', ' + (height / 2) + ' )'); 

  var slice = svg.selectAll('.slice')
                 .data(dataByStudy)
                 .enter()
                 .append('g')
                 .attr('class', 'slice');

  var startRadius = 140,
      endRadius = startRadius;

  for ( var x = 0; x < 4; x++ ) {
    var path = slice.append('path')
                    .attr({
                      'd' : function(d, i) {
                        var arc = d3.svg.arc()
                                    .innerRadius(startRadius)
                                    .outerRadius(endRadius)
                                    .startAngle(angleSize * i)
                                    .endAngle(angleSize * (i + 1));

                        return arc;
                       },
                      'class' : function(d, i) {
                        if ( x == 0 ) {
                          return d.values[i].group1_class;
                        } else if ( x == 1 ) {
                          return d.values[i].group2_class;
                        } else if ( x == 2 ) {
                          return d.values[i].group3_class;
                        } else {
                          return d.values[i].group4_class;
                        }
                      },
                      'company' : function(d, i) {
                        return d.values[i].brand_name;
                      },
                      'cat' : function(d, i) {
                        if ( x == 0 ) {
                          return 'Mobile';
                        } else if ( x == 1 ) {
                          return 'Social';
                        } else if ( x == 2 ) {
                          return 'Digital Marketing';
                        } else {
                          return 'Site';
                        }
                      },
                      'study' : function(d, i) {
                        return d.values[i].study_name;
                      },
                      'endradius' : function(d, i) {
                        if ( x == 0 ) {
                          return endRadius += Number(d.values[i].group1_score) * 5;
                        } else if ( x == 1 ) {
                          return endRadius += Number(d.values[i].group2_score) * 5;
                        } else if ( x == 2 ) {
                          return endRadius += Number(d.values[i].group3_score) * 5;
                        } else {
                          return endRadius += Number(d.values[i].group4_score) * 5;
                        }
                      },
                      'startradius' : startRadius,
                      'startangle' : function(d, i) { 
                        return angleSize * i;
                      },
                      'endangle' : function(d, i) {
                        return angleSize * (i + 1);
                      },
                      'companyid' : function(d, i) {
                        return d.values[i].brand_id;
                      }
                    });

    startRadius = endRadius + 0.3
  }
}

有没有人知道我怎么能重构代码块B像Code Block A一样工作?谢谢。

1 个答案:

答案 0 :(得分:0)

在代码块A中,for循环遍历csv中的每一行,并且在另一个for循环中迭代四次(四个数据组中的每一个都重复一次)。移动所有这些功能(尤其是声明弧功能)是最令人困惑的部分。

进一步研究,我发现你可以创建弧函数:var arc = d3.svg.arc();并在处理了innerRadius,startAngle等后传递参数。

slice.selectAll('path')
   .attr({
     'd' : function(d) {
        return arc({
          innerRadius : //value,
          outerRadius : //value,
          startAngle : //value,
          endAngle : //value
        })
      }
   });

完整代码如下。谢谢,全部。

Array.prototype.max = function() { return Math.max.apply(null, this); };

Array.prototype.min = function() { return Math.min.apply(null, this); };

Number.prototype.map = function (in_min, in_max, out_min, out_max) {
  return (this - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

var colors = {
  'rank1' : '#3FA548',
  'rank2' : '#00B09E',
  'rank3' : '#8971B3',
  'rank4' : '#DFC423',
  'rank5' : '#E74341'
};

var $container = $('.chart'),
    m = 40,
    width = $container.width() - m,
    height = $container.height() - m,
    r = Math.min(width, height) / 2;

var angleSize,
    study = null;

var arc = d3.svg.arc();

d3.csv('text.csv', ready);

function ready(err, data) {
  if (err) console.warn('Error', err);

  var svg = d3.select('.chart')
              .append('svg')
              .attr({
                'width' : (r + m) * 2,
                'height' : (r + m) * 2,
                'class' : 'container'
              })
              .append('g')
              .attr('transform', 'translate(' + (width / 4) + ', ' + (height / 2) + ' )'); 

  angleSize = (2 * Math.PI) / data.length; 

  var slice = svg.selectAll('.slice')
                 .data(theData)
                 .enter()
                 .append('g')
                 .attr('class', 'slice');

  var startRadArr = [],
      endRadArr = [];

  for ( var i = 0; i < data.length; i++ ) {
    var startRadius = 140,
        endRadius = startRadius;

    for ( var x = 0; x < 4; x++ ) {
      startRadArr.push(startRadius);

      if ( x == 0 ) {
        endRadius += Number(data[i].group1_score) * 5;
      } else if ( x == 1 ) {
        endRadius += Number(data[i].group2_score) * 5;
      } else if ( x == 2 ) {
        endRadius += Number(data[i].group3_score) * 5;
      } else {
        endRadius += Number(data[i].group4_score) * 5;
      }

      endRadArr.push(endRadius);

      startRadius = endRadius + 0.3;
    }
  }

  var startRadGroup = [],
      endRadGroup = [];

  for (i = 0; i < startRadArr.length; i += 4) { 
    startRadGroup.push(startRadArr.slice(i, i + 4)); 
  }

  for (i = 0; i < endRadArr.length; i += 4) { 
    endRadGroup.push(endRadArr.slice(i, i + 4)); 
  }

  for ( var x = 0; x < 4; x++ ) {
    var path = slice.append('path')
                    .attr({
                      'class' : function(d, i) {
                        if ( x == 0 ) {
                          return d.group1_class;
                        } else if ( x == 1 ) {
                          return d.group2_class;
                        } else if ( x == 2 ) {
                          return d.group3_class;
                        } else {
                          return d.group4_class;
                        }
                      },
                      'company' : function(d, i) { 
                        return d.brand_name; 
                      },
                      'cat' : function(d, i) {
                        if ( x == 0 ) {
                          return 'Mobile';
                        } else if ( x == 1 ) {
                          return 'Social';
                        } else if ( x == 2 ) {
                          return 'Digital Marketing';
                        } else {
                          return 'Site';
                        }
                      },
                      'study' : function(d, i) { 
                        return d.study_name; 
                      },
                      'companyid' : function(d, i) { 
                        return d.brand_id; 
                      },
                      'startradius' : function(d, i) {
                        return startRadGroup[i][x];
                      },
                      'endradius' : function(d, i) {
                        return endRadGroup[i][x];
                      },
                      'startangle' : function(d, i) {
                        return angleSize * i;
                      },
                      'endangle' : function(d, i) {
                        return angleSize * (i + 1);
                      }
                    });
  }

  slice.selectAll('path')
       .attr({
         'd' : function(d) {
            return arc({
              innerRadius : +d3.select(this)[0][0].attributes.startradius.nodeValue,
              outerRadius : +d3.select(this)[0][0].attributes.endradius.nodeValue,
              startAngle : +d3.select(this)[0][0].attributes.startangle.nodeValue,
              endAngle : +d3.select(this)[0][0].attributes.endangle.nodeValue
            })
          }
       });
}