risk-network 0.0.13b3__tar.gz → 0.0.13b4__tar.gz

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.
Files changed (52) hide show
  1. {risk_network-0.0.13b3/src/risk_network.egg-info → risk_network-0.0.13b4}/PKG-INFO +2 -2
  2. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/pyproject.toml +1 -1
  3. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk/__init__.py +1 -1
  4. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk/annotation/annotation.py +22 -8
  5. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk/annotation/io.py +58 -20
  6. {risk_network-0.0.13b3 → risk_network-0.0.13b4/src/risk_network.egg-info}/PKG-INFO +2 -2
  7. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/tests/test_load_annotation.py +44 -2
  8. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/tests/test_log.py +2 -0
  9. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/LICENSE +0 -0
  10. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/README.md +0 -0
  11. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/setup.cfg +0 -0
  12. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk/annotation/__init__.py +0 -0
  13. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk/annotation/nltk_setup.py +0 -0
  14. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk/log/__init__.py +0 -0
  15. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk/log/console.py +0 -0
  16. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk/log/parameters.py +0 -0
  17. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk/neighborhoods/__init__.py +0 -0
  18. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk/neighborhoods/api.py +0 -0
  19. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk/neighborhoods/community.py +0 -0
  20. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk/neighborhoods/domains.py +0 -0
  21. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk/neighborhoods/neighborhoods.py +0 -0
  22. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk/neighborhoods/stats/__init__.py +0 -0
  23. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk/neighborhoods/stats/permutation/__init__.py +0 -0
  24. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk/neighborhoods/stats/permutation/permutation.py +0 -0
  25. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk/neighborhoods/stats/permutation/test_functions.py +0 -0
  26. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk/neighborhoods/stats/tests.py +0 -0
  27. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk/network/__init__.py +0 -0
  28. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk/network/graph/__init__.py +0 -0
  29. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk/network/graph/api.py +0 -0
  30. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk/network/graph/graph.py +0 -0
  31. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk/network/graph/stats.py +0 -0
  32. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk/network/graph/summary.py +0 -0
  33. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk/network/io.py +0 -0
  34. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk/network/plotter/__init__.py +0 -0
  35. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk/network/plotter/api.py +0 -0
  36. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk/network/plotter/canvas.py +0 -0
  37. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk/network/plotter/contour.py +0 -0
  38. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk/network/plotter/labels.py +0 -0
  39. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk/network/plotter/network.py +0 -0
  40. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk/network/plotter/plotter.py +0 -0
  41. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk/network/plotter/utils/colors.py +0 -0
  42. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk/network/plotter/utils/layout.py +0 -0
  43. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk/risk.py +0 -0
  44. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk_network.egg-info/SOURCES.txt +0 -0
  45. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk_network.egg-info/dependency_links.txt +0 -0
  46. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk_network.egg-info/requires.txt +0 -0
  47. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/src/risk_network.egg-info/top_level.txt +0 -0
  48. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/tests/test_load_graph.py +0 -0
  49. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/tests/test_load_io_combinations.py +0 -0
  50. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/tests/test_load_neighborhoods.py +0 -0
  51. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/tests/test_load_network.py +0 -0
  52. {risk_network-0.0.13b3 → risk_network-0.0.13b4}/tests/test_load_plotter.py +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: risk-network
3
- Version: 0.0.13b3
4
- Summary: A Python package for biological network analysis.
3
+ Version: 0.0.13b4
4
+ Summary: A Python package for scalable network analysis and high-quality visualization.
5
5
  Author-email: Ira Horecka <ira89@icloud.com>
6
6
  License: GPL-3.0-or-later
7
7
  Project-URL: Homepage, https://github.com/riskportal/network
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
5
5
  [project]
6
6
  name = "risk-network"
7
7
  dynamic = ["version"]
8
- description = "A Python package for biological network analysis."
8
+ description = "A Python package for scalable network analysis and high-quality visualization."
9
9
  authors = [
10
10
  { name = "Ira Horecka", email = "ira89@icloud.com" },
11
11
  ]
