risk-network 0.0.7b11__py3-none-any.whl → 0.0.8__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/network/graph.py CHANGED
@@ -4,12 +4,11 @@ risk/network/graph
4
4
  """
5
5
 
6
6
  from collections import defaultdict
7
- from typing import Any, Dict, List, Tuple, Union
7
+ from typing import Any, Dict, List
8
8
 
9
9
  import networkx as nx
10
10
  import numpy as np
11
11
  import pandas as pd
12
- import matplotlib
13
12
 
14
13
 
15
14
  class NetworkGraph:
@@ -37,7 +36,7 @@ class NetworkGraph:
37
36
  top_annotations (pd.DataFrame): DataFrame containing annotations data for the network nodes.
38
37
  domains (pd.DataFrame): DataFrame containing domain data for the network nodes.
39
38
  trimmed_domains (pd.DataFrame): DataFrame containing trimmed domain data for the network nodes.
40
- node_label_to_node_id_map (dict): A dictionary mapping node labels to their corresponding IDs.
39
+ node_label_to_node_id_map (Dict[str, Any]): A dictionary mapping node labels to their corresponding IDs.
41
40
  node_enrichment_sums (np.ndarray): Array containing the enrichment sums for the nodes.
42
41
  """
43
42
  self.top_annotations = top_annotations
@@ -46,7 +45,14 @@ class NetworkGraph:
46
45
  self.domain_id_to_domain_terms_map = self._create_domain_id_to_domain_terms_map(
47
46
  trimmed_domains
48
47
  )
48
+ self.domain_id_to_domain_info_map = self._create_domain_id_to_domain_info_map(
49
+ trimmed_domains
50
+ )
51
+ self.trimmed_domains = trimmed_domains
49
52
  self.node_enrichment_sums = node_enrichment_sums
53
+ self.node_id_to_domain_ids_and_enrichments_map = (
54
+ self._create_node_id_to_domain_ids_and_enrichments(domains)
55
+ )
50
56
  self.node_id_to_node_label_map = {v: k for k, v in node_label_to_node_id_map.items()}
