From 69b53a0e93edd4f86e971e2298276ee32e65bcd7 Mon Sep 17 00:00:00 2001 From: James Hadfield Date: Fri, 28 Jan 2022 19:03:49 +1300 Subject: [PATCH] Group nuc mutations on-hover Grouping nucleotide mutations (as per previous commits) while hovering on branches is really helpful for understanding the tree. The penalty is the use of more space, and so I've chosen to not group AA mutations here; one can shift+click on the branch to see these grouped if needed. --- src/components/tree/infoPanels/hover.js | 54 ++++++++++++------------- src/components/tree/tree.js | 1 + 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/src/components/tree/infoPanels/hover.js b/src/components/tree/infoPanels/hover.js index efb61a12e..71e392fab 100644 --- a/src/components/tree/infoPanels/hover.js +++ b/src/components/tree/infoPanels/hover.js @@ -4,9 +4,10 @@ import { numericToCalendar } from "../../../util/dateHelpers"; import { getTipColorAttribute } from "../../../util/colorHelpers"; import { isColorByGenotype, decodeColorByGenotype } from "../../../util/getGenotype"; import { getTraitFromNode, getDivFromNode, getVaccineFromNode, - getFullAuthorInfoFromNode, getTipChanges } from "../../../util/treeMiscHelpers"; + getFullAuthorInfoFromNode, getTipChanges, getBranchMutations } from "../../../util/treeMiscHelpers"; import { isValueValid } from "../../../util/globals"; import { formatDivergence, getIdxOfInViewRootNode } from "../phyloTree/helpers"; +import { parseIntervalsOfNsOrGaps } from "./MutationTable"; const InfoLine = ({name, value, padBelow=false}) => { const renderValues = () => { @@ -173,41 +174,39 @@ const TipMutations = ({node, t}) => { * @param {Object} props * @param {Object} props.node branch node which is currently highlighted * @param {Object} props.geneSortFn function to sort a list of genes + * @param {Object} props.observedMutations counts of all observed mutations across the tree + */ -const BranchMutations = ({node, geneSortFn, t}) => { +const BranchMutations = ({node, geneSortFn, observedMutations, t}) => { if (!node.branch_attrs || !node.branch_attrs.mutations) return null; const elements = []; // elements to render const mutations = node.branch_attrs.mutations; - /* --------- NUCLEOTIDE MUTATIONS --------------- */ - /* Nt mutations are found at `mutations.nuc` -> Array of strings */ - if (mutations.nuc && mutations.nuc.length) { - const nDisplay = 9; // max number of mutations to display - - const isMutGap = (mut) => mut.slice(-1) === "-" || mut.slice(0, 1) === "-"; - const isMutUnknown = (mut) => mut.slice(-1) === "N" || mut.slice(0, 1) === "N"; + const categorisedMutations = getBranchMutations(node, observedMutations); - // gather muts which aren't to/from a gap or a "N" - const nucs = mutations.nuc.filter((mut) => (!isMutGap(mut) && !(isMutUnknown(mut)))); - const nucLen = nucs.length; // number of mutations that exist without N/- + const subset = (muts, maxNum) => + muts.slice(0, Math.min(maxNum, muts.length)).join(", ") + + (muts.length > maxNum ? ` + ${muts.length-maxNum} more` : ''); - let m = nucs.slice(0, Math.min(nDisplay, nucLen)).join(", "); - if (nucLen > nDisplay) { - m += " + " + t("{{x}} more", {x: nucLen - nDisplay}); + /* --------- NUCLEOTIDE MUTATIONS --------------- */ + if (categorisedMutations.nuc) { + const nDisplay = 5; // max number of mutations to display per category + if (categorisedMutations.nuc.unique.length) { + elements.push(); } - - if (nucLen !== 0) { - elements.push(); + if (categorisedMutations.nuc.homoplasies.length) { + elements.push(); } - - const nGapMutations = mutations.nuc.filter((mut) => isMutGap(mut)).length; - if (nGapMutations) { - elements.push(); + if (categorisedMutations.nuc.reversionsToRoot.length) { + elements.push(); } - - const nUnknownMutations = mutations.nuc.filter((mut) => isMutUnknown(mut)).length; - if (nUnknownMutations) { - elements.push(); + if (categorisedMutations.nuc.gaps.length) { + const value = `${parseIntervalsOfNsOrGaps(categorisedMutations.nuc.gaps).length} regions, ${categorisedMutations.nuc.gaps.length}bp.`; + elements.push(); + } + if (categorisedMutations.nuc.ns.length) { + const value = `${parseIntervalsOfNsOrGaps(categorisedMutations.nuc.ns).length} regions, ${categorisedMutations.nuc.ns.length}bp.`; + elements.push(); } } else { elements.push(); @@ -390,6 +389,7 @@ const HoverInfoPanel = ({ panelDims, colorings, geneSortFn, + observedMutations, t }) => { if (selectedNode.event !== "hover") return null; @@ -411,7 +411,7 @@ const HoverInfoPanel = ({ ) : ( <> - + diff --git a/src/components/tree/tree.js b/src/components/tree/tree.js index 01333cdc0..d9eb25c3c 100644 --- a/src/components/tree/tree.js +++ b/src/components/tree/tree.js @@ -191,6 +191,7 @@ class Tree extends React.Component { colorScale={this.props.colorScale} colorings={this.props.metadata.colorings} geneSortFn={this.state.geneSortFn} + observedMutations={this.props.tree.observedMutations} panelDims={{width: this.props.width, height: this.props.height, spaceBetweenTrees}} t={t} />