risk-network 0.0.8b6__py3-none-any.whl → 0.0.8b8__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.8-beta.6"
10
+ __version__ = "0.0.8-beta.8"
@@ -0,0 +1,6 @@
1
+ """
2
+ risk/network/plot
3
+ ~~~~~~~~~~~~~~~~~
4
+ """
5
+
6
+ from risk.network.plot.plotter import NetworkPlotter
@@ -0,0 +1,226 @@
1
+ """
2
+ risk/network/plot/canvas
3
+ ~~~~~~~~~~~~~~~~~~~~~~~~
4
+ """
5
+
6
+ from typing import List, Tuple, Union
7
+
8
+ import matplotlib.pyplot as plt
9
+ import numpy as np
10
+
11
+ from risk.log import params
12
+ from risk.network.graph import NetworkGraph
13
+ from risk.network.plot.utils import calculate_bounding_box, to_rgba
14
+
15
+
16
+ class Canvas:
17
+ """A class for laying out the canvas in a network graph."""
18
+
19
+ def __init__(self, graph: NetworkGraph, ax: plt.Axes) -> None:
20
+ """Initialize the Canvas with a NetworkGraph and axis for plotting.
21
+
22
+ Args:
23
+ graph (NetworkGraph): The NetworkGraph object containing the network data.
24
+ ax (plt.Axes): The axis to plot the canvas on.
25
+ """
26
+ self.graph = graph
27
+ self.ax = ax
28
+
29
+ def plot_title(
30
+ self,
31
+ title: Union[str, None] = None,
32
+ subtitle: Union[str, None] = None,
33
+ title_fontsize: int = 20,
34
+ subtitle_fontsize: int = 14,
35
+ font: str = "Arial",
36
+ title_color: str = "black",
37
+ subtitle_color: str = "gray",
38
+ title_y: float = 0.975,
39
+ title_space_offset: float = 0.075,
40
+ subtitle_offset: float = 0.025,
41
+ ) -> None:
42
+ """Plot title and subtitle on the network graph with customizable parameters.
43
+
44
+ Args:
45
+ title (str, optional): Title of the plot. Defaults to None.
46
+ subtitle (str, optional): Subtitle of the plot. Defaults to None.
47
+ title_fontsize (int, optional): Font size for the title. Defaults to 16.
48
+ subtitle_fontsize (int, optional): Font size for the subtitle. Defaults to 12.
49
+ font (str, optional): Font family used for both title and subtitle. Defaults to "Arial".
50
+ title_color (str, optional): Color of the title text. Defaults to "black".
51
+ subtitle_color (str, optional): Color of the subtitle text. Defaults to "gray".
52
+ title_y (float, optional): Y-axis position of the title. Defaults to 0.975.
53
+ title_space_offset (float, optional): Fraction of figure height to leave for the space above the plot. Defaults to 0.075.
54
+ subtitle_offset (float, optional): Offset factor to position the subtitle below the title. Defaults to 0.025.
55
+ """
56
+ # Log the title and subtitle parameters
57
+ params.log_plotter(
58
+ title=title,
59
+ subtitle=subtitle,
60
+ title_fontsize=title_fontsize,
61
+ subtitle_fontsize=subtitle_fontsize,
62
+ title_subtitle_font=font,
63
+ title_color=title_color,
64
+ subtitle_color=subtitle_color,
65
+ subtitle_offset=subtitle_offset,
66
+ title_y=title_y,
67
+ title_space_offset=title_space_offset,
68
+ )
69
+
70
+ # Get the current figure and axis dimensions
71
+ fig = self.ax.figure
72
+ # Use a tight layout to ensure that title and subtitle do not overlap with the original plot
73
+ fig.tight_layout(
74
+ rect=[0, 0, 1, 1 - title_space_offset]
75
+ ) # Leave space above the plot for title
76
+
77
+ # Plot title if provided
78
+ if title:
79
+ # Set the title using figure's suptitle to ensure centering
80
+ self.ax.figure.suptitle(
81
+ title,
82
+ fontsize=title_fontsize,
83
+ color=title_color,
84
+ fontname=font,
85
+ x=0.5, # Center the title horizontally
86
+ ha="center",
87
+ va="top",
88
+ y=title_y,
89
+ )
90
+
91
+ # Plot subtitle if provided
92
+ if subtitle:
93
+ # Calculate the subtitle's y position based on title's position and subtitle_offset
94
+ subtitle_y_position = title_y - subtitle_offset
95
+ self.ax.figure.text(
96
+ 0.5, # Ensure horizontal centering for subtitle
97
+ subtitle_y_position,
98
+ subtitle,
99
+ ha="center",
100
+ va="top",
101
+ fontname=font,
102
+ fontsize=subtitle_fontsize,
103
+ color=subtitle_color,
104
+ )
105
+
106
+ def plot_circle_perimeter(
107
+ self,
108
+ scale: float = 1.0,
109
+ linestyle: str = "dashed",
110
+ linewidth: float = 1.5,
111
+ color: Union[str, List, Tuple, np.ndarray] = "black",
112
+ outline_alpha: Union[float, None] = 1.0,
113
+ fill_alpha: Union[float, None] = 0.0,
114
+ ) -> None:
115
+ """Plot a circle around the network graph to represent the network perimeter.
116
+
117
+ Args:
118
+ scale (float, optional): Scaling factor for the perimeter diameter. Defaults to 1.0.
119
+ linestyle (str, optional): Line style for the network perimeter circle (e.g., dashed, solid). Defaults to "dashed".
120
+ linewidth (float, optional): Width of the circle's outline. Defaults to 1.5.
121
+ color (str, list, tuple, or np.ndarray, optional): Color of the network perimeter circle. Defaults to "black".
122
+ outline_alpha (float, None, optional): Transparency level of the circle outline. If provided, it overrides any existing alpha
123
+ values found in color. Defaults to 1.0.
124
+ fill_alpha (float, None, optional): Transparency level of the circle fill. If provided, it overrides any existing alpha values
125
+ found in color. Defaults to 0.0.
126
+ """
127
+ # Log the circle perimeter plotting parameters
128
+ params.log_plotter(
129
+ perimeter_type="circle",
130
+ perimeter_scale=scale,
131
+ perimeter_linestyle=linestyle,
132
+ perimeter_linewidth=linewidth,
133
+ perimeter_color=(
134
+ "custom" if isinstance(color, (list, tuple, np.ndarray)) else color
135
+ ), # np.ndarray usually indicates custom colors
136
+ perimeter_outline_alpha=outline_alpha,
137
+ perimeter_fill_alpha=fill_alpha,
138
+ )
139
+
140
+ # Convert color to RGBA using the to_rgba helper function - use outline_alpha for the perimeter
141
+ color = to_rgba(color=color, alpha=outline_alpha)
142
+ # Set the fill_alpha to 0 if not provided
143
+ fill_alpha = fill_alpha if fill_alpha is not None else 0.0
144
+ # Extract node coordinates from the network graph
145
+ node_coordinates = self.graph.node_coordinates
146
+ # Calculate the center and radius of the bounding box around the network
147
+ center, radius = calculate_bounding_box(node_coordinates)
148
+ # Scale the radius by the scale factor
149
+ scaled_radius = radius * scale
150
+
151
+ # Draw a circle to represent the network perimeter
152
+ circle = plt.Circle(
153
+ center,
154
+ scaled_radius,
155
+ linestyle=linestyle,
156
+ linewidth=linewidth,
157
+ color=color,
158
+ fill=fill_alpha > 0, # Fill the circle if fill_alpha is greater than 0
159
+ )
160
+ # Set the transparency of the fill if applicable
161
+ if fill_alpha > 0:
162
+ circle.set_facecolor(to_rgba(color=color, alpha=fill_alpha))
163
+
164
+ self.ax.add_artist(circle)
165
+
166
+ def plot_contour_perimeter(
167
+ self,
168
+ scale: float = 1.0,
169
+ levels: int = 3,
170
+ bandwidth: float = 0.8,
171
+ grid_size: int = 250,
172
+ color: Union[str, List, Tuple, np.ndarray] = "black",
173
+ linestyle: str = "solid",
174
+ linewidth: float = 1.5,
175
+ outline_alpha: Union[float, None] = 1.0,
176
+ fill_alpha: Union[float, None] = 0.0,
177
+ ) -> None:
178
+ """
179
+ Plot a KDE-based contour around the network graph to represent the network perimeter.
180
+
181
+ Args:
182
+ scale (float, optional): Scaling factor for the perimeter size. Defaults to 1.0.
183
+ levels (int, optional): Number of contour levels. Defaults to 3.
184
+ bandwidth (float, optional): Bandwidth for the KDE. Controls smoothness. Defaults to 0.8.
185
+ grid_size (int, optional): Grid resolution for the KDE. Higher values yield finer contours. Defaults to 250.
186
+ color (str, list, tuple, or np.ndarray, optional): Color of the network perimeter contour. Defaults to "black".
187
+ linestyle (str, optional): Line style for the network perimeter contour (e.g., dashed, solid). Defaults to "solid".
188
+ linewidth (float, optional): Width of the contour's outline. Defaults to 1.5.
189
+ outline_alpha (float, None, optional): Transparency level of the contour outline. If provided, it overrides any existing
190
+ alpha values found in color. Defaults to 1.0.
191
+ fill_alpha (float, None, optional): Transparency level of the contour fill. If provided, it overrides any existing alpha
192
+ values found in color. Defaults to 0.0.
193
+ """
194
+ # Log the contour perimeter plotting parameters
195
+ params.log_plotter(
196
+ perimeter_type="contour",
197
+ perimeter_scale=scale,
198
+ perimeter_levels=levels,
199
+ perimeter_bandwidth=bandwidth,
200
+ perimeter_grid_size=grid_size,
201
+ perimeter_linestyle=linestyle,
202
+ perimeter_linewidth=linewidth,
203
+ perimeter_color=("custom" if isinstance(color, (list, tuple, np.ndarray)) else color),
204
+ perimeter_outline_alpha=outline_alpha,
205
+ perimeter_fill_alpha=fill_alpha,
206
+ )
207
+
208
+ # Convert color to RGBA using the to_rgba helper function - use outline_alpha for the perimeter
209
+ color = to_rgba(color=color, alpha=outline_alpha)
210
+ # Extract node coordinates from the network graph
211
+ node_coordinates = self.graph.node_coordinates
212
+ # Scale the node coordinates if needed
213
+ scaled_coordinates = node_coordinates * scale
214
+ # Use the existing _draw_kde_contour method
215
+ self._draw_kde_contour(
216
+ ax=self.ax,
217
+ pos=scaled_coordinates,
218
+ nodes=list(range(len(node_coordinates))), # All nodes are included
219
+ levels=levels,
220
+ bandwidth=bandwidth,
221
+ grid_size=grid_size,
222
+ color=color,
223
+ linestyle=linestyle,
224
+ linewidth=linewidth,
225
+ alpha=fill_alpha,
226
+ )
@@ -0,0 +1,319 @@
1
+ """
2
+ risk/network/plot/contour
3
+ ~~~~~~~~~~~~~~~~~~~~~~~~~
4
+ """
5
+
6
+ from typing import List, Tuple, Union
7
+
8
+ import matplotlib.pyplot as plt
9
+ import numpy as np
10
+ from scipy import linalg
11
+ from scipy.ndimage import label
12
+ from scipy.stats import gaussian_kde
13
+
14
+ from risk.log import params, logger
15
+ from risk.network.graph import NetworkGraph
16
+ from risk.network.plot.utils import get_annotated_domain_colors, to_rgba
17
+
18
+
19
+ class Contour:
20
+ """Class to generate Kernel Density Estimate (KDE) contours for nodes in a network graph."""
21
+
22
+ def __init__(self, graph: NetworkGraph, ax: plt.Axes) -> None:
23
+ """Initialize the Contour with a NetworkGraph and axis for plotting.
24
+
25
+ Args:
26
+ graph (NetworkGraph): The NetworkGraph object containing the network data.
27
+ ax (plt.Axes): The axis to plot the contours on.
28
+ """
29
+ self.graph = graph
30
+ self.ax = ax
31
+
32
+ def plot_contours(
33
+ self,
34
+ levels: int = 5,
35
+ bandwidth: float = 0.8,
36
+ grid_size: int = 250,
37
+ color: Union[str, List, Tuple, np.ndarray] = "white",
38
+ linestyle: str = "solid",
39
+ linewidth: float = 1.5,
40
+ alpha: Union[float, None] = 1.0,
41
+ fill_alpha: Union[float, None] = None,
42
+ ) -> None:
43
+ """Draw KDE contours for nodes in various domains of a network graph, highlighting areas of high density.
44
+
45
+ Args:
46
+ levels (int, optional): Number of contour levels to plot. Defaults to 5.
47
+ bandwidth (float, optional): Bandwidth for KDE. Controls the smoothness of the contour. Defaults to 0.8.
48
+ grid_size (int, optional): Resolution of the grid for KDE. Higher values create finer contours. Defaults to 250.
49
+ color (str, list, tuple, or np.ndarray, optional): Color of the contours. Can be a single color or an array of colors.
50
+ Defaults to "white".
51
+ linestyle (str, optional): Line style for the contours. Defaults to "solid".
52
+ linewidth (float, optional): Line width for the contours. Defaults to 1.5.
53
+ alpha (float, None, optional): Transparency level of the contour lines. If provided, it overrides any existing alpha values
54
+ found in color. Defaults to 1.0.
55
+ fill_alpha (float, None, optional): Transparency level of the contour fill. If provided, it overrides any existing alpha
56
+ values found in color. Defaults to None.
57
+ """
58
+ # Log the contour plotting parameters
59
+ params.log_plotter(
60
+ contour_levels=levels,
61
+ contour_bandwidth=bandwidth,
62
+ contour_grid_size=grid_size,
63
+ contour_color=(
64
+ "custom" if isinstance(color, np.ndarray) else color
65
+ ), # np.ndarray usually indicates custom colors
66
+ contour_alpha=alpha,
67
+ contour_fill_alpha=fill_alpha,
68
+ )
69
+
70
+ # Ensure color is converted to RGBA with repetition matching the number of domains
71
+ color = to_rgba(
72
+ color=color, alpha=alpha, num_repeats=len(self.graph.domain_id_to_node_ids_map)
73
+ )
74
+ # Extract node coordinates from the network graph
75
+ node_coordinates = self.graph.node_coordinates
76
+ # Draw contours for each domain in the network
77
+ for idx, (_, node_ids) in enumerate(self.graph.domain_id_to_node_ids_map.items()):
78
+ if len(node_ids) > 1:
79
+ self._draw_kde_contour(
80
+ self.ax,
81
+ node_coordinates,
82
+ node_ids,
83
+ color=color[idx],
84
+ levels=levels,
85
+ bandwidth=bandwidth,
86
+ grid_size=grid_size,
87
+ linestyle=linestyle,
88
+ linewidth=linewidth,
89
+ alpha=alpha,
90
+ fill_alpha=fill_alpha,
91
+ )
92
+
93
+ def plot_subcontour(
94
+ self,
95
+ nodes: Union[List, Tuple, np.ndarray],
96
+ levels: int = 5,
97
+ bandwidth: float = 0.8,
98
+ grid_size: int = 250,
99
+ color: Union[str, List, Tuple, np.ndarray] = "white",
100
+ linestyle: str = "solid",
101
+ linewidth: float = 1.5,
102
+ alpha: Union[float, None] = 1.0,
103
+ fill_alpha: Union[float, None] = None,
104
+ ) -> None:
105
+ """Plot a subcontour for a given set of nodes or a list of node sets using Kernel Density Estimation (KDE).
106
+
107
+ Args:
108
+ nodes (list, tuple, or np.ndarray): List of node labels or list of lists of node labels to plot the contour for.
109
+ levels (int, optional): Number of contour levels to plot. Defaults to 5.
110
+ bandwidth (float, optional): Bandwidth for KDE. Controls the smoothness of the contour. Defaults to 0.8.
111
+ grid_size (int, optional): Resolution of the grid for KDE. Higher values create finer contours. Defaults to 250.
112
+ color (str, list, tuple, or np.ndarray, optional): Color of the contour. Can be a string (e.g., 'white') or RGBA array.
113
+ Defaults to "white".
114
+ linestyle (str, optional): Line style for the contour. Defaults to "solid".
115
+ linewidth (float, optional): Line width for the contour. Defaults to 1.5.
116
+ alpha (float, None, optional): Transparency level of the contour lines. If provided, it overrides any existing alpha values
117
+ found in color. Defaults to 1.0.
118
+ fill_alpha (float, None, optional): Transparency level of the contour fill. If provided, it overrides any existing alpha
119
+ values found in color. Defaults to None.
120
+
121
+ Raises:
122
+ ValueError: If no valid nodes are found in the network graph.
123
+ """
124
+ # Check if nodes is a list of lists or a flat list
125
+ if any(isinstance(item, (list, tuple, np.ndarray)) for item in nodes):
126
+ # If it's a list of lists, iterate over sublists
127
+ node_groups = nodes
128
+ else:
129
+ # If it's a flat list of nodes, treat it as a single group
130
+ node_groups = [nodes]
131
+
132
+ # Convert color to RGBA using the to_rgba helper function
133
+ color_rgba = to_rgba(color=color, alpha=alpha)
134
+
135
+ # Iterate over each group of nodes (either sublists or flat list)
136
+ for sublist in node_groups:
137
+ # Filter to get node IDs and their coordinates for each sublist
138
+ node_ids = [
139
+ self.graph.node_label_to_node_id_map.get(node)
140
+ for node in sublist
141
+ if node in self.graph.node_label_to_node_id_map
142
+ ]
143
+ if not node_ids or len(node_ids) == 1:
144
+ raise ValueError(
145
+ "No nodes found in the network graph or insufficient nodes to plot."
146
+ )
147
+
148
+ # Draw the KDE contour for the specified nodes
149
+ node_coordinates = self.graph.node_coordinates
150
+ self._draw_kde_contour(
151
+ self.ax,
152
+ node_coordinates,
153
+ node_ids,
154
+ color=color_rgba,
155
+ levels=levels,
156
+ bandwidth=bandwidth,
157
+ grid_size=grid_size,
158
+ linestyle=linestyle,
159
+ linewidth=linewidth,
160
+ alpha=alpha,
161
+ fill_alpha=fill_alpha,
162
+ )
163
+
164
+ def _draw_kde_contour(
165
+ self,
166
+ ax: plt.Axes,
167
+ pos: np.ndarray,
168
+ nodes: List,
169
+ levels: int = 5,
170
+ bandwidth: float = 0.8,
171
+ grid_size: int = 250,
172
+ color: Union[str, np.ndarray] = "white",
173
+ linestyle: str = "solid",
174
+ linewidth: float = 1.5,
175
+ alpha: Union[float, None] = 1.0,
176
+ fill_alpha: Union[float, None] = 0.2,
177
+ ) -> None:
178
+ """Draw a Kernel Density Estimate (KDE) contour plot for a set of nodes on a given axis.
179
+
180
+ Args:
181
+ ax (plt.Axes): The axis to draw the contour on.
182
+ pos (np.ndarray): Array of node positions (x, y).
183
+ nodes (list): List of node indices to include in the contour.
184
+ levels (int, optional): Number of contour levels. Defaults to 5.
185
+ bandwidth (float, optional): Bandwidth for the KDE. Controls smoothness. Defaults to 0.8.
186
+ grid_size (int, optional): Grid resolution for the KDE. Higher values yield finer contours. Defaults to 250.
187
+ color (str or np.ndarray): Color for the contour. Can be a string or RGBA array. Defaults to "white".
188
+ linestyle (str, optional): Line style for the contour. Defaults to "solid".
189
+ linewidth (float, optional): Line width for the contour. Defaults to 1.5.
190
+ alpha (float, None, optional): Transparency level for the contour lines. If provided, it overrides any existing alpha
191
+ values found in color. Defaults to 1.0.
192
+ fill_alpha (float, None, optional): Transparency level for the contour fill. If provided, it overrides any existing
193
+ alpha values found in color. Defaults to 0.2.
194
+ """
195
+ # Extract the positions of the specified nodes
196
+ points = np.array([pos[n] for n in nodes])
197
+ if len(points) <= 1:
198
+ return None # Not enough points to form a contour
199
+
200
+ # Check if the KDE forms a single connected component
201
+ connected = False
202
+ z = None # Initialize z to None to avoid UnboundLocalError
203
+ while not connected and bandwidth <= 100.0:
204
+ try:
205
+ # Perform KDE on the points with the given bandwidth
206
+ kde = gaussian_kde(points.T, bw_method=bandwidth)
207
+ xmin, ymin = points.min(axis=0) - bandwidth
208
+ xmax, ymax = points.max(axis=0) + bandwidth
209
+ x, y = np.mgrid[
210
+ xmin : xmax : complex(0, grid_size), ymin : ymax : complex(0, grid_size)
211
+ ]
212
+ z = kde(np.vstack([x.ravel(), y.ravel()])).reshape(x.shape)
213
+ # Check if the KDE forms a single connected component
214
+ connected = _is_connected(z)
215
+ if not connected:
216
+ bandwidth += 0.05 # Increase bandwidth slightly and retry
217
+ except linalg.LinAlgError:
218
+ bandwidth += 0.05 # Increase bandwidth and retry
219
+ except Exception as e:
220
+ # Catch any other exceptions and log them
221
+ logger.error(f"Unexpected error when drawing KDE contour: {e}")
222
+ return None
223
+
224
+ # If z is still None, the KDE computation failed
225
+ if z is None:
226
+ logger.error("Failed to compute KDE. Skipping contour plot for these nodes.")
227
+ return None
228
+
229
+ # Define contour levels based on the density
230
+ min_density, max_density = z.min(), z.max()
231
+ if min_density == max_density:
232
+ logger.warning(
233
+ "Contour levels could not be created due to lack of variation in density."
234
+ )
235
+ return None
236
+
237
+ # Create contour levels based on the density values
238
+ contour_levels = np.linspace(min_density, max_density, levels)[1:]
239
+ if len(contour_levels) < 2 or not np.all(np.diff(contour_levels) > 0):
240
+ logger.error("Contour levels must be strictly increasing. Skipping contour plot.")
241
+ return None
242
+
243
+ # Set the contour color and linestyle
244
+ contour_colors = [color for _ in range(levels - 1)]
245
+ # Plot the filled contours using fill_alpha for transparency
246
+ if fill_alpha and fill_alpha > 0:
247
+ ax.contourf(
248
+ x,
249
+ y,
250
+ z,
251
+ levels=contour_levels,
252
+ colors=contour_colors,
253
+ antialiased=True,
254
+ alpha=fill_alpha,
255
+ )
256
+
257
+ # Plot the contour lines with the specified alpha for transparency
258
+ c = ax.contour(
259
+ x,
260
+ y,
261
+ z,
262
+ levels=contour_levels,
263
+ colors=contour_colors,
264
+ linestyles=linestyle,
265
+ linewidths=linewidth,
266
+ alpha=alpha,
267
+ )
268
+
269
+ # Set linewidth for the contour lines to 0 for levels other than the base level
270
+ for i in range(1, len(contour_levels)):
271
+ c.collections[i].set_linewidth(0)
272
+
273
+ def get_annotated_contour_colors(
274
+ self,
275
+ cmap: str = "gist_rainbow",
276
+ color: Union[str, None] = None,
277
+ min_scale: float = 0.8,
278
+ max_scale: float = 1.0,
279
+ scale_factor: float = 1.0,
280
+ random_seed: int = 888,
281
+ ) -> np.ndarray:
282
+ """Get colors for the contours based on node annotations or a specified colormap.
283
+
284
+ Args:
285
+ cmap (str, optional): Name of the colormap to use for generating contour colors. Defaults to "gist_rainbow".
286
+ color (str or None, optional): Color to use for the contours. If None, the colormap will be used. Defaults to None.
287
+ min_scale (float, optional): Minimum intensity scale for the colors generated by the colormap.
288
+ Controls the dimmest colors. Defaults to 0.8.
289
+ max_scale (float, optional): Maximum intensity scale for the colors generated by the colormap.
290
+ Controls the brightest colors. Defaults to 1.0.
291
+ scale_factor (float, optional): Exponent for adjusting color scaling based on enrichment scores.
292
+ A higher value increases contrast by dimming lower scores more. Defaults to 1.0.
293
+ random_seed (int, optional): Seed for random number generation to ensure reproducibility. Defaults to 888.
294
+
295
+ Returns:
296
+ np.ndarray: Array of RGBA colors for contour annotations.
297
+ """
298
+ return get_annotated_domain_colors(
299
+ graph=self.graph,
300
+ cmap=cmap,
301
+ color=color,
302
+ min_scale=min_scale,
303
+ max_scale=max_scale,
304
+ scale_factor=scale_factor,
305
+ random_seed=random_seed,
306
+ )
307
+
308
+
309
+ def _is_connected(z: np.ndarray) -> bool:
310
+ """Determine if a thresholded grid represents a single, connected component.
311
+
312
+ Args:
313
+ z (np.ndarray): A binary grid where the component connectivity is evaluated.
314
+
315
+ Returns:
316
+ bool: True if the grid represents a single connected component, False otherwise.
317
+ """
318
+ _, num_features = label(z)
319
+ return num_features == 1 # Return True if only one connected component is found