@@ -7,4 +7,4 @@ RISK: Regional Inference of Significant Kinships
7
7
 
8
8
  from risk.risk import RISK
9
9
 
10
- __version__ = "0.0.13-beta.3"
10
+ __version__ = "0.0.13-beta.4"
@@ -36,7 +36,10 @@ initialize_nltk()
36
36
 
37
37
 
38
38
  def load_annotation(
39
- network: nx.Graph, annotation_input: Dict[str, Any], min_nodes_per_term: int = 2
39
+ network: nx.Graph,
40
+ annotation_input: Dict[str, Any],
41
+ min_nodes_per_term: int = 1,
42
+ max_nodes_per_term: int = 10_000,
40
43
  ) -> Dict[str, Any]:
41
44
  """Convert annotation input to a sparse matrix and reindex based on the network's node labels.
42
45
 
@@ -44,7 +47,9 @@ def load_annotation(
44
47
  network (nx.Graph): The network graph.
45
48
  annotation_input (Dict[str, Any]): An annotation dictionary.
46
49
  min_nodes_per_term (int, optional): The minimum number of network nodes required for each annotation
47
- term to be included. Defaults to 2.
50
+ term to be included. Defaults to 1.
51
+ max_nodes_per_term (int, optional): The maximum number of network nodes allowed for each annotation
52
+ term. Defaults to 10_000.
48
53
 
49
54
  Returns:
50
55
  Dict[str, Any]: A dictionary containing ordered nodes, ordered annotations, and the sparse binary annotations
@@ -52,7 +57,6 @@ def load_annotation(
52
57
 
53
58
  Raises:
54
59
  ValueError: If no annotation is found for the nodes in the network.
55
- ValueError: If no annotation has at least min_nodes_per_term nodes in the network.
56
60
  """
57
61
  # Step 1: Map nodes and annotations to indices
58
62
  node_label_order = [attr["label"] for _, attr in network.nodes(data=True) if "label" in attr]
