risk-network 0.0.7b1__py3-none-any.whl → 0.0.7b3__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
@@ -7,4 +7,4 @@ RISK: RISK Infers Spatial Kinships
7
7
 
8
8
  from risk.risk import RISK
9
9
 
10
- __version__ = "0.0.7-beta.1"
10
+ __version__ = "0.0.7-beta.3"
risk/network/graph.py CHANGED
@@ -55,10 +55,9 @@ class NetworkGraph:
55
55
  self.node_label_to_node_id_map = node_label_to_node_id_map
56
56
  # NOTE: Below this point, instance attributes (i.e., self) will be used!
57
57
  self.domain_id_to_node_labels_map = self._create_domain_id_to_node_labels_map()
58
- # self.network and self.node_coordinates are properly declared in _initialize_network
59
- self.network = None
60
- self.node_coordinates = None
61
- self._initialize_network(network)
58
+ # Unfold the network's 3D coordinates to 2D and extract node coordinates
59
+ self.network = _unfold_sphere_to_plane(network)
60
+ self.node_coordinates = _extract_node_coordinates(self.network)
62
61
 
63
62
  def _create_domain_id_to_node_ids_map(self, domains: pd.DataFrame) -> Dict[str, Any]:
64
63
  """Create a mapping from domains to the list of node IDs belonging to each domain.
@@ -109,19 +108,6 @@ class NetworkGraph:
109
108
 
110
109
  return domain_id_to_label_map
111
110
 
112
- def _initialize_network(self, G: nx.Graph) -> None:
113
- """Initialize the network by unfolding it and extracting node coordinates.
114
-
115
- Args:
116
- G (nx.Graph): The input network graph with 3D node coordinates.
117
- """
118
- # Unfold the network's 3D coordinates to 2D
119
- G_2d = _unfold_sphere_to_plane(G)
120
- # Assign the unfolded graph to self.network
121
- self.network = G_2d
122
- # Extract 2D coordinates of nodes
123
- self.node_coordinates = _extract_node_coordinates(G_2d)
124
-
125
111
  def get_domain_colors(
126
112
  self,
127
113
  cmap: str = "gist_rainbow",
@@ -200,14 +186,15 @@ class NetworkGraph:
200
186
  Returns:
201
187
  dict: A dictionary mapping domain keys to their corresponding RGBA colors.
202
188
  """
203
- # Exclude non-numeric domain columns
204
- numeric_domains = [
205
- col for col in self.domains.columns if isinstance(col, (int, np.integer))
206
- ]
207
- domains = np.sort(numeric_domains)
189
+ # Get colors for each domain based on node positions
208
190
  domain_colors = _get_colors(
209
- num_colors_to_generate=len(domains), cmap=cmap, color=color, random_seed=random_seed
191
+ self.network,
192
+ self.domain_id_to_node_ids_map,
193
+ cmap=cmap,
194
+ color=color,
195
+ random_seed=random_seed,
210
196
  )
197
+ self.network, self.domain_id_to_node_ids_map
211
198
  return dict(zip(self.domain_id_to_node_ids_map.keys(), domain_colors))
212
199
 
213
200
 
@@ -300,35 +287,110 @@ def _extract_node_coordinates(G: nx.Graph) -> np.ndarray:
300
287
 
301
288
 
302
289
  def _get_colors(
303
- num_colors_to_generate: int = 10,
290
+ network,
291
+ domain_id_to_node_ids_map,
304
292
  cmap: str = "gist_rainbow",
305
293
  color: Union[str, None] = None,
306
294
  random_seed: int = 888,
307
295
  ) -> List[Tuple]:
308
- """Generate a list of RGBA colors from a specified colormap or use a direct color string.
296
+ """Generate a list of RGBA colors based on domain centroids, ensuring that domains
297
+ close in space get maximally separated colors, while keeping some randomness.
309
298
 
310
299
  Args:
311
- num_colors_to_generate (int): The number of colors to generate. Defaults to 10.
300
+ network (NetworkX graph): The graph representing the network.
301
+ domain_id_to_node_ids_map (dict): Mapping from domain IDs to lists of node IDs.
312
302
  cmap (str, optional): The name of the colormap to use. Defaults to "gist_rainbow".
313
303
  color (str or None, optional): A specific color to use for all generated colors.
314
304
  random_seed (int): Seed for random number generation. Defaults to 888.
315
- Defaults to None.
316
305
 
317
306
  Returns:
