risk-network 0.0.3b4__py3-none-any.whl → 0.0.4b1__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.
risk/__init__.py CHANGED
@@ -10,4 +10,4 @@ RISK: RISK Infers Spatial Kinship
10
10
 
11
11
  from risk.risk import RISK
12
12
 
13
- __version__ = "0.0.3-beta.4"
13
+ __version__ = "0.0.4-beta.1"
@@ -171,7 +171,9 @@ def get_description(words_column: pd.Series) -> str:
171
171
  stop_words = set(stopwords.words("english"))
172
172
  # Tokenize the concatenated string and filter out stopwords and non-alphabetic words
173
173
  words = [
174
- word.lower()
174
+ (
175
+ word.lower() if word.istitle() else word
176
+ ) # Lowercase all words except proper nouns (e.g., RNA, mRNA)
175
177
  for word in word_tokenize(words_column.str.cat(sep=" "))
176
178
  if word.isalpha() and word.lower() not in stop_words
177
179
  ]
risk/annotations/io.py CHANGED
@@ -25,7 +25,7 @@ class AnnotationsIO:
25
25
  def __init__(self):
26
26
  pass
27
27
 
28
- def load_json_annotations(self, filepath: str, network: nx.Graph) -> Dict[str, Any]:
28
+ def load_json_annotation(self, filepath: str, network: nx.Graph) -> Dict[str, Any]:
29
29
  """Load annotations from a JSON file and convert them to a DataFrame.
30
30
 
31
31
  Args:
@@ -170,7 +170,16 @@ def _impute_neighbors(
170
170
  # Calculate shortest distances for each node to determine the distance threshold
171
171
  shortest_distances = []
172
172
  for node in network.nodes():
173
- neighbors = [n for n in network.neighbors(node) if binary_enrichment_matrix[n].sum() != 0]
173
+ try:
174
+ neighbors = [
175
+ n for n in network.neighbors(node) if binary_enrichment_matrix[n].sum() != 0
176
+ ]
177
+ except IndexError as e:
178
+ raise IndexError(
179
+ f"Failed to find neighbors for node '{node}': Ensure that the node exists in the network and that the binary enrichment matrix is correctly indexed."
180
+ ) from e
181
+
182
+ # Calculate the shortest distance to a neighbor
174
183
  if neighbors:
175
184
  shortest_distance = min([_get_euclidean_distance(node, n, network) for n in neighbors])
176
185
  shortest_distances.append(shortest_distance)
risk/network/graph.py CHANGED
@@ -49,8 +49,8 @@ class NetworkGraph:
49
49
  self.trimmed_domains = trimmed_domains
50
50
  self.node_label_to_id_map = node_label_to_id_map
51
51
  self.node_enrichment_sums = node_enrichment_sums
52
- # NOTE: self.G and self.node_coordinates are declared in _initialize_network
53
- self.G = None
52
+ # NOTE: self.network and self.node_coordinates are declared in _initialize_network
53
+ self.network = None
54
54
  self.node_coordinates = None
55
55
  self._initialize_network(network)
56
56
 
@@ -95,8 +95,8 @@ class NetworkGraph:
95
95
  """
96
96
  # Unfold the network's 3D coordinates to 2D
97
97
  G_2d = _unfold_sphere_to_plane(G)
98
- # Assign the unfolded graph to self.G
99
- self.G = G_2d
98
+ # Assign the unfolded graph to self.network
99
+ self.network = G_2d
100
100
  # Extract 2D coordinates of nodes
101
101
  self.node_coordinates = _extract_node_coordinates(G_2d)
102
102
 
risk/network/io.py CHANGED
@@ -29,25 +29,67 @@ class NetworkIO:
29
29
  self,
30
30
  compute_sphere: bool = True,
31
31
  surface_depth: float = 0.0,
32
- distance_metric: str = "dijkstra",
33
- edge_length_threshold: float = 0.5,
34
- louvain_resolution: float = 0.1,
35
32
  min_edges_per_node: int = 0,
36
33
  include_edge_weight: bool = True,
37
34
  weight_label: str = "weight",
38
35
  ):
36
+ """Initialize the NetworkIO class.
37
+
38
+ Args:
39
+ compute_sphere (bool, optional): Whether to map nodes to a sphere. Defaults to True.
40
+ surface_depth (float, optional): Surface depth for the sphere. Defaults to 0.0.
41
+ min_edges_per_node (int, optional): Minimum number of edges per node. Defaults to 0.
42
+ include_edge_weight (bool, optional): Whether to include edge weights in calculations. Defaults to True.
43
+ weight_label (str, optional): Label for edge weights. Defaults to "weight".
44
+ """
39
45
  self.compute_sphere = compute_sphere
40
46
  self.surface_depth = surface_depth
47
+ self.min_edges_per_node = min_edges_per_node
41
48
  self.include_edge_weight = include_edge_weight
42
49
  self.weight_label = weight_label
43
- self.distance_metric = distance_metric
44
- self.edge_length_threshold = edge_length_threshold
45
- self.louvain_resolution = louvain_resolution
46
- self.min_edges_per_node = min_edges_per_node
50
+ params.log_network(
51
+ compute_sphere=compute_sphere,
52
+ surface_depth=surface_depth,
53
+ min_edges_per_node=min_edges_per_node,
54
+ include_edge_weight=include_edge_weight,
55
+ weight_label=weight_label,
56
+ )
47
57
 
48
- def load_gpickle_network(self, filepath: str) -> nx.Graph:
58
+ @classmethod
59
+ def load_gpickle_network(
60
+ cls,
61
+ filepath: str,
62
+ compute_sphere: bool = True,
63
+ surface_depth: float = 0.0,
64
+ min_edges_per_node: int = 0,
65
+ include_edge_weight: bool = True,
66
+ weight_label: str = "weight",
67
+ ) -> nx.Graph:
49
68
  """Load a network from a GPickle file.
50
69
 
70
+ Args:
71
+ filepath (str): Path to the GPickle file.
72
+ compute_sphere (bool, optional): Whether to map nodes to a sphere. Defaults to True.
73
+ surface_depth (float, optional): Surface depth for the sphere. Defaults to 0.0.
74
+ min_edges_per_node (int, optional): Minimum number of edges per node. Defaults to 0.
75
+ include_edge_weight (bool, optional): Whether to include edge weights in calculations. Defaults to True.
76
+ weight_label (str, optional): Label for edge weights. Defaults to "weight".
77
+
78
+ Returns:
79
+ nx.Graph: Loaded and processed network.
80
+ """
81
+ networkio = cls(
82
+ compute_sphere=compute_sphere,
83
+ surface_depth=surface_depth,
84
+ min_edges_per_node=min_edges_per_node,
85
+ include_edge_weight=include_edge_weight,
86
+ weight_label=weight_label,
87
+ )
88
+ return networkio._load_gpickle_network(filepath=filepath)
89
+
90
+ def _load_gpickle_network(self, filepath: str) -> nx.Graph:
91
+ """Private method to load a network from a GPickle file.
92
+
51
93
  Args:
52
94
  filepath (str): Path to the GPickle file.
53
95
 
@@ -62,11 +104,43 @@ class NetworkIO:
62
104
 
63
105
  return self._initialize_graph(G)
64
106
 
65
- def load_networkx_network(self, G: nx.Graph) -> nx.Graph:
107
+ @classmethod
108
+ def load_networkx_network(
109
+ cls,
110
+ network: nx.Graph,
111
+ compute_sphere: bool = True,
112
+ surface_depth: float = 0.0,
113
+ min_edges_per_node: int = 0,
114
+ include_edge_weight: bool = True,
115
+ weight_label: str = "weight",
116
+ ) -> nx.Graph:
66
117
  """Load a NetworkX graph.
