我正在制作D3和弦图,并希望具有更新功能。
这是我目前拥有的代码
// Genres, check de readme daar staat visueel hoe je dit uitleest.
var data = [
[9962, 1196, 94, 93, 18],
[1196, 9102, 11, 343, 169],
[94, 11, 7143, 138, 32],
[93, 343, 138, 6440, 75],
[18, 169, 32, 75, 4886]
]
var genres = ["Psychologischverhaal", "Thriller", "Detective", "Romantischverhaal", "Sciencefiction"]
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
outerRadius = Math.min(width, height) * 0.5 - 40,
innerRadius = outerRadius - 30;
// Zet getallen naar 1K ipv 1000
var formatValue = d3.formatPrefix(",.0", 1e3);
var chord = d3.chord()
.padAngle(0.05)
.sortSubgroups(d3.ascending);
var arc = d3.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
var ribbon = d3.ribbon()
.radius(innerRadius);
var color = d3.scaleOrdinal()
.range(["#ed0b0b", "#03aa24", "#f2ae04", "#1f03f1", "#e1ed04"]);
var g = svg.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
.datum(chord(data));
var group = g.append("g")
.attr("class", "groups")
.selectAll("g")
.data(function(chords) { return chords.groups; })
.enter().append("g");
group.append("path")
.style("fill", function(d) { return color(d.index); })
.style("stroke", function(d) { return d3.rgb(color(d.index)).darker(); })
.attr("id", function(d, i) { return "group" + d.index; })
.attr("d", arc)
.on("mouseover", fade(.1))
.on("mouseout", fade(1));
group.append("title").text(function(d) {
return groupTip(d);
});
group.append("text")
.attr("x", 6)
.attr("dy", 15)
.append("textPath")
.attr("xlink:href", function(d) { return "#group" + d.index; })
.text(function(chords, i){return genres[i];})
.style("fill", "black");
var groupTick = group.selectAll(".group-tick")
.data(function(d) { return groupTicks(d, 1e3); })
.enter().append("g")
.attr("class", "group-tick")
.attr("transform", function(d) { return "rotate(" + (d.angle * 180 / Math.PI - 90) + ") translate(" + outerRadius + ",0)"; });
groupTick.append("line")
.attr("x1", 1)
.attr("y1", 0)
.attr("x2", 5)
.attr("y2", 0)
.style("stroke", "#000")
groupTick
.filter(function(d) { return d.value % 1e3 === 0; })
.append("text")
.attr("x", 8)
.attr("dy", ".35em")
.attr("transform", function(d) { return d.angle > Math.PI ? "rotate(180) translate(-16)" : null; })
.style("text-anchor", function(d) { return d.angle > Math.PI ? "end" : null; })
.text(function(d) { return formatValue(d.value); });
var ribbons = g.append("g")
.attr("class", "ribbons")
.selectAll("path")
.data(function(chords) { return chords; })
.enter().append("path")
.attr("d", ribbon)
.style("fill", function(d) { return color(d.target.index); })
.style("stroke", function(d) { return d3.rgb(color(d.target.index)).darker(); })
ribbons.append("title").
text(function(d){return chordTip(d);});
// Returns an array of tick angles and values for a given group and step.
function groupTicks(d, step) {
var k = (d.endAngle - d.startAngle) / d.value;
return d3.range(0, d.value, step).map(function(value) {
return {value: value, angle: value * k + d.startAngle};
});
}
function fade(opacity) {
return function(d, i) {
ribbons
.filter(function(d) {
return d.source.index != i && d.target.index != i;
})
.transition()
.style("opacity", opacity);
};
}
function chordTip(d){
var j = d3.formatPrefix(",.0", 1e1)
return "Aantal boeken met genres:\n"
+ genres[d.target.index] + " en " + genres[d.source.index] + ": " + j(d.source.value)
}
function groupTip(d) {
var j = d3.formatPrefix(",.0", 1e1)
return "Totaal aantal boeken met het genre " + genres[d.index] + ":\n" + j(d.value)
}
和
<body>
<h1>Boeken met enkele & dubbele genres</h1>
<button id="doubleGenre">Alleen dubbele genres</button>
<button id="reset">Reset</button>
<svg width="960" height="900"></svg>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="assets/index.js"></script>
我想在用户单击按钮 Alleen dubbele流派时更新和弦,所以它变成这样:
所以我想自行删除和弦,因此数据看起来像:
var data = [
[1196, 94, 93, 18],
[1196, 11, 343, 169],
[94, 11, 138, 32],
[93, 343, 138, 75],
[18, 169, 32, 75]
]
如果用户点击重置按钮,我想回到原始视图。有谁可以帮助我吗?
答案 0 :(得分:1)
这里是指向您的示例的简化版本的链接,其中包含以下转换:https://stackblitz.com/edit/q53412789
如果要删除自身的和弦,则应将对角线上的值替换为零(而不仅仅是删除它们:矩阵必须保持正方形):
const data2 = [
[0, 1196, 94, 93, 18],
[1196, 0, 11, 343, 169],
[94, 11, 0, 138, 32],
[93, 343, 138, 0, 75],
[18, 169, 32, 75, 0]
]
就像@ rioV8所建议的那样,第一步是将用于绘制和更新图表的代码包装到一个函数中(为了简洁起见,我省略了代码,为了简洁起见,它们的原理是相同的):
var g = svg.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
var ribbons = g.append("g");
function update(data) {
const chords = chord(data);
const ribbonsUpdate = ribbons.selectAll("path")
.data(chords, ({source, target}) => source.index + '-' + target.index)
const duration = 3000;
ribbonsUpdate
.transition()
.duration(duration)
.attr("d", ribbon)
.style("fill", function(d) { return color(d.target.index); })
.style("stroke", function(d) { return d3.rgb(color(d.target.index)).darker(); })
ribbonsUpdate
.enter()
.append("path")
.attr("opacity", 0)
.attr("d", ribbon)
.style("fill", function(d) { return color(d.target.index); })
.style("stroke", function(d) { return d3.rgb(color(d.target.index)).darker(); })
.transition()
.duration(duration)
.attr('opacity', 1)
ribbonsUpdate
.exit()
.transition()
.duration(duration)
.attr("opacity", 0)
.remove();
}
update(data1);
我已将代码中的.datum(val)
和.data(fun)
的组合替换为单个.data(vals)
。这不是必需的,但我认为后者在d3社区中更为常见。
.data
的第二个参数是键函数。它可以确保在过渡期间,每个路径在新数据中都映射到自身(和弦数不相等:我们删除了自身的和弦)。
如果不需要动画过渡,则代码甚至更简单:
function simpleUpdate(data) {
const chords = chord(data);
const ribbonsUpdate = ribbons.selectAll("path")
.data(chords, ({source, target}) => source.index + '-' + target.index)
ribbonsUpdate
.enter().append("path")
.merge(ribbonsUpdate)
.attr("d", ribbon)
.style("fill", function(d) { return color(d.target.index); })
.style("stroke", function(d) { return d3.rgb(color(d.target.index)).darker(); })
ribbonsUpdate.exit().remove();
}