我正在尝试创建下面的图表:
每个'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一样工作?谢谢。
答案 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
})
}
});
}