67
118
 
68
119
  Args:
69
- G (nx.Graph): A NetworkX graph object.
120
+ network (nx.Graph): A NetworkX graph object.
121
+ compute_sphere (bool, optional): Whether to map nodes to a sphere. Defaults to True.
122
+ surface_depth (float, optional): Surface depth for the sphere. Defaults to 0.0.
123
+ min_edges_per_node (int, optional): Minimum number of edges per node. Defaults to 0.
124
+ include_edge_weight (bool, optional): Whether to include edge weights in calculations. Defaults to True.
125
+ weight_label (str, optional): Label for edge weights. Defaults to "weight".
126
+
127
+ Returns:
128
+ nx.Graph: Loaded and processed network.
129
+ """
130
+ networkio = cls(
131
+ compute_sphere=compute_sphere,
132
+ surface_depth=surface_depth,
133
+ min_edges_per_node=min_edges_per_node,
134
+ include_edge_weight=include_edge_weight,
135
+ weight_label=weight_label,
136
+ )
137
+ return networkio._load_networkx_network(network=network)
138
+
139
+ def _load_networkx_network(self, network: nx.Graph) -> nx.Graph:
140
+ """Private method to load a NetworkX graph.
141
+
142
+ Args:
143
+ network (nx.Graph): A NetworkX graph object.
70
144
 
71
145
  Returns:
72
146
  nx.Graph: Processed network.
@@ -74,17 +148,60 @@ class NetworkIO:
74
148
  filetype = "NetworkX"
75
149
  params.log_network(filetype=filetype)
76
150
  self._log_loading(filetype)
77
- return self._initialize_graph(G)
151
+ return self._initialize_graph(network)
78
152
 
153
+ @classmethod
79
154
  def load_cytoscape_network(
80
- self,
155
+ cls,
81
156
  filepath: str,
82
157
  source_label: str = "source",
83
158
  target_label: str = "target",
159
+ compute_sphere: bool = True,
160
+ surface_depth: float = 0.0,
161
+ min_edges_per_node: int = 0,
162
+ include_edge_weight: bool = True,
163
+ weight_label: str = "weight",
84
164
  view_name: str = "",
85
165
  ) -> nx.Graph:
86
166
  """Load a network from a Cytoscape file.
87
167
 
168
+ Args:
169
+ filepath (str): Path to the Cytoscape file.
170
+ source_label (str, optional): Source node label. Defaults to "source".
171
+ target_label (str, optional): Target node label. Defaults to "target".
172
+ view_name (str, optional): Specific view name to load. Defaults to None.
173
+ compute_sphere (bool, optional): Whether to map nodes to a sphere. Defaults to True.
174
+ surface_depth (float, optional): Surface depth for the sphere. Defaults to 0.0.
175
+ min_edges_per_node (int, optional): Minimum number of edges per node. Defaults to 0.
176
+ include_edge_weight (bool, optional): Whether to include edge weights in calculations. Defaults to True.
177
+ weight_label (str, optional): Label for edge weights. Defaults to "weight".
178
+
179
+ Returns:
180
+ nx.Graph: Loaded and processed network.
181
+ """
182
+ networkio = cls(
183
+ compute_sphere=compute_sphere,
184
+ surface_depth=surface_depth,
185
+ min_edges_per_node=min_edges_per_node,
186
+ include_edge_weight=include_edge_weight,
187
+ weight_label=weight_label,
188
+ )
189
+ return networkio._load_cytoscape_network(
190
+ filepath=filepath,
191
+ source_label=source_label,
192
+ target_label=target_label,
193
+ view_name=view_name,
194
+ )
195
+
196
+ def _load_cytoscape_network(
197
+ self,
198
+ filepath: str,
199
+ source_label: str = "source",
200
+ target_label: str = "target",
201
+ view_name: str = "",
202
+ ) -> nx.Graph:
203
+ """Private method to load a network from a Cytoscape file.
204
+
88
205
  Args:
89
206
  filepath (str): Path to the Cytoscape file.
90
207
  source_label (str, optional): Source node label. Defaults to "source".
@@ -179,9 +296,49 @@ class NetworkIO:
179
296
  for dirname in cys_dirnames:
180
297
  shutil.rmtree(dirname)
181
298
 
182
- def load_cytoscape_json_network(self, filepath, source_label="source", target_label="target"):
299
+ @classmethod
300
+ def load_cytoscape_json_network(
301
+ cls,
302
+ filepath: str,
303
+ source_label: str = "source",
304
+ target_label: str = "target",
305
+ compute_sphere: bool = True,
306
+ surface_depth: float = 0.0,
307
+ min_edges_per_node: int = 0,
308
+ include_edge_weight: bool = True,
309
+ weight_label: str = "weight",
310
+ ) -> nx.Graph:
183
311
  """Load a network from a Cytoscape JSON (.cyjs) file.
184
312
 
313
+ Args:
314
+ filepath (str): Path to the Cytoscape JSON file.
315
+ source_label (str, optional): Source node label. Default is "source".
316
+ target_label (str, optional): Target node label. Default is "target".
317
+ compute_sphere (bool, optional): Whether to map nodes to a sphere. Defaults to True.
318
+ surface_depth (float, optional): Surface depth for the sphere. Defaults to 0.0.
319
+ min_edges_per_node (int, optional): Minimum number of edges per node. Defaults to 0.
320
+ include_edge_weight (bool, optional): Whether to include edge weights in calculations. Defaults to True.
321
+ weight_label (str, optional): Label for edge weights. Defaults to "weight".
322
+
323
+ Returns:
324
+ NetworkX graph: Loaded and processed network.
325
+ """
326
+ networkio = cls(
327
+ compute_sphere=compute_sphere,
328
+ surface_depth=surface_depth,
329
+ min_edges_per_node=min_edges_per_node,
330
+ include_edge_weight=include_edge_weight,
331
+ weight_label=weight_label,
332
+ )
333
+ return networkio._load_cytoscape_json_network(
334
+ filepath=filepath,
335
+ source_label=source_label,
336
+ target_label=target_label,
337
+ )
338
+
339
+ def _load_cytoscape_json_network(self, filepath, source_label="source", target_label="target"):
340
+ """Private method to load a network from a Cytoscape JSON (.cyjs) file.
341
+
185
342
  Args:
186
343
  filepath (str): Path to the Cytoscape JSON file.
187
344
  source_label (str, optional): Source node label. Default is "source".
