Skip to content

Commit

Permalink
🚧 Add types to tree component
Browse files Browse the repository at this point in the history
  • Loading branch information
victorlin committed Oct 8, 2024
1 parent 3cd0c1e commit 34d10ba
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { NODE_VISIBLE } from "../../../util/globals";
import { getBranchVisibility, strokeForBranch } from "./renderers";
import { shouldDisplayTemporalConfidence } from "../../../reducers/controls";
import { makeTipLabelFunc } from "./labels";
import { PhyloTree } from "./phyloTree";

/* loop through the nodes and update each provided prop with the new value
* additionally, set d.update -> whether or not the node props changed
Expand Down Expand Up @@ -199,7 +200,7 @@ export const modifySVG = function modifySVG(elemsToUpdate, svgPropsToUpdate, tra
* step 2: when step 1 has finished, move tips across the screen.
* step 3: when step 2 has finished, redraw everything. No transition here.
*/
export const modifySVGInStages = function modifySVGInStages(elemsToUpdate, svgPropsToUpdate, transitionTimeFadeOut, transitionTimeMoveTips, extras) {
export const modifySVGInStages = function modifySVGInStages(this: PhyloTree, elemsToUpdate, svgPropsToUpdate, transitionTimeFadeOut, transitionTimeMoveTips, extras) {
elemsToUpdate.delete(".tip");
this.hideGrid();
let inProgress = 0; /* counter of transitions currently in progress */
Expand Down Expand Up @@ -243,35 +244,63 @@ export const modifySVGInStages = function modifySVGInStages(elemsToUpdate, svgPr
* simply call change and tell it what should be changed.
* try to do a single change() call with as many things as possible in it
*/
export const change = function change({
/* booleans for what should be changed */
changeColorBy = false,
changeVisibility = false,
changeTipRadii = false,
changeBranchThickness = false,
showConfidences = false,
removeConfidences = false,
zoomIntoClade = false,
svgHasChangedDimensions = false,
animationInProgress = false,
changeNodeOrder = false,
/* change these things to provided value (unless undefined) */
newDistance = undefined,
newLayout = undefined,
updateLayout = undefined, // todo - this seems identical to `newLayout`
newBranchLabellingKey = undefined,
showAllBranchLabels = undefined,
newTipLabelKey = undefined,
/* arrays of data (the same length as nodes) */
branchStroke = undefined,
tipStroke = undefined,
fill = undefined,
visibility = undefined,
tipRadii = undefined,
branchThickness = undefined,
/* other data */
scatterVariables = undefined
}) {
export interface ChangeParams {
changeColorBy?: boolean
changeVisibility?: boolean
changeTipRadii?: boolean
changeBranchThickness?: boolean
showConfidences?: boolean
removeConfidences?: boolean
zoomIntoClade?: boolean
svgHasChangedDimensions?: boolean
animationInProgress?: boolean
changeNodeOrder?: boolean
newDistance?: any
newLayout?: any
updateLayout?: any
newBranchLabellingKey?: any
showAllBranchLabels?: any
newTipLabelKey?: any
branchStroke?: any[]
tipStroke?: any[]
fill?: any[]
visibility?: any[]
tipRadii?: any[]
branchThickness?: any[]
scatterVariables?: any
}

export const change = function change(params: ChangeParams) {
const {
/* booleans for what should be changed */
changeColorBy = false,
changeVisibility = false,
changeTipRadii = false,
changeBranchThickness = false,
showConfidences = false,
removeConfidences = false,
zoomIntoClade = false,
svgHasChangedDimensions = false,
animationInProgress = false,
changeNodeOrder = false,
/* change these things to provided value (unless undefined) */
newDistance = undefined,
newLayout = undefined,
updateLayout = undefined, // todo - this seems identical to `newLayout`
newBranchLabellingKey = undefined,
showAllBranchLabels = undefined,
newTipLabelKey = undefined,
/* arrays of data (the same length as nodes) */
branchStroke = undefined,
tipStroke = undefined,
fill = undefined,
visibility = undefined,
tipRadii = undefined,
branchThickness = undefined,
/* other data */
scatterVariables = undefined
} = params;

// console.log("\n** phylotree.change() (time since last run:", Date.now() - this.timeLastRenderRequested, "ms) **\n\n");
timerStart("phylotree.change()");
const elemsToUpdate = new Set(); /* what needs updating? E.g. ".branch", ".tip" etc */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,69 @@ import * as confidence from "./confidence";
import * as labels from "./labels";
import * as regression from "./regression";

interface ReduxNode {
inView?: boolean
name: string
shell?: PhyloNode
}

interface PhyloNode {
that: PhyloTree
n: ReduxNode
x: number
y: number
inView: boolean
}

export interface PhyloTree {
grid: boolean
attributes: string[]
params: ReturnType<typeof createDefaultParams>
groups: Record<string, any>
id: string
nodes: PhyloNode[]
zoomNode: PhyloNode
strainToNode: Record<string, PhyloNode>
change: typeof change
modifySVG: typeof modifySVG
modifySVGInStages: typeof modifySVGInStages
render: typeof renderers.render
clearSVG: typeof renderers.clearSVG
setClipMask: typeof renderers.setClipMask
drawTips: typeof renderers.drawTips
drawBranches: typeof renderers.drawBranches
drawVaccines: typeof renderers.drawVaccines
drawRegression: typeof renderers.drawRegression
removeRegression: typeof renderers.removeRegression
updateColorBy: typeof renderers.updateColorBy
setDistance: typeof layouts.setDistance
setLayout: typeof layouts.setLayout
rectangularLayout: typeof layouts.rectangularLayout
scatterplotLayout: typeof layouts.scatterplotLayout
unrootedLayout: typeof layouts.unrootedLayout
radialLayout: typeof layouts.radialLayout
setScales: typeof layouts.setScales
mapToScreen: typeof layouts.mapToScreen
calculateRegression: typeof regression.calculateRegression
removeConfidence: typeof confidence.removeConfidence
drawConfidence: typeof confidence.drawConfidence
drawSingleCI: typeof confidence.drawSingleCI
drawBranchLabels: typeof labels.drawBranchLabels
removeBranchLabels: typeof labels.removeBranchLabels
updateBranchLabels: typeof labels.updateBranchLabels
updateTipLabels: typeof labels.updateTipLabels
removeTipLabels: typeof labels.removeTipLabels
hideGrid: typeof grid.hideGrid
addGrid: typeof grid.addGrid
showTemporalSlice: typeof grid.showTemporalSlice
hideTemporalSlice: typeof grid.hideTemporalSlice

confidencesInSVG: boolean
regression: regression.Regression
}

/* phylogenetic tree drawing function - the actual tree is rendered by the render prototype */
const PhyloTree = function PhyloTree(reduxNodes, id, idxOfInViewRootNode) {
const PhyloTree = function PhyloTree(this: PhyloTree, reduxNodes: ReduxNode[], id: string, idxOfInViewRootNode: number) {
this.grid = false;
this.attributes = ['r', 'cx', 'cy', 'id', 'class', 'd'];
this.params = createDefaultParams();
Expand All @@ -24,14 +85,14 @@ const PhyloTree = function PhyloTree(reduxNodes, id, idxOfInViewRootNode) {
-- this.nodes[i].n = reduxNodes[i]
-- reduxNodes[i].shell = this.nodes[i] */
this.nodes = reduxNodes.map((d) => {
const phyloNode = {
const phyloNode: PhyloNode = {
that: this,
n: d, /* a back link to the redux node */
n: d,
x: 0,
y: 0,
inView: d.inView !== undefined ? d.inView : true /* each node is visible, unless set earlier! */
};
d.shell = phyloNode; /* set the link from the redux node to the phylotree node */
d.shell = phyloNode;
return phyloNode;
});
this.zoomNode = this.nodes[idxOfInViewRootNode];
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,28 @@
import { sum } from "d3-array";
import { formatDivergence, guessAreMutationsPerSite} from "./helpers";
import { NODE_VISIBLE } from "../../../util/globals";
import { NODE_NOT_VISIBLE, NODE_VISIBLE_TO_MAP_ONLY, NODE_VISIBLE } from "../../../util/globals";

interface Node {
n: {
hasChildren: boolean
}
x: number
y: number
visibility: typeof NODE_NOT_VISIBLE | typeof NODE_VISIBLE_TO_MAP_ONLY | typeof NODE_VISIBLE
}

export interface Regression {
slope?: number
intercept?: number
r2?: number
}

/**
* this function calculates a regression between
* the x and y values of terminal nodes which are also visible.
* The regression is forced to pass through nodes[0].
*/
function calculateRegressionThroughRoot(nodes) {
function calculateRegressionThroughRoot(nodes: Node[]): Regression {
const terminalNodes = nodes.filter((d) => !d.n.hasChildren && d.visibility === NODE_VISIBLE);
const nTips = terminalNodes.length;
if (nTips===0) {
Expand All @@ -31,7 +45,7 @@ function calculateRegressionThroughRoot(nodes) {
* Calculate regression through visible terminal nodes which have both x & y values
* set. These values must be numeric.
*/
function calculateRegressionWithFreeIntercept(nodes) {
function calculateRegressionWithFreeIntercept(nodes: Node[]): Regression {
const terminalNodesWithXY = nodes.filter(
(d) => (!d.n.hasChildren) && d.x!==undefined && d.y!==undefined && d.visibility === NODE_VISIBLE
);
Expand All @@ -50,15 +64,15 @@ function calculateRegressionWithFreeIntercept(nodes) {
}

/** sets this.regression */
export function calculateRegression() {
export function calculateRegression(this: { layout: string; nodes: Node[]; regression: Regression }) {
if (this.layout==="clock") {
this.regression = calculateRegressionThroughRoot(this.nodes);
} else {
this.regression = calculateRegressionWithFreeIntercept(this.nodes);
}
}

export function makeRegressionText(regression, layout, yScale) {
export function makeRegressionText(regression: Regression, layout: string, yScale: any): string {
if (layout==="clock") {
if (guessAreMutationsPerSite(yScale)) {
return `rate estimate: ${regression.slope.toExponential(2)} subs per site per year`;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { calculateStrokeColors, getBrighterColor } from "../../../util/colorHelpers";
import { ChangeParams } from "../phyloTree/change";

export const changePhyloTreeViaPropsComparison = (mainTree, phylotree, oldProps, newProps) => {
const args = {};
const newState = {};
const args: ChangeParams = {};
const newState: any = {};
/* do not use oldProps.tree or newTreeRedux */
const oldTreeRedux = mainTree ? oldProps.tree : oldProps.treeToo;
const newTreeRedux = mainTree ? newProps.tree : newProps.treeToo;
Expand Down

0 comments on commit 34d10ba

Please sign in to comment.