318
- list of tuple: List of RGBA colors.
307
+ List[Tuple]: List of RGBA colors.
319
308
  """
320
309
  # Set random seed for reproducibility
321
310
  random.seed(random_seed)
311
+ # Determine the number of colors to generate based on the number of domains
312
+ num_colors_to_generate = len(domain_id_to_node_ids_map)
322
313
  if color:
323
- # If a direct color is provided, generate a list with that color
314
+ # Generate all colors as the same specified color
324
315
  rgba = matplotlib.colors.to_rgba(color)
325
- rgbas = [rgba] * num_colors_to_generate
326
- else:
327
- colormap = matplotlib.colormaps.get_cmap(cmap)
328
- # Generate evenly distributed color positions
329
- color_positions = np.linspace(0, 1, num_colors_to_generate)
330
- random.shuffle(color_positions) # Shuffle the positions to randomize colors
331
- # Generate colors based on shuffled positions
332
- rgbas = [colormap(pos) for pos in color_positions]
333
-
334
- return rgbas
316
+ return [rgba] * num_colors_to_generate
317
+
318
+ # Load colormap
319
+ colormap = matplotlib.colormaps.get_cmap(cmap)
320
+ # Step 1: Calculate centroids for each domain
321
+ centroids = _calculate_centroids(network, domain_id_to_node_ids_map)
322
+ # Step 2: Calculate pairwise distances between centroids
323
+ centroid_array = np.array(centroids)
324
+ dist_matrix = np.linalg.norm(centroid_array[:, None] - centroid_array, axis=-1)
325
+
326
+ # Step 3: Generate positions in the colormap, with a focus on centroids that are close
327
+ remaining_indices = set(range(num_colors_to_generate))
328
+ # Assign distant colors to close centroids
329
+ color_positions = _assign_distant_colors(
330
+ remaining_indices, dist_matrix, colormap, num_colors_to_generate
331
+ )
332
+
333
+ # Step 4: Randomly shuffle color positions to generate a new color palette
334
+ # while maintaining the dissimilarity between neighboring colors. This shuffling
335
+ # preserves the relative distances between centroids, ensuring that close centroids
336
+ # remain visually distinct while introducing randomness into the overall color arrangement.
337
+ random.shuffle(color_positions)
338
+ # Ensure that all positions remain between 0 and 1
339
+ color_positions = np.clip(color_positions, 0, 1)
340
+
341
+ # Step 5: Generate colors based on positions
342
+ return [colormap(pos) for pos in color_positions]
343
+
344
+
345
+ def _calculate_centroids(network, domain_id_to_node_ids_map):
346
+ """Calculate the centroid for each domain based on node x and y coordinates in the network.
347
+
348
+ Args:
349
+ network (NetworkX graph): The graph representing the network.
350
+ domain_id_to_node_ids_map (dict): Mapping from domain IDs to lists of node IDs.
351
+
352
+ Returns:
353
+ List[Tuple[float, float]]: List of centroids (x, y) for each domain.
354
+ """
355
+ centroids = []
356
+ for domain_id, node_ids in domain_id_to_node_ids_map.items():
357
+ # Extract x and y coordinates from the network nodes
358
+ node_positions = np.array(
359
+ [[network.nodes[node_id]["x"], network.nodes[node_id]["y"]] for node_id in node_ids]
360
+ )
361
+ # Compute the centroid as the mean of the x and y coordinates
362
+ centroid = np.mean(node_positions, axis=0)
363
+ centroids.append(tuple(centroid))
364
+
365
+ return centroids
366
+
367
+
368
+ def _assign_distant_colors(remaining_indices, dist_matrix, colormap, num_colors_to_generate):
369
+ """Assign colors to centroids that are close in space, ensuring stark color differences.
370
+
371
+ Args:
372
+ remaining_indices (set): Indices of centroids left to color.
373
+ dist_matrix (ndarray): Matrix of pairwise centroid distances.
374
+ colormap (Colormap): The colormap used to assign colors.
375
+ num_colors_to_generate (int): Number of colors to generate.
376
+
377
+ Returns:
378
+ np.array: Array of color positions in the colormap.
379
+ """
380
+ color_positions = np.zeros(num_colors_to_generate)
381
+ # Convert the set to a list to index over it
382
+ remaining_indices = list(remaining_indices)
383
+ # Sort remaining indices by centroid proximity (based on sum of distances to others)
384
+ proximity_order = sorted(remaining_indices, key=lambda idx: np.sum(dist_matrix[idx]))
385
+ # Assign colors starting with the most distant points in proximity order
386
+ for i, idx in enumerate(proximity_order):
387
+ color_positions[idx] = i / num_colors_to_generate
388
+
389
+ # Adjust colors so that centroids close to one another are maximally distant on the color spectrum
390
+ half_spectrum = int(num_colors_to_generate / 2)
391
+ for i in range(half_spectrum):
392
+ # Split the spectrum so that close centroids are assigned distant colors
393
+ color_positions[proximity_order[i]] = (i * 2) / num_colors_to_generate
394
+ color_positions[proximity_order[-(i + 1)]] = ((i * 2) + 1) / num_colors_to_generate
395
+
396
+ return color_positions
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: risk-network
3
- Version: 0.0.7b1
3
+ Version: 0.0.7b3
4
4
  Summary: A Python package for biological network analysis
5
5
  Author: Ira Horecka
6
6
  Author-email: Ira Horecka <ira89@icloud.com>
@@ -1,4 +1,4 @@
1
- risk/__init__.py,sha256=kKRKe-z54BZkkomARTvXCfcVgS-KX50Kgryn6By_kdc,112
1
+ risk/__init__.py,sha256=Yoz9l74qVwPoFeWtUKqy_dgQZlDTZtaNIvtmzNx5G78,112
2
2
  risk/constants.py,sha256=XInRaH78Slnw_sWgAsBFbUHkyA0h0jL0DKGuQNbOvjM,550
3
3
  risk/risk.py,sha256=jhfOv60iZdOssCF35tAjJ_br9w8aIqPFT2owVTehgtA,20648
4
4
  risk/annotations/__init__.py,sha256=vUpVvMRE5if01Ic8QY6M2Ae3EFGJHdugEe9PdEkAW4Y,138
@@ -13,7 +13,7 @@ risk/neighborhoods/domains.py,sha256=bxJUxqFTynzX0mf3E8-AA4_Rfccje1reeVVhfzb1-pE
13
13
  risk/neighborhoods/neighborhoods.py,sha256=cEk4gDvIkBky5POZhtHnO78iV-NXu4BeV-e5XdhYOkM,17508
14
14
  risk/network/__init__.py,sha256=iEPeJdZfqp0toxtbElryB8jbz9_t_k4QQ3iDvKE8C_0,126
15
15
  risk/network/geometry.py,sha256=H1yGVVqgbfpzBzJwEheDLfvGLSA284jGQQTn612L4Vc,6759
16
- risk/network/graph.py,sha256=7haHu4M3fleqbrIzs6HC9jnKizSERzmmAYSmUwdoSXA,13953
16
+ risk/network/graph.py,sha256=_ZCyT2b9RtKAYzwul-Kp9__uQwTcagECf-mPMiAmP8U,16977
17
17
  risk/network/io.py,sha256=gG50kOknO-D3HkW1HsbHMkTMvjUtn3l4W4Jwd-rXNr8,21202
18
18
  risk/network/plot.py,sha256=F6KPjmBYWrThKZScHs9SuzoKQiytBvzrmGhGberHjwo,62063
19
19
  risk/stats/__init__.py,sha256=e-BE_Dr_jgiK6hKM-T-tlG4yvHnId8e5qjnM0pdwNVc,230
@@ -23,8 +23,8 @@ risk/stats/stats.py,sha256=kvShov-94W6ffgDUTb522vB9hDJQSyTsYif_UIaFfSM,7059
23
23
  risk/stats/permutation/__init__.py,sha256=neJp7FENC-zg_CGOXqv-iIvz1r5XUKI9Ruxhmq7kDOI,105
24
24
  risk/stats/permutation/permutation.py,sha256=qLWdwxEY6nmkYPxpM8HLDcd2mbqYv9Qr7CKtJvhLqIM,9220
25
25
  risk/stats/permutation/test_functions.py,sha256=HuDIM-V1jkkfE1rlaIqrWWBSKZt3dQ1f-YEDjWpnLSE,2343
26
- risk_network-0.0.7b1.dist-info/LICENSE,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
27
- risk_network-0.0.7b1.dist-info/METADATA,sha256=I0cAqenkwnGxhVcAkX_ipuB3rvmHV4OcR9S7tjOdaC8,43142
28
- risk_network-0.0.7b1.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
29
- risk_network-0.0.7b1.dist-info/top_level.txt,sha256=NX7C2PFKTvC1JhVKv14DFlFAIFnKc6Lpsu1ZfxvQwVw,5
30
- risk_network-0.0.7b1.dist-info/RECORD,,
26
+ risk_network-0.0.7b3.dist-info/LICENSE,sha256=jOtLnuWt7d5Hsx6XXB2QxzrSe2sWWh3NgMfFRetluQM,35147
27
+ risk_network-0.0.7b3.dist-info/METADATA,sha256=6D_1SuZdpPYaUQLLzctNrVLC_gdzsTrx7V1leqBvcio,43142
28
+ risk_network-0.0.7b3.dist-info/WHEEL,sha256=GV9aMThwP_4oNCtvEC2ec3qUYutgWeAzklro_0m4WJQ,91
29
+ risk_network-0.0.7b3.dist-info/top_level.txt,sha256=NX7C2PFKTvC1JhVKv14DFlFAIFnKc6Lpsu1ZfxvQwVw,5
30
+ risk_network-0.0.7b3.dist-info/RECORD,,