@@ -193,36 +350,46 @@ class NetworkIO:
193
350
  filetype = "Cytoscape JSON"
194
351
  params.log_network(filetype=filetype, filepath=str(filepath))
195
352
  self._log_loading(filetype, filepath=filepath)
353
+
196
354
  # Load the Cytoscape JSON file
197
355
  with open(filepath, "r") as f:
198
356
  cyjs_data = json.load(f)
199
357
 
200
358
  # Create a graph
201
359
  G = nx.Graph()
202
- # Process nodes
360
+ # Store node positions for later use
203
361
  node_x_positions = {}
204
362
  node_y_positions = {}
205
363
  for node in cyjs_data["elements"]["nodes"]:
206
364
  node_data = node["data"]
207
- node_id = node_data["id"]
365
+ node_id = node_data["id_original"]
208
366
  node_x_positions[node_id] = node["position"]["x"]
209
367
  node_y_positions[node_id] = node["position"]["y"]
210
- G.add_node(node_id)
211
- G.nodes[node_id]["label"] = node_data.get("name", node_id)
212
- G.nodes[node_id]["x"] = node["position"]["x"]
213
- G.nodes[node_id]["y"] = node["position"]["y"]
214
368
 
215
- # Process edges
369
+ # Process edges and add them to the graph
216
370
  for edge in cyjs_data["elements"]["edges"]:
217
371
  edge_data = edge["data"]
218
- source = edge_data[source_label]
219
- target = edge_data[target_label]
372
+ source = edge_data[f"{source_label}_original"]
373
+ target = edge_data[f"{target_label}_original"]
374
+ # Add the edge to the graph, optionally including weights
220
375
  if self.weight_label is not None and self.weight_label in edge_data:
221
376
  weight = float(edge_data[self.weight_label])
222
377
  G.add_edge(source, target, weight=weight)
223
378
  else:
224
379
  G.add_edge(source, target)
225
380
 
381
+ # Ensure nodes exist in the graph and add them if not present
382
+ if source not in G:
383
+ G.add_node(source)
384
+ if target not in G:
385
+ G.add_node(target)
386
+
387
+ # Add node attributes (like label, x, y positions)
388
+ for node in G.nodes():
389
+ G.nodes[node]["label"] = node
390
+ G.nodes[node]["x"] = node_x_positions.get(node, 0) # Use stored positions
391
+ G.nodes[node]["y"] = node_y_positions.get(node, 0) # Use stored positions
392
+
226
393
  # Initialize the graph
227
394
  return self._initialize_graph(G)
228
395
 
@@ -320,7 +487,6 @@ class NetworkIO:
320
487
  print(f"Projection: {'Sphere' if self.compute_sphere else 'Plane'}")
321
488
  if self.compute_sphere:
322
489
  print(f"Surface depth: {self.surface_depth}")
323
- print(f"Edge length threshold: {self.edge_length_threshold}")
324
490
  print(f"Edge weight: {'Included' if self.include_edge_weight else 'Excluded'}")
325
491
  if self.include_edge_weight:
326
492
  print(f"Weight label: {self.weight_label}")
risk/network/plot.py CHANGED
@@ -27,7 +27,7 @@ class NetworkPlotter:
27
27
 