@@ -72,9 +76,18 @@ def load_annotation(
72
76
  # Create a sparse binary matrix
73
77
  num_nodes = len(node_to_idx)
74
78
  num_annotation = len(annotation_to_idx)
75
- annotation_pivot = coo_matrix((data, (row, col)), shape=(num_nodes, num_annotation)).tocsr()
76
- # Step 3: Filter out annotations with fewer than min_nodes_per_term occurrences
77
- valid_annotation = annotation_pivot.sum(axis=0).A1 >= min_nodes_per_term
79
+ # Convert to a sparse matrix and set the data type to uint8 for binary representation
80
+ annotation_pivot = (
81
+ coo_matrix((data, (row, col)), shape=(num_nodes, num_annotation)).tocsr().astype(np.uint8)
82
+ )
83
+ # Step 3: Filter out annotations with too few or too many nodes
84
+ valid_annotation = np.array(
85
+ [
86
+ annotation_pivot[:, i].sum() >= min_nodes_per_term
87
+ and annotation_pivot[:, i].sum() <= max_nodes_per_term
88
+ for i in range(num_annotation)
89
+ ]
90
+ )
78
91
  annotation_pivot = annotation_pivot[:, valid_annotation]
79
92
  # Step 4: Raise errors for empty matrices
80
93
  if annotation_pivot.nnz == 0:
@@ -83,7 +96,7 @@ def load_annotation(
83
96
  num_remaining_annotation = annotation_pivot.shape[1]
84
97
  if num_remaining_annotation == 0:
85
98
  raise ValueError(
86
- f"No annotation terms found with at least {min_nodes_per_term} nodes in the network."
99
+ f"No annotation terms found with at least {min_nodes_per_term} nodes and at most {max_nodes_per_term} nodes."
87
100
  )
88
101
 
89
102
  # Step 5: Extract ordered nodes and annotations
@@ -94,6 +107,7 @@ def load_annotation(
94
107
 
95
108
  # Log the filtering details
96
109
  logger.info(f"Minimum number of nodes per annotation term: {min_nodes_per_term}")
110
+ logger.info(f"Maximum number of nodes per annotation term: {max_nodes_per_term}")
97
111
  logger.info(f"Number of input annotation terms: {num_annotation}")
98
112
  logger.info(f"Number of remaining annotation terms: {num_remaining_annotation}")
99
113
 
@@ -122,7 +136,7 @@ def define_top_annotation(
122
136
  significant_significance_matrix (np.ndarray): Enrichment matrix below alpha threshold.
123
137
  significant_binary_significance_matrix (np.ndarray): Binary significance matrix below alpha threshold.
124
138
  min_cluster_size (int, optional): Minimum cluster size. Defaults to 5.
125
- max_cluster_size (int, optional): Maximum cluster size. Defaults to 1000.
139
+ max_cluster_size (int, optional): Maximum cluster size. Defaults to 10_000.
126
140
 
127
141
  Returns:
128
142
  pd.DataFrame: DataFrame with top annotations and their properties.
@@ -21,7 +21,11 @@ class AnnotationIO:
21
21
  """
22
22
 
23
23
  def load_annotation_json(
24
- self, network: nx.Graph, filepath: str, min_nodes_per_term: int = 2
24
+ self,
25
+ network: nx.Graph,
26
+ filepath: str,
27
+ min_nodes_per_term: int = 1,
28
+ max_nodes_per_term: int = 10_000,
25
29
  ) -> Dict[str, Any]:
26
30
  """Load annotation from a JSON file and convert them to a DataFrame.
27
31
 
@@ -29,7 +33,9 @@ class AnnotationIO:
29
33
  network (NetworkX graph): The network to which the annotation is related.
30
34
  filepath (str): Path to the JSON annotation file.
31
35
  min_nodes_per_term (int, optional): The minimum number of network nodes required for each annotation
32
- term to be included. Defaults to 2.
36
+ term to be included. Defaults to 1.
37
+ max_nodes_per_term (int, optional): The maximum number of network nodes allowed for each annotation
38
+ term to be included. Defaults to 10_000.
33
39
 
34
40
  Returns:
35
41
  Dict[str, Any]: A dictionary containing ordered nodes, ordered annotations, and the annotation matrix.
@@ -37,7 +43,10 @@ class AnnotationIO:
37
43
  filetype = "JSON"
38
44
  # Log the loading of the JSON file
39
45
  params.log_annotation(
40
- filetype=filetype, filepath=filepath, min_nodes_per_term=min_nodes_per_term
46
+ filetype=filetype,
47
+ filepath=filepath,
48
+ min_nodes_per_term=min_nodes_per_term,
49
+ max_nodes_per_term=max_nodes_per_term,
41
50
  )
42
51
  self._log_loading_annotation(filetype, filepath=filepath)
43
52
 
@@ -45,7 +54,7 @@ class AnnotationIO:
45
54
  with open(filepath, "r", encoding="utf-8") as file:
46
55
  annotation_input = json.load(file)
47
56
 
48
- return load_annotation(network, annotation_input, min_nodes_per_term)
57
+ return load_annotation(network, annotation_input, min_nodes_per_term, max_nodes_per_term)
49
58
 
50
59
  def load_annotation_excel(
51
60
  self,
@@ -55,7 +64,8 @@ class AnnotationIO:
55
64
  nodes_colname: str = "nodes",
56
65
  sheet_name: str = "Sheet1",
57
66
  nodes_delimiter: str = ";",
58
- min_nodes_per_term: int = 2,
67
+ min_nodes_per_term: int = 1,
68
+ max_nodes_per_term: int = 10_000,
59
69
  ) -> Dict[str, Any]:
60
70
  """Load annotation from an Excel file and associate them with the network.
61
71
 
@@ -67,7 +77,9 @@ class AnnotationIO:
67
77
  sheet_name (str, optional): The name of the Excel sheet to load (default is 'Sheet1').
68
78
  nodes_delimiter (str, optional): Delimiter used to separate multiple nodes within the nodes column (default is ';').
69
79
  min_nodes_per_term (int, optional): The minimum number of network nodes required for each annotation
70
- term to be included. Defaults to 2.
80
+ term to be included. Defaults to 1.
81
+ max_nodes_per_term (int, optional): The maximum number of network nodes allowed for each annotation
82
+ term to be included. Defaults to 10_000.
71
83
 
72
84
  Returns:
73
85
  Dict[str, Any]: A dictionary where each label is paired with its respective list of nodes,
@@ -76,7 +88,10 @@ class AnnotationIO:
76
88
  filetype = "Excel"
77
89
  # Log the loading of the Excel file
78
90
  params.log_annotation(
79
- filetype=filetype, filepath=filepath, min_nodes_per_term=min_nodes_per_term
91
+ filetype=filetype,
92
+ filepath=filepath,
93
+ min_nodes_per_term=min_nodes_per_term,
94
+ max_nodes_per_term=max_nodes_per_term,
80
95
  )
81
96
  self._log_loading_annotation(filetype, filepath=filepath)
82
97
 
@@ -89,7 +104,7 @@ class AnnotationIO:
89
104
  # Convert the DataFrame to a dictionary pairing labels with their corresponding nodes
90
105
  annotation_input = annotation.set_index(label_colname)[nodes_colname].to_dict()
91
106
 
92
- return load_annotation(network, annotation_input, min_nodes_per_term)
107
+ return load_annotation(network, annotation_input, min_nodes_per_term, max_nodes_per_term)
93
108
 
94
109
  def load_annotation_csv(
95
110
  self,
@@ -98,7 +113,8 @@ class AnnotationIO:
98
113
  label_colname: str = "label",
99
114
  nodes_colname: str = "nodes",
100
115
  nodes_delimiter: str = ";",
101
- min_nodes_per_term: int = 2,
116
+ min_nodes_per_term: int = 1,
117
+ max_nodes_per_term: int = 10_000,
102
118
  ) -> Dict[str, Any]:
103
119
  """Load annotation from a CSV file and associate them with the network.
104
120
 
@@ -109,7 +125,9 @@ class AnnotationIO:
109
125
  nodes_colname (str): Name of the column containing the nodes associated with each label.
110
126
  nodes_delimiter (str, optional): Delimiter used to separate multiple nodes within the nodes column (default is ';').
111
127
  min_nodes_per_term (int, optional): The minimum number of network nodes required for each annotation
112
- term to be included. Defaults to 2.
128
+ term to be included. Defaults to 1.
129
+ max_nodes_per_term (int, optional): The maximum number of network nodes allowed for each annotation
130
+ term to be included. Defaults to 10_000.
113
131
 
114
132
  Returns:
115
133
  Dict[str, Any]: A dictionary where each label is paired with its respective list of nodes,
@@ -118,7 +136,10 @@ class AnnotationIO:
118
136
  filetype = "CSV"
119
137
  # Log the loading of the CSV file
120
138
  params.log_annotation(
121
- filetype=filetype, filepath=filepath, min_nodes_per_term=min_nodes_per_term
139
+ filetype=filetype,
140
+ filepath=filepath,
141
+ min_nodes_per_term=min_nodes_per_term,
142
+ max_nodes_per_term=max_nodes_per_term,
122
143
  )
123
144
  self._log_loading_annotation(filetype, filepath=filepath)
124
145
 
@@ -127,7 +148,7 @@ class AnnotationIO:
127
148
  filepath, label_colname, nodes_colname, delimiter=",", nodes_delimiter=nodes_delimiter
128
149
  )
129
150
 
130
- return load_annotation(network, annotation_input, min_nodes_per_term)
151
+ return load_annotation(network, annotation_input, min_nodes_per_term, max_nodes_per_term)
131
152
 
132
153
  def load_annotation_tsv(
133
154
  self,
@@ -136,7 +157,8 @@ class AnnotationIO:
136
157
  label_colname: str = "label",
137
158
  nodes_colname: str = "nodes",
138
159
  nodes_delimiter: str = ";",
139
- min_nodes_per_term: int = 2,
160
+ min_nodes_per_term: int = 1,
161
+ max_nodes_per_term: int = 10_000,
140
162
  ) -> Dict[str, Any]:
141
163
  """Load annotation from a TSV file and associate them with the network.
142
164
 
@@ -147,7 +169,9 @@ class AnnotationIO:
147
169
  nodes_colname (str): Name of the column containing the nodes associated with each label.
148
170
  nodes_delimiter (str, optional): Delimiter used to separate multiple nodes within the nodes column (default is ';').
149
171
  min_nodes_per_term (int, optional): The minimum number of network nodes required for each annotation
150
- term to be included. Defaults to 2.
172
+ term to be included. Defaults to 1.
173
+ max_nodes_per_term (int, optional): The maximum number of network nodes allowed for each annotation
174
+ term to be included. Defaults to 10_000.
151
175
 
152
176
  Returns:
153
177
  Dict[str, Any]: A dictionary where each label is paired with its respective list of nodes,
@@ -156,7 +180,10 @@ class AnnotationIO:
156
180
  filetype = "TSV"
157
181
  # Log the loading of the TSV file
158
182
  params.log_annotation(
159
- filetype=filetype, filepath=filepath, min_nodes_per_term=min_nodes_per_term
183
+ filetype=filetype,
184
+ filepath=filepath,
185
+ min_nodes_per_term=min_nodes_per_term,
186
+ max_nodes_per_term=max_nodes_per_term,
160
187
  )
161
188
  self._log_loading_annotation(filetype, filepath=filepath)
162
189
 
@@ -165,10 +192,14 @@ class AnnotationIO:
165
192
  filepath, label_colname, nodes_colname, delimiter="\t", nodes_delimiter=nodes_delimiter
166
193
  )
167
194
 
168
- return load_annotation(network, annotation_input, min_nodes_per_term)
195
+ return load_annotation(network, annotation_input, min_nodes_per_term, max_nodes_per_term)
169
196
 
170
197
  def load_annotation_dict(
171
- self, network: nx.Graph, content: Dict[str, Any], min_nodes_per_term: int = 2
198
+ self,
199
+ network: nx.Graph,
200
+ content: Dict[str, Any],
201
+ min_nodes_per_term: int = 1,
202
+ max_nodes_per_term: int = 10_000,
172
203
  ) -> Dict[str, Any]:
173
204
  """Load annotation from a provided dictionary and convert them to a dictionary annotation.
174
205
 
@@ -176,7 +207,9 @@ class AnnotationIO:
176
207
  network (NetworkX graph): The network to which the annotation is related.
177
208
  content (Dict[str, Any]): The annotation dictionary to load.
178
209
  min_nodes_per_term (int, optional): The minimum number of network nodes required for each annotation
179
- term to be included. Defaults to 2.
210
+ term to be included. Defaults to 1.
211
+ max_nodes_per_term (int, optional): The maximum number of network nodes allowed for each annotation
212
+ term to be included. Defaults to 10_000.
180
213
 
181
214
  Returns:
182
215
  Dict[str, Any]: A dictionary containing ordered nodes, ordered annotations, and the annotation matrix.
@@ -192,11 +225,16 @@ class AnnotationIO:
192
225
 
193
226
  filetype = "Dictionary"
194
227
  # Log the loading of the annotation from the dictionary
195
- params.log_annotation(filepath="In-memory dictionary", filetype=filetype)
228
+ params.log_annotation(
229
+ filepath="In-memory dictionary",
230
+ filetype=filetype,
231
+ min_nodes_per_term=min_nodes_per_term,
232
+ max_nodes_per_term=max_nodes_per_term,
233
+ )
196
234
  self._log_loading_annotation(filetype, "In-memory dictionary")
197
235
 
198
236
  # Load the annotation as a dictionary from the provided dictionary
199
- return load_annotation(network, content, min_nodes_per_term)
237
+ return load_annotation(network, content, min_nodes_per_term, max_nodes_per_term)
200
238
 
201
239
  def _load_matrix_file(
202
240
  self,
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: risk-network
3
- Version: 0.0.13b3
4
- Summary: A Python package for biological network analysis.
3
+ Version: 0.0.13b4
4
+ Summary: A Python package for scalable network analysis and high-quality visualization.
5
5
  Author-email: Ira Horecka <ira89@icloud.com>
6
6
  License: GPL-3.0-or-later
7
7
  Project-URL: Homepage, https://github.com/riskportal/network
@@ -3,11 +3,11 @@ tests/test_load_annotation
3
3
  ~~~~~~~~~~~~~~~~~~~~~~~~~~
4
4
  """
5
5
 
6
+ import json
7
+
6
8
  import pytest
7
9
  from scipy.sparse import csr_matrix, vstack
8
10
 
9
- # Ensure dummy fixtures are imported by referencing them in test signatures below.
10
-
11
11
 
12
12
  def test_missing_annotation_file(risk_obj, dummy_network):
13
13
  """Test loading an annotation file that does not exist.
@@ -22,6 +22,7 @@ def test_missing_annotation_file(risk_obj, dummy_network):
22
22
  filepath=annotation_file,
23
23
  network=dummy_network,
24
24
  min_nodes_per_term=1,
25
+ max_nodes_per_term=1000,
25
26
  )
26
27
 
27
28
 
@@ -38,6 +39,7 @@ def test_load_annotation_csv(risk_obj, cytoscape_network, data_path):
38
39
  filepath=str(annotation_file),
39
40
  network=cytoscape_network,
40
41
  min_nodes_per_term=1,
42
+ max_nodes_per_term=1000,
41
43
  )
42
44
 
43
45
  assert annotation is not None
@@ -57,6 +59,7 @@ def test_csv_annotation_structure(risk_obj, cytoscape_network, data_path):
57
59
  filepath=str(annotation_file),
58
60
  network=cytoscape_network,
59
61
  min_nodes_per_term=1,
62
+ max_nodes_per_term=1000,
60
63
  )
61
64
 
62
65
  assert isinstance(annotation, dict), "Annotation should be a dictionary"
@@ -82,6 +85,7 @@ def test_load_annotation_dict(risk_obj, dummy_network, dummy_annotation_dict):
82
85
  content=dummy_annotation_dict,
83
86
  network=dummy_network,
84
87
  min_nodes_per_term=1,
88
+ max_nodes_per_term=1000,
85
89
  )