51
57
  self.node_label_to_enrichment_map = dict(
52
58
  zip(node_label_to_node_id_map.keys(), node_enrichment_sums)
@@ -58,179 +64,107 @@ class NetworkGraph:
58
64
  self.network = _unfold_sphere_to_plane(network)
59
65
  self.node_coordinates = _extract_node_coordinates(self.network)
60
66
 
61
- def _create_domain_id_to_node_ids_map(self, domains: pd.DataFrame) -> Dict[str, Any]:
67
+ @staticmethod
68
+ def _create_domain_id_to_node_ids_map(domains: pd.DataFrame) -> Dict[int, Any]:
62
69
  """Create a mapping from domains to the list of node IDs belonging to each domain.
63
70
 
64
71
  Args:
65
72
  domains (pd.DataFrame): DataFrame containing domain information, including the 'primary domain' for each node.
66
73
 
67
74
  Returns:
68
- dict: A dictionary where keys are domain IDs and values are lists of node IDs belonging to each domain.
75
+ Dict[int, Any]: A dictionary where keys are domain IDs and values are lists of node IDs belonging to each domain.
69
76
  """
70
- cleaned_domains_matrix = domains.reset_index()[["index", "primary domain"]]
71
- node_to_domains_map = cleaned_domains_matrix.set_index("index")["primary domain"].to_dict()
77
+ cleaned_domains_matrix = domains.reset_index()[["index", "primary_domain"]]
78
+ node_to_domains_map = cleaned_domains_matrix.set_index("index")["primary_domain"].to_dict()
72
79
  domain_id_to_node_ids_map = defaultdict(list)
73
80
  for k, v in node_to_domains_map.items():
74
81
  domain_id_to_node_ids_map[v].append(k)
75
82
 
76
83
  return domain_id_to_node_ids_map
77
84
 
78
- def _create_domain_id_to_domain_terms_map(
79
- self, trimmed_domains: pd.DataFrame
80
- ) -> Dict[str, Any]:
85
+ @staticmethod
86
+ def _create_domain_id_to_domain_terms_map(trimmed_domains: pd.DataFrame) -> Dict[int, Any]:
81
87
  """Create a mapping from domain IDs to their corresponding terms.
82
88
 
83
89
  Args:
84
90
  trimmed_domains (pd.DataFrame): DataFrame containing domain IDs and their corresponding labels.
85
91
 
86
92
  Returns:
87
- dict: A dictionary mapping domain IDs to their corresponding terms.
93
+ Dict[int, Any]: A dictionary mapping domain IDs to their corresponding terms.
88
94
  """
89
95
  return dict(
90
96
  zip(
91
97
  trimmed_domains.index,
92
- trimmed_domains["label"],
98
+ trimmed_domains["normalized_description"],
93
99
  )
94
100
  )
95
101
 
96
- def _create_domain_id_to_node_labels_map(self) -> Dict[int, List[str]]:
97
- """Create a map from domain IDs to node labels.
98
-
99
- Returns:
100
- dict: A dictionary mapping domain IDs to the corresponding node labels.
101
- """
102
- domain_id_to_label_map = {}
103
- for domain_id, node_ids in self.domain_id_to_node_ids_map.items():
104
- domain_id_to_label_map[domain_id] = [
105
- self.node_id_to_node_label_map[node_id] for node_id in node_ids
106
- ]
107
-
108
- return domain_id_to_label_map
109
-
110
- def get_domain_colors(
111
- self,
112
- cmap: str = "gist_rainbow",
113
- color: Union[str, None] = None,
114
- min_scale: float = 0.8,
115
- max_scale: float = 1.0,
116
- scale_factor: float = 1.0,
117
- random_seed: int = 888,
118
- ) -> np.ndarray:
119
- """Generate composite colors for domains based on enrichment or specified colors.
102
+ @staticmethod
103
+ def _create_domain_id_to_domain_info_map(
104
+ trimmed_domains: pd.DataFrame,
105
+ ) -> Dict[int, Dict[str, Any]]:
106
+ """Create a mapping from domain IDs to their corresponding full description and enrichment score.
120
107
 
121
108
  Args:
122
- cmap (str, optional): Name of the colormap to use for generating domain colors. Defaults to "gist_rainbow".
123
- color (str or None, optional): A specific color to use for all generated colors. Defaults to None.
124
- min_scale (float, optional): Minimum intensity scale for the colors generated by the colormap.
125
- Controls the dimmest colors. Defaults to 0.8.
126
- max_scale (float, optional): Maximum intensity scale for the colors generated by the colormap.
127
- Controls the brightest colors. Defaults to 1.0.
128
- scale_factor (float, optional): Exponent for adjusting the color scaling based on enrichment scores.
129
- A higher value increases contrast by dimming lower scores more. Defaults to 1.0.
130
- random_seed (int, optional): Seed for random number generation to ensure reproducibility of color assignments.
131
- Defaults to 888.
109
+ trimmed_domains (pd.DataFrame): DataFrame containing domain IDs, full descriptions, and enrichment scores.
132
110
 
133
111
  Returns:
134
- np.ndarray: Array of RGBA colors generated for each domain, based on enrichment or the specified color.
112
+ Dict[int, Dict[str, Any]]: A dictionary mapping domain IDs (int) to a dictionary with 'full_descriptions' and 'enrichment_scores'.
135
113
  """
136
- # Get colors for each domain
137
- domain_colors = self._get_domain_colors(cmap=cmap, color=color, random_seed=random_seed)
138
- # Generate composite colors for nodes
139
- node_colors = self._get_composite_node_colors(domain_colors)
140
- # Transform colors to ensure proper alpha values and intensity
141
- transformed_colors = _transform_colors(
142
- node_colors,
143
- self.node_enrichment_sums,
144
- min_scale=min_scale,
145
- max_scale=max_scale,
146
- scale_factor=scale_factor,
147
- )
148
-
149
- return transformed_colors
150
-
151
- def _get_composite_node_colors(self, domain_colors: np.ndarray) -> np.ndarray:
152
- """Generate composite colors for nodes based on domain colors and counts.
114
+ return {
115
+ int(id_): {
116
+ "full_descriptions": trimmed_domains.at[id_, "full_descriptions"],
117
+ "enrichment_scores": trimmed_domains.at[id_, "enrichment_scores"],
118
+ }
119
+ for id_ in trimmed_domains.index
120
+ }
121
+
122
+ @staticmethod
123
+ def _create_node_id_to_domain_ids_and_enrichments(domains: pd.DataFrame) -> Dict[int, Dict]:
124
+ """Creates a dictionary mapping each node ID to its corresponding domain IDs and enrichment values.
153
125
 
154
126
  Args:
155
- domain_colors (np.ndarray): Array of colors corresponding to each domain.
127
+ domains (pd.DataFrame): A DataFrame containing domain information for each node. Assumes the last
128
+ two columns are 'all domains' and 'primary domain', which are excluded from processing.
156
129
 
157
130
  Returns:
158
- np.ndarray: Array of composite colors for each node.
131
+ Dict[int, Dict]: A dictionary where the key is the node ID (index of the DataFrame), and the value is another dictionary
132
+ with 'domain' (a list of domain IDs with non-zero enrichment) and 'enrichment'
133
+ (a dict of domain IDs and their corresponding enrichment values).
159
134
  """
160
- # Determine the number of nodes
161
- num_nodes = len(self.node_coordinates)
162
- # Initialize composite colors array with shape (number of nodes, 4) for RGBA
163
- composite_colors = np.zeros((num_nodes, 4))
164
- # Assign colors to nodes based on domain_colors
165
- for domain_id, nodes in self.domain_id_to_node_ids_map.items():
166
- color = domain_colors[domain_id]
167
- for node in nodes:
168
- composite_colors[node] = color
169
-
170
- return composite_colors
171
-
172
- def _get_domain_colors(
173
- self,
174
- cmap: str = "gist_rainbow",
175
- color: Union[str, None] = None,
176
- random_seed: int = 888,
177
- ) -> Dict[str, Any]:
178
- """Get colors for each domain.
135
+ # Initialize an empty dictionary to store the result
136
+ node_id_to_domain_ids_and_enrichments = {}
137
+ # Get the list of domain columns (excluding 'all domains' and 'primary domain')
138
+ domain_columns = domains.columns[
139
+ :-2
140
+ ] # The last two columns are 'all domains' and 'primary domain'
141
+ # Iterate over each row in the dataframe
142
+ for idx, row in domains.iterrows():
143
+ # Get the domains (column names) where the enrichment score is greater than 0
144
+ all_domains = domain_columns[row[domain_columns] > 0].tolist()
145
+ # Get the enrichment values for those domains
146
+ enrichment_values = row[all_domains].to_dict()
147
+ # Store the result in the dictionary with index as the key
148
+ node_id_to_domain_ids_and_enrichments[idx] = {
149
+ "domains": all_domains, # The column names where enrichment > 0
150
+ "enrichments": enrichment_values, # The actual enrichment values for those columns
151
+ }
152
+
153
+ return node_id_to_domain_ids_and_enrichments
179
154
 
180
- Args:
181
- cmap (str, optional): The name of the colormap to use. Defaults to "gist_rainbow".
182
- color (str or None, optional): A specific color to use for all generated colors. Defaults to None.
183
- random_seed (int, optional): Seed for random number generation. Defaults to 888.
155
+ def _create_domain_id_to_node_labels_map(self) -> Dict[int, List[str]]:
156
+ """Create a map from domain IDs to node labels.
184
157
 
185
158
  Returns:
186
- dict: A dictionary mapping domain keys to their corresponding RGBA colors.
159
+ Dict[int, List[str]]: A dictionary mapping domain IDs to the corresponding node labels.
187
160
  """
188
- # Get colors for each domain based on node positions
189
- domain_colors = _get_colors(
190
- self.network,
191
- self.domain_id_to_node_ids_map,
192
- cmap=cmap,
193
- color=color,
194
- random_seed=random_seed,
195
- )
196
- self.network, self.domain_id_to_node_ids_map
197
- return dict(zip(self.domain_id_to_node_ids_map.keys(), domain_colors))
198
-
199
-
200
- def _transform_colors(
201
- colors: np.ndarray,
202
- enrichment_sums: np.ndarray,
203
- min_scale: float = 0.8,
204
- max_scale: float = 1.0,
205
- scale_factor: float = 1.0,
206
- ) -> np.ndarray:
207
- """Transform colors using power scaling to emphasize high enrichment sums more.
208
-
209
- Args:
210
- colors (np.ndarray): An array of RGBA colors.
211
- enrichment_sums (np.ndarray): An array of enrichment sums corresponding to the colors.
212
- min_scale (float, optional): Minimum scale for color intensity. Defaults to 0.8.
213
- max_scale (float, optional): Maximum scale for color intensity. Defaults to 1.0.
214
- scale_factor (float, optional): Exponent for scaling, where values > 1 increase contrast by dimming small
215
- values more. Defaults to 1.0.
216
-
217
- Returns:
218
- np.ndarray: The transformed array of RGBA colors with adjusted intensities.
219
- """
220
- if min_scale == max_scale:
221
- min_scale = max_scale - 10e-6 # Avoid division by zero
222
-
223
- # Normalize the enrichment sums to the range [0, 1]
224
- normalized_sums = enrichment_sums / np.max(enrichment_sums)
225
- # Apply power scaling to dim lower values and emphasize higher values
226
- scaled_sums = normalized_sums**scale_factor
227
- # Linearly scale the normalized sums to the range [min_scale, max_scale]
228
- scaled_sums = min_scale + (max_scale - min_scale) * scaled_sums
229
- # Adjust RGB values based on scaled sums
230
- for i in range(3): # Only adjust RGB values
231
- colors[:, i] = scaled_sums * colors[:, i]
161
+ domain_id_to_label_map = {}
162
+ for domain_id, node_ids in self.domain_id_to_node_ids_map.items():
163
+ domain_id_to_label_map[domain_id] = [
164
+ self.node_id_to_node_label_map[node_id] for node_id in node_ids
165
+ ]
232
166
 
233
- return colors
167
+ return domain_id_to_label_map
234
168
 
235
169
 
236
170
  def _unfold_sphere_to_plane(G: nx.Graph) -> nx.Graph:
@@ -283,103 +217,3 @@ def _extract_node_coordinates(G: nx.Graph) -> np.ndarray:
283
217
  }
284
218
  node_coordinates = np.vstack(list(node_positions.values()))
285
219
  return node_coordinates
286
-
287
-
288
- def _get_colors(
289
- network,
290
- domain_id_to_node_ids_map,
291
- cmap: str = "gist_rainbow",
292
- color: Union[str, None] = None,
293
- random_seed: int = 888,
294
- ) -> List[Tuple]:
295
- """Generate a list of RGBA colors based on domain centroids, ensuring that domains
296
- close in space get maximally separated colors, while keeping some randomness.
297
-
298
- Args:
299
- network (NetworkX graph): The graph representing the network.
300
- domain_id_to_node_ids_map (dict): Mapping from domain IDs to lists of node IDs.
301
- cmap (str, optional): The name of the colormap to use. Defaults to "gist_rainbow".
302
- color (str or None, optional): A specific color to use for all generated colors.
303
- random_seed (int): Seed for random number generation. Defaults to 888.
304
-
305
- Returns:
306
- List[Tuple]: List of RGBA colors.
307
- """
308
- # Set random seed for reproducibility
309
- np.random.seed(random_seed)
310
- # Determine the number of colors to generate based on the number of domains
311
- num_colors_to_generate = len(domain_id_to_node_ids_map)
312
- if color:
313
- # Generate all colors as the same specified color
314
- rgba = matplotlib.colors.to_rgba(color)
315
- return [rgba] * num_colors_to_generate
316
-
317
- # Load colormap
318
- colormap = matplotlib.colormaps.get_cmap(cmap)
319
- # Step 1: Calculate centroids for each domain
320
- centroids = _calculate_centroids(network, domain_id_to_node_ids_map)
321
- # Step 2: Calculate pairwise distances between centroids
322
- centroid_array = np.array(centroids)
323
- dist_matrix = np.linalg.norm(centroid_array[:, None] - centroid_array, axis=-1)
324
- # Step 3: Assign distant colors to close centroids
325
- color_positions = _assign_distant_colors(dist_matrix, num_colors_to_generate)
326
- # Step 4: Randomly shift the entire color palette while maintaining relative distances
327
- global_shift = np.random.uniform(-0.1, 0.1) # Small global shift to change the overall palette
328
- color_positions = (color_positions + global_shift) % 1 # Wrap around to keep within [0, 1]
329
- # Step 5: Ensure that all positions remain between 0 and 1
330
- color_positions = np.clip(color_positions, 0, 1)
331
-
332
- # Step 6: Generate RGBA colors based on positions
333
- return [colormap(pos) for pos in color_positions]
334
-
335
-
336
- def _calculate_centroids(network, domain_id_to_node_ids_map):
337
- """Calculate the centroid for each domain based on node x and y coordinates in the network.
338
-
339
- Args:
340
- network (NetworkX graph): The graph representing the network.
341
- domain_id_to_node_ids_map (dict): Mapping from domain IDs to lists of node IDs.
342
-
343
- Returns:
344
- List[Tuple[float, float]]: List of centroids (x, y) for each domain.
345
- """
346
- centroids = []
347
- for domain_id, node_ids in domain_id_to_node_ids_map.items():
348
- # Extract x and y coordinates from the network nodes
349
- node_positions = np.array(
350
- [[network.nodes[node_id]["x"], network.nodes[node_id]["y"]] for node_id in node_ids]
351
- )
352
- # Compute the centroid as the mean of the x and y coordinates
353
- centroid = np.mean(node_positions, axis=0)
354
- centroids.append(tuple(centroid))
355
-
356
- return centroids
357
-
358
-
359
- def _assign_distant_colors(dist_matrix, num_colors_to_generate):
360
- """Assign colors to centroids that are close in space, ensuring stark color differences.
361
-
362
- Args:
363
- dist_matrix (ndarray): Matrix of pairwise centroid distances.
364
- num_colors_to_generate (int): Number of colors to generate.
365
-
366
- Returns:
367
- np.array: Array of color positions in the range [0, 1].
368
- """
369
- color_positions = np.zeros(num_colors_to_generate)
370
- # Step 1: Sort indices by centroid proximity (based on sum of distances to others)
371
- proximity_order = sorted(
372
- range(num_colors_to_generate), key=lambda idx: np.sum(dist_matrix[idx])
373
- )
374
- # Step 2: Assign colors starting with the most distant points in proximity order
375
- for i, idx in enumerate(proximity_order):
376
- color_positions[idx] = i / num_colors_to_generate
377
-
378
- # Step 3: Adjust colors so that centroids close to one another are maximally distant on the color spectrum
379
- half_spectrum = int(num_colors_to_generate / 2)
380
- for i in range(half_spectrum):
381
- # Split the spectrum so that close centroids are assigned distant colors
382
- color_positions[proximity_order[i]] = (i * 2) / num_colors_to_generate
383
- color_positions[proximity_order[-(i + 1)]] = ((i * 2) + 1) / num_colors_to_generate
384
-
385
- return color_positions
risk/network/io.py CHANGED
@@ -5,6 +5,7 @@ risk/network/io
5
5
  This file contains the code for the RISK class and command-line access.
6
6
  """
7
7
 
8
+ import copy
8
9
  import json
9
10
  import os
10
11
  import pickle
@@ -13,6 +14,7 @@ import zipfile
13
14
  from xml.dom import minidom
14
15
 
15
16
  import networkx as nx
17
+ import numpy as np
16
18
  import pandas as pd
17
19
 
18
20
  from risk.network.geometry import assign_edge_lengths
@@ -153,8 +155,10 @@ class NetworkIO:
153
155
  params.log_network(filetype=filetype)
154
156
  self._log_loading(filetype)
155
157
 
158
+ # Important: Make a copy of the network to avoid modifying the original
159
+ network_copy = copy.deepcopy(network)
156
160
  # Initialize the graph
157
- return self._initialize_graph(network)
161
+ return self._initialize_graph(network_copy)
158
162
 
159
163
  @staticmethod
160
164
  def load_cytoscape_network(
@@ -451,10 +455,10 @@ class NetworkIO:
451
455
  # Log the number of nodes and edges before and after cleaning
452
456
  num_final_nodes = G.number_of_nodes()
453
457
  num_final_edges = G.number_of_edges()
454
- logger.info(f"Initial node count: {num_initial_nodes}")
455
- logger.info(f"Final node count: {num_final_nodes}")
456
- logger.info(f"Initial edge count: {num_initial_edges}")
457
- logger.info(f"Final edge count: {num_final_edges}")
458
+ logger.debug(f"Initial node count: {num_initial_nodes}")
459
+ logger.debug(f"Final node count: {num_final_nodes}")
460
+ logger.debug(f"Initial edge count: {num_initial_edges}")
461
+ logger.debug(f"Final edge count: {num_final_edges}")
458
462
 
459
463
  def _assign_edge_weights(self, G: nx.Graph) -> None:
460
464
  """Assign weights to the edges in the graph.
@@ -472,19 +476,53 @@ class NetworkIO:
472
476
  ) # Default to 1.0 if 'weight' not present
473
477
 
474
478
  if self.include_edge_weight and missing_weights:
475
- logger.info(f"Total edges missing weights: {missing_weights}")
479
+ logger.debug(f"Total edges missing weights: {missing_weights}")
476
480
 
477
481
  def _validate_nodes(self, G: nx.Graph) -> None:
478
- """Validate the graph structure and attributes.
482
+ """Validate the graph structure and attributes with attribute fallback for positions and labels.
479
483
 
480
484
  Args:
481
485
  G (nx.Graph): A NetworkX graph object.
482
486
  """
487
+ # Keep track of nodes missing labels
488
+ nodes_with_missing_labels = []
489
+
483
490
  for node, attrs in G.nodes(data=True):
484
- assert (
485
- "x" in attrs and "y" in attrs
486
- ), f"Node {node} is missing 'x' or 'y' position attributes."
487
- assert "label" in attrs, f"Node {node} is missing a 'label' attribute."
491
+ # Attribute fallback for 'x' and 'y' attributes
492
+ if "x" not in attrs or "y" not in attrs:
493
+ if (
494
+ "pos" in attrs
495
+ and isinstance(attrs["pos"], (list, tuple, np.ndarray))
496
+ and len(attrs["pos"]) >= 2
497
+ ):
498
+ attrs["x"], attrs["y"] = attrs["pos"][
499
+ :2
500
+ ] # Use only x and y, ignoring z if present
501
+ else:
502
+ raise ValueError(
503
+ f"Node {node} is missing 'x', 'y', and a valid 'pos' attribute."
504
+ )
505
+
506
+ # Attribute fallback for 'label' attribute
507
+ if "label" not in attrs:
508
+ # Try alternative attribute names for label
509
+ if "name" in attrs:
510
+ attrs["label"] = attrs["name"]
511
+ elif "id" in attrs:
512
+ attrs["label"] = attrs["id"]
513
+ else:
514
+ # Collect nodes with missing labels
515
+ nodes_with_missing_labels.append(node)
516
+ attrs["label"] = str(node) # Use node ID as the label
517
+
518
+ # Issue a single warning if any labels were missing
519
+ if nodes_with_missing_labels:
520
+ total_nodes = len(G.nodes)
521
+ fraction_missing_labels = len(nodes_with_missing_labels) / total_nodes
522
+ logger.warning(
523
+ f"{len(nodes_with_missing_labels)} out of {total_nodes} nodes "
524
+ f"({fraction_missing_labels:.2%}) were missing 'label' attributes and were assigned node IDs."
525
+ )
488
526
 
489
527
  def _assign_edge_lengths(self, G: nx.Graph) -> None:
490
528
  """Prepare the network by adjusting surface depth and calculating edge lengths.
@@ -511,13 +549,13 @@ class NetworkIO:
511
549
  filepath (str, optional): The path to the file being loaded. Defaults to "".
512
550
  """
513
551
  log_header("Loading network")
514
- logger.info(f"Filetype: {filetype}")
552
+ logger.debug(f"Filetype: {filetype}")
515
553
  if filepath:
516
- logger.info(f"Filepath: {filepath}")
517
- logger.info(f"Edge weight: {'Included' if self.include_edge_weight else 'Excluded'}")
554
+ logger.debug(f"Filepath: {filepath}")
555
+ logger.debug(f"Edge weight: {'Included' if self.include_edge_weight else 'Excluded'}")
518
556
  if self.include_edge_weight:
519
- logger.info(f"Weight label: {self.weight_label}")
520
- logger.info(f"Minimum edges per node: {self.min_edges_per_node}")
521
- logger.info(f"Projection: {'Sphere' if self.compute_sphere else 'Plane'}")
557
+ logger.debug(f"Weight label: {self.weight_label}")
558
+ logger.debug(f"Minimum edges per node: {self.min_edges_per_node}")
559
+ logger.debug(f"Projection: {'Sphere' if self.compute_sphere else 'Plane'}")
522
560
  if self.compute_sphere:
523
- logger.info(f"Surface depth: {self.surface_depth}")
561
+ logger.debug(f"Surface depth: {self.surface_depth}")
@@ -0,0 +1,6 @@
1
+ """
2
+ risk/network/plot
3
+ ~~~~~~~~~~~~~~~~~
4
+ """
5
+
6
+ from risk.network.plot.plotter import NetworkPlotter