Skip to content

Commit

Permalink
feat: vote on clade-like attributes too
Browse files Browse the repository at this point in the history
This just extends the voting to not only clade_membership clade, but to other clade-like attributes which might be present on the tree (in `.meta.extensions.nextclade`)
  • Loading branch information
ivan-aksamentov committed Oct 18, 2024
1 parent f8b860b commit 592c887
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 1 deletion.
12 changes: 12 additions & 0 deletions packages/nextclade/src/tree/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,11 @@ impl AuspiceGraphNodePayload {
.and_then(|val| val.as_str())
}

/// Sets clade-like node attribute
pub fn set_clade_node_attr(&mut self, key: impl AsRef<str>, value: String) {
self.node_attrs.other[key.as_ref()] = serde_json::Value::String(value);
}

/// Extracts clade-like node attributes, given a list of key descriptions
pub fn get_clade_node_attrs(&self, clade_node_attr_descs: &[CladeNodeAttrKeyDesc]) -> BTreeMap<String, String> {
clade_node_attr_descs
Expand All @@ -292,6 +297,13 @@ impl AuspiceGraphNodePayload {
})
.collect()
}

/// Sets clade-like node attributes. Inserts if key does not exist and overwrites existing.
pub fn set_clade_node_attrs(&mut self, attrs: BTreeMap<String, String>) {
for (key, val) in attrs {
self.set_clade_node_attr(key, val);
}
}
}

impl GraphNode for AuspiceGraphNodePayload {}
Expand Down
32 changes: 31 additions & 1 deletion packages/nextclade/src/tree/tree_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use crate::types::outputs::NextcladeOutputs;
use crate::utils::collections::concat_to_vec;
use crate::utils::stats::mode;
use eyre::{Report, WrapErr};
use itertools::Itertools;
use itertools::{chain, Itertools};
use std::collections::BTreeMap;

pub fn graph_attach_new_nodes_in_place(
Expand Down Expand Up @@ -385,6 +385,10 @@ pub fn knit_into_graph(
let (clade, should_relabel) = vote_for_clade(graph, target_node, result);
new_internal_node.node_attrs.clade_membership = clade.as_deref().map(TreeNodeAttr::new);

// Vote for the most plausible clade-like attrs
let clade_attrs = vote_for_clade_like_attrs(graph, target_node, result);
new_internal_node.set_clade_node_attrs(clade_attrs);

// If decided, then move the clade label from target node to the internal node
if should_relabel {
let target_node = graph.get_node_mut(target_key)?;
Expand Down Expand Up @@ -478,3 +482,29 @@ fn vote_for_clade(

(clade, should_relabel)
}

// Vote for the most plausible clade-like attribute values, for the new internal node
fn vote_for_clade_like_attrs(
graph: &AuspiceGraph,
target_node: &Node<AuspiceGraphNodePayload>,
result: &NextcladeOutputs,
) -> BTreeMap<String, String> {
let attr_descs = graph.data.meta.clade_node_attr_descs();

let query_attrs: &BTreeMap<String, String> = &result.custom_node_attributes;

let parent_node = &graph.parent_of(target_node);
let parent_attrs: &BTreeMap<String, String> = &parent_node
.map(|node| node.payload().get_clade_node_attrs(attr_descs))
.unwrap_or_default();

let target_attrs: &BTreeMap<String, String> = &target_node.payload().get_clade_node_attrs(attr_descs);

chain!(query_attrs.iter(), parent_attrs.iter(), target_attrs.iter())
.into_group_map()
.into_iter()
.filter_map(|(key, grouped_values)| {
mode(grouped_values.into_iter().cloned()).map(|most_common| (key.clone(), most_common))
})
.collect()
}

0 comments on commit 592c887

Please sign in to comment.