86
90
 
87
91
  assert annotation is not None
@@ -100,6 +104,7 @@ def test_dict_annotation_structure(risk_obj, dummy_network, dummy_annotation_dic
100
104
  content=dummy_annotation_dict,
101
105
  network=dummy_network,
102
106
  min_nodes_per_term=1,
107
+ max_nodes_per_term=1000,
103
108
  )
104
109
 
105
110
  assert isinstance(annotation, dict), "Annotation should be a dictionary"
@@ -126,6 +131,7 @@ def test_load_annotation_json(risk_obj, cytoscape_network, data_path):
126
131
  filepath=str(annotation_file),
127
132
  network=cytoscape_network,
128
133
  min_nodes_per_term=1,
134
+ max_nodes_per_term=1000,
129
135
  )
130
136
 
131
137
  assert annotation is not None
@@ -145,6 +151,7 @@ def test_json_annotation_structure(risk_obj, cytoscape_network, data_path):
145
151
  filepath=str(annotation_file),
146
152
  network=cytoscape_network,
147
153
  min_nodes_per_term=1,
154
+ max_nodes_per_term=1000,
148
155
  )
149
156
 
150
157
  assert isinstance(annotation, dict), "Annotation should be a dictionary"
@@ -171,6 +178,7 @@ def test_load_annotation_tsv(risk_obj, cytoscape_network, data_path):
171
178
  filepath=str(annotation_file),
