From c3e2af35535f8e358842be64fe872f55dbc06cdb Mon Sep 17 00:00:00 2001
From: veronicavenafra <77729333+veronicavenafra@users.noreply.github.com>
Date: Tue, 19 Nov 2024 16:10:53 +0100
Subject: [PATCH 1/5] signalingprofiler implementation
---
docs/src/_static/nc_signalingprofiler.svg | 802 +++++++++++++++++++
docs/src/api.rst | 15 +
docs/src/methods.rst | 31 +-
networkcommons/methods/_signalingprofiler.py | 221 +++++
4 files changed, 1068 insertions(+), 1 deletion(-)
create mode 100644 docs/src/_static/nc_signalingprofiler.svg
create mode 100644 networkcommons/methods/_signalingprofiler.py
diff --git a/docs/src/_static/nc_signalingprofiler.svg b/docs/src/_static/nc_signalingprofiler.svg
new file mode 100644
index 0000000..e98808b
--- /dev/null
+++ b/docs/src/_static/nc_signalingprofiler.svg
@@ -0,0 +1,802 @@
+
+
+
diff --git a/docs/src/api.rst b/docs/src/api.rst
index 9be4608..d93a00f 100644
--- a/docs/src/api.rst
+++ b/docs/src/api.rst
@@ -79,6 +79,21 @@ CORNETO
methods.run_corneto_carnival
+
+.. _api-signalingprofiler:
+
+SignalingProfiler
+=================
+.. module::networkcommons.methods
+.. currentmodule:: networkcommons
+
+.. autosummary::
+ :toctree: api
+ :recursive:
+
+ methods.mf_classifier
+ methods.run_signalingprofiler
+
.. _api-pk:
Prior Knowledge
diff --git a/docs/src/methods.rst b/docs/src/methods.rst
index 9e8067c..2b55094 100644
--- a/docs/src/methods.rst
+++ b/docs/src/methods.rst
@@ -178,4 +178,33 @@ CORNETO (Constraint-based Optimization for the Reconstruction of NETworks from O
**Edge weights:** w(e) ∈ {1, −1}
-**Functions:** See API documentation for :ref:`CORNETO `.
\ No newline at end of file
+**Functions:** See API documentation for :ref:`CORNETO `.
+
+SignalingProfiler
+------------------
+
+SignalingProfiler (https://doi.org/10.1038/s41540-024-00417-6) Python implementation is a two-steps pipeline.
+In the first step, SignalingProfiler generates the Naïve Network, a hierarchical and multi-layered network between source and target nodes using networkcommons "All paths".
+Three different layouts can be chosen, defined as one-, two-, or three-layers networks, with an increasing level of deepness.
+
+Each layer is defined by a different set of molecular functions.
+The molecular function for each protein is obtained by parsing the UNIPROT database GO Molecular Function annotation according to relative GO Ancestor terms.
+This molecular function annotation refers to signal trasduction context: K, kinase; PP, phosphatases; T, transcription factor; O, all the other molecular functions.
+
+In the one-layer network, the perturbed node is connected to every target and is molecular function agnostic.
+The two-layers network connects the perturbed node to kinases/phosphatases/others (first layer) and then connect the latters to transcription factors (second layer).
+The three-layers network adds another layer between kinases/phosphatases and other signaling proteins.
+
+In the second step, SignalingProfiler calls "CORNETO - CARNIVAL" to retrieve only sign-consistent edges from the naïve network (removing grey dashed edges).
+
+.. raw:: html
+
+
+
+**Input:** Set of weighted target and source nodes, network graph
+
+**Node weights:** w(v) ∈ ℝ
+
+**Edge weights:** w(e) ∈ {1, −1}
+
+**Functions:** See API documentation for :ref:`SignalingProfiler `.
\ No newline at end of file
diff --git a/networkcommons/methods/_signalingprofiler.py b/networkcommons/methods/_signalingprofiler.py
new file mode 100644
index 0000000..438acd6
--- /dev/null
+++ b/networkcommons/methods/_signalingprofiler.py
@@ -0,0 +1,221 @@
+#!/usr/bin/env python
+
+#
+# This file is part of the `networkcommons` Python module
+#
+# Copyright 2024
+# Heidelberg University Hospital
+#
+# File author(s): Perfetto Lab (livia.perfetto@gmail.com)
+#
+# Distributed under the GPLv3 license
+# See the file `LICENSE` or read a copy at
+# https://www.gnu.org/licenses/gpl-3.0.txt
+#
+
+"""
+SignalingProfiler: a multi-step pipeline integrating topological and causal inference methods to derive context-specific signaling networks
+"""
+
+__all__ = [
+ 'run_phosphoscore',
+ 'run_signalingprofiler',
+]
+
+import networkcommons as nc
+import pandas as pd
+import networkx as nx
+from typing import Union, List
+from networkcommons._session import _log
+
+
+def mf_classifier(proteins, with_exp=False, comp_list=None):
+ """
+ Classify proteins in four broad molecular functions (MF) according to Gene Ontology: kinases (kin), phosphatases (phos), transcription factors (tf), and all other types (other).
+
+ Args:
+ - proteins (dict): A dictionary of protein names and exp values to classify.
+ - with_exp (bool): If True, return a dictionary with exp value -1 or 1. If False, return a dictionary with sets.
+ - comp_list (list): A list of protein names to use to subset proteins
+
+ Returns:
+ - dict: A dictionary where keys are MF categories and values are sets or dictionaries with experimental values.
+ """
+
+ if comp_list:
+ proteins = {k: v for k, v in proteins.items() if k in comp_list}
+
+ # Read the GO molecular function (MF) data
+ GO_mf_df = pd.read_csv('https://filedn.eu/ld7S7VEWtgOf5uN0V7fbp84/gomf_annotation_networkcommons.tsv', sep='\t')
+ mf_dict = GO_mf_df.groupby('mf')['gene_name'].apply(set).to_dict()
+
+ proteins_dict = {
+ mf: {gene: proteins[gene] if with_exp else '' for gene in genes if gene in proteins}
+ for mf, genes in mf_dict.items()
+ }
+
+ # Identify unclassified proteins
+ classified_proteins = {gene for genes in proteins_dict.values() for gene in (genes if isinstance(genes, set) else genes.keys())}
+ unclassified_proteins = set(proteins) - classified_proteins
+
+ if unclassified_proteins:
+ proteins_dict['other'] = (
+ {protein: proteins[protein] for protein in unclassified_proteins} if with_exp else ''
+ )
+
+ return proteins_dict
+
+def validate_inputs(sources, measurements, graph, layers, max_length):
+ if not isinstance(graph, nx.Graph):
+ raise TypeError("The 'graph' parameter must be an instance of networkx.Graph.")
+
+ if not isinstance(sources, dict) or not sources:
+ raise ValueError("The 'sources' parameter must be a non-empty list or dictionary.")
+
+ if not isinstance(measurements, dict) or not measurements:
+ raise ValueError("The 'measurements' parameter must be a non-empty list or dictionary.")
+
+ if layers not in ['one', 'two', 'three']:
+ raise ValueError("The 'layers' parameter must be 'one', 'two', or 'three'.")
+
+ if layers == 'one' and not isinstance(max_length, int):
+ raise TypeError("For 'one' layer, 'max_length' must be an integer.")
+
+ if layers in ['two', 'three'] and (not isinstance(max_length, list) or len(max_length) != 2):
+ raise ValueError("For 'two' or 'three' layers, 'max_length' must be a list of two integers.")
+
+ if isinstance(max_length, list) and any(not isinstance(x, int) or x <= 0 for x in max_length):
+ raise ValueError("'max_length' values must be positive integers.")
+
+ if isinstance(max_length, int) and max_length <= 0:
+ raise ValueError("'max_length' must be a positive integer.")
+
+
+def generate_naive_network(source_dict, measurements, graph, layers, max_length: Union[int, List[int]]):
+
+ """
+ Generates a hierarchical (multi)layered network from source nodes defining layers by distinguishing measured nodes by molecular function.
+
+ Args:
+ - source_dict (dict): A dictionary containing the sources and sign of perturbation.
+ - measurements (dict): A dictionary containing the targets and sign of measurements.
+ - graph (nx.Graph): The network.
+ - layers (str): specifies the number of layers to generate ('one', 'two', or 'three').
+ - max_length (int or list of int): The depth cutoff for finding paths. If `layers` is 'one', this should be an int. For 'two' or 'three', it should be a list of ints.
+
+ Returns:
+ - naive_network (nx.Graph): The constructed multi-layered network.
+ """
+
+ _log('SignalingProfiler naive network building via all paths algorithm...')
+
+ validate_inputs(source_dict, measurements, graph, layers, max_length)
+
+ # Define targets with molecular function classification
+ targets = mf_classifier(measurements, with_exp=True)
+
+ if layers == 'one':
+ # Generate one-layered network
+ naive_network, _ = nc.methods.run_all_paths(graph, source_dict, targets, depth_cutoff=max_length)
+
+
+ elif layers == 'two':
+ # Generate the first layer
+ all_paths_network1, _ = nc.methods.run_all_paths(
+ graph,
+ source_dict,
+ {**targets.get('kin'), **targets.get('phos'), **targets.get('other')},
+ depth_cutoff=max_length[0]
+ )
+
+ # Prepare new sources for the second layer
+ gene_nodes = list(all_paths_network1.nodes())
+ sources_new = mf_classifier(measurements, with_exp=True, comp_list=gene_nodes)
+
+ # Generate the second layer
+ all_paths_network2, _ = nc.methods.run_all_paths(
+ graph,
+ {**sources_new.get('kin'), **sources_new.get('phos'), **sources_new.get('other')},
+ targets.get('tf'),
+ depth_cutoff=max_length[1]
+ )
+
+ # Combine the first and second layer
+ naive_network = nx.compose(all_paths_network1, all_paths_network2)
+
+ elif layers == 'three':
+ # Generate the first layer
+ all_paths_network1, _ = nc.methods.run_all_paths(
+ graph,
+ source_dict,
+ {**targets.get('kin'), **targets.get('phos')},
+ depth_cutoff=max_length[0]
+ )
+
+ # Prepare new sources for the second layer
+ gene_nodes = list(all_paths_network1.nodes())
+ sources_new = mf_classifier(measurements, with_exp=True,comp_list=gene_nodes)
+
+ # Generate the second layer
+ all_paths_network2, _ = nc.methods.run_all_paths(
+ graph,
+ {**sources_new.get('kin'), **sources_new.get('phos')},
+ {**targets.get('kin'), **targets.get('phos'), **targets.get('other')},
+ depth_cutoff=1
+ )
+
+ # Combine the first and second layers
+ combined_network = nx.compose(all_paths_network1, all_paths_network2)
+
+ # Prepare new sources for the thirs layer
+ gene_nodes2 = list(combined_network.nodes())
+ sources_new2 = mf_classifier(measurements, with_exp=True, comp_list=gene_nodes2)
+
+ ### Third layer
+ all_paths_network3, _ = nc.methods.run_all_paths(
+ graph,
+ {**sources_new2.get('kin'), **sources_new2.get('phos'), **sources_new2.get('other')},
+ targets.get('tf'),
+ depth_cutoff=max_length[1]
+ )
+
+ naive_network = nx.compose(combined_network, all_paths_network3)
+
+ else:
+ raise ValueError("Invalid value for 'layers'. Choose 'one', 'two', or 'three'.")
+
+ return(naive_network)
+
+def run_signalingprofiler(source_dict, measurements, graph, layers, max_length, betaWeight=0.2, solver=None, verbose=False):
+ """
+ Generates a hierarchical (multi)layered network from source nodes defining layers by distinguishing measured nodes by molecular function and run the Vanilla Carnival algorithm via CORNETO to retrieve sign-coherent edges with nodes measured activity.
+ Args:
+ - source_dict (dict): A dictionary containing the sources and sign of perturbation.
+ - measurements (dict): A dictionary containing the targets and sign of measurements.
+ - graph (nx.Graph): The network.
+ - layers (str): specifies the number of layers to generate ('one', 'two', or 'three').
+ - max_length (int or list of int): The depth cutoff for finding paths. If `layers` is 'one', this should be an int. For 'two' or 'three', it should be a list of ints.
+
+ Returns:
+ - naive_network (nx.Graph): The constructed multi-layered network.
+ """
+ # Generate naive_network
+ naive_network = generate_naive_network(
+ source_dict=source_dict,
+ measurements=measurements,
+ graph=graph,
+ layers=layers,
+ max_length=max_length
+ )
+
+ # Optimize network using CORNETO
+ opt_net = nc.methods.run_corneto_carnival(
+ naive_network,
+ source_dict,
+ measurements,
+ betaWeight=betaWeight,
+ solver=solver,
+ verbose=verbose
+ )
+
+ return(opt_net)
\ No newline at end of file
From b3030a9dab3fe93ea42e7bda3c77bb087f27368e Mon Sep 17 00:00:00 2001
From: veronicavenafra
Date: Tue, 19 Nov 2024 16:37:39 +0100
Subject: [PATCH 2/5] signalingprofiler implementation
---
networkcommons/methods/_signalingprofiler.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/networkcommons/methods/_signalingprofiler.py b/networkcommons/methods/_signalingprofiler.py
index 438acd6..dbc8ada 100644
--- a/networkcommons/methods/_signalingprofiler.py
+++ b/networkcommons/methods/_signalingprofiler.py
@@ -18,7 +18,6 @@
"""
__all__ = [
- 'run_phosphoscore',
'run_signalingprofiler',
]
From b8d8ae8067b2142cdfa843d00e42a6039a7c1a80 Mon Sep 17 00:00:00 2001
From: deeenes
Date: Thu, 21 Nov 2024 23:17:31 +0100
Subject: [PATCH 3/5] `signalingprofiler`: first refactoring
---
networkcommons/methods/_signalingprofiler.py | 352 ++++++++++++-------
1 file changed, 223 insertions(+), 129 deletions(-)
diff --git a/networkcommons/methods/_signalingprofiler.py b/networkcommons/methods/_signalingprofiler.py
index dbc8ada..4d42669 100644
--- a/networkcommons/methods/_signalingprofiler.py
+++ b/networkcommons/methods/_signalingprofiler.py
@@ -14,207 +14,301 @@
#
"""
-SignalingProfiler: a multi-step pipeline integrating topological and causal inference methods to derive context-specific signaling networks
+SignalingProfiler: a multi-step pipeline integrating topological and causal
+inference methods to derive context-specific signaling networks
"""
+from __future__ import annotations
+
__all__ = [
'run_signalingprofiler',
]
-import networkcommons as nc
+from typing import Literal
+from collections.abc import Collection
+from collections import ChainMap
+import functools as ft
+
import pandas as pd
import networkx as nx
-from typing import Union, List
+from pypath_common import _misc
+
from networkcommons._session import _log
+from networkcommons.methods import _causal, _graph
+from networkcommons.data.omics import _common as _downloader
-def mf_classifier(proteins, with_exp=False, comp_list=None):
+def _mf_classifier(
+ proteins: dict[str, float],
+ with_exp: bool = False,
+ only_proteins: Collection | None = None,
+ ):
"""
- Classify proteins in four broad molecular functions (MF) according to Gene Ontology: kinases (kin), phosphatases (phos), transcription factors (tf), and all other types (other).
+ Classify proteins in four broad molecular functions (MF) according to Gene
+ Ontology: kinases (kin), phosphatases (phos), transcription factors (tf),
+ and all other types (other).
Args:
- - proteins (dict): A dictionary of protein names and exp values to classify.
- - with_exp (bool): If True, return a dictionary with exp value -1 or 1. If False, return a dictionary with sets.
- - comp_list (list): A list of protein names to use to subset proteins
+ proteins: A dictionary of protein names and exp values to classify.
+ with_exp: If True, return a dictionary with exp value -1 or 1. If
+ False, return a dictionary with sets.
+ only_proteins: A list of protein
+ names to use to subset proteins
Returns:
- - dict: A dictionary where keys are MF categories and values are sets or dictionaries with experimental values.
+ A dictionary where keys are MF categories and values are sets or
+ dictionaries with experimental values.
"""
- if comp_list:
- proteins = {k: v for k, v in proteins.items() if k in comp_list}
+ if only_proteins:
+
+ proteins = {k: v for k, v in proteins.items() if k in only_proteins}
# Read the GO molecular function (MF) data
- GO_mf_df = pd.read_csv('https://filedn.eu/ld7S7VEWtgOf5uN0V7fbp84/gomf_annotation_networkcommons.tsv', sep='\t')
+ GO_mf_df = _downloader._open(
+ (
+ 'https://filedn.eu/ld7S7VEWtgOf5uN0V7fbp84/'
+ 'gomf_annotation_networkcommons.tsv'
+ ),
+ ftype = 'tsv',
+ )
+
mf_dict = GO_mf_df.groupby('mf')['gene_name'].apply(set).to_dict()
proteins_dict = {
- mf: {gene: proteins[gene] if with_exp else '' for gene in genes if gene in proteins}
+ mf: {
+ gene: proteins[gene] if with_exp else ''
+ for gene in genes
+ if gene in proteins
+ }
for mf, genes in mf_dict.items()
}
# Identify unclassified proteins
- classified_proteins = {gene for genes in proteins_dict.values() for gene in (genes if isinstance(genes, set) else genes.keys())}
+ classified_proteins = {
+ gene
+ for genes in proteins_dict.values()
+ for gene in set(genes)
+ }
unclassified_proteins = set(proteins) - classified_proteins
if unclassified_proteins:
+
proteins_dict['other'] = (
- {protein: proteins[protein] for protein in unclassified_proteins} if with_exp else ''
+ {
+ protein: proteins[protein]
+ for protein in unclassified_proteins
+ }
+ if with_exp else {}
)
return proteins_dict
-def validate_inputs(sources, measurements, graph, layers, max_length):
+
+def _validate_inputs(
+ sources: dict,
+ measurements: dict,
+ graph: nx.Graph,
+ layers: int,
+ max_length: int | list[int],
+ ) -> None:
+
+ err = []
+
if not isinstance(graph, nx.Graph):
- raise TypeError("The 'graph' parameter must be an instance of networkx.Graph.")
-
+ err.append(
+ "The 'graph' parameter must be an instance of networkx.Graph."
+ )
+
if not isinstance(sources, dict) or not sources:
- raise ValueError("The 'sources' parameter must be a non-empty list or dictionary.")
-
+ err.append(
+ "The 'sources' parameter must be a non-empty list or dictionary."
+ )
+
if not isinstance(measurements, dict) or not measurements:
- raise ValueError("The 'measurements' parameter must be a non-empty list or dictionary.")
-
- if layers not in ['one', 'two', 'three']:
- raise ValueError("The 'layers' parameter must be 'one', 'two', or 'three'.")
-
- if layers == 'one' and not isinstance(max_length, int):
- raise TypeError("For 'one' layer, 'max_length' must be an integer.")
-
- if layers in ['two', 'three'] and (not isinstance(max_length, list) or len(max_length) != 2):
- raise ValueError("For 'two' or 'three' layers, 'max_length' must be a list of two integers.")
-
- if isinstance(max_length, list) and any(not isinstance(x, int) or x <= 0 for x in max_length):
- raise ValueError("'max_length' values must be positive integers.")
-
+ err.append(
+ "The 'measurements' parameter must be "
+ "a non-empty list or dictionary."
+ )
+
+ if not (isinstance(layers, int) and 0 < layers < 4):
+ err.append("The 'layers' parameter must be 1, 2, or 3.")
+
+ if layers == 1 and not isinstance(max_length, int):
+ err.append("For 1 layers, 'max_length' must be an integer.")
+
+ if (
+ layers in [2, 3] and (
+ not isinstance(max_length, list) or
+ len(max_length) != 2
+ )
+ ):
+ err.append(
+ "For 2 or 3 layers, 'max_length' "
+ "must be a list of two integers."
+ )
+
+ if (
+ isinstance(max_length, list) and
+ any(
+ not isinstance(x, int) or
+ x <= 0 for x in max_length
+ )
+ ):
+ err.append("'max_length' values must be positive integers.")
+
if isinstance(max_length, int) and max_length <= 0:
- raise ValueError("'max_length' must be a positive integer.")
+ err.append("'max_length' must be a positive integer.")
+
+ if err:
+
+ msg = 'Problem(s) with SignalingProfiler inputs: '
+
+ for e in err:
+
+ _log(f'{msg}{e}')
+ raise ValueError(f'{msg}{"; ".join(err)}')
-def generate_naive_network(source_dict, measurements, graph, layers, max_length: Union[int, List[int]]):
+
+def _generate_naive_network(
+ sources: dict,
+ measurements: dict,
+ graph: nx.Graph,
+ layers: int,
+ max_length: int | list[int],
+ ) -> nx.Graph:
"""
- Generates a hierarchical (multi)layered network from source nodes defining layers by distinguishing measured nodes by molecular function.
+ Generates a hierarchical (multi)layersed network from source nodes defining
+ layers by distinguishing measured nodes by molecular function.
Args:
- - source_dict (dict): A dictionary containing the sources and sign of perturbation.
- - measurements (dict): A dictionary containing the targets and sign of measurements.
- - graph (nx.Graph): The network.
- - layers (str): specifies the number of layers to generate ('one', 'two', or 'three').
- - max_length (int or list of int): The depth cutoff for finding paths. If `layers` is 'one', this should be an int. For 'two' or 'three', it should be a list of ints.
+ sources: A dictionary containing the sources and sign of
+ perturbation.
+ measurements: A dictionary containing the targets and sign of
+ measurements.
+ graph: The network.
+ layers: specifies the number of layers to generate.
+ Must be > 0 and < 4.
+ max_length: The depth cutoff for finding paths.
+ If `layers` is 1, this should be an int. For 2 or 3,
+ it should be a list of ints.
Returns:
- - naive_network (nx.Graph): The constructed multi-layered network.
+ The constructed multi-layersed network.
"""
_log('SignalingProfiler naive network building via all paths algorithm...')
- validate_inputs(source_dict, measurements, graph, layers, max_length)
+ _validate_inputs(sources, measurements, graph, layers, max_length)
+
+
+ def _by_func(
+ classes: dict,
+ funcs: Collection[Literal['kin', 'phos', 'other', 'tf']] | None = None,
+ ) -> dict:
+
+ return (
+ classes
+ if funcs is None else
+ ChainMap(*(classes.get(func, {}) for func in _misc.to_set(funcs)))
+ )
+
# Define targets with molecular function classification
- targets = mf_classifier(measurements, with_exp=True)
+ targets = _mf_classifier(measurements, with_exp=True)
+ max_length = _misc.to_list(max_length)
+
+ stages = (
+ None,
+ ('kin', 'phos'),
+ ('kin', 'phos', 'other'),
+ None if layers == 0 else 'tf',
+ )
+ stages = (stages[0],) + stages[-layers:]
+ networks = []
- if layers == 'one':
- # Generate one-layered network
- naive_network, _ = nc.methods.run_all_paths(graph, source_dict, targets, depth_cutoff=max_length)
+ for i, (src_funcs, tgt_funcs) in enumerate(zip(stages[:-1], stages[1:])):
+ _log(f'SignalingProfiler naive network: stage {i + 1}')
- elif layers == 'two':
- # Generate the first layer
- all_paths_network1, _ = nc.methods.run_all_paths(
- graph,
- source_dict,
- {**targets.get('kin'), **targets.get('phos'), **targets.get('other')},
- depth_cutoff=max_length[0]
+ networks.append(
+ _graph.run_all_paths(
+ graph,
+ _by_func(sources, src_funcs),
+ _by_func(targets, tgt_funcs),
+ depth_cutoff = max_length[i],
+ )
)
- # Prepare new sources for the second layer
- gene_nodes = list(all_paths_network1.nodes())
- sources_new = mf_classifier(measurements, with_exp=True, comp_list=gene_nodes)
+ if i == layers - 1:
- # Generate the second layer
- all_paths_network2, _ = nc.methods.run_all_paths(
- graph,
- {**sources_new.get('kin'), **sources_new.get('phos'), **sources_new.get('other')},
- targets.get('tf'),
- depth_cutoff=max_length[1]
- )
+ break
- # Combine the first and second layer
- naive_network = nx.compose(all_paths_network1, all_paths_network2)
-
- elif layers == 'three':
- # Generate the first layer
- all_paths_network1, _ = nc.methods.run_all_paths(
- graph,
- source_dict,
- {**targets.get('kin'), **targets.get('phos')},
- depth_cutoff=max_length[0]
+ sources = _mf_classifier(
+ measurements,
+ with_exp = True,
+ only_proteins = networks[-1].nodes(),
)
- # Prepare new sources for the second layer
- gene_nodes = list(all_paths_network1.nodes())
- sources_new = mf_classifier(measurements, with_exp=True,comp_list=gene_nodes)
+ naive_network = ft.reduce(nx.compose, networks)
- # Generate the second layer
- all_paths_network2, _ = nc.methods.run_all_paths(
- graph,
- {**sources_new.get('kin'), **sources_new.get('phos')},
- {**targets.get('kin'), **targets.get('phos'), **targets.get('other')},
- depth_cutoff=1
- )
-
- # Combine the first and second layers
- combined_network = nx.compose(all_paths_network1, all_paths_network2)
-
- # Prepare new sources for the thirs layer
- gene_nodes2 = list(combined_network.nodes())
- sources_new2 = mf_classifier(measurements, with_exp=True, comp_list=gene_nodes2)
-
- ### Third layer
- all_paths_network3, _ = nc.methods.run_all_paths(
- graph,
- {**sources_new2.get('kin'), **sources_new2.get('phos'), **sources_new2.get('other')},
- targets.get('tf'),
- depth_cutoff=max_length[1]
- )
+ _log('SignalingProfiler naive network building ready.')
- naive_network = nx.compose(combined_network, all_paths_network3)
-
- else:
- raise ValueError("Invalid value for 'layers'. Choose 'one', 'two', or 'three'.")
-
- return(naive_network)
+ return naive_network
-def run_signalingprofiler(source_dict, measurements, graph, layers, max_length, betaWeight=0.2, solver=None, verbose=False):
+
+def run_signalingprofiler(
+ sources: dict,
+ measurements: dict,
+ graph: nx.Graph,
+ layers: int,
+ max_length: int | list[int],
+ betaWeight: float = 0.2,
+ solver: str | None = None,
+ verbose: bool = False,
+ ) -> nx.Graph:
"""
- Generates a hierarchical (multi)layered network from source nodes defining layers by distinguishing measured nodes by molecular function and run the Vanilla Carnival algorithm via CORNETO to retrieve sign-coherent edges with nodes measured activity.
+ Contextualize networks by the SignalingProfiler algorithm.
+
+ Generates a hierarchical (multi)layersed network from source nodes defining
+ layers by distinguishing measured nodes by molecular function and run the
+ Vanilla Carnival algorithm via CORNETO to retrieve sign-coherent edges with
+ nodes measured activity.
+
Args:
- - source_dict (dict): A dictionary containing the sources and sign of perturbation.
- - measurements (dict): A dictionary containing the targets and sign of measurements.
- - graph (nx.Graph): The network.
- - layers (str): specifies the number of layers to generate ('one', 'two', or 'three').
- - max_length (int or list of int): The depth cutoff for finding paths. If `layers` is 'one', this should be an int. For 'two' or 'three', it should be a list of ints.
+ sources: A dictionary containing the sources and sign of perturbation.
+ measurements: A dictionary containing the targets and sign of
+ measurements.
+ graph: The network.
+ layers: specifies the number of layers to generate.
+ Must be > 0 and < 4.
+ max_length: The depth cutoff for finding paths. If `layers` is 1,
+ this should be an int. For 2 or 3, it should be a list of
+ ints.
Returns:
- - naive_network (nx.Graph): The constructed multi-layered network.
+ The constructed multi-layersed network.
"""
+
# Generate naive_network
- naive_network = generate_naive_network(
- source_dict=source_dict,
- measurements=measurements,
- graph=graph,
- layers=layers,
- max_length=max_length
+ naive_network = _generate_naive_network(
+ sources = sources,
+ measurements = measurements,
+ graph = graph,
+ layers = layers,
+ max_length = max_length
)
# Optimize network using CORNETO
- opt_net = nc.methods.run_corneto_carnival(
- naive_network,
- source_dict,
- measurements,
- betaWeight=betaWeight,
- solver=solver,
- verbose=verbose
+ opt_net = _causal.run_corneto_carnival(
+ naive_network,
+ sources,
+ measurements,
+ betaWeight = betaWeight,
+ solver = solver,
+ verbose = verbose
)
-
- return(opt_net)
\ No newline at end of file
+
+ return opt_net
From f253263e89cd5164e1240f13df8a4c61e49093ab Mon Sep 17 00:00:00 2001
From: deeenes
Date: Thu, 21 Nov 2024 23:38:09 +0100
Subject: [PATCH 4/5] `signalingprofiler`: exports
---
networkcommons/methods/__init__.py | 1 +
1 file changed, 1 insertion(+)
diff --git a/networkcommons/methods/__init__.py b/networkcommons/methods/__init__.py
index 4497219..a76615a 100644
--- a/networkcommons/methods/__init__.py
+++ b/networkcommons/methods/__init__.py
@@ -20,3 +20,4 @@
from ._graph import *
from ._causal import *
from ._moon import *
+from ._signalingprofiler import *
From e4708d519826621fc3cf459e4fd5c08438795807 Mon Sep 17 00:00:00 2001
From: deeenes
Date: Thu, 21 Nov 2024 23:45:26 +0100
Subject: [PATCH 5/5] `signalingprofiler`: docs: `mf_classifier` is not
exported
---
docs/src/api.rst | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/docs/src/api.rst b/docs/src/api.rst
index d93a00f..c4637ff 100644
--- a/docs/src/api.rst
+++ b/docs/src/api.rst
@@ -91,7 +91,6 @@ SignalingProfiler
:toctree: api
:recursive:
- methods.mf_classifier
methods.run_signalingprofiler
.. _api-pk:
@@ -236,7 +235,7 @@ Evaluation and description
eval.get_phosphorylation_status
eval.perform_random_controls
eval.shuffle_dict_keys
-
+
.. _api-vis:
Visualization
@@ -282,7 +281,7 @@ Utilities
:toctree: api
:recursive:
-
+
utils.to_cornetograph
utils.to_networkx
utils.read_network_from_file