很长时间用户第一次在这里提问(第一次我无法使用我搜索到的答案来解决问题)。我用自己的数据在JS D3中重建了超级和弦图表。我的实现可以找到here,虽然该地址可能永远不会保持良好,所以这里是代码(原谅一些错位):
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script type="text/javascript" src="d3/d3.js"></script>
<script type="text/javascript" src="d3/d3.layout.js"></script>
<link type="text/css" rel="stylesheet" href="style.css"/>
</head>
<body>
<div id="body">
<div id="footer">
Purdue OIR Testing - Migration
<div class="hint">mouseover groups to highlight</div>
</div>
</div>
<div id="tooltip"></div>
<script type="text/javascript">
//import the data and call the draw chords function
d3.text("migrationdata.csv", function(data) {
var matrix = d3.csv.parseRows(data).map(function(row) {
return row.map(function(value) {
return +value;
});
});
d3.text("headersColors.csv", function(headerdata) {
var headersColors = d3.csv.parseRows(headerdata);
var headers = headersColors[1];
var colors = headersColors[2];
drawChords(matrix, headers, colors);
});
});
//create the chord viz
function drawChords (matrix, headers, colors){
var w = 980,
h = 800,
r1 = h / 2,
r0 = r1 - 110,
fadeOutA = 0,
fadeInA = 0.8;
var fill = d3.scale.category20c();
var chord = d3.layout.chord()
.padding(.02)
.sortSubgroups(d3.descending)
.sortChords(d3.descending);
var arc = d3.svg.arc()
.innerRadius(r0)
.outerRadius(r0 + 20);
var svg = d3.select("body").append("svg:svg")
.attr("width", w)
.attr("height", h)
.append("svg:g")
.attr("id", "circle")
.attr("transform", "translate(" + w / 2 + "," + h / 2 + ")");
svg.append("circle")
.attr("r", r0 + 20);
//.attr("fill-opacity",0);
//assign the matrix
chord.matrix(matrix);
//create the groups
var g = svg.selectAll("g.group")
.data(chord.groups)
.enter().append("svg:g")
.attr("class", "group")
.on("mouseover", mouseover)
.on("mouseout", function (d) { d3.select("#tooltip").style("visibility", "hidden") });
g.append("svg:path")
.style("stroke", function(d) { return colors[d.index]; })
.style("fill", function(d) { return colors[d.index]; })
.attr("d", arc);
g.append("svg:text")
.each(function(d) { d.angle = (d.startAngle + d.endAngle) / 2; })
.attr("dy", ".35em")
.attr("text-anchor", function(d) { return d.angle > Math.PI ? "end" : null; })
.attr("transform", function(d) {
return "rotate(" + (d.angle * 180 / Math.PI - 90) + ")"
+ "translate(" + (r0 + 26) + ")"
+ (d.angle > Math.PI ? "rotate(180)" : "");
})
.text(function(d) { return headers[d.index]; });
var chordPaths = svg.selectAll("path.chord")
.data(chord.chords)
.enter().append("svg:path")
.attr("class", "chord")
.style("stroke", function(d) { return d3.rgb(colors[d.source.index]).darker(); })
.style("fill", function(d) { return colors[d.source.index]; })
.attr("d", d3.svg.chord().radius(r0))
.on("mouseover", function (d) {
d3.select("#tooltip")
.style("visibility","visible")
.html(chordTip(d))
.style("left", (d3.event.pageX - 100) + "px")
.style("top", (d3.event.pageY - 100) + "px");
})
.on("mouseout", function (d) { d3.select("#tooltip").style("visibility", "hidden") });
function chordTip (d) {
var p = d3.format(".1%"), q = d3.format(",.2r")
return "Migration Info:<br/>"
+ headers[d.source.index] + " → " + headers[d.target.index]
+ ": " + Math.round(d.source.value) + "<br/>"
+ headers[d.target.index] + " → " + headers[d.source.index]
+ ": " + Math.round(d.target.value) + "<br/>";
}
function groupTip (d) {
return "College Info:<br/>"
+ headers[d.index] + " : " + Math.round(d.value) + "<br/>";
}
function mouseover(d, i) {
d3.select("#tooltip")
.style("visibility", "visible")
.html(groupTip(d))
.style("top", function () { return (d3.event.pageY - 80)+"px"})
.style("left", function () { return (d3.event.pageX - 130)+"px";})
chordPaths.classed("fade", function(p) {
return p.source.index != i
&& p.target.index != i;
});
}
}
// Returns an event handler for fading a given chord group.
function fade(opacity) {
return function(d, i) {
svg.selectAll("path.chord")
.filter(function(d) { return d.source.index != i && d.target.index != i; })
.transition()
.style("stroke-opacity", opacity)
.style("fill-opacity", opacity);
};
}
</script>
</body>
</html>
这很好用,功能齐全。它显示了2012年秋季至2013年秋季学院之间的学生运动(我计划在屏幕上做出更好的解释)。我的下一步是让这个可钻孔。因此,举例来说,如果你点击一所大学,我想把这所大学扩展到各个部门,并展示各个部门之间的和弦,以及#34;其他&#34;这将是所有其他学院的组合。此外,您将能够以相同的方式深入到部门以获得主要细节。我拥有完成此操作所需的所有原始数据,并且我非常自信地知道如何在单击某个组时动态创建新矩阵。
我的问题是,如果我只是将当前的viz转换为每次都有新数据的新视频,那么我上面描述的内容就相当简单,但这将是一个严峻的过渡。我喜欢像this这样的动画。但是,该示例仅在转换的每一端的矩阵大小相同时才有效。由于我希望如何深入研究这些数据,对我来说并非总是如此。我可以拥有比以前更少或更多的组/和弦。我的问题是,如果我使用比当前屏幕更大/更小的矩阵创建新的和弦布局,我能否以某种方式平滑地为/新的/不需要的组/和弦制作动画?如果是这样,我将如何解决这个问题,那里有任何例子吗?
我对D3仍然相当新,但我正在努力学习,因为这些类型的可视化对此有很多需求。如果有一个关于这个的教程可以随意链接它,我现在已经开启和关闭了几天,并且没有找到任何令人满意的解释如何在d3中顺利添加/删除元素布局。
答案 0 :(得分:1)
为了回答这个问题,我使用了AmeliaBR对这个问题的出色答案:here
我对此解决方案做了一些更改:
首先,我更新了组出口以获得起始不透明度。它的编码方式,如果我使用属性而不是样式,那么退出的任何内容都会弹出而不是淡出,因为转换需要一个起始属性值而无法获取当前值:
groupG.exit()
.attr("fill-opacity", 1)
.attr("stroke-opacity", 1)
.transition()
.duration(300)
//change fill and stroke opacity to avoid CSS conflicts
.attr("fill-opacity", 0)
.attr("stroke-opacity", 0)
.remove(); //remove after transitions are complete
这确实会导致褪色的和弦在动画过程中快速淡化和淡化,但它看起来比弹出更平滑,所以我保留了它。
另外,我在IE中遇到了问题,特别是因为我们在校园中安装的IE默认文件模式为IE7,而你至少需要IE9才能工作。它只需要一行代码来强制进行此更改:
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
此外,指针事件在IE11之前的IE中不起作用,我在示例中使用了div工具提示而不是工具提示,因此我需要将工具提示设置得远离鼠标,用户不会触摸它。这是一个......不太优雅的解决方案,我想找到一个更好的解决方案,但它可能不值得花时间。
我的最终解决方案可以找到here。我打算更新这个,1)解读一些不必要的和弦重叠和2)使我的数据更新功能与模板数据集一起工作,而不是我为此目的创建的一个特定数据集。