172
179
  network=cytoscape_network,
173
180
  min_nodes_per_term=1,
181
+ max_nodes_per_term=1000,
174
182
  )
175
183
 
176
184
  assert annotation is not None
@@ -190,6 +198,7 @@ def test_tsv_annotation_structure(risk_obj, cytoscape_network, data_path):
190
198
  filepath=str(annotation_file),
191
199
  network=cytoscape_network,
192
200
  min_nodes_per_term=1,
201
+ max_nodes_per_term=1000,
193
202
  )
194
203
 
195
204
  assert isinstance(annotation, dict), "Annotation should be a dictionary"
@@ -216,6 +225,7 @@ def test_load_annotation_excel(risk_obj, cytoscape_network, data_path):
216
225
  filepath=str(annotation_file),
217
226
  network=cytoscape_network,
218
227
  min_nodes_per_term=1,
228
+ max_nodes_per_term=1000,
219
229
  )
220
230
 
221
231
  assert annotation is not None
@@ -235,6 +245,7 @@ def test_excel_annotation_structure(risk_obj, cytoscape_network, data_path):
235
245
  filepath=str(annotation_file),
236
246
  network=cytoscape_network,
237
247
  min_nodes_per_term=1,
248
+ max_nodes_per_term=1000,
238
249
  )
