我想用d3js创建和弦图。这是我正在实现的示例代码:
SonataBlockBundle
以下是data.csv文件:
<script src="http://d3js.org/d3.v3.min.js"></script>
<body>
<svg width="960" height="960"></svg>
<script>
d3.text("data.csv", function(error, datas) {
var dataf = d3.csv.parseRows(datas);
dataf.shift();
var text = [];
var nest = d3.nest()
.key(function(d) { return d[1]; })
.entries(dataf)
.sort(function(a, b) { return a.key < b.key ? -1 : 1; });
nest.forEach(function(d) {
text.push(d.key);
});
nest = d3.nest()
.key(function(d) { return d[2]; })
.entries(dataf)
.sort(function(a, b) { return a.key < b.key ? -1 : 1; });
nest.forEach(function(d) {
text.push(d.key);
});
var textnested = [];
d3.nest()
.key(function(d) { return d; })
.entries(text)
.forEach(function(d) {
textnested.push(d.key);
});
if(textnested.length < text.length) {
var inDirection = 1;
text = textnested;
text.sort(function(a, b) { return a < b ? -1 : 1; });
}
nest = d3.nest()
.key(function(d) { return d[0]; })
.entries(dataf);
if(nest.length < dataf.length) {
nest.forEach(function(d) {
d.values.forEach(function(e) { e.push(1/d.values.length); });
});
}
var matrix = [];
text.forEach(function(d, i) {
matrix[i] = d3.range(text.length).map(function() { return 0; });
});
dataf.forEach(function(d) {
var x = text.indexOf(d[1]),
y = text.indexOf(d[2]);
if(nest.length < dataf.length) matrix[x][y]+=d[d.length-1];
else matrix[x][y]++;
if(!inDirection) {
if(nest.length < dataf.length) matrix[y][x]+=d[d.length-1];
else matrix[y][x]++;
}
});
var chord = d3.layout.chord()
.padding(.04)
.matrix(matrix);
var svg = d3.select("svg")
.append("g")
.attr("transform", "translate(480, 480)");
var fill = d3.scale.category20();
var g = svg.selectAll(".group")
.data(chord.groups)
.enter()
.append("g")
.attr("class", "group");
g.append("path")
.attr("d", d3.svg.arc().innerRadius(350).outerRadius(370))
.style("fill", function(d) { return fill(d.index); })
.on("mouseover", standOut(0.1))
.on("mouseout", standOut(1));
g.append("text")
.attr("transform", function(d) {
return "rotate("+(((d.startAngle+d.endAngle)/2) * (180/Math.PI) - 90)+")"
+ "translate(376)" + (((d.startAngle+d.endAngle)/2) > Math.PI ? "rotate(180)" : ""); })
.attr("text-anchor", function(d) { return ((d.startAngle+d.endAngle)/2) > Math.PI ? "end" : ""; })
.text(function(d) { return text[d.index]; });
svg.selectAll(".chord")
.data(chord.chords)
.enter()
.append("path")
.attr("class", "chord")
.attr("d", d3.svg.chord().radius(350))
.style("fill", function(d) { return fill(d.source.index); })
.style("stroke", function(d) { return d3.rgb(fill(d.source.index)).darker(); });
function standOut(o) {
return function(d, i) {
var gstandout = [];
svg.selectAll(".chord")
.each(function(e) { e.source.index == i ? gstandout.push(e.target.index) : e.target.index == i ? gstandout.push(e.source.index) : ""; })
.filter(function(e) { return e.source.index != i && e.target.index != i; })
.style("opacity", o);
svg.selectAll(".group")
.filter(function(e, j) { return gstandout.indexOf(j) == -1 && j != i; })
.style("opacity", o);
};
}
});
</script>
</body>
但我想用椭圆形而不是圆形来表示和弦。有人知道怎么可能吗?非常感谢您的帮助。
答案 0 :(得分:0)
首先,和弦不是绘制成圆形,而是绘制在图形中心有一个控制点的贝塞尔曲线(哪种看起来像圆圈)。我建议将两个控制点放在靠近边缘的地方,以获得一个类似椭圆的&#34;效果。
我不确定如何从头开始绘制这样的弧,但是可以在绘制路径后编辑路径的d
属性。
这是我的editPath
功能:
function editPath() {
var ratio = 0.6;
var path=d3.select(this).attr("d")
console.log(path);
find=path.match(/([\-\.0-9]+)\,([\-\.0-9]+)Q 0,0 ([\-\.0-9]+),([\-\.0-9]+)/);
if (!find) return;
path=path.replace(/Q 0,0/,"C "+find[1]*ratio+","+find[2]*ratio+" "+find[3]*ratio+","+find[4]*ratio);
console.log(path);
d3.select(this).attr("d", path)
}
此功能执行以下操作:
path
)Q
0,0
)
find
)C
)这只替换了路径中的一条贝塞尔曲线,因此您需要为每个和弦调用两次:
[...]
.attr("class", "chord")
.attr("d", d3.svg.chord().radius(350))
.each(editPath).each(editPath) //call twice!
我在此示例中对此进行了测试:http://bl.ocks.org/mbostock/raw/4062006/ ...它在那里工作,我希望它可以使用d3.svg.chord
在任何图表上工作。