2016-08-15 53 views
0

我试图创建下表:数据连接在D3旭日形图

enter image description here

每个“片”代表一个研究中,每行是在研究中发现的一个品牌。

我收到以下代码以添加转换(请参阅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像代码块A一样工作?谢谢。

回答

0

在代码块A中,用于通过在CSV每一行循环迭代,和内部的另一个用于循环迭代四次(一次对四个数据组)。中移动所有这些功能(特别声明弧功能)是最令人困惑的部分。

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

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

Full code is below。谢谢,所有。

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