28
28
  def __init__(
29
29
  self,
30
- network_graph: NetworkGraph,
30
+ graph: NetworkGraph,
31
31
  figsize: tuple = (10, 10),
32
32
  background_color: str = "white",
33
33
  plot_outline: bool = True,
@@ -37,22 +37,22 @@ class NetworkPlotter:
37
37
  """Initialize the NetworkPlotter with a NetworkGraph object and plotting parameters.
38
38
 
39
39
  Args:
40
- network_graph (NetworkGraph): The network data and attributes to be visualized.
40
+ graph (NetworkGraph): The network data and attributes to be visualized.
41
41
  figsize (tuple, optional): Size of the figure in inches (width, height). Defaults to (10, 10).
42
42
  background_color (str, optional): Background color of the plot. Defaults to "white".
43
43
  plot_outline (bool, optional): Whether to plot the network perimeter circle. Defaults to True.
44
44
  outline_color (str, optional): Color of the network perimeter circle. Defaults to "black".
45
45
  outline_scale (float, optional): Outline scaling factor for the perimeter diameter. Defaults to 1.0.
46
46
  """
47
- self.network_graph = network_graph
47
+ self.graph = graph
48
48
  # Initialize the plot with the specified parameters
49
49
  self.ax = self._initialize_plot(
50
- network_graph, figsize, background_color, plot_outline, outline_color, outline_scale
50
+ graph, figsize, background_color, plot_outline, outline_color, outline_scale
51
51
  )
52
52
 
53
53
  def _initialize_plot(
54
54
  self,
55
- network_graph: NetworkGraph,
55
+ graph: NetworkGraph,
56
56
  figsize: tuple,
57
57
  background_color: str,
58
58
  plot_outline: bool,
@@ -62,7 +62,7 @@ class NetworkPlotter:
62
62
  """Set up the plot with figure size, optional circle perimeter, and background color.
63
63
 
64
64
  Args:
65
- network_graph (NetworkGraph): The network data and attributes to be visualized.
65
+ graph (NetworkGraph): The network data and attributes to be visualized.
66
66
  figsize (tuple): Size of the figure in inches (width, height).
67
67
  background_color (str): Background color of the plot.
68
68
  plot_outline (bool): Whether to plot the network perimeter circle.
@@ -73,7 +73,7 @@ class NetworkPlotter:
73
73
  plt.Axes: The axis object for the plot.
74
74
  """
75
75
  # Extract node coordinates from the network graph
76
- node_coordinates = network_graph.node_coordinates
76
+ node_coordinates = graph.node_coordinates
77
77
  # Calculate the center and radius of the bounding box around the network
78
78
  center, radius = _calculate_bounding_box(node_coordinates)
79
79
  # Scale the radius by the outline_scale factor
@@ -141,10 +141,10 @@ class NetworkPlotter:
141
141
  network_node_shape=node_shape,
142
142
  )
143
143
  # Extract node coordinates from the network graph
144
- node_coordinates = self.network_graph.node_coordinates
144
+ node_coordinates = self.graph.node_coordinates
145
145
  # Draw the nodes of the graph
146
146
  nx.draw_networkx_nodes(
147
- self.network_graph.G,
147
+ self.graph.network,
148
148
  pos=node_coordinates,
149
149
  node_size=node_size,
150
150
  node_color=node_color,
@@ -155,7 +155,7 @@ class NetworkPlotter:
155
155
  )
156
156
  # Draw the edges of the graph
157
157
  nx.draw_networkx_edges(
158
- self.network_graph.G,
158
+ self.graph.network,
159
159
  pos=node_coordinates,
160
160
  width=edge_width,
161
161
  edge_color=edge_color,
@@ -197,20 +197,18 @@ class NetworkPlotter:
197
197
  )
198
198
  # Filter to get node IDs and their coordinates
199
199
  node_ids = [
200
- self.network_graph.node_label_to_id_map.get(node)
200
+ self.graph.node_label_to_id_map.get(node)
201
201
  for node in nodes
202
- if node in self.network_graph.node_label_to_id_map
202
+ if node in self.graph.node_label_to_id_map
203
203
  ]
204
204
  if not node_ids:
205
205
  raise ValueError("No nodes found in the network graph.")
206
206
 
207
207
  # Get the coordinates of the filtered nodes
208
- node_coordinates = {
209
- node_id: self.network_graph.node_coordinates[node_id] for node_id in node_ids
210
- }
208
+ node_coordinates = {node_id: self.graph.node_coordinates[node_id] for node_id in node_ids}
211
209
  # Draw the nodes in the subnetwork
212
210
  nx.draw_networkx_nodes(
213
- self.network_graph.G,
211
+ self.graph.network,
214
212
  pos=node_coordinates,
215
213
  nodelist=node_ids,
216
214
  node_size=node_size,
@@ -221,7 +219,7 @@ class NetworkPlotter:
221
219
  ax=self.ax,
222
220
  )
223
221
  # Draw the edges between the specified nodes in the subnetwork
224
- subgraph = self.network_graph.G.subgraph(node_ids)
222
+ subgraph = self.graph.network.subgraph(node_ids)
225
223
  nx.draw_networkx_edges(
226
224
  subgraph,
227
225
  pos=node_coordinates,
@@ -260,9 +258,9 @@ class NetworkPlotter:
260
258
  color = self.get_annotated_contour_colors(color=color)
261
259
 
262
260
  # Extract node coordinates from the network graph
263
- node_coordinates = self.network_graph.node_coordinates
261
+ node_coordinates = self.graph.node_coordinates
264
262
  # Draw contours for each domain in the network
265
- for idx, (_, nodes) in enumerate(self.network_graph.domain_to_nodes.items()):
263
+ for idx, (_, nodes) in enumerate(self.graph.domain_to_nodes.items()):
266
264
  if len(nodes) > 1:
267
265
  self._draw_kde_contour(
268
266
  self.ax,
@@ -299,23 +297,23 @@ class NetworkPlotter:
299
297
  """
300
298
  # Log the plotting parameters
301
299
  params.log_plotter(
302
- contour_levels=levels,
303
- contour_bandwidth=bandwidth,
304
- contour_grid_size=grid_size,
305
- contour_alpha=alpha,
306
- contour_color="custom" if isinstance(color, np.ndarray) else color,
300
+ subcontour_levels=levels,
301
+ subcontour_bandwidth=bandwidth,
302
+ subcontour_grid_size=grid_size,
303
+ subcontour_alpha=alpha,
304
+ subcontour_color="custom" if isinstance(color, np.ndarray) else color,
307
305
  )
308
306
  # Filter to get node IDs and their coordinates
309
307
  node_ids = [
310
- self.network_graph.node_label_to_id_map.get(node)
308
+ self.graph.node_label_to_id_map.get(node)
311
309
  for node in nodes
312
- if node in self.network_graph.node_label_to_id_map
310
+ if node in self.graph.node_label_to_id_map
313
311
  ]
314
312
  if not node_ids or len(node_ids) == 1:
315
313
  raise ValueError("No nodes found in the network graph or insufficient nodes to plot.")
316
314
 
317
315
  # Draw the KDE contour for the specified nodes
318
- node_coordinates = self.network_graph.node_coordinates
316
+ node_coordinates = self.graph.node_coordinates
319
317
  self._draw_kde_contour(
320
318
  self.ax,
321
319
  node_coordinates,
@@ -402,7 +400,7 @@ class NetworkPlotter:
402
400
  fontcolor: Union[str, np.ndarray] = "black",
403
401
  arrow_linewidth: float = 1,
404
402
  arrow_color: Union[str, np.ndarray] = "black",
405
- num_words: int = 10,
403
+ max_words: int = 10,
406
404
  min_words: int = 1,
407
405
  ) -> None:
408
406
  """Annotate the network graph with labels for different domains, positioned around the network for clarity.
@@ -415,7 +413,7 @@ class NetworkPlotter:
415
413
  fontcolor (str or np.ndarray, optional): Color of the label text. Can be a string or RGBA array. Defaults to "black".
416
414
  arrow_linewidth (float, optional): Line width of the arrows pointing to centroids. Defaults to 1.
417
415
  arrow_color (str or np.ndarray, optional): Color of the arrows. Can be a string or RGBA array. Defaults to "black".
418
- num_words (int, optional): Maximum number of words in a label. Defaults to 10.
416
+ max_words (int, optional): Maximum number of words in a label. Defaults to 10.
419
417
  min_words (int, optional): Minimum number of words required to display a label. Defaults to 1.
420
418
  """
421
419
  # Log the plotting parameters
@@ -427,7 +425,7 @@ class NetworkPlotter:
427
425
  label_fontcolor="custom" if isinstance(fontcolor, np.ndarray) else fontcolor,
428
426
  label_arrow_linewidth=arrow_linewidth,
429
427
  label_arrow_color="custom" if isinstance(arrow_color, np.ndarray) else arrow_color,
430
- label_num_words=num_words,
428
+ label_max_words=max_words,
431
429
  label_min_words=min_words,
432
430
  )
433
431
  # Convert color strings to RGBA arrays if necessary
@@ -438,28 +436,38 @@ class NetworkPlotter:
438
436
 
439
437
  # Calculate the center and radius of the network
440
438
  domain_centroids = {}
441
- for domain, nodes in self.network_graph.domain_to_nodes.items():
439
+ for domain, nodes in self.graph.domain_to_nodes.items():
442
440
  if nodes: # Skip if the domain has no nodes
443
441
  domain_centroids[domain] = self._calculate_domain_centroid(nodes)
444
442
 
443
+ # Initialize empty lists to collect valid indices
444
+ valid_indices = []
445
+ filtered_domain_centroids = {}
446
+ # Loop through domain_centroids with index
447
+ for idx, (domain, centroid) in enumerate(domain_centroids.items()):
448
+ # Check if the domain passes the word count condition
449
+ if len(self.graph.trimmed_domain_to_term[domain].split(" ")[:max_words]) >= min_words:
450
+ # Add to filtered_domain_centroids
451
+ filtered_domain_centroids[domain] = centroid
452
+ # Keep track of the valid index
453
+ valid_indices.append(idx)
454
+
455
+ # Now filter fontcolor and arrow_color to keep only the valid indices
456
+ fontcolor = fontcolor[valid_indices]
457
+ arrow_color = arrow_color[valid_indices]
458
+
445
459
  # Calculate the bounding box around the network
446
460
  center, radius = _calculate_bounding_box(
447
- self.network_graph.node_coordinates, radius_margin=perimeter_scale
461
+ self.graph.node_coordinates, radius_margin=perimeter_scale
448
462
  )
449
-
450
- # Filter out domains with insufficient words for labeling
451
- filtered_domains = {
452
- domain: centroid
453
- for domain, centroid in domain_centroids.items()
454
- if len(self.network_graph.trimmed_domain_to_term[domain].split(" ")[:num_words])
455
- >= min_words
456
- }
457
463
  # Calculate the best positions for labels around the perimeter
458
- best_label_positions = _best_label_positions(filtered_domains, center, radius, offset)
464
+ best_label_positions = _best_label_positions(
465
+ filtered_domain_centroids, center, radius, offset
466
+ )
459
467
  # Annotate the network with labels
460
468
  for idx, (domain, pos) in enumerate(best_label_positions.items()):
461
- centroid = filtered_domains[domain]
462
- annotations = self.network_graph.trimmed_domain_to_term[domain].split(" ")[:num_words]
469
+ centroid = filtered_domain_centroids[domain]
470
+ annotations = self.graph.trimmed_domain_to_term[domain].split(" ")[:max_words]
463
471
  self.ax.annotate(
464
472
  "\n".join(annotations),
465
473
  xy=centroid,
@@ -473,6 +481,83 @@ class NetworkPlotter:
473
481
  arrowprops=dict(arrowstyle="->", color=arrow_color[idx], linewidth=arrow_linewidth),
474
482
  )
475
483
 
484
+ def plot_sublabel(
485
+ self,
486
+ nodes: list,
487
+ label: str,
488
+ radial_position: float = 0.0,
489
+ perimeter_scale: float = 1.05,
490
+ offset: float = 0.10,
491
+ font: str = "Arial",
492
+ fontsize: int = 10,
493
+ fontcolor: str = "black",
494
+ arrow_linewidth: float = 1,
495
+ arrow_color: str = "black",
496
+ ) -> None:
497
+ """Annotate the network graph with a single label for the given nodes, positioned at a specified radial angle.
498
+
499
+ Args:
500
+ nodes (List[str]): List of node labels to be used for calculating the centroid.
501
+ label (str): The label to be annotated on the network.
502
+ radial_position (float, optional): Radial angle for positioning the label, in degrees (0-360). Defaults to 0.0.
503
+ perimeter_scale (float, optional): Scale factor for positioning the label around the perimeter. Defaults to 1.05.
504
+ offset (float, optional): Offset distance for the label from the perimeter. Defaults to 0.10.
505
+ font (str, optional): Font name for the label. Defaults to "Arial".
506
+ fontsize (int, optional): Font size for the label. Defaults to 10.
507
+ fontcolor (str, optional): Color of the label text. Defaults to "black".
508
+ arrow_linewidth (float, optional): Line width of the arrow pointing to the centroid. Defaults to 1.
509
+ arrow_color (str, optional): Color of the arrow. Defaults to "black".
510
+ """
511
+ # Log the plotting parameters
512
+ params.log_plotter(
513
+ sublabel_perimeter_scale=perimeter_scale,
514
+ sublabel_offset=offset,
515
+ sublabel_font=font,
516
+ sublabel_fontsize=fontsize,
517
+ sublabel_fontcolor="custom" if isinstance(fontcolor, np.ndarray) else fontcolor,
518
+ sublabel_arrow_linewidth=arrow_linewidth,
519
+ sublabel_arrow_color="custom" if isinstance(arrow_color, np.ndarray) else arrow_color,
520
+ sublabel_radial_position=radial_position,
521
+ )
522
+
523
+ # Map node labels to IDs
524
+ node_ids = [
525
+ self.graph.node_label_to_id_map.get(node)
526
+ for node in nodes
527
+ if node in self.graph.node_label_to_id_map
528
+ ]
529
+ if not node_ids or len(node_ids) == 1:
530
+ raise ValueError("No nodes found in the network graph or insufficient nodes to plot.")
531
+
532
+ # Calculate the centroid of the provided nodes
533
+ centroid = self._calculate_domain_centroid(node_ids)
534
+
535
+ # Calculate the bounding box around the network
536
+ center, radius = _calculate_bounding_box(
537
+ self.graph.node_coordinates, radius_margin=perimeter_scale
538
+ )
539
+
540
+ # Convert radial position to radians, adjusting for a 90-degree rotation
541
+ radial_radians = np.deg2rad(radial_position - 90)
542
+ label_position = (
543
+ center[0] + (radius + offset) * np.cos(radial_radians),
544
+ center[1] + (radius + offset) * np.sin(radial_radians),
545
+ )
546
+
547
+ # Annotate the network with the label
548
+ self.ax.annotate(
549
+ label,
550
+ xy=centroid,
551
+ xytext=label_position,
552
+ textcoords="data",
553
+ ha="center",
554
+ va="center",
555
+ fontsize=fontsize,
556
+ fontname=font,
557
+ color=fontcolor,
558
+ arrowprops=dict(arrowstyle="->", color=arrow_color, linewidth=arrow_linewidth),
559
+ )
560
+
476
561
  def _calculate_domain_centroid(self, nodes: list) -> tuple:
477
562
  """Calculate the most centrally located node in .
478
563
 
@@ -483,7 +568,7 @@ class NetworkPlotter:
483
568
  tuple: A tuple containing the domain's central node coordinates.
484
569
  """
485
570
  # Extract positions of all nodes in the domain
486
- node_positions = self.network_graph.node_coordinates[nodes, :]
571
+ node_positions = self.graph.node_coordinates[nodes, :]
487
572
  # Calculate the pairwise distance matrix between all nodes in the domain
488
573
  distances_matrix = np.linalg.norm(node_positions[:, np.newaxis] - node_positions, axis=2)
489
574
  # Sum the distances for each node to all other nodes in the domain
@@ -508,7 +593,7 @@ class NetworkPlotter:
508
593
  np.ndarray: Array of RGBA colors adjusted for enrichment status.
509
594
  """
510
595
  # Get the initial domain colors for each node
511
- network_colors = self.network_graph.get_domain_colors(**kwargs, random_seed=random_seed)
596
+ network_colors = self.graph.get_domain_colors(**kwargs, random_seed=random_seed)
512
597
  if isinstance(nonenriched_color, str):
513
598
  # Convert the non-enriched color from string to RGBA
514
599
  nonenriched_color = mcolors.to_rgba(nonenriched_color)
@@ -535,14 +620,14 @@ class NetworkPlotter:
535
620
  """
536
621
  # Merge all enriched nodes from the domain_to_nodes dictionary
537
622
  enriched_nodes = set()
538
- for _, nodes in self.network_graph.domain_to_nodes.items():
623
+ for _, nodes in self.graph.domain_to_nodes.items():
539
624
  enriched_nodes.update(nodes)
540
625
 
541
626
  # Initialize all node sizes to the non-enriched size
542
- node_sizes = np.full(len(self.network_graph.G.nodes), nonenriched_nodesize)
627
+ node_sizes = np.full(len(self.graph.network.nodes), nonenriched_nodesize)
543
628
  # Set the size for enriched nodes
544
629
  for node in enriched_nodes:
545
- if node in self.network_graph.G.nodes:
630
+ if node in self.graph.network.nodes:
546
631
  node_sizes[node] = enriched_nodesize
547
632
 
548
633
  return node_sizes
@@ -587,12 +672,12 @@ class NetworkPlotter:
587
672
  if isinstance(color, str):
588
673
  # If a single color string is provided, convert it to RGBA and apply to all domains
589
674
  rgba_color = np.array(matplotlib.colors.to_rgba(color))
590
- return np.array([rgba_color for _ in self.network_graph.domain_to_nodes])
675
+ return np.array([rgba_color for _ in self.graph.domain_to_nodes])
591
676
 
592
677
  # Generate colors for each domain using the provided arguments and random seed
593
- node_colors = self.network_graph.get_domain_colors(**kwargs, random_seed=random_seed)
678
+ node_colors = self.graph.get_domain_colors(**kwargs, random_seed=random_seed)
594
679
  annotated_colors = []
595
- for _, nodes in self.network_graph.domain_to_nodes.items():
680
+ for _, nodes in self.graph.domain_to_nodes.items():
596
681
  if len(nodes) > 1:
597
682
  # For domains with multiple nodes, choose the brightest color (sum of RGB values)
598
683
  domain_colors = np.array([node_colors[node] for node in nodes])
@@ -662,12 +747,12 @@ def _calculate_bounding_box(
662
747
 
663
748
 
664
749
  def _best_label_positions(
665
- filtered_domains: Dict[str, Any], center: np.ndarray, radius: float, offset: float
750
+ filtered_domain_centroids: Dict[str, Any], center: np.ndarray, radius: float, offset: float
666
751
  ) -> Dict[str, Any]:
667
752
  """Calculate and optimize label positions for clarity.
668
753
 
669
754
  Args:
670
- filtered_domains (dict): Centroids of the filtered domains.
755
+ filtered_domain_centroids (dict): Centroids of the filtered domains.
671
756
  center (np.ndarray): The center coordinates for label positioning.
672
757
  radius (float): The radius for positioning labels around the center.
673
758
  offset (float): The offset distance from the radius for positioning labels.
@@ -675,15 +760,16 @@ def _best_label_positions(
675
760
  Returns:
676
761
  dict: Optimized positions for labels.
677
762
  """
678
- num_domains = len(filtered_domains)
763
+ num_domains = len(filtered_domain_centroids)
679
764
  # Calculate equidistant positions around the center for initial label placement
680
765
  equidistant_positions = _equidistant_angles_around_center(center, radius, offset, num_domains)
681
766
  # Create a mapping of domains to their initial label positions
682
767
  label_positions = {
683
- domain: position for domain, position in zip(filtered_domains.keys(), equidistant_positions)
768
+ domain: position
769
+ for domain, position in zip(filtered_domain_centroids.keys(), equidistant_positions)
684
770
  }
685
771
  # Optimize the label positions to minimize distance to domain centroids
686
- return _optimize_label_positions(label_positions, filtered_domains)
772
+ return _optimize_label_positions(label_positions, filtered_domain_centroids)
687
773
 
688
774
 
689
775
  def _equidistant_angles_around_center(
risk/risk.py CHANGED
@@ -27,64 +27,12 @@ class RISK(NetworkIO, AnnotationsIO):
27
27
  and performing network-based statistical analysis, such as neighborhood significance testing.
28
28
  """
29
29
 
30
- def __init__(
31
- self,
32
- compute_sphere: bool = True,
33
- surface_depth: float = 0.0,
34
- distance_metric: str = "dijkstra",
35
- louvain_resolution: float = 0.1,
36
- min_edges_per_node: int = 0,
37
- edge_length_threshold: float = 0.5,
38
- include_edge_weight: bool = True,
39
- weight_label: str = "weight",
40
- ):
41
- """Initialize the RISK class with configuration settings.
42
-
43
- Args:
44
- compute_sphere (bool, optional): Whether to map nodes to a sphere. Defaults to True.
45
- surface_depth (float, optional): Surface depth for the sphere. Defaults to 0.0.
46
- distance_metric (str, optional): Distance metric to use in network analysis. Defaults to "dijkstra".
47
- louvain_resolution (float, optional): Resolution parameter for Louvain clustering. Defaults to 0.1.
48
- min_edges_per_node (int, optional): Minimum number of edges per node. Defaults to 0.
49
- edge_length_threshold (float, optional): Edge length threshold for analysis. Defaults to 0.5.
50
- include_edge_weight (bool, optional): Whether to include edge weights in calculations. Defaults to True.
51
- weight_label (str, optional): Label for edge weights. Defaults to "weight".
52
- """
30
+ def __init__(self, *args, **kwargs):
31
+ """Initialize the RISK class with configuration settings."""
53
32
  # Initialize and log network parameters
54
33
  params.initialize()
55
- params.log_network(
56
- compute_sphere=compute_sphere,
57
- surface_depth=surface_depth,
58
- distance_metric=distance_metric,
59
- louvain_resolution=louvain_resolution,
60
- min_edges_per_node=min_edges_per_node,
61
- edge_length_threshold=edge_length_threshold,
62
- include_edge_weight=include_edge_weight,
63
- weight_label=weight_label,
64
- )
65
- # Initialize parent classes
66
- NetworkIO.__init__(
67
- self,
68
- compute_sphere=compute_sphere,
69
- surface_depth=surface_depth,
70
- distance_metric=distance_metric,
71
- louvain_resolution=louvain_resolution,
72
- min_edges_per_node=min_edges_per_node,
73
- edge_length_threshold=edge_length_threshold,
74
- include_edge_weight=include_edge_weight,
75
- weight_label=weight_label,
76
- )
77
- AnnotationsIO.__init__(self)
78
-
79
- # Set class attributes
80
- self.compute_sphere = compute_sphere
81
- self.surface_depth = surface_depth
82
- self.distance_metric = distance_metric
83
- self.louvain_resolution = louvain_resolution
84
- self.min_edges_per_node = min_edges_per_node
85
- self.edge_length_threshold = edge_length_threshold
86
- self.include_edge_weight = include_edge_weight
87
- self.weight_label = weight_label
34
+ # Initialize the parent classes
35
+ super().__init__(*args, **kwargs)
88
36
 
89
37
  @property
90
38
  def params(self):
@@ -95,6 +43,9 @@ class RISK(NetworkIO, AnnotationsIO):
95
43
  self,
96
44
  network: nx.Graph,
97
45
  annotations: Dict[str, Any],
46
+ distance_metric: str = "dijkstra",
47
+ louvain_resolution: float = 0.1,
48
+ edge_length_threshold: float = 0.5,
98
49
  score_metric: str = "sum",
99
50
  null_distribution: str = "network",
100
51
  num_permutations: int = 1000,
@@ -106,6 +57,9 @@ class RISK(NetworkIO, AnnotationsIO):
106
57
  Args:
107
58
  network (nx.Graph): The network graph.
108
59
  annotations (pd.DataFrame): The matrix of annotations associated with the network.
60
+ distance_metric (str, optional): Distance metric for neighborhood analysis. Defaults to "dijkstra".
61
+ louvain_resolution (float, optional): Resolution parameter for Louvain clustering. Defaults to 0.1.
62
+ edge_length_threshold (float, optional): Edge length threshold for neighborhood analysis. Defaults to 0.5.
109
63
  score_metric (str, optional): Scoring metric for neighborhood significance. Defaults to "sum".
110
64
  null_distribution (str, optional): Distribution used for permutation tests. Defaults to "network".
111
65
  num_permutations (int, optional): Number of permutations for significance testing. Defaults to 1000.
@@ -118,6 +72,9 @@ class RISK(NetworkIO, AnnotationsIO):
118
72
  print_header("Running permutation test")
119
73
  # Log neighborhood analysis parameters
120
74
  params.log_neighborhoods(
75
+ distance_metric=distance_metric,
76
+ louvain_resolution=louvain_resolution,
77
+ edge_length_threshold=edge_length_threshold,
121
78
  score_metric=score_metric,
122
79
  null_distribution=null_distribution,
123
80
  num_permutations=num_permutations,
@@ -126,17 +83,18 @@ class RISK(NetworkIO, AnnotationsIO):
126
83
  )
127
84
 
128
85
  # Display the chosen distance metric
129
- if self.distance_metric == "louvain":
130
- for_print_distance_metric = f"louvain (resolution={self.louvain_resolution})"
86
+ if distance_metric == "louvain":
87
+ for_print_distance_metric = f"louvain (resolution={louvain_resolution})"
131
88
  else:
132
- for_print_distance_metric = self.distance_metric
89
+ for_print_distance_metric = distance_metric
133
90
  print(f"Distance metric: '{for_print_distance_metric}'")
91
+ print(f"Edge length threshold: {edge_length_threshold}")
134
92
  # Compute neighborhoods based on the network and distance metric
135
93
  neighborhoods = get_network_neighborhoods(
136
94
  network,
137
- self.distance_metric,
138
- self.edge_length_threshold,
139
- louvain_resolution=self.louvain_resolution,
95
+ distance_metric,
96
+ edge_length_threshold,
97
+ louvain_resolution=louvain_resolution,
140
98
  random_seed=random_seed,
141
99
  )
142
100
 
@@ -144,6 +102,8 @@ class RISK(NetworkIO, AnnotationsIO):
144
102
  print(f"Null distribution: '{null_distribution}'")
145
103
  print(f"Neighborhood scoring metric: '{score_metric}'")
146
104
  print(f"Number of permutations: {num_permutations}")
105
+ print(f"Random seed: {random_seed}")
106
+ print(f"Maximum workers: {max_workers}")
147
107
  # Run the permutation test to compute neighborhood significance
148
108
  neighborhood_significance = compute_permutation(
149
109
  neighborhoods=neighborhoods,
risk/stats/stats.py CHANGED
@@ -150,14 +150,14 @@ def _run_permutation_test(
150
150
  ]
151
151
 
152
152
  # Start the permutation process in parallel
153
- results = pool.starmap_async(_permutation_process_subset, params_list)
153
+ results = pool.starmap_async(_permutation_process_subset, params_list, chunksize=1)
154
154
 
155
155
  # Update progress bar based on progress_counter
156
156
  # NOTE: Waiting for results to be ready while updating progress bar gives a big improvement
157
157
  # in performance, especially for large number of permutations and workers
158
158
  while not results.ready():
159
159
  progress.update(progress_counter.value - progress.n)
160
- results.wait(1) # Wait for 1 second
160
+ results.wait(0.05) # Wait for 50ms
161
161
 
162
162
  # Ensure progress bar reaches 100%
163
163
  progress.update(total_progress - progress.n)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: risk-network
3
- Version: 0.0.3b4
3
+ Version: 0.0.4b1
4
4
  Summary: A Python package for biological network analysis
5
5
  Author: Ira Horecka
6
6
  Author-email: Ira Horecka <ira89@icloud.com>
@@ -684,14 +684,14 @@ Classifier: Intended Audience :: Science/Research
684
684
  Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
685
685
  Classifier: Operating System :: OS Independent
686
686
  Classifier: Programming Language :: Python :: 3
687
- Classifier: Programming Language :: Python :: 3.7
687
+ Classifier: Programming Language :: Python :: 3.8
688
688
  Classifier: Programming Language :: Python :: 3 :: Only
689
689
  Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
690
690
  Classifier: Topic :: Scientific/Engineering :: Information Analysis
691
691
  Classifier: Topic :: Scientific/Engineering :: Visualization
692
692
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
693
693
  Classifier: Development Status :: 4 - Beta
694
- Requires-Python: >=3.7
694
+ Requires-Python: >=3.8
695
695
  Description-Content-Type: text/markdown
696
696
  License-File: LICENSE
697
697
  Requires-Dist: ipywidgets
@@ -716,7 +716,7 @@ Requires-Dist: tqdm
716
716
 
717
717
  <p align="center">
718
718
  <a href="https://pypi.python.org/pypi/risk-network"><img src="https://img.shields.io/pypi/v/risk-network.svg" alt="pypiv"></a>
719
- <a href="https://www.python.org/downloads/"><img src="https://img.shields.io/badge/python-3.7+-blue.svg" alt="Python 3.7+"></a>
719
+ <a href="https://www.python.org/downloads/"><img src="https://img.shields.io/badge/python-3.8+-blue.svg" alt="Python 3.8+"></a>
720
720
  <a href="https://raw.githubusercontent.com/irahorecka/chrono24/main/LICENSE"><img src="https://img.shields.io/badge/License-GPLv3-blue.svg" alt="License: GPL v3"></a>
721
721
  </p>
722
722
 
@@ -736,7 +736,7 @@ RISK is a software tool for visualizing spatial relationships in networks. It ai
736
736
 
737
737
  *Saccharomyces cerevisiae* proteins oriented by physical interactions discovered through affinity enrichment and mass spectrometry (Michaelis et al., 2023).
738
738
 
739
- ![Metabolic Network Demo](./docs/github/network.png)
739
+ ![PPI Network Demo](./docs/github/network.png)
740
740
 
741
741
  ## Installation
742
742
 
@@ -0,0 +1,26 @@
1
+ risk/__init__.py,sha256=mAHhUWFzKCookp6VYUp1WNQXgQStNGIUXaOZ2QfFtwc,122
2
+ risk/constants.py,sha256=AICk3x5qRQhls_ijTb4VdbdxU6mZ1aLGbAjLEdBwfJI,550
3
+ risk/risk.py,sha256=Kaju0siA2piDWuawSB1iZcngm9BND_R7iJAqAS_55E0,14717
4
+ risk/annotations/__init__.py,sha256=vUpVvMRE5if01Ic8QY6M2Ae3EFGJHdugEe9PdEkAW4Y,138
5
+ risk/annotations/annotations.py,sha256=0-Yf2XPVdMzpttLLgLxtTTnH0Eed_Uv8VXMur6E6xKw,10481
6
+ risk/annotations/io.py,sha256=TMicRACfY8bNtmbvVrxHoh8zkOVLOIhZwWrpxUlR28Q,7988
7
+ risk/log/__init__.py,sha256=xuLImfxFlKpnVhzi_gDYlr2_c9cLkrw2c_3iEsXb1as,107
8
+ risk/log/console.py,sha256=im9DRExwf6wHlcn9fewoDcKIpo3vPcorZIaNAl-0csY,355
9
+ risk/log/params.py,sha256=Tbb-sovFTptGBqPDKafUA8KOpby4zFObutAT_Iti1hE,6302
10
+ risk/neighborhoods/__init__.py,sha256=tKKEg4lsbqFukpgYlUGxU_v_9FOqK7V0uvM9T2QzoL0,206
11
+ risk/neighborhoods/community.py,sha256=eL2IGT-8sbiJIyfyb_FGngev7pEMxw7tZb8YzbzOYw8,6512
12
+ risk/neighborhoods/domains.py,sha256=HwuChmZH0RGD9eQOvk2-ezQDJRUHHn93vhVgHb-kX6I,10192
13
+ risk/neighborhoods/neighborhoods.py,sha256=benMk6ZCufhi9FKo6ByaeOzwJ8y43vkFbCD-wUNaCAU,13828
14
+ risk/network/__init__.py,sha256=iEPeJdZfqp0toxtbElryB8jbz9_t_k4QQ3iDvKE8C_0,126
15
+ risk/network/geometry.py,sha256=euBMOVvxpj-0WZam40IbHdsT7E4WXpTwSxuGbmAGTDg,6757
16
+ risk/network/graph.py,sha256=m3bFWU5528OEm246LPG5XP3l_30vaBiJv4AO4iq0pSA,11552
17
+ risk/network/io.py,sha256=Vn__hWla0EI9djIv7mWc1bFSTS2pRpUwOjPCqMWQOYI,19689
18
+ risk/network/plot.py,sha256=-8LyRqeQi4cxEVxNsTDCyHhmTfFuObLLaFbKQGZwHCI,38289
19
+ risk/stats/__init__.py,sha256=4s9gdJo5B1G_cQc0iMoeIBt5OrQNXkdtNXkAMFQkLxc,103
20
+ risk/stats/permutation.py,sha256=xgaZbaxo57t_FzPlpcb2nsq8oCzc_wj-zAm-xj3P2dA,3404
21
+ risk/stats/stats.py,sha256=7Z-1sJ5zvS3XDjG2UfOV0Y3c3xliYeB-6fk_UHNqfiE,16019
22
+ risk_network-0.0.4b1.dist-info/LICENSE,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
23
+ risk_network-0.0.4b1.dist-info/METADATA,sha256=YyRQOzpjmA1i506SBsBljqbz2hthqVYMfaSL5xIyz7I,43250
24
+ risk_network-0.0.4b1.dist-info/WHEEL,sha256=Mdi9PDNwEZptOjTlUcAth7XJDFtKrHYaQMPulZeBCiQ,91
25
+ risk_network-0.0.4b1.dist-info/top_level.txt,sha256=NX7C2PFKTvC1JhVKv14DFlFAIFnKc6Lpsu1ZfxvQwVw,5
26
+ risk_network-0.0.4b1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (72.2.0)
2
+ Generator: setuptools (73.0.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,26 +0,0 @@
1
- risk/__init__.py,sha256=7JTz-sr7kIgP1-2x6p8-HirKCr90zZTsy-gIbKdeYMw,122
2
- risk/constants.py,sha256=AICk3x5qRQhls_ijTb4VdbdxU6mZ1aLGbAjLEdBwfJI,550
3
- risk/risk.py,sha256=cWpYogZ-vma4ZZjewVNRMzb2TqHv8YABuzP2brXpOqo,16399
4
- risk/annotations/__init__.py,sha256=vUpVvMRE5if01Ic8QY6M2Ae3EFGJHdugEe9PdEkAW4Y,138
5
- risk/annotations/annotations.py,sha256=gZ9gihK_eTWaX3eByh08xr97FX4-XKe6MBwCCjasEDU,10368
6
- risk/annotations/io.py,sha256=ozi7aFn3_geB6G0kt7Ya1qVhNOqP6rB0YISjriSZyNw,7989
7
- risk/log/__init__.py,sha256=xuLImfxFlKpnVhzi_gDYlr2_c9cLkrw2c_3iEsXb1as,107
8
- risk/log/console.py,sha256=im9DRExwf6wHlcn9fewoDcKIpo3vPcorZIaNAl-0csY,355
9
- risk/log/params.py,sha256=Tbb-sovFTptGBqPDKafUA8KOpby4zFObutAT_Iti1hE,6302
10
- risk/neighborhoods/__init__.py,sha256=tKKEg4lsbqFukpgYlUGxU_v_9FOqK7V0uvM9T2QzoL0,206
11
- risk/neighborhoods/community.py,sha256=eL2IGT-8sbiJIyfyb_FGngev7pEMxw7tZb8YzbzOYw8,6512
12
- risk/neighborhoods/domains.py,sha256=HwuChmZH0RGD9eQOvk2-ezQDJRUHHn93vhVgHb-kX6I,10192
13
- risk/neighborhoods/neighborhoods.py,sha256=zGtxVIs0_Bg0wt1By6d77_lqW0PGXpOtQxeCEtyZFzA,13475
14
- risk/network/__init__.py,sha256=iEPeJdZfqp0toxtbElryB8jbz9_t_k4QQ3iDvKE8C_0,126
15
- risk/network/geometry.py,sha256=euBMOVvxpj-0WZam40IbHdsT7E4WXpTwSxuGbmAGTDg,6757
16
- risk/network/graph.py,sha256=a7gM1d2jHqscFVwn1GZaJWb3oZOFraNsQ2RxC4osaV4,11528
17
- risk/network/io.py,sha256=KmdrsDZe-ZT4O59NYZM_nQd8Ew9qpbzQcqWS_PaE7eA,12559
18
- risk/network/plot.py,sha256=fy21X677xqJPFkn564Jegxy05C9x0pJXovd5fm3NZ4Q,34554
19
- risk/stats/__init__.py,sha256=4s9gdJo5B1G_cQc0iMoeIBt5OrQNXkdtNXkAMFQkLxc,103
20
- risk/stats/permutation.py,sha256=xgaZbaxo57t_FzPlpcb2nsq8oCzc_wj-zAm-xj3P2dA,3404
21
- risk/stats/stats.py,sha256=Yu9LMSUtCRkg-h0ErJurb-rkajHgTvdzBcymHldJs5k,16007
22
- risk_network-0.0.3b4.dist-info/LICENSE,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
23
- risk_network-0.0.3b4.dist-info/METADATA,sha256=_xhdIlmS0XAYJWRI1yjQppksLevhfTX_wFjKzX5hf9Q,43256
24
- risk_network-0.0.3b4.dist-info/WHEEL,sha256=HiCZjzuy6Dw0hdX5R3LCFPDmFS4BWl8H-8W39XfmgX4,91
25
- risk_network-0.0.3b4.dist-info/top_level.txt,sha256=NX7C2PFKTvC1JhVKv14DFlFAIFnKc6Lpsu1ZfxvQwVw,5
26
- risk_network-0.0.3b4.dist-info/RECORD,,