239
250
 
240
251
  assert isinstance(annotation, dict), "Annotation should be a dictionary"
@@ -262,11 +273,13 @@ def test_combined_annotation(risk_obj, cytoscape_network, data_path):
262
273
  filepath=str(csv_file),
263
274
  network=cytoscape_network,
264
275
  min_nodes_per_term=1,
276
+ max_nodes_per_term=1000,
265
277
  )
266
278
  json_annotation = risk_obj.load_annotation_json(
267
279
  filepath=str(json_file),
268
280
  network=cytoscape_network,
269
281
  min_nodes_per_term=1,
282
+ max_nodes_per_term=1000,
270
283
  )
271
284
  # Combine the components of the annotations
272
285
  combined_annotation = {
@@ -289,3 +302,32 @@ def test_combined_annotation(risk_obj, cytoscape_network, data_path):
289
302
  assert len(combined_annotation["ordered_nodes"]) == len(csv_annotation["ordered_nodes"]) + len(
290
303
  json_annotation["ordered_nodes"]
291
304
  )
305
+
306
+
307
+ def test_min_max_nodes_per_term(risk_obj, cytoscape_network, data_path):
308
+ """Test that loaded annotation respects min and max node limits per term.
309
+
310
+ Args:
311
+ risk_obj: The RISK object instance used for loading annotation.
312
+ cytoscape_network: The network object to which annotation will be applied.
313
+ data_path: The base path to the directory containing the annotation files.
314
+ """
315
+ annotation_file = data_path / "json" / "annotation" / "go_biological_process.json"
316
+ min_nodes = 2
317
+ max_nodes = 100
318
+ # Load annotation with filtering
319
+ annotation = risk_obj.load_annotation_json(
320
+ filepath=str(annotation_file),
321
+ network=cytoscape_network,
322
+ min_nodes_per_term=min_nodes,
323
+ max_nodes_per_term=max_nodes,
324
+ )
325
+ # Extract the mapping of term to genes from the raw JSON input
326
+ with open(annotation_file, "r") as f:
327
+ raw_dict = json.load(f)
328
+
329
+ filtered_terms = annotation["ordered_annotation"]
330
+ for term in filtered_terms:
331
+ gene_count = len(raw_dict[term])
332
+ assert gene_count >= min_nodes, f"Term {term} has too few genes: {gene_count}"
333
+ assert gene_count <= max_nodes, f"Term {term} has too many genes: {gene_count}"
@@ -66,7 +66,9 @@ def test_params_log_annotation(log_capture):
66
66
  filetype="CSV",
67
67
  filepath="mock/path/to/file.csv",
68
68
  min_nodes_per_term=3,
69
+ max_nodes_per_term=5,
69
70
  )
70
71
  assert params.annotation["filetype"] == "CSV"
71
72
  assert params.annotation["filepath"] == "mock/path/to/file.csv"
72
73
  assert params.annotation["min_nodes_per_term"] == 3
74
+ assert params.annotation["max_nodes_per_term"] == 5
File without changes