cellmaps-utils 0.10.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,198 @@
1
+ import json
2
+ import os
3
+
4
+ import ndex2
5
+ from ndex2.cx2 import CX2Network, RawCX2NetworkFactory
6
+
7
+ from cellmaps_utils.exceptions import CellMapsError
8
+
9
+
10
+ def get_host_and_uuid_from_network_url(network_url):
11
+ """
12
+ Extracts the host and UUID from a given NDEx network URL.
13
+
14
+ :param network_url: The URL of the NDEx network.
15
+ :type network_url: str
16
+ :return: A tuple containing the host and the UUID of the network.
17
+ :rtype: tuple
18
+ """
19
+ if network_url is None:
20
+ return None, None
21
+ parts = network_url.replace('https://', '').replace('http:/', '').split('/')
22
+ host, uuid = parts[0], parts[-1]
23
+ return host, uuid
24
+
25
+
26
+ def get_interactome(host, uuid, username, password, parent_edgelist):
27
+ """
28
+ Retrieves the interactome either from NDEx or from a local edge list.
29
+
30
+ :param host: The NDEx server host.
31
+ :type host: str
32
+ :param uuid: The UUID of the interactome network in NDEx.
33
+ :type uuid: str
34
+ :param username: The NDEx username for authentication.
35
+ :type username: str
36
+ :param password: The NDEx password for authentication.
37
+ :type password: str
38
+ :param parent_edgelist: Path to a file containing the interactome edge list.
39
+ :type parent_edgelist: str
40
+ :return: A CX2Network object representing the interactome.
41
+ :rtype: CX2Network
42
+ """
43
+ interactome = CX2Network()
44
+ if parent_edgelist is not None:
45
+ with open(parent_edgelist, 'r') as f:
46
+ for line in f:
47
+ parts = line.split()
48
+ id_source_node = interactome.lookup_node_id_by_name(parts[0])
49
+ source_node = id_source_node if id_source_node is not None else interactome.add_node(
50
+ attributes={'name': parts[0]})
51
+ id_target_node = interactome.lookup_node_id_by_name(parts[1])
52
+ target_node = id_target_node if id_target_node is not None else interactome.add_node(
53
+ attributes={'name': parts[1]})
54
+ interactome.add_edge(source=source_node, target=target_node)
55
+ elif host is not None and uuid is not None:
56
+ client = ndex2.client.Ndex2(host=host, username=username, password=password)
57
+ factory = RawCX2NetworkFactory()
58
+ client_resp = client.get_network_as_cx2_stream(uuid)
59
+ interactome = factory.get_cx2network(json.loads(client_resp.content))
60
+ return interactome
61
+
62
+
63
+ def get_root_nodes(hierarchy):
64
+ """
65
+ Identifies the root nodes in a hierarchical network.
66
+
67
+ In CDAPS the root node has only source edges to children
68
+ so this function counts up number of target edges for each node
69
+ and the one with 0 is the root
70
+
71
+ :return: root node ids
72
+ :rtype: set
73
+ """
74
+ all_nodes = set()
75
+ for node_id, node_obj in hierarchy.get_nodes().items():
76
+ all_nodes.add(node_id)
77
+
78
+ nodes_with_targets = set()
79
+ for edge_id, edge_obj in hierarchy.get_edges().items():
80
+ nodes_with_targets.add(edge_obj['t'])
81
+ return all_nodes.difference(nodes_with_targets)
82
+
83
+
84
+ def add_isroot_node_attribute(hierarchy, root_nodes):
85
+ """
86
+ Using the **root_nodes** set or list, add
87
+ ``HCX::isRoot`` to
88
+ every node setting value to ``True``
89
+ if node id is in **root_nodes**
90
+ otherwise set the value to ``False``
91
+ """
92
+ attr_name = 'HCX::isRoot'
93
+ for node_id, node_obj in hierarchy.get_nodes().items():
94
+ if node_id in root_nodes:
95
+ hierarchy.add_node_attribute(node_id, attr_name, True)
96
+ else:
97
+ hierarchy.add_node_attribute(node_id, attr_name, False)
98
+
99
+
100
+ def add_hcx_network_annotations(hierarchy, interactome=None, output_dir='.',
101
+ interactome_name='hierarchy_parent.cx2', host='www.ndexbio.org', uuid=None):
102
+ """
103
+ Adds HCX network annotations to the hierarchy.
104
+
105
+ :param hierarchy: The hierarchical network in CX2 format.
106
+ :type hierarchy: CX2Network
107
+ :param interactome: The interactome network.
108
+ :type interactome: CX2Network, optional
109
+ :param output_dir: Directory where the interactome file will be saved.
110
+ :type output_dir: str, optional
111
+ :param interactome_name: Name of the interactome file.
112
+ :type interactome_name: str, optional
113
+ :param host: NDEx host for interactome retrieval.
114
+ :type host: str, optional
115
+ :param uuid: UUID of the interactome in NDEx.
116
+ :type uuid: str, optional
117
+ :return: The updated hierarchy network with annotations.
118
+ :rtype: CX2Network
119
+ """
120
+ if not isinstance(hierarchy, CX2Network):
121
+ raise CellMapsError("Hierarchy must be an instance of CX2Network.")
122
+ if uuid is None and interactome is None:
123
+ raise CellMapsError("UUID of interactome or interactome (instance of CX2Network) must be specified!")
124
+
125
+ hierarchy.add_network_attribute('ndexSchema', 'hierarchy_v0.1',
126
+ datatype='string')
127
+ hierarchy.add_network_attribute('HCX::modelFileCount', '2',
128
+ datatype='integer')
129
+
130
+ if host and uuid:
131
+ hierarchy.add_network_attribute('HCX::interactionNetworkHost', host)
132
+ hierarchy.add_network_attribute('HCX::interactionNetworkUUID', uuid)
133
+ else:
134
+ interactome_path = os.path.join(output_dir, interactome_name)
135
+ interactome.write_as_raw_cx2(interactome_path)
136
+ hierarchy.add_network_attribute('HCX::interactionNetworkName', interactome_name,
137
+ datatype='string')
138
+ return hierarchy
139
+
140
+
141
+ def add_hcx_members_annotation(hierarchy, interactome, gene_column='CD_MemberList'):
142
+ """
143
+ Adds the 'HCX::members' attribute to nodes in the hierarchy based on the interactome.
144
+
145
+ :param hierarchy: The hierarchical network in CX2 format.
146
+ :type hierarchy: CX2Network
147
+ :param interactome: The interactome network.
148
+ :type interactome: CX2Network
149
+ :param gene_column: Column name containing gene members.
150
+ :type gene_column: str, optional
151
+ """
152
+ for node_id, node_obj in hierarchy.get_nodes().items():
153
+ memberlist = hierarchy.get_node(node_id).get('v', {}).get(gene_column, '').split(' ')
154
+ membersids = []
155
+ for member in memberlist:
156
+ id_interactome = interactome.lookup_node_id_by_name(member)
157
+ if id_interactome is not None:
158
+ membersids.append(id_interactome)
159
+ hierarchy.add_node_attribute(node_id, 'HCX::members', membersids, datatype='list_of_integer')
160
+
161
+
162
+ def convert_hierarchical_network_to_hcx(hierarchy, interactome_url, ndex_username=None, ndex_password=None,
163
+ gene_column='CD_MemberList'):
164
+ """
165
+ Converts a hierarchical network into HCX format by adding necessary annotations and interactome details.
166
+
167
+ :param hierarchy: The hierarchical network in CX2 format or a path to the CX2 file.
168
+ :type hierarchy: CX2Network or str
169
+ :param interactome_url: URL of the interactome network in NDEx.
170
+ :type interactome_url: str
171
+ :param ndex_username: NDEx username for authentication.
172
+ :type ndex_username: str, optional
173
+ :param ndex_password: NDEx password for authentication.
174
+ :type ndex_password: str, optional
175
+ :param gene_column: Column name containing gene members.
176
+ :type gene_column: str, optional
177
+ :return: The updated hierarchy network in CX2 format with HCX annotations.
178
+ :rtype: CX2Network
179
+ """
180
+ factory = RawCX2NetworkFactory()
181
+ if isinstance(hierarchy, str):
182
+ hierarchy = factory.get_cx2network(hierarchy)
183
+
184
+ # Get the host and uuid of the interactome
185
+ host, uuid = get_host_and_uuid_from_network_url(interactome_url)
186
+ hierarchy = add_hcx_network_annotations(hierarchy, host=host, uuid=uuid)
187
+
188
+ # Create CX2Network object from interactome from NDEx
189
+ client = ndex2.client.Ndex2(host=host, username=ndex_username, password=ndex_password)
190
+ client_resp = client.get_network_as_cx2_stream(uuid)
191
+ interactome = factory.get_cx2network(json.loads(client_resp.content))
192
+
193
+ # Add HCX::members attribute to node attributes
194
+ add_hcx_members_annotation(hierarchy, interactome, gene_column)
195
+
196
+ # Add isRoot attribute to node attributes
197
+ add_isroot_node_attribute(hierarchy, get_root_nodes(hierarchy))
198
+ return hierarchy
@@ -0,0 +1,245 @@
1
+ import json
2
+ import logging
3
+ import os
4
+
5
+ import ndex2
6
+ from ndex2.cx2 import RawCX2NetworkFactory, CX2Network
7
+ import ndex2.constants as constants
8
+ import cellmaps_utils.constants as cellmaps_constants
9
+ from cellmaps_utils import hcx_utils
10
+ from cellmaps_utils.exceptions import CellMapsError
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ class HierarchyToHiDeFConverter:
16
+ """
17
+ A class to convert a hierarchy network (in CX2 format) to a HiDeF format.
18
+ """
19
+ HIDEF_OUT_PREFIX = 'hidef_output_gene_names'
20
+
21
+ def __init__(self, output_dir, input_dir=None, hierarchy=None):
22
+ """
23
+ Constructor
24
+
25
+ :param input_dir: The directory containing the hierarchy file.
26
+ :type input_dir: str
27
+ :param output_dir: The directory where the output files will be stored.
28
+ :type output_dir: str
29
+ """
30
+ self.output_dir = output_dir
31
+ if hierarchy is None:
32
+ if input_dir is None:
33
+ raise CellMapsError("Either hierarch_path or input_dir should be specified!")
34
+ self.hierarchy_path = os.path.join(input_dir,
35
+ cellmaps_constants.HIERARCHY_NETWORK_PREFIX +
36
+ cellmaps_constants.CX2_SUFFIX)
37
+ else:
38
+ self.hierarchy_path = hierarchy
39
+ try:
40
+ factory = RawCX2NetworkFactory()
41
+ self.hierarchy = factory.get_cx2network(self.hierarchy_path)
42
+ except Exception as e:
43
+ logger.error(f"Failed to load hierarchy: {e}")
44
+ raise CellMapsError(f"Failed to load hierarchy: {e}")
45
+
46
+ def generate_hidef_files(self, nodes_filename=HIDEF_OUT_PREFIX + '.nodes',
47
+ edges_filename=HIDEF_OUT_PREFIX + '.edges'):
48
+ """
49
+ Generates HiDeF files .nodes and .edges from the hierarchy network.
50
+ """
51
+ try:
52
+ nodes = self.hierarchy.get_nodes()
53
+ edges = self.hierarchy.get_edges()
54
+ formatted_nodes = self._format_aspect(nodes, self._format_node)
55
+ formatted_edges = self._format_aspect(edges, self._format_edge)
56
+ nodes_path = self._write_to_file(nodes_filename, formatted_nodes)
57
+ edges_path = self._write_to_file(edges_filename, formatted_edges)
58
+ return nodes_path, edges_path
59
+ except Exception as e:
60
+ logger.error(f"Error during HiDeF generation: {e}")
61
+ raise CellMapsError(f"Error during HiDeF generation: {e}")
62
+
63
+ @staticmethod
64
+ def _format_aspect(aspect, format_function):
65
+ """
66
+ Formats aspect list (nodes or edges) using a specified format function.
67
+
68
+ :param aspect: A list of aspect IDs (nodes or edges).
69
+ :type aspect: dict
70
+ :param format_function: A function to format a single entity.
71
+ :type format_function: function
72
+ :return: A list of formatted nodes or edges.
73
+ :rtype: list
74
+ """
75
+ return [format_function(aspect_id) for aspect_id in aspect]
76
+
77
+ def _format_node(self, node_id):
78
+ """
79
+ Formats a node for HiDeF output.
80
+
81
+ :param node_id: The ID of the node to be formatted.
82
+ :type node_id: int
83
+ :return: A formatted string representing the node.
84
+ :rtype: str
85
+ """
86
+ node = self.hierarchy.get_node(node_id)
87
+ node_attr = node[constants.ASPECT_VALUES]
88
+ formatted_node = (node_attr.get(constants.NODE_NAME_EXPANDED, node_id), node_attr.get('CD_MemberList_Size', 0),
89
+ node_attr.get('CD_MemberList', ''), node_attr.get('HiDeF_persistence', 0))
90
+ return "\t".join(map(str, formatted_node))
91
+
92
+ def _format_edge(self, edge_id):
93
+ """
94
+ Formats an edge for HiDeF output.
95
+
96
+ :param edge_id: The ID of the edge to be formatted.
97
+ :type edge_id: int
98
+ :return: A formatted string representing the edge.
99
+ :rtype: str
100
+ """
101
+ edge = self.hierarchy.get_edge(edge_id)
102
+ source_node = self._find_node_name_by_id(edge[constants.EDGE_SOURCE])
103
+ target_node = self._find_node_name_by_id(edge[constants.EDGE_TARGET])
104
+ return f"{source_node}\t{target_node}\tdefault"
105
+
106
+ def _find_node_name_by_id(self, node_id):
107
+ """
108
+ Finds the name of a node given its ID.
109
+
110
+ :param node_id: The ID of the node.
111
+ :type node_id: int
112
+ :return: The name of the node.
113
+ :rtype: str
114
+ """
115
+ node = self.hierarchy.get_node(node_id)
116
+ return node[constants.ASPECT_VALUES].get(constants.NODE_NAME_EXPANDED, node_id)
117
+
118
+ def _write_to_file(self, filename, lines):
119
+ """
120
+ Writes output to a file.
121
+
122
+ :param filename: The name of the file to write to.
123
+ :type filename: str
124
+ :param lines: A list of strings to be written to the file.
125
+ :type lines: list
126
+ """
127
+ file_path = os.path.join(self.output_dir, filename)
128
+ with open(file_path, 'w') as file:
129
+ file.write('\n'.join(lines))
130
+ return file_path
131
+
132
+
133
+ class HiDeFToHierarchyConverter:
134
+ """
135
+ A class to convert a edge list and node list in HiDeF format to hierarchy in HCX.
136
+
137
+ .. versionadded:: 0.5.0
138
+ The class was added to enable conversion from HiDeF-formatted edge and node files to hierarchy in HCX.
139
+ """
140
+
141
+ def __init__(self, output_dir, nodes_file_path, edges_file_path, parent_edgelist_path=None, parent_ndex_url=None,
142
+ host='ndexbio.org', parent_uuid=None, ndex_user=None, ndex_password=None):
143
+ """
144
+ Initializes the converter with file paths and optional parent network details.
145
+
146
+ Parent network can be specified one of the following:
147
+ - edge list file
148
+ - link to interactome in NDEx
149
+ - uuid of NDEx network along with the host where the network is hosted.
150
+ If the network is private, username and password need to be specified.
151
+
152
+ :param output_dir: Directory where the output files will be stored.
153
+ :type output_dir: str
154
+ :param nodes_file_path: File path for the nodes file.
155
+ :type nodes_file_path: str
156
+ :param edges_file_path: File path for the edges file.
157
+ :type edges_file_path: str
158
+ :param parent_edgelist_path: Path to the edge list of the interactome (optional).
159
+ :type parent_edgelist_path: str, optional
160
+ :param parent_ndex_url: URL of parent interactome in NDEx (optional).
161
+ :type parent_ndex_url: str, optional
162
+ :param parent_uuid: UUID of the network in NDEx.
163
+ :type parent_uuid: str, optional
164
+ :param host: NDEx host.
165
+ :type host: str, optional
166
+ :param ndex_user: NDEx username (optional).
167
+ :type ndex_user: str, optional
168
+ :param ndex_password: NDEx password (optional).
169
+ :type ndex_password: str, optional
170
+ """
171
+ self.output_dir = output_dir
172
+ self.nodes_file_path = nodes_file_path
173
+ self.edges_file_path = edges_file_path
174
+ if parent_ndex_url is None and parent_edgelist_path is None:
175
+ raise CellMapsError("Specifying either url of parent interactome in NDEx, or edge list of the interactome"
176
+ " is required!")
177
+ if parent_edgelist_path is not None and (parent_ndex_url is not None or parent_uuid is not None):
178
+ raise CellMapsError("You need to specify parent network as edge list in file, or as network in NDEx, "
179
+ "not both!")
180
+ self.parent_edgelist = parent_edgelist_path
181
+ self.parent_url = parent_ndex_url
182
+ self.host = host
183
+ self.uuid = parent_uuid
184
+ self.username = ndex_user
185
+ self.password = ndex_password
186
+
187
+ def generate_hierarchy_hcx_file(self, hierarchy_filename='hierarchy.cx2',
188
+ interactome_filename='hierarchy_parent.cx2'):
189
+ """
190
+ Generates the HiDeF hierarchy file in CX2 format. If the object is initialized with parent network's edge list,
191
+ the interactome in CX2 format will be generated in output directory as well. If the object is initialized with
192
+ uuid of parent network, only hierarchy will be generated.
193
+
194
+ :param hierarchy_filename: The name of the file to write the hierarchy.
195
+ :type hierarchy_filename: str
196
+ :param interactome_filename: The name of the file to write the interactome (parent network of the hierarchy).
197
+ :type interactome_filename: str
198
+ """
199
+ hierarchy_path = os.path.join(self.output_dir, hierarchy_filename)
200
+ if self.parent_url is not None:
201
+ self.host, self.uuid = hcx_utils.get_host_and_uuid_from_network_url(self.parent_url)
202
+ interactome = hcx_utils.get_interactome(self.host, self.uuid, self.username, self.password,
203
+ self.parent_edgelist)
204
+ hierarchy = hcx_utils.add_hcx_network_annotations(self._get_hierarchy(interactome), interactome,
205
+ self.output_dir, interactome_filename, self.host, self.uuid)
206
+ hierarchy.write_as_raw_cx2(hierarchy_path)
207
+
208
+ def _get_hierarchy(self, interactome):
209
+ """
210
+ Constructs the hierarchy based on the HiDeF edge list and node list and uses interactome to add HCX information.
211
+
212
+ :param interactome: The interactome network.
213
+ :type interactome: CX2Network
214
+ :return: A CX2Network object representing the hierarchy.
215
+ :rtype: CX2Network
216
+ """
217
+ hierarchy = CX2Network()
218
+
219
+ with open(self.nodes_file_path, 'r') as f:
220
+ for line in f:
221
+ name, size, genes, persistence = line.strip().split('\t')
222
+ hcx_members = []
223
+ for gene in genes.split():
224
+ hcx_members.append(interactome.lookup_node_id_by_name(gene))
225
+ node_attributes = {
226
+ constants.NODE_NAME_EXPANDED: name,
227
+ 'CD_MemberList_Size': size,
228
+ 'CD_MemberList': genes,
229
+ 'HCX::members': hcx_members,
230
+ 'HiDeF_persistence': persistence
231
+ }
232
+ hierarchy.add_node(attributes=node_attributes)
233
+
234
+ with open(self.edges_file_path, 'r') as f:
235
+ for line in f:
236
+ source, target, _ = line.strip().split('\t')
237
+ source_id = hierarchy.lookup_node_id_by_name(source)
238
+ target_id = hierarchy.lookup_node_id_by_name(target)
239
+ if source_id is not None and target_id is not None:
240
+ hierarchy.add_edge(source=source_id, target=target_id)
241
+
242
+ root_nodes = hcx_utils.get_root_nodes(hierarchy)
243
+ hcx_utils.add_isroot_node_attribute(hierarchy, root_nodes=root_nodes)
244
+
245
+ return hierarchy
@@ -0,0 +1,142 @@
1
+ import logging
2
+
3
+ import numpy as np
4
+ import pandas as pd
5
+ from ndex2.cx2 import RawCX2NetworkFactory, CX2Network
6
+
7
+ logger = logging.getLogger(__name__)
8
+
9
+
10
+ class HierarchyDiff:
11
+ """
12
+ A class to compare two hierarchies in CX2 (HCX)
13
+ """
14
+
15
+ def __init__(self):
16
+ """
17
+ Constructor
18
+ """
19
+ pass
20
+
21
+ @staticmethod
22
+ def _calculate_jaccard(setA, setB):
23
+ """
24
+ Calculate the Jaccard similarity between two sets.
25
+
26
+ The Jaccard similarity is defined as |A ∩ B| / |A ∪ B|.
27
+
28
+ :param setA: First set.
29
+ :type setA: set
30
+ :param setB: Second set.
31
+ :type setB: set
32
+ :return: The Jaccard similarity index.
33
+ :rtype: float
34
+ """
35
+ overlap = len(setA.intersection(setB))
36
+ union = len(setA.union(setB))
37
+ return overlap / union if union > 0 else 0
38
+
39
+ def _hierarchy_overlap(self, ref_hierarchy, alt_hierarchy):
40
+ """
41
+ Computes a Jaccard similarity between nodes in two CX2Network hierarchies.
42
+ For each node in the alternative hierarchy, it calculates the Jaccard index with each node in
43
+ the reference hierarchy.
44
+
45
+ :param ref_hierarchy: The reference hierarchy to compare against.
46
+ :type ref_hierarchy: ndex2.cx2.CX2Network
47
+ :param alt_hierarchy: The alternative hierarchy being compared.
48
+ :type alt_hierarchy: ndex2.cx2.CX2Network
49
+ :return: A DataFrame of pass/fail (1/0) based on Jaccard similarity.
50
+ :rtype: pandas.DataFrame
51
+ """
52
+ ref_nodes = ref_hierarchy.get_nodes()
53
+ nodes = alt_hierarchy.get_nodes()
54
+
55
+ # Prepare a DataFrame to hold JI values
56
+ ji_df = pd.DataFrame(index=list(nodes.keys()), columns=list(ref_nodes.keys()), dtype=float)
57
+
58
+ for node_id, node_obj in nodes.items():
59
+ ont_comp_genes = set(node_obj.get('v', {}).get('CD_MemberList', '').split())
60
+ for ref_node_id, ref_node_obj in ref_nodes.items():
61
+ comp_genes = set(ref_node_obj.get('v', {}).get('CD_MemberList', '').split())
62
+ ji_df.at[node_id, ref_node_id] = self._calculate_jaccard(ont_comp_genes, comp_genes) \
63
+ if ont_comp_genes and comp_genes else 0
64
+
65
+ return ji_df
66
+
67
+ def compute_hierarchy_robustness(self, ref_hierarchy, alt_hierarchies, ji_thre=0.4):
68
+ """
69
+ Computes a robustness score for each node in a reference hierarchy based on its structural overlap
70
+ across multiple alternative hierarchies. The overlap is measured using the Jaccard Index (JI),
71
+ and a threshold that determines if a node is considered to have sufficient overlap in a given
72
+ alternative hierarchy (values above the threshold are set to 1, while values below are set to 0).
73
+ The higher the overlap across the alternative hierarchies, the higher the robustness score.
74
+
75
+ robustness = (# hierarchies where JI > ji_thre) / (total number of alternative hierarchies)
76
+
77
+ :param ref_hierarchy: The reference hierarchy whose nodes' robustness is computed.
78
+ :type ref_hierarchy: ndex2.cx2.CX2Network or dict (raw CX2)
79
+ :param alt_hierarchies: A list of alternative hierarchies to compare against.
80
+ :type alt_hierarchies: list[ndex2.cx2.CX2Network or dict]
81
+ :param ji_thre: The Jaccard threshold used to determine overlap.
82
+ :type ji_thre: float
83
+ :return: The reference hierarchy with an added 'robustness' attribute for each node.
84
+ :rtype: ndex2.cx2.CX2Network
85
+ """
86
+ factory = RawCX2NetworkFactory()
87
+ ref_hier = ref_hierarchy if isinstance(ref_hierarchy, CX2Network) else factory.get_cx2network(ref_hierarchy)
88
+ alt_hiers = []
89
+ for hier in alt_hierarchies:
90
+ alt_hiers.append(hier if isinstance(hier, CX2Network) else factory.get_cx2network(hier))
91
+ r_hier = pd.DataFrame(index=list(ref_hier.get_nodes().keys()))
92
+ r_hier['robustness'] = [0] * len(r_hier)
93
+ for hierarchy in alt_hiers:
94
+ ji_df = self._hierarchy_overlap(ref_hier, hierarchy)
95
+ # Make a "pass/fail" matrix: 0 if JI <= threshold, 1 otherwise
96
+ pass_fail_df = (ji_df > ji_thre).astype(int)
97
+ maxs = pass_fail_df.max(axis=0)
98
+ r_hier.loc[pass_fail_df.columns, 'robustness'] += np.array(maxs).astype(int)
99
+ r_hier['robustness'] /= len(alt_hiers)
100
+ for node_id, robustness in r_hier['robustness'].to_dict().items():
101
+ ref_hier.add_node_attribute(node_id, 'robustness', robustness)
102
+
103
+ return ref_hier
104
+
105
+ def compare_hierarchies(self, hierarchy_a=None, hierarchy_b=None):
106
+ """
107
+ Compare two hierarchies in CX2 format by calculating Jaccard overlaps and
108
+ assigning a 'robustness' (overlap) score to each node in the first hierarchy.
109
+
110
+ :param hierarchy_a: The first (reference) hierarchy to compare.
111
+ :type hierarchy_a: ndex2.cx2.CX2Network
112
+ :param hierarchy_b: The second (alternative) hierarchy to compare against.
113
+ :type hierarchy_b: ndex2.cx2.CX2Network
114
+ :return: The first hierarchy with an added 'robustness' node attribute.
115
+ :rtype: ndex2.cx2.CX2Network
116
+ """
117
+ ji_df = self._hierarchy_overlap(hierarchy_a, hierarchy_b)
118
+ maxs = ji_df.max(axis=0)
119
+ node_overlap_scores = maxs.to_dict()
120
+
121
+ # Add nodes annotate nodes in hierarchy_a robustness scores
122
+ for node_id, data in hierarchy_a.get_nodes().items():
123
+ score = node_overlap_scores.get(node_id, 0)
124
+ hierarchy_a.add_node_attribute(node_id, 'robustness', score)
125
+
126
+ return hierarchy_a
127
+
128
+ def compare_hierarchies_from_files(self, hierarchy_a_path=None, hierarchy_b_path=None):
129
+ """
130
+ Compare two hierarchies from files then calculating overlap-based scores.
131
+
132
+ :param hierarchy_a_path: Path to the first (reference) hierarchy file.
133
+ :type hierarchy_a_path: str
134
+ :param hierarchy_b_path: Path to the second (alternative) hierarchy file.
135
+ :type hierarchy_b_path: str
136
+ :return: The first hierarchy (from hierarchy_a_path) with added robustness scores.
137
+ :rtype: ndex2.cx2.CX2Network
138
+ """
139
+ factory = RawCX2NetworkFactory()
140
+ hierarchy_a = factory.get_cx2network(hierarchy_a_path)
141
+ hierarchy_b = factory.get_cx2network(hierarchy_b_path)
142
+ return self.compare_hierarchies(hierarchy_a, hierarchy_b)
@@ -0,0 +1,31 @@
1
+ This data set has been generated in the Emma Lundberg lab (https://ell-core.stanford.edu/)
2
+ as part of the CM4AI Research Program (https://cm4ai.org/).
3
+
4
+ This data set displays the spatial localization of proteins in the cell line MDA-MB-468.
5
+ MDA-MB-468 cells were seeded into 96-well glass bottom plates
6
+ and treated either with the chemotherapeutic drug Paclitaxel or with the chemotherapeutic
7
+ drug Vorinostat (SAHA) or not treated. For drug treatment, higher cell numbers were
8
+ seeded than for the cells that were not treated to reach a sufficient amount of
9
+ remaining cells at the end of the experiment (treatment with Paclitaxel or Vorinostat
10
+ disturbs cell growth). After fixation of the cells with PFA, for each protein, the
11
+ subcellular distribution of the protein was investigated by immunofluorescence-based
12
+ staining (ICC-IF) and confocal microscopy. Each well was stained with
13
+ DAPI (to label nuclei, "blue" channel),
14
+ a Calreticulin antibody (to label the endoplasmic reticulum, "yellow" channel),
15
+ a Tubulin antibody (to label Microtubuli, "red" channel), and an antibody against a
16
+ protein of interest (a different antibody / protein for each well, "green" channel).
17
+ In the green channel, for each well, each one of the proteins was stained with an antibody
18
+ from the proteinatlas.org project.
19
+
20
+ The .tsv file describes each image in the data set. Each row represents one image.
21
+ The columns describe the staining from which the image was taken:
22
+ "Antibody ID" describes the antibody ID for the antibody applied to stain the protein
23
+ visible in the "green" channel. The antibody ID can be looked up at proteinatlas.org
24
+ to find out more information about the antibody.
25
+ "ENSEMBL ID" indicates the ENSEMBL ID(s) of the gene(s) of the proteins visualized
26
+ in the "green" channel.
27
+
28
+ Treatment refers to how the cells that are depicted in the image were treated
29
+ (with Paclitaxel, Vorinostat, or untreated)
30
+ "Well" refers to the well coordinate on the 96-well plate
31
+ "Region" is a unique identifier for the position in the well, where the cells were acquired.