提问人:Ssylvia 提问时间:3/14/2023 最后编辑:Mr. PolywhirlSsylvia 更新时间:3/14/2023 访问量:30
从chorddiag交互式图表输出基因列表
Output list of genes from chorddiag interactive diagram
问:
我们目前正在实验室中探索 ChordDiag,以更好地显示大型蛋白质组学和 CRISPR 筛选数据集。图表的初始显示似乎效果很好。但是,我们有一些基本问题:chorddiag 是否内置了任何函数,允许与图表交互的用户单击给定的和弦并输出结果比较的列表或 CSV?也就是说,如果单击连接数据集 A 和数据集 B 的和弦,它会给出重叠值的输出吗?我们已经浏览了 chorddiag 文档,但没有看到任何明显的东西。如果这是我们必须自己构建的东西,那很好 - 我们只是想在意外重新发明轮子之前确定一下。
干杯!
这是目前的图表。我们有兴趣确定某种方法,通过这种方法,我们单击突出显示的和弦并查看由该和弦表示的重叠项目的精确列表(即数据集 A 和数据集 B 之间的重叠项目)。
答:
1赞
Mr. Polywhirl
3/14/2023
#1
您可以为每个和弦添加一个处理程序(又名“丝带”):click
const matrixToCsv = (matrix, delimiter = ',') =>
matrix.map(row => row.join(delimiter)).join('\n');
.on("click", function(d) {
const { source, target } = d;
const csv = matrixToCsv([
'source,target,value'.split(','),
[office[source.index], office[target.index], target.value],
[office[target.index], office[source.index], source.value]])
console.log(csv);
});
单击和弦后,源/目标/值的 CSV 数据将打印到控制台。
完整示例
下面是一个完整的和弦图的修改版本。我将点击处理程序(如上所示)添加到跨组之间的和弦(又名“丝带”)中。
// Source: https://stackoverflow.com/a/43778409/1762224
function fade(opacity) {
return function(d, i) {
ribbons
.filter(function(d) {
return d.source.index != i && d.target.index != i;
})
.transition()
.style("opacity", opacity);
};
}
/********************************/
var matrix = [
[11975, 5871, 8916, 2868],
[ 1951, 10048, 2060, 6171],
[ 8010, 16145, 8090, 8045],
[ 1013, 990, 940, 6907]
];
var office = ["A", "B", "C", "D"]
//Initialize canvas and inner/outer radii of the chords
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height"),
outerRadius = Math.min(width, height) * 0.5 - 65,
innerRadius = outerRadius - 20;
//Set number format to show $M for millions with thousands separator (i.e. $1,000M).
var formatValue = d3.formatPrefix("$,.0", 1e3);
// Initialize chord diagram
var chord = d3.chord()
.padAngle(0.05)
.sortSubgroups(d3.descending);
// Set Arc Raddii
var arc = d3.arc()
.innerRadius(innerRadius)
.outerRadius(outerRadius);
// Set Ribbbons
var ribbon = d3.ribbon()
.radius(innerRadius);
// Initialize colors to an ordinal scheme with 10 categories
var color = d3.scaleOrdinal(d3.schemeCategory10);
// Center origin
var g = svg.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")")
.datum(chord(matrix));
// Defines each "group" in the chord diagram
var group = g.append("g")
.attr("class", "groups")
.selectAll("g")
.data(function(chords) {
return chords.groups;
})
.enter().append("g")
// Draw the radial arcs for each group
group.append("path")
.style("fill", function(d) {
return color(d.index);
})
.style("stroke", function(d) {
return d3.rgb(color(d.index)).darker();
})
.attr("d", arc)
.on("mouseover", fade(.1))
.on("mouseout", fade(1))
group.append("title").text(function(d) {
return groupTip(d);
});
// Add labels to each group
group.append("text")
.attr("dy", ".35em") // Width
.attr("class", "office-label")
.attr("transform", function(d, i) { // Angle
d.angle = (d.startAngle + d.endAngle) / 2; // Calculate the average of the start angle and the end angle
d.name = office[i]; // Assignment for the city
return "rotate(" + (d.angle * 180 / Math.PI) + ")" +
"translate(0," + -1.1 * (outerRadius + 30) + ")" +
((d.angle > Math.PI * 3 / 4 && d.angle < Math.PI * 5 / 4) ? "rotate(180)" : "");
}) // To spin when the angle between 135 to 225 degrees
.text(function(d) {
return d.name;
});
const matrixToCsv = (matrix, delimiter = ',') =>
matrix.map(row => row.join(delimiter)).join('\n');
// Draw the ribbons that go from group to group
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();
})
.on("click", function(d) {
const { source, target } = d;
const csv = matrixToCsv([
'source,target,value'.split(','),
[office[source.index], office[target.index], target.value],
[office[target.index], office[source.index], source.value]
])
console.log(csv);
});
ribbons.append("title").
text(function(d) {
return chordTip(d);
});
// Define tick marks to run along each arc
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("x2", 6);
groupTick
.filter(function(d) {
return d.value % 2e3 === 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);
});
// 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 chordTip(d) {
var p = d3.format(".2%"),
q = d3.formatPrefix("$,.2", 1e3)
return "Flow Info:\n" +
office[d.source.index] + " → " + office[d.target.index] + ": " + q(d.target.value) + "\n" +
office[d.target.index] + " → " + office[d.source.index] + ": " + q(d.source.value);
}
function groupTip(d) {
var q = d3.formatPrefix("$,.2", 1e3)
return "Total Managed by " + office[d.index] + ":\n" + q(d.value)
}
body {
font: 10px sans-serif;
}
.group-tick line {
stroke: #000;
}
.office-label {
font-size: 25px;
font: sans-serif;
text-anchor: middle;
}
.ribbons {
fill-opacity: 0.6;
}
<script src="https://d3js.org/d3.v4.js"></script>
<svg width="450" height="450"></svg>
评论
0赞
Ssylvia
3/14/2023
谢谢你 - 真的很有帮助的起点。我们将尝试一下,看看 CSV 或嵌入式表格是否最有意义。
评论