Skip to content

Commit

Permalink
prototype gradient along (stem) branches
Browse files Browse the repository at this point in the history
Inferred transitions from A-B (parent-child) are now represented as colour gradients from the parent to the child (previously the entire branch had the colour of the child, which could be misinterpreted to imply that the time of the transition was known). 

This requires using SVG rect(angles) for the branch stem as gradients are overly complex to add to paths. As such, lots of things are broken (e.g. all layouts except rect), and some functionality (branch hover colour changes, branch click to zoom) is disabled here.
  • Loading branch information
jameshadfield committed Feb 17, 2020
1 parent f9edbaa commit 21d6bbf
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 25 deletions.
3 changes: 2 additions & 1 deletion src/components/tree/phyloTree/layouts.js
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,8 @@ export const mapToScreen = function mapToScreen() {
const childrenY = [this.yScale(d.yRange[0]), this.yScale(d.yRange[1])];
d.branch =[
[` M ${d.xBase - stem_offset},${d.yBase} L ${d.xTip},${d.yTip}`],
[` M ${d.xTip},${childrenY[0]} L ${d.xTip},${childrenY[1]}`]
[` M ${d.xTip},${childrenY[0]} L ${d.xTip},${childrenY[1]}`],
[d.xBase - stem_offset, d.yBase, d.xTip, d.yTip] // TMP ONLY
];
if (this.params.confidence) {
d.confLine =` M ${this.xScale(d.conf[0])},${d.yBase} L ${this.xScale(d.conf[1])},${d.yTip}`;
Expand Down
45 changes: 40 additions & 5 deletions src/components/tree/phyloTree/renderers.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,21 +171,56 @@ export const drawBranches = function drawBranches() {
}

/* PART 2: draw the branch stems (i.e. the actual branches) */
if (!this.groups.branchGradientDefs) {
this.groups.branchGradientDefs = this.svg.append("defs");
}
this.groups.branchGradientDefs.selectAll("*").remove();
const gradients = {};
this.nodes.forEach((d) => {
const a = d.parent.branchStroke;
const b = d.branchStroke;
if (a===b) return;
const id = `${d.parent.n.arrayIdx}:${d.n.arrayIdx}`;
if (gradients[id]) return;
const linearGradient = this.groups.branchGradientDefs.append("linearGradient")
.attr("id", id)
.attr("x1", "0%")
.attr("x2", "100%")
.attr("y1", "0%")
.attr("y2", "0%");
linearGradient.append("stop")
.attr("offset", "0%")
.attr("stop-color", a);
linearGradient.append("stop")
.attr("offset", "100%")
.attr("stop-color", b);
});

if (!("branchStem" in this.groups)) {
this.groups.branchStem = this.svg.append("g").attr("id", "branchStem");
}
this.groups.branchStem
.selectAll('.branch')
.data(this.nodes)
.enter()
.append("path")
.append("rect")
.attr("x", (d) => d.branch[2][0])
.attr("y", (d) => d.branch[2][1]-0.5*(d['stroke-width'] || params.branchStrokeWidth))
.attr("width", (d) => d.branch[2][2] - d.branch[2][0])
.attr("height", (d) => d['stroke-width']+"px" || params.branchStrokeWidth)
.attr("class", "branch S")
.attr("id", (d) => getDomId("branchS", d.n.name))
.attr("d", (d) => d.branch[0])
.style("stroke", (d) => d.branchStroke || params.branchStroke)
.style("stroke-linecap", "round")
.style("stroke-width", (d) => d['stroke-width']+"px" || params.branchStrokeWidth)
.style("fill", "none")
.style("fill", (d) => {
if (!d.branchStroke) return params.branchStroke;
if (d.branchStroke === d.parent.branchStroke) {
return d.branchStroke;
}
return `url(#${d.parent.n.arrayIdx}:${d.n.arrayIdx})`;
})
// .style("stroke-linecap", "round")
// .style("stroke-width", (d) => d['stroke-width']+"px" || params.branchStrokeWidth)
.style("stroke", "none")
.style("visibility", getBranchVisibility)
.style("cursor", (d) => d.visibility === NODE_VISIBLE ? "pointer" : "default")
.style("pointer-events", "auto")
Expand Down
40 changes: 21 additions & 19 deletions src/components/tree/reactD3Interface/callbacks.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,22 +38,23 @@ export const onTipClick = function onTipClick(d) {

export const onBranchHover = function onBranchHover(d) {
if (d.visibility !== NODE_VISIBLE) return;
console.log(d)
/* emphasize the color of the branch */
for (const id of [getDomId("#branchS", d.n.name), getDomId("#branchT", d.n.name)]) {
if (this.props.colorByConfidence) {
this.state.tree.svg.select(id)
.style("stroke", (el) => { // eslint-disable-line no-loop-func
const entropyValue = getTraitFromNode(this.props.tree.nodes[el.n.arrayIdx], this.props.colorBy, {entropy: true});
const ramp = branchOpacityFunction(entropyValue);
const raw = this.props.tree.nodeColors[el.n.arrayIdx];
const base = el.branchStroke;
return rgb(interpolateRgb(raw, base)(ramp)).toString();
});
} else {
this.state.tree.svg.select(id)
.style("stroke", (el) => this.props.tree.nodeColors[el.n.arrayIdx]);
}
}
// for (const id of [getDomId("#branchS", d.n.name), getDomId("#branchT", d.n.name)]) {
// if (this.props.colorByConfidence) {
// this.state.tree.svg.select(id)
// .style("stroke", (el) => { // eslint-disable-line no-loop-func
// const entropyValue = getTraitFromNode(this.props.tree.nodes[el.n.arrayIdx], this.props.colorBy, {entropy: true});
// const ramp = branchOpacityFunction(entropyValue);
// const raw = this.props.tree.nodeColors[el.n.arrayIdx];
// const base = el.branchStroke;
// return rgb(interpolateRgb(raw, base)(ramp)).toString();
// });
// } else {
// this.state.tree.svg.select(id)
// .style("stroke", (el) => this.props.tree.nodeColors[el.n.arrayIdx]);
// }
// }
if (this.props.temporalConfidence.exists && this.props.temporalConfidence.display && !this.props.temporalConfidence.on) {
const tree = d.that.params.orientation[0] === 1 ? this.state.tree : this.state.treeToo;
if (!("confidenceIntervals" in tree.groups)) {
Expand All @@ -71,6 +72,7 @@ export const onBranchHover = function onBranchHover(d) {
};

export const onBranchClick = function onBranchClick(d) {
return;
if (d.visibility !== NODE_VISIBLE) return;
if (this.props.narrativeMode) return;
const root = [undefined, undefined];
Expand Down Expand Up @@ -102,10 +104,10 @@ export const onBranchClick = function onBranchClick(d) {

/* onBranchLeave called when mouse-off, i.e. anti-hover */
export const onBranchLeave = function onBranchLeave(d) {
for (const id of [getDomId("#branchT", d.n.name), getDomId("#branchS", d.n.name)]) {
this.state.tree.svg.select(id)
.style("stroke", (el) => el.branchStroke);
}
// for (const id of [getDomId("#branchT", d.n.name), getDomId("#branchS", d.n.name)]) {
// this.state.tree.svg.select(id)
// .style("stroke", (el) => el.branchStroke);
// }
if (this.props.temporalConfidence.exists && this.props.temporalConfidence.display && !this.props.temporalConfidence.on) {
const tree = d.that.params.orientation[0] === 1 ? this.state.tree : this.state.treeToo;
tree.removeConfidence();
Expand Down

0 comments on commit 21d6bbf

Please sign in to comment.