Graph Representation#
Module defining the nodes and edges of the graph representing the lymphatic system.
Anything related to the network of nodes and edges is defined here. This includes the
nodes themselves (either Tumor
or LymphNodeLevel
), the edges
(Edge
), and the graph (Representation
).
The nodes and edges are used to define the structure of the graph, which may then be
accessed via the Representation
class. This in turn is then used to
compute e.g. the transition matrix of the model.
- class lymph.graph.AbstractNode(name: str, state: int, allowed_states: list[int] | None = None)[source]#
Bases:
object
Abstract base class for nodes in the graph reprsenting the lymphatic system.
- __init__(name: str, state: int, allowed_states: list[int] | None = None) None [source]#
Make a new node.
Upon initialization, the
name
andstate
of the node must be provided. Thestate
must be one of theallowed_states
. The constructor makes sure that theallowed_states
are a list of ints, even when, e.g., a tuple of floats is provided.
- property name: str#
Return the name of the node.
- property state: int#
Return the state of the node.
- comp_obs_prob(obs: int, obs_table: ndarray, log: bool = False) float [source]#
Compute the probability of the diagnosis
obs
, given the current state.The
obs_table
is a 2D array with the rows corresponding to the states and the columns corresponding to the observations. It encodes for each state and diagnosis the corresponding probability.
- class lymph.graph.Tumor(name: str, state: int = 1)[source]#
Bases:
AbstractNode
A tumor in the graph representation of the lymphatic system.
- class lymph.graph.LymphNodeLevel(name: str, state: int = 0, allowed_states: list[int] | None = None)[source]#
Bases:
AbstractNode
A lymph node level (LNL) in the graph representation of the lymphatic system.
- __init__(name: str, state: int = 0, allowed_states: list[int] | None = None) None [source]#
Create a new lymph node level.
- classmethod binary(name: str, state: int = 0) LymphNodeLevel [source]#
Create a new binary LNL.
- classmethod trinary(name: str, state: int = 0) LymphNodeLevel [source]#
Create a new trinary LNL.
- property is_binary: bool#
Return whether the node is binary.
- property is_trinary: bool#
Return whether the node is trinary.
- class lymph.graph.Edge(parent: Tumor | LymphNodeLevel, child: LymphNodeLevel, spread_prob: float = 0.0, micro_mod: float = 1.0, callbacks: list[callable] | None = None)[source]#
Bases:
object
This class represents an arc in the graph representation of the lymph system.
- __init__(parent: Tumor | LymphNodeLevel, child: LymphNodeLevel, spread_prob: float = 0.0, micro_mod: float = 1.0, callbacks: list[callable] | None = None) None [source]#
Create a new edge between two nodes.
The
parent
node must be aTumor
or aLymphNodeLevel
, and thechild
node must be aLymphNodeLevel
.The
spread_prob
parameter is the probability of a tumor or involved LNL to spread to the next LNL. Themicro_mod
parameter is a modifier for the spread probability in case of only a microscopic node involvement.
- property parent: Tumor | LymphNodeLevel#
Return the parent node that drains lymphatically via the edge.
- property child: LymphNodeLevel#
Return the child node of the edge, receiving lymphatic drainage.
- get_name(middle='to') str [source]#
Return the name of the edge.
An edge’s name is simply the name of the parent node and the child node, connected by the string provided via the
middle
argument.This is used to identify and assign spread probabilities to it e.g. in the
set_params()
method and elsewhere.>>> lnl_II = LymphNodeLevel("II") >>> lnl_III = LymphNodeLevel("III") >>> edge = Edge(lnl_II, lnl_III) >>> edge.get_name() 'IItoIII' >>> edge.get_name(middle='->') 'II->III'
- property is_growth: bool#
Check if this edge represents a node’s growth.
- property is_tumor_spread: bool#
Check if this edge represents spread from a tumor to an LNL.
- set_micro_mod(new_micro_mod: float | None) None [source]#
Set the spread modifier for LNLs with microscopic involvement.
- property micro_mod: float#
Parameter modifying spread probability in case of macroscopic involvement
- set_spread_prob(new_spread_prob: float | None) None [source]#
Set the spread probability of the edge.
- property spread_prob: float#
Spread probability of the edge
- get_params(as_dict: bool = True, **_kwargs) types.ParamsType [source]#
Return the value of the parameter
param
or all params in a dict.See also
lymph.diagnosis_times.Distribution.get_params()
lymph.diagnosis_times.DistributionsUserDict.get_params()
lymph.models.Unilateral.get_params()
lymph.models.Bilateral.get_params()
- set_params(*args, **kwargs) tuple[float] [source]#
Set the values of the edge’s parameters.
If provided as positional arguments, the edge connects to a trinary node, and is not a growth node, the first argument is the spread probability and the second argument is the microscopic spread modifier. Otherwise it only consumes one argument, which is the growth or spread probability.
Keyword arguments (i.e.,
"growth"
,"spread"
, and"micro"
) override positional arguments. Unused args are returned.>>> edge = Edge(LymphNodeLevel("II", allowed_states=[0, 1, 2]), LymphNodeLevel("III")) >>> _ = edge.set_params(0.1, 0.2) >>> edge.spread_prob 0.1 >>> edge.micro_mod 0.2 >>> _ = edge.set_params(spread=0.3, micro=0.4) >>> edge.spread_prob 0.3 >>> edge.micro_mod 0.4
- property transition_tensor: ndarray#
Return the transition tensor of the edge.
See also
lymph.helper.comp_transition_tensor()
- class lymph.graph.Representation(graph_dict: dict[tuple[str], list[str]], tumor_state: int | None = None, allowed_states: list[int] | None = None, on_edge_change: list[callable] | None = None)[source]#
Bases:
object
Class holding the graph structure of the model.
This class allows accessing the connected nodes (
Tumor
andLymphNodeLevel
) and edges (Edge
) of themodels
.- __init__(graph_dict: dict[tuple[str], list[str]], tumor_state: int | None = None, allowed_states: list[int] | None = None, on_edge_change: list[callable] | None = None) None [source]#
Create a new graph representation of nodes and edges.
The
graph_dict
is a dictionary that defines which nodes are created and with what edges they are connected. The keys of the dictionary are tuples of the form(node_type, node_name)
. Thenode_type
can be either"tumor"
or"lnl"
. Thenode_name
is a string that uniquely identifies the node. The values of the dictionary are lists of node names to which the key node should be connected.
- property nodes: dict[str, Tumor | LymphNodeLevel]#
List of both
Tumor
andLymphNodeLevel
instances.
- property lnls: dict[str, LymphNodeLevel]#
List of all
LymphNodeLevel
nodes in the graph.
- property allowed_states: list[int]#
Return the list of allowed states for each
LymphNodeLevel
.
- property is_binary: bool#
Indicate if the model is binary.
Returns
True
if allLymphNodeLevel
instances are binary,False
otherwise.
- property is_trinary: bool#
Returns
True
if the graph is trinary,False
otherwise.Similar to
is_binary()
.
- property tumor_edges: dict[str, Edge]#
List of all tumor
Edge
instances in the graph.This contains all edges who’s parents are instances of
Tumor
and who’s children are instances ofLymphNodeLevel
.
- property lnl_edges: dict[str, Edge]#
List of all LNL
Edge
instances in the graph.This contains all edges who’s parents and children are instances of
LymphNodeLevel
, including growth edges (if the graph is trinary).
- property growth_edges: dict[str, Edge]#
List of all growth
Edge
instances in the graph.Growth edges are only present in trinary models and are arcs where the parent and child are the same
LymphNodeLevel
instance. They facilitate the change from a micsoscopically positive to a macroscopically positive LNL.
- to_dict() dict[tuple[str, str], set[str]] [source]#
Returns graph representing this instance’s nodes and egdes as dictionary.
>>> graph_dict = { ... ('tumor', 'T'): ['II', 'III'], ... ('lnl', 'II'): ['III'], ... ('lnl', 'III'): [], ... } >>> graph = Representation(graph_dict) >>> graph.to_dict() == graph_dict True
- get_mermaid() str [source]#
Prints the graph in mermaid format.
>>> graph_dict = { ... ('tumor', 'T'): ['II', 'III'], ... ('lnl', 'II'): ['III'], ... ('lnl', 'III'): [], ... } >>> graph = Representation(graph_dict) >>> graph.edges["TtoII"].spread_prob = 0.1 >>> graph.edges["TtoIII"].spread_prob = 0.2 >>> graph.edges["IItoIII"].spread_prob = 0.3 >>> print(graph.get_mermaid()) flowchart TD T-->|10%| II T-->|20%| III II-->|30%| III
- get_state(as_dict: bool = False) dict[str, int] | list[int] [source]#
Return the states of the system’s LNLs.
If
as_dict
isTrue
, the result is a dictionary with the names of the LNLs as keys and their states as values. Otherwise, the result is a list of the states of the LNLs in the order they appear in the graph.
- set_state(*new_states_args, **new_states_kwargs) None [source]#
Assign a new state to the system’s LNLs.
The state can either be provided with positional arguments or as keyword arguments. In case of positional arguments, the order must be the same as the order of the LNLs in the graph. If keyword arguments are used, the keys must be the names of the LNLs. The order of the keyword arguments does not matter.
The keyword arguments override the positional arguments.
- property state_list#
Return list of all possible hidden states.
E.g., for three binary LNLs I, II, III, the first state would be where all LNLs are in state 0. The second state would be where LNL III is in state 1 and all others are in state 0, etc. The third represents the case where LNL II is in state 1 and all others are in state 0, etc. Essentially, it looks like binary counting:
>>> graph = Representation(graph_dict={ ... ("tumor", "T"): ["I", "II" , "III"], ... ("lnl", "I"): [], ... ("lnl", "II"): ["I", "III"], ... ("lnl", "III"): [], ... }) >>> graph.state_list array([[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]])
- get_params(as_dict: bool = True, as_flat: bool = True) types.ParamsType [source]#
Return the parameters of the edges in the graph.
If
as_dict
isFalse
, return an iterable of all parameter values. Ifas_dict
isTrue
, return a nested dictionary with the edges’ names as keys and the edges’ parameter dicts as values.If
as_flat
isTrue
, return a flat dictionary with the T-stages and parameters as keys and values, respectively. This is the result of passing the nested dictionary toflatten()
.
- set_params(*args, **kwargs) tuple[float] [source]#
Set the parameters of the edges in the graph.
The arguments are passed to the
set_params()
method of the edges. Global keyword arguments (e.g."spread"
) are passed to each edge’sset_params
method. Unused args are returned.Specific keyword arguments take precedence over global ones which in turn take precedence over positional arguments.
>>> graph = Representation(graph_dict={ ... ("tumor", "T"): ["II" , "III"], ... ("lnl", "II"): ["III"], ... ("lnl", "III"): [], ... }) >>> _ = graph.set_params(0.1, 0.2, 0.3, spread=0.4, TtoII_spread=0.5) >>> graph.get_params(as_dict=True) {'TtoII_spread': 0.5, 'TtoIII_spread': 0.4, 'IItoIII_spread': 0.4}