Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Time slicing #638

Merged
merged 4 commits into from
Aug 25, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/components/tree/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import UnconnectedTree from "./tree";
const Tree = connect((state) => ({
tree: state.tree,
treeToo: state.treeToo,
dateMinNumeric: state.controls.dateMinNumeric,
dateMaxNumeric: state.controls.dateMaxNumeric,
quickdraw: state.controls.quickdraw,
colorBy: state.controls.colorBy,
colorByConfidence: state.controls.colorByConfidence,
Expand Down
29 changes: 19 additions & 10 deletions src/components/tree/phyloTree/change.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const updateNodesWithNewData = (nodes, newNodeProps) => {
* Note that only the relevant functions are called on a transition.
*/
const svgSetters = {
"attrs": {
attrs: {
".tip": {
r: (d) => d.r,
cx: (d) => d.xTip,
Expand All @@ -44,19 +44,20 @@ const svgSetters = {
d: (d) => d.confLine
}
},
"styles": {
styles: {
".tip": {
"fill": (d) => d.fill,
"stroke": (d) => d.tipStroke,
"visibility": (d) => d["visibility"]
fill: (d) => d.fill,
stroke: (d) => d.tipStroke,
visibility: (d) => d["visibility"]
},
".conf": {
"stroke": (d) => d.branchStroke,
stroke: (d) => d.branchStroke,
"stroke-width": calcConfidenceWidth
},
".branch": {
"stroke": (d) => d.branchStroke,
"stroke-width": (d) => d["stroke-width"] + "px" // style - as per drawBranches()
stroke: (d) => d.branchStroke,
"stroke-width": (d) => d["stroke-width"] + "px", // style - as per drawBranches()
cursor: (d) => d.visibility === "visible" ? "pointer" : "default"
}
}
};
Expand Down Expand Up @@ -149,7 +150,7 @@ export const modifySVG = function modifySVG(elemsToUpdate, svgPropsToUpdate, tra
this.updateTipLabels();
}
if (elemsToUpdate.has('.grid')) {
if (this.grid && this.layout !== "unrooted") this.addGrid(this.layout);
if (this.grid && this.layout !== "unrooted") this.addGrid();
else this.hideGrid();
}
if (elemsToUpdate.has('.regression')) {
Expand All @@ -171,6 +172,11 @@ export const modifySVG = function modifySVG(elemsToUpdate, svgPropsToUpdate, tra
}
}

/* background temporal time slice */
if (extras.timeSliceHasPotentiallyChanged) {
this.addTemporalSlice();
}

/* branch labels */
if (extras.newBranchLabellingKey) {
this.removeBranchLabels();
Expand All @@ -196,6 +202,7 @@ export const modifySVGInStages = function modifySVGInStages(elemsToUpdate, svgPr
this.svg.selectAll(".tip").remove();
this.drawTips();
if (this.vaccines) this.drawVaccines();
this.addTemporalSlice();
if (this.layout === "clock" && this.distance === "num_date") this.drawRegression();
if (elemsToUpdate.has(".branchLabel")) this.drawBranchLabels(this.params.branchLabelKey);
};
Expand All @@ -217,6 +224,7 @@ export const modifySVGInStages = function modifySVGInStages(elemsToUpdate, svgPr
.remove()
.on("start", () => inProgress++)
.on("end", step2);
this.removeTemporalSlice();
if (!transitionTimeFadeOut) timerFlush();
};

Expand Down Expand Up @@ -275,7 +283,7 @@ export const change = function change({
/* check that visibility is not undefined */
/* in the future we also change the branch visibility (after skeleton merge) */
elemsToUpdate.add(".tip");
svgPropsToUpdate.add("visibility");
svgPropsToUpdate.add("visibility").add("cursor");
nodePropsToModify.visibility = visibility;
}
if (changeTipRadii) {
Expand Down Expand Up @@ -335,6 +343,7 @@ export const change = function change({

/* Finally, actually change the SVG elements themselves */
const extras = {removeConfidences, showConfidences, newBranchLabellingKey};
extras.timeSliceHasPotentiallyChanged = changeVisibility || newDistance;
if (useModifySVGInStages) {
this.modifySVGInStages(elemsToUpdate, svgPropsToUpdate, transitionTime, 1000);
} else {
Expand Down
54 changes: 51 additions & 3 deletions src/components/tree/phyloTree/grid.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ export const hideGrid = function hideGrid() {
};

const addSVGGroupsIfNeeded = (groups, svg) => {
if (!("temporalWindow" in groups)) {
groups.temporalWindow = svg.append("g").attr("id", "temporalWindow");
}
if (!("majorGrid" in groups)) {
groups.majorGrid = svg.append("g").attr("id", "majorGrid");
}
Expand All @@ -41,8 +44,8 @@ const calculateMajorGridSeperation = (range) => {
* add a grid to the svg
* @param {layout}
*/
export const addGrid = function addGrid(layout) {
if (typeof layout==="undefined") {layout=this.layout;} // eslint-disable-line no-param-reassign
export const addGrid = function addGrid() {
const layout = this.layout;
addSVGGroupsIfNeeded(this.groups, this.svg);
if (layout==="unrooted") return;
timerStart("addGrid");
Expand Down Expand Up @@ -161,7 +164,6 @@ export const addGrid = function addGrid(layout) {

/* D3 commands to add grid + text to the DOM
Note that the groups were created the first time this function was called */

// add major grid to svg
this.groups.majorGrid.selectAll("*").remove();
this.groups.majorGrid
Expand Down Expand Up @@ -215,3 +217,49 @@ export const addGrid = function addGrid(layout) {
this.grid=true;
timerEnd("addGrid");
};


export const removeTemporalSlice = function removeTemporalSlice() {
this.groups.temporalWindow.selectAll("*").remove();
};

/**
* add background grey rectangles to demarcate the temporal slice
*/
export const addTemporalSlice = function addTemporalSlice() {
this.removeTemporalSlice();
if (this.layout !== "rect" || this.distance !== "num_date") return;

const xWindow = [this.xScale(this.dateRange[0]), this.xScale(this.dateRange[1])];
const height = this.yScale.range()[1];
const fill = "#EEE"; // this.params.minorGridStroke
const minPxThreshold = 30;
const rightHandTree = this.params.orientation[0] === -1;
const rootXPos = this.xScale(this.nodes[0].x);
let totalWidth = rightHandTree ? this.xScale.range()[0] : this.xScale.range()[1];
totalWidth += (this.params.margins.left + this.params.margins.right);

/* the gray region between the root (ish) and the minimum date */
if (Math.abs(xWindow[0]-rootXPos) > minPxThreshold) { /* don't render anything less than this num of px */
this.groups.temporalWindow.append("rect")
.attr("x", rightHandTree ? xWindow[0] : 0)
.attr("width", rightHandTree ? totalWidth-xWindow[0]: xWindow[0])
.attr("y", 0)
.attr("height", height)
.attr("fill", fill);
}

/* the gray region between the maximum selected date and the last tip */
const startingX = rightHandTree ? this.params.margins.right : xWindow[1];
const rectWidth = rightHandTree ?
xWindow[1]-this.params.margins.right :
totalWidth-this.params.margins.right-xWindow[1];
if (rectWidth > minPxThreshold) {
this.groups.temporalWindow.append("rect")
.attr("x", startingX)
.attr("width", rectWidth)
.attr("y", 0)
.attr("height", height)
.attr("fill", fill);
}
};
2 changes: 2 additions & 0 deletions src/components/tree/phyloTree/phyloTree.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,5 +91,7 @@ PhyloTree.prototype.updateTipLabels = labels.updateTipLabels;
/* G R I D */
PhyloTree.prototype.hideGrid = grid.hideGrid;
PhyloTree.prototype.addGrid = grid.addGrid;
PhyloTree.prototype.addTemporalSlice = grid.addTemporalSlice;
PhyloTree.prototype.removeTemporalSlice = grid.removeTemporalSlice;

export default PhyloTree;
10 changes: 7 additions & 3 deletions src/components/tree/phyloTree/renderers.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@ import { timerStart, timerEnd } from "../../../util/perf";
* @param {array|null} tipRadii -- array of tip radius'
* @return {null}
*/
export const render = function render(svg, layout, distance, parameters, callbacks, branchThickness, visibility, drawConfidence, vaccines, branchStroke, tipStroke, tipFill, tipRadii) {
export const render = function render(svg, layout, distance, parameters, callbacks, branchThickness, visibility, drawConfidence, vaccines, branchStroke, tipStroke, tipFill, tipRadii, dateRange) {
timerStart("phyloTree render()");
this.svg = svg;
this.params = Object.assign(this.params, parameters);
this.callbacks = callbacks;
this.vaccines = vaccines ? vaccines.map((d) => d.shell) : undefined;
this.dateRange = dateRange;

/* set x, y values & scale them to the screen */
this.setDistance(distance);
Expand All @@ -39,7 +40,10 @@ export const render = function render(svg, layout, distance, parameters, callbac
});

/* draw functions */
if (this.params.showGrid) this.addGrid();
if (this.params.showGrid) {
this.addGrid();
this.addTemporalSlice();
}
this.drawBranches();
this.drawTips();
if (this.params.branchLabelKey) this.drawBranchLabels(this.params.branchLabelKey);
Expand Down Expand Up @@ -162,7 +166,7 @@ export const drawBranches = function drawBranches() {
.style("stroke-linecap", "round")
.style("stroke-width", (d) => d['stroke-width']+"px" || params.branchStrokeWidth)
.style("fill", "none")
.style("cursor", "pointer")
.style("cursor", (d) => d.visibility === "visible" ? "pointer" : "default")
.style("pointer-events", "auto")
.on("mouseover", this.callbacks.onBranchHover)
.on("mouseout", this.callbacks.onBranchLeave)
Expand Down
4 changes: 4 additions & 0 deletions src/components/tree/reactD3Interface/callbacks.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { branchOpacityFunction } from "../../../util/colorHelpers";
/* Callbacks used by the tips / branches when hovered / selected */

export const onTipHover = function onTipHover(d) {
if (d.visibility !== "visible") return;
const phylotree = d.that.params.orientation[0] === 1 ?
this.state.tree :
this.state.treeToo;
Expand All @@ -18,6 +19,7 @@ export const onTipHover = function onTipHover(d) {
};

export const onTipClick = function onTipClick(d) {
if (d.visibility !== "visible") return;
// console.log("tip click", d)
this.setState({
hovered: null,
Expand All @@ -32,6 +34,7 @@ export const onTipClick = function onTipClick(d) {


export const onBranchHover = function onBranchHover(d) {
if (d.visibility !== "visible") return;
/* emphasize the color of the branch */
for (const id of ["#branch_S_" + d.n.clade, "#branch_T_" + d.n.clade]) {
if (this.props.colorByConfidence) {
Expand Down Expand Up @@ -64,6 +67,7 @@ export const onBranchHover = function onBranchHover(d) {
};

export const onBranchClick = function onBranchClick(d) {
if (d.visibility !== "visible") return;
const root = [undefined, undefined];
if (d.that.params.orientation[0] === 1) root[0] = d.n.arrayIdx;
else root[1] = d.n.arrayIdx;
Expand Down
4 changes: 4 additions & 0 deletions src/components/tree/reactD3Interface/change.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ export const changePhyloTreeViaPropsComparison = (mainTree, phylotree, oldProps,
const oldTreeRedux = mainTree ? oldProps.tree : oldProps.treeToo;
const newTreeRedux = mainTree ? newProps.tree : newProps.treeToo;

/* do any properties on the tree object need to be updated?
Note that updating properties itself won't trigger any visual changes */
phylotree.dateRange = [newProps.dateMinNumeric, newProps.dateMaxNumeric];

/* catch selectedStrain dissapearence seperately to visibility and remove modal */
if (oldTreeRedux.selectedStrain && !newTreeRedux.selectedStrain) {
/* TODO change back the tip radius */
Expand Down
4 changes: 2 additions & 2 deletions src/components/tree/reactD3Interface/initialRender.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ export const renderTree = (that, main, phylotree, props) => {
console.warn("can't run renderTree (not loaded)");
return;
}

/* simply the call to phylotree.render */
phylotree.render(
select(ref),
Expand Down Expand Up @@ -40,6 +39,7 @@ export const renderTree = (that, main, phylotree, props) => {
calcBranchStrokeCols(treeState, props.colorByConfidence, props.colorBy),
treeState.nodeColors,
treeState.nodeColors.map((col) => rgb(col).brighter([0.65]).toString()),
treeState.tipRadii /* might be null */
treeState.tipRadii, /* might be null */
[props.dateMinNumeric, props.dateMaxNumeric]
);
};
2 changes: 1 addition & 1 deletion src/util/treeVisibilityHelpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const calcBranchThickness = (nodes, visibility, rootIdx) => {
maxTipCount = 1;
}
return nodes.map((d, idx) => (
visibility[idx] === "visible" ? freqScale((d.tipCount + 5) / (maxTipCount + 5)) : 1
visibility[idx] === "visible" ? freqScale((d.tipCount + 5) / (maxTipCount + 5)) : 0.5
));
};

Expand Down