diff --git a/src/components/tree/infoPanels/click.js b/src/components/tree/infoPanels/click.js index 8a4234999..619208482 100644 --- a/src/components/tree/infoPanels/click.js +++ b/src/components/tree/infoPanels/click.js @@ -6,7 +6,7 @@ import { getTraitFromNode, getFullAuthorInfoFromNode, getVaccineFromNode, getAccessionFromNode, getUrlFromNode } from "../../../util/treeMiscHelpers"; import { MutationTable } from "./MutationTable"; import { lhsTreeId} from "../tree"; -import { nodeDisplayName } from "./helpers"; +import { nodeDisplayName, dateInfo } from "./helpers"; export const styles = { container: { @@ -174,20 +174,22 @@ const StrainName = ({children}) => ( ); const SampleDate = ({isTerminal, node, t}) => { - const date = getTraitFromNode(node, "num_date"); + const {date, dateRange, inferred, ambiguousDate} = dateInfo(node, isTerminal); if (!date) return null; - const dateUncertainty = getTraitFromNode(node, "num_date", {confidence: true}); - if (date && dateUncertainty && dateUncertainty[0] !== dateUncertainty[1]) { - return ( - <> - {item(t(isTerminal ? "Inferred collection date" : "Inferred date"), numericToCalendar(date))} - {item(t("Date Confidence Interval"), `(${numericToCalendar(dateUncertainty[0])}, ${numericToCalendar(dateUncertainty[1])})`)} - - ); - } - /* internal nodes are always inferred, regardless of whether uncertainty bounds are present */ - return item(t(isTerminal ? "Collection date" : "Inferred date"), numericToCalendar(date)); + const dateDescription = isTerminal ? + (inferred ? "Inferred collection date" : "Collection date") : + "Inferred date"; // hardcoded assumption that internal nodes are inferred + + return ( + <> + {item(t(dateDescription), date)} + {inferred && dateRange && + item(t("Date Confidence Interval"), `(${dateRange.join(', ')})`)} + {ambiguousDate && + item(t("Provided date"), ambiguousDate)} + + ) }; const getTraitsToDisplay = (node) => { diff --git a/src/components/tree/infoPanels/helpers.js b/src/components/tree/infoPanels/helpers.js index 5a3bf824a..3c34e5d6d 100644 --- a/src/components/tree/infoPanels/helpers.js +++ b/src/components/tree/infoPanels/helpers.js @@ -21,3 +21,27 @@ export function nodeDisplayName(t, node, tipLabelKey, branch) { /* TIP */ return tipLabel; } + +export function dateInfo(node, isTerminal) { + const num_date = getTraitFromNode(node, "num_date"); + if (!num_date) return {}; + + // Decide if the date is inferred and, if so, attempt to get the underlying ambiguous date (for tips) + let inferred, ambiguousDate; + const dateUncertainty = getTraitFromNode(node, "num_date", {confidence: true}); + if (!isTerminal) { + inferred=true; + } else if (Object.hasOwn(node.node_attrs.num_date, "inferred")) { + inferred = node.node_attrs.num_date.inferred; + ambiguousDate = getTraitFromNode(node, "num_date", {raw: true}); + } else { + inferred = dateUncertainty && dateUncertainty[0] !== dateUncertainty[1]; + } + + const dateRange = dateUncertainty ? + [numericToCalendar(dateUncertainty[0]), numericToCalendar(dateUncertainty[1])] : + undefined; + const date = numericToCalendar(num_date); + + return {date, dateRange, inferred, ambiguousDate}; +} diff --git a/src/components/tree/infoPanels/hover.js b/src/components/tree/infoPanels/hover.js index 2ba7c5fc3..36db9ebac 100644 --- a/src/components/tree/infoPanels/hover.js +++ b/src/components/tree/infoPanels/hover.js @@ -8,7 +8,7 @@ import { getTraitFromNode, getDivFromNode, getVaccineFromNode, import { isValueValid, strainSymbol } from "../../../util/globals"; import { formatDivergence, getIdxOfInViewRootNode } from "../phyloTree/helpers"; import { parseIntervalsOfNsOrGaps } from "./MutationTable"; -import { nodeDisplayName } from "./helpers"; +import { nodeDisplayName, dateInfo } from "./helpers"; export const InfoLine = ({name, value, padBelow=false}) => { const renderValues = () => { @@ -37,30 +37,27 @@ export const InfoLine = ({name, value, padBelow=false}) => { * A React component to display information about the branch's time & divergence (where applicable) * @param {Object} props * @param {Object} props.node branch node currently highlighted + * @param {boolean} props.isTerminal */ -const BranchLength = ({node, t}) => { +const BranchLength = ({node, t, isTerminal}) => { const elements = []; // elements to render const divergence = getDivFromNode(node); - const numDate = getTraitFromNode(node, "num_date"); if (divergence) { elements.push(); } - if (numDate !== undefined) { - const date = numericToCalendar(numDate); - const numDateConfidence = getTraitFromNode(node, "num_date", {confidence: true}); - if (numDateConfidence && numDateConfidence[0] !== numDateConfidence[1]) { - elements.push(); - const dateRange = [numericToCalendar(numDateConfidence[0]), numericToCalendar(numDateConfidence[1])]; - if (dateRange[0] !== dateRange[1]) { - elements.push(); - } - } else { - elements.push(); + const {date, dateRange, inferred, ambiguousDate} = dateInfo(node, isTerminal); + if (date) { + const dateDescription = inferred ? 'Inferred Date' : 'Date'; + elements.push(); + if (inferred && dateRange) { + elements.push(); + } + if (ambiguousDate) { + elements.push(); } } - return elements; }; @@ -409,7 +406,7 @@ const HoverInfoPanel = ({ {tipLabelKey!==strainSymbol && } - + {t("Click on tip to display more info")} @@ -418,7 +415,7 @@ const HoverInfoPanel = ({ <> - + {idxOfInViewRootNode === node.arrayIdx ? t('Click to zoom out to parent clade') : t('Click to zoom into clade')} diff --git a/src/util/treeMiscHelpers.js b/src/util/treeMiscHelpers.js index ef71a66c0..6960bd8c9 100644 --- a/src/util/treeMiscHelpers.js +++ b/src/util/treeMiscHelpers.js @@ -25,10 +25,10 @@ james hadfield, nov 2019. * NOTE: do not use this for "div", "vaccine" or other traits set on `node_attrs` * which don't share the same structure as traits. See the JSON spec for more details. */ -export const getTraitFromNode = (node, trait, {entropy=false, confidence=false}={}) => { +export const getTraitFromNode = (node, trait, {entropy=false, confidence=false, raw=false}={}) => { if (!node.node_attrs) return undefined; - if (!entropy && !confidence) { + if (!entropy && !confidence && !raw) { if (!node.node_attrs[trait]) { if (trait === strainSymbol) return node.name; return undefined; @@ -42,6 +42,9 @@ export const getTraitFromNode = (node, trait, {entropy=false, confidence=false}= } else if (confidence) { if (node.node_attrs[trait]) return node.node_attrs[trait].confidence; return undefined; + } else if (raw) { + if (node.node_attrs[trait]) return node.node_attrs[trait].raw_value; + return undefined; } return undefined; };