Source code for cellsystem.logging.treelogs

from ..utils import Tree
from .core import WeakLog

[docs]class TreeLog(WeakLog): 'Base class for logs that grow trees.' def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.tree = Tree() self.alive = dict() self.tmp = None # --- @property def alive_nodes(self): return self.alive.values() # ---
[docs] def add_child(self, parent=None, name=None): # Select node if parent is None: parent_node = self.tree else: parent_node = self.alive[parent] # Add child to the current node child = parent_node.add_child(name=str(name)) return child
# ---
[docs] def fetch_tree(self, prune_death=False): """Fetch a copy of the tree. If `prune_death` is True, remove the leaves that correspond to death cells. """ # Make a copy of the tree original = self.tree t = original.copy() # Remove death cells. if prune_death: alive = { node.name for node in self.alive_nodes } t.prune_leaves(to_stay=alive) return t
# ---
[docs] def preparefor_division(self, cell): # Save the previous cell state self.tmp = cell.index
# ---
[docs] def log_death(self, cell): # No need to keep tracking del self.alive[cell.index]
# --- # --- TreeLog
[docs]class AncestryLog(TreeLog): """A tree log that maintains a \"family tree\". Each leaf represents a cell. When that cell divides, the leaf branches into leaves representing the daughters. The current state of an object 'tree' is handily accessible by 'print(tree)' """
[docs] def add_child(self, *args, **kwargs): # First add the node normally to the tree child_node = super().add_child(*args, **kwargs) # Then register the new cell node # in the alive cells self.alive[kwargs['name']] = child_node
# ---
[docs] def log_newcell(self, cell): # Add a new child to the tree self.add_child(name=cell.index)
# ---
[docs] def log_division(self, daughters): 'Add 2 new branches to the father of the cells.' d1, d2 = daughters father = self.tmp # Create new tree nodes self.add_child(father, name=d1.index) self.add_child(father, name=d2.index) # Cleanup del self.alive[father] self.tmp = None
# --- # --- AncestryLog
[docs]class MutationsLog(TreeLog): """A tree log that maintains a record of genome branching events. Each leaf represents a genome that may be present in one or more cells. When one of those cells mutates, the new genome is added as a child of that leaf. The current state of an object 'tree' is handily accessible by 'print(tree)' """
[docs] def log_newcell(self, cell): # Add a new child to the tree child = self.add_child(name=cell.genome) # Register cell as alive representative for the genome node self.alive[cell.index] = child
# ---
[docs] def log_division(self, daughters): 'Remove the father from the alive cells.' d1, d2 = daughters father = self.tmp # Replace the genome representative. # Now the daughter cells are representatives # as having the genome of the father. genome_node = self.alive[father] self.alive[d1.index] = genome_node self.alive[d2.index] = genome_node # Cleanup del self.alive[father] self.tmp = None
# ---
[docs] def log_mutation(self, cell): 'Add a new child to the parent genome.' child = self.add_child(cell.index, name=cell.genome) # New genome # Register cell as an alive representative # for the genome node self.alive[cell.index] = child
# --- # --- MutationsLog