cellects 0.1.2__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.
Files changed (44) hide show
  1. cellects/__init__.py +0 -0
  2. cellects/__main__.py +49 -0
  3. cellects/config/__init__.py +0 -0
  4. cellects/config/all_vars_dict.py +155 -0
  5. cellects/core/__init__.py +0 -0
  6. cellects/core/cellects_paths.py +31 -0
  7. cellects/core/cellects_threads.py +1451 -0
  8. cellects/core/motion_analysis.py +2010 -0
  9. cellects/core/one_image_analysis.py +1061 -0
  10. cellects/core/one_video_per_blob.py +540 -0
  11. cellects/core/program_organizer.py +1316 -0
  12. cellects/core/script_based_run.py +154 -0
  13. cellects/gui/__init__.py +0 -0
  14. cellects/gui/advanced_parameters.py +1258 -0
  15. cellects/gui/cellects.py +189 -0
  16. cellects/gui/custom_widgets.py +790 -0
  17. cellects/gui/first_window.py +449 -0
  18. cellects/gui/if_several_folders_window.py +239 -0
  19. cellects/gui/image_analysis_window.py +2066 -0
  20. cellects/gui/required_output.py +232 -0
  21. cellects/gui/video_analysis_window.py +656 -0
  22. cellects/icons/__init__.py +0 -0
  23. cellects/icons/cellects_icon.icns +0 -0
  24. cellects/icons/cellects_icon.ico +0 -0
  25. cellects/image_analysis/__init__.py +0 -0
  26. cellects/image_analysis/cell_leaving_detection.py +54 -0
  27. cellects/image_analysis/cluster_flux_study.py +102 -0
  28. cellects/image_analysis/image_segmentation.py +706 -0
  29. cellects/image_analysis/morphological_operations.py +1635 -0
  30. cellects/image_analysis/network_functions.py +1757 -0
  31. cellects/image_analysis/one_image_analysis_threads.py +289 -0
  32. cellects/image_analysis/progressively_add_distant_shapes.py +508 -0
  33. cellects/image_analysis/shape_descriptors.py +1016 -0
  34. cellects/utils/__init__.py +0 -0
  35. cellects/utils/decorators.py +14 -0
  36. cellects/utils/formulas.py +637 -0
  37. cellects/utils/load_display_save.py +1054 -0
  38. cellects/utils/utilitarian.py +490 -0
  39. cellects-0.1.2.dist-info/LICENSE.odt +0 -0
  40. cellects-0.1.2.dist-info/METADATA +132 -0
  41. cellects-0.1.2.dist-info/RECORD +44 -0
  42. cellects-0.1.2.dist-info/WHEEL +5 -0
  43. cellects-0.1.2.dist-info/entry_points.txt +2 -0
  44. cellects-0.1.2.dist-info/top_level.txt +1 -0
File without changes
@@ -0,0 +1,14 @@
1
+ import os
2
+ from numba import njit as _real_njit
3
+
4
+ USE_NUMBA = os.getenv("USE_NUMBA", "1") == "1"
5
+
6
+ def njit(*args, **kwargs):
7
+ """ numba.njit decorator that can be disabled. Useful for testing.
8
+ """
9
+ if USE_NUMBA:
10
+ return _real_njit(*args, **kwargs)
11
+ # test mode: return identity decorator
12
+ def deco(func):
13
+ return func
14
+ return deco
@@ -0,0 +1,637 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Statistical and geometric analysis tools for numerical arrays.
4
+
5
+ This module provides a collection of functions and unit tests for calculating distances,
6
+ statistical properties (skewness, kurtosis), array transformations, and image moment-based
7
+ analysis. The tools are optimized for applications involving binary images, coordinate data,
8
+ and mathematical modeling operations where performance-critical calculations benefit from
9
+ vectorized or JIT-compiled implementations.
10
+
11
+ Functions:
12
+ eudist : Calculate Euclidean distance between two vectors
13
+ to_uint8 : Convert array to 8-bit unsigned integers using NumBA acceleration
14
+ translate_dict : Transform dictionary structures into alternative formats
15
+ linear_model : Compute y = a*x + b regression model values (JIT-compiled)
16
+ moving_average : Calculate sliding window averages with specified step size
17
+ get_var : Derive variance from image moments and spatial coordinates
18
+ find_common_coord : Identify shared coordinate pairs between two arrays
19
+ get_skewness/get_kurtosis : Calculate third/fourth standardized moment statistics
20
+ sum_of_abs_differences : Compute total absolute differences between arrays (JIT)
21
+ bracket_to_uint8_image_contrast : Convert images to 8-bit with contrast normalization
22
+ find_duplicates_coord : Locate rows with duplicate coordinate values
23
+ get_power_dists : Generate radial distance measures from image centers
24
+ get_inertia_axes : Calculate principal axes of inertia for binary shapes
25
+
26
+ Notes:
27
+ - All Numba-accelerated functions require congruent NumPy arrays as inputs
28
+ - Image processing functions expect binary (boolean/int8) input matrices
29
+ """
30
+ from copy import deepcopy
31
+ from cellects.utils.decorators import njit
32
+ import numpy as np
33
+ from numpy.typing import NDArray
34
+ from typing import Tuple
35
+
36
+
37
+ @njit()
38
+ def sum_of_abs_differences(array1: NDArray, array2: NDArray):
39
+ """
40
+ Compute the sum of absolute differences between two arrays.
41
+
42
+ Parameters
43
+ ----------
44
+ array1 : NDArray
45
+ The first input array.
46
+ array2 : NDArray
47
+ The second input array.
48
+
49
+ Returns
50
+ -------
51
+ int
52
+ Sum of absolute differences between elements of `array1` and `array2`.
53
+
54
+ Examples
55
+ --------
56
+ >>> arr1 = np.array([1.2, 2.5, -3.7])
57
+ >>> arr2 = np.array([12, 25, -37])
58
+ >>> result = sum_of_abs_differences(arr1, arr2)
59
+ >>> print(result)
60
+ 66.6
61
+ """
62
+ return np.sum(np.absolute(array1 - array2))
63
+
64
+
65
+ @njit()
66
+ def to_uint8(an_array: NDArray):
67
+ """
68
+ Convert an array to unsigned 8-bit integers.
69
+
70
+ Parameters
71
+ ----------
72
+ an_array : ndarray
73
+ Input array to be converted. It can be of any numeric dtype.
74
+
75
+ Returns
76
+ -------
77
+ ndarray
78
+ The input array rounded to the nearest integer and then cast to
79
+ unsigned 8-bit integers.
80
+
81
+ Raises
82
+ ------
83
+ TypeError
84
+ If `an_array` is not a ndarray.
85
+
86
+ Notes
87
+ -----
88
+ This function uses Numba's `@njit` decorator for performance optimization.
89
+
90
+ Examples
91
+ --------
92
+ >>> result = to_uint8(np.array([1.2, 2.5, -3.7]))
93
+ >>> print(result)
94
+ [1 3 0]
95
+ """
96
+ out = np.empty_like(an_array)
97
+ return np.round(an_array, 0, out).astype(np.uint8)
98
+
99
+
100
+ @njit()
101
+ def bracket_to_uint8_image_contrast(image: NDArray):
102
+ """
103
+ Convert an image with bracket contrast values to uint8 type.
104
+
105
+ This function normalizes an input image by scaling the minimum and maximum
106
+ values of the image to the range [0, 255] and then converts it to uint8
107
+ data type.
108
+
109
+ Parameters
110
+ ----------
111
+ image : ndarray
112
+ Input image as a numpy array with floating-point values.
113
+
114
+ Returns
115
+ -------
116
+ ndarray of uint8
117
+ Output image converted to uint8 type after normalization.
118
+ """
119
+ image -= np.min(image)
120
+ return to_uint8(255 * (image / np.max(image)))
121
+
122
+
123
+ @njit()
124
+ def linear_model(x: NDArray, a: float, b: float) -> float:
125
+ """
126
+ Perform a linear transformation on input data using slope and intercept.
127
+
128
+ Parameters
129
+ ----------
130
+ x : array_like
131
+ Input data.
132
+ a : float
133
+ Slope coefficient.
134
+ b : float
135
+ Intercept.
136
+
137
+ Returns
138
+ -------
139
+ float
140
+ Resulting value from linear transformation: `a` * `x` + `b`.
141
+
142
+ Examples
143
+ --------
144
+ >>> result = linear_model(5, 2.0, 1.5)
145
+ >>> print(result) # doctest: +SKIP
146
+ 11.5
147
+
148
+ Notes
149
+ -----
150
+ This function uses Numba's @njit decorator for performance.
151
+ """
152
+ return a * x + b
153
+
154
+
155
+ @njit()
156
+ def get_power_dists(binary_image: np.ndarray, cx: float, cy: float, n: int):
157
+ """
158
+ Calculate the power distributions based on the given center coordinates and exponent.
159
+
160
+ This function computes the `n`th powers of x and y distances from
161
+ a given center point `(cx, cy)` for each pixel in the binary image.
162
+
163
+ Parameters
164
+ ----------
165
+ binary_image : np.ndarray
166
+ A 2D array (binary image) where the power distributions are calculated.
167
+ cx : float
168
+ The x-coordinate of the center point.
169
+ cy : float
170
+ The y-coordinate of the center point.
171
+ n : int
172
+ The exponent for power distribution calculation.
173
+
174
+ Returns
175
+ -------
176
+ tuple[np.ndarray, np.ndarray]
177
+ A tuple containing two arrays:
178
+ - The first array contains the `n`th power of x distances from the center.
179
+ - The second array contains the `n`th power of y distances from the center.
180
+
181
+ Notes
182
+ -----
183
+ This function uses Numba's `@njit` decorator for performance optimization.
184
+ Ensure that `binary_image` is a NumPy ndarray to avoid type issues.
185
+
186
+ Examples
187
+ --------
188
+ >>> binary_image = np.zeros((10, 10))
189
+ >>> xn, yn = get_power_dists(binary_image, 5.0, 5.0, 2)
190
+ >>> print(xn.shape), print(yn.shape)
191
+ (10,) (10,)
192
+ """
193
+ xn = (np.arange(binary_image.shape[1]) - cx) ** n
194
+ yn = (np.arange(binary_image.shape[0]) - cy) ** n
195
+ return xn, yn
196
+
197
+
198
+ @njit()
199
+ def get_var(mo: dict, binary_image: NDArray, Xn: NDArray, Yn: NDArray) -> Tuple[float, float]:
200
+ """
201
+ Compute the center of mass in 2D space.
202
+
203
+ This function calculates the weighted average position (centroid) of
204
+ a binary image using given pixel coordinates and moments.
205
+
206
+ Parameters
207
+ ----------
208
+ mo : dict
209
+ Dictionary containing moments of binary image.
210
+ binary_image : ndarray
211
+ 2D binary image where non-zero pixels are considered.
212
+ Xn : ndarray
213
+ Array of x-coordinates for each pixel in `binary_image`.
214
+ Yn : ndarray
215
+ Array of y-coordinates for each pixel in `binary_image`.
216
+
217
+ Returns
218
+ -------
219
+ tuple
220
+ A tuple of two floats `(vx, vy)` representing the centroid coordinates.
221
+
222
+ Raises
223
+ ------
224
+ ZeroDivisionError
225
+ If `mo['m00']` is zero, indicating no valid pixels in the image.
226
+ The function raises a `ZeroDivisionError`.
227
+
228
+ Notes
229
+ -----
230
+ Performance considerations: This function uses Numba's `@njit` decorator for performance.
231
+ """
232
+ vx = np.sum(binary_image * Xn) / mo["m00"]
233
+ vy = np.sum(binary_image * Yn) / mo["m00"]
234
+ return vx, vy
235
+
236
+
237
+ @njit()
238
+ def get_skewness_kurtosis(mnx: float, mny: float, sx: float, sy: float, n: int) -> Tuple[float, float]:
239
+ """
240
+ Calculates skewness and kurtosis of a distribution.
241
+
242
+ This function computes the skewness and kurtosis from given statistical
243
+ moments, standard deviations, and order of moments.
244
+
245
+ Parameters
246
+ ----------
247
+ mnx : float
248
+ The third moment about the mean for x.
249
+ mny : float
250
+ The fourth moment about the mean for y.
251
+ sx : float
252
+ The standard deviation of x.
253
+ sy : float
254
+ The standard deviation of y.
255
+ n : int
256
+ Order of the moment (3 for skewness, 4 for kurtosis).
257
+
258
+ Returns
259
+ -------
260
+ skewness : float
261
+ The computed skewness.
262
+ kurtosis : float
263
+ The computed kurtosis.
264
+
265
+ Notes
266
+ -----
267
+ This function uses Numba's `@njit` decorator for performance.
268
+ Ensure that the values of `mnx`, `mny`, `sx`, and `sy` are non-zero to avoid division by zero.
269
+ If `n = 3`, the function calculates skewness. If `n = 4`, it calculates kurtosis.
270
+
271
+ Examples
272
+ --------
273
+ >>> skewness, kurtosis = get_skewness_kurtosis(1.5, 2.0, 0.5, 0.75, 3)
274
+ >>> print("Skewness:", skewness)
275
+ Skewness: 8.0
276
+ >>> print("Kurtosis:", kurtosis)
277
+ Kurtosis: nan
278
+
279
+ """
280
+ return mnx / sx ** n, mny / sy ** n
281
+
282
+
283
+ def get_standard_deviations(mo: dict, binary_image: NDArray, cx: float, cy: float) -> Tuple[float, float]:
284
+ """
285
+ Return spatial standard deviations for a given moment and binary image.
286
+
287
+ This function computes the square root of variances along `x` (horizontal)
288
+ and `y` (vertical) axes for the given binary image and moment.
289
+
290
+ Parameters
291
+ ----------
292
+ mo : dict
293
+ Dictionary containing moments of binary image.
294
+ binary_image : ndarray of bool or int8
295
+ The binary input image where the moments are computed.
296
+ cx : float64
297
+ X-coordinate of center of mass (horizontal position).
298
+ cy : float64
299
+ Y-coordinate of center of mass (vertical position).
300
+
301
+ Returns
302
+ -------
303
+ tuple[ndarray of float64, ndarray of float64]
304
+ Tuple containing the standard deviations along the x and y axes.
305
+
306
+ Raises
307
+ ------
308
+ ValueError
309
+ If `binary_image` is not a binary image or has an invalid datatype.
310
+
311
+ Notes
312
+ -----
313
+ This function uses the `get_power_dists` and `get_var` functions to compute
314
+ the distributed variances, which are then transformed into standard deviations.
315
+
316
+ Examples
317
+ --------
318
+ >>> import numpy as np
319
+ >>> binary_image = np.array([[0, 1], [1, 0]], dtype=np.int8)
320
+ >>> mo = np.array([[2.0], [3.0]])
321
+ >>> cx, cy = 1.5, 1.5
322
+ >>> stdx, stdy = get_standard_deviations(mo, binary_image, cx, cy)
323
+ >>> print(stdx)
324
+ [1.1]
325
+ >>> print(stdy)
326
+ [0.8366600265...]
327
+ """
328
+ x2, y2 = get_power_dists(binary_image, cx, cy, 2)
329
+ X2, Y2 = np.meshgrid(x2, y2)
330
+ vx, vy = get_var(mo, binary_image, X2, Y2)
331
+ return np.sqrt(vx), np.sqrt(vy)
332
+
333
+
334
+ def get_skewness(mo: dict, binary_image: NDArray, cx: float, cy: float, sx: float, sy: float) -> Tuple[float, float]:
335
+ """Calculate skewness of the given moment.
336
+
337
+ This function computes the skewness based on the third moments
338
+ and the central moments of a binary image.
339
+
340
+ Parameters
341
+ ----------
342
+ mo : dict
343
+ Dictionary containing moments of binary image.
344
+ binary_image : ndarray
345
+ Binary image as a 2D numpy array.
346
+ cx : float
347
+ Description of parameter `cx`.
348
+ cy : float
349
+ Description of parameter `cy`.
350
+ sx : float
351
+ Description of parameter `sx`.
352
+ sy : float
353
+ Description of parameter `sy`.
354
+
355
+ Returns
356
+ -------
357
+ Tuple[float, float]
358
+ Tuple containing skewness values.
359
+
360
+ Examples
361
+ --------
362
+ >>> result = get_skewness(mo=example_mo, binary_image=binary_img,
363
+ ... cx=0.5, cy=0.5, sx=1.0, sy=1.0)
364
+ >>> print(result)
365
+ (skewness_x, skewness_y) # Example output
366
+ """
367
+ x3, y3 = get_power_dists(binary_image, cx, cy, 3)
368
+ X3, Y3 = np.meshgrid(x3, y3)
369
+ m3x, m3y = get_var(mo, binary_image, X3, Y3)
370
+ return get_skewness_kurtosis(m3x, m3y, sx, sy, 3)
371
+
372
+
373
+ def get_kurtosis(mo: dict, binary_image: NDArray, cx: float, cy: float, sx: float, sy: float) -> Tuple[float, float]:
374
+ """
375
+ Calculate the kurtosis of a binary image.
376
+
377
+ The function calculates the fourth moment (kurtosis) of the given
378
+ binary image around the specified center coordinates with an option
379
+ to specify the size of the square window.
380
+
381
+ Parameters
382
+ ----------
383
+ mo : dict
384
+ Dictionary containing moments of binary image.
385
+ binary_image : np.ndarray
386
+ A 2D numpy ndarray representing a binary image.
387
+ cx : int or float
388
+ The x-coordinate of the center point of the square window.
389
+ cy : int or float
390
+ The y-coordinate of the center point of the square window.
391
+ sx : int or float
392
+ The x-length of the square window (width).
393
+ sy : int or float
394
+ The y-length of the square window (height).
395
+
396
+ Returns
397
+ -------
398
+ float
399
+ The kurtosis value calculated from the moments.
400
+
401
+ Examples
402
+ --------
403
+ >>> mo = np.array([[0, 1], [2, 3]])
404
+ >>> binary_image = np.array([[1, 0], [0, 1]])
405
+ >>> cx = 2
406
+ >>> cy = 3
407
+ >>> sx = 5
408
+ >>> sy = 6
409
+ >>> result = get_kurtosis(mo, binary_image, cx, cy, sx, sy)
410
+ >>> print(result)
411
+ expected output
412
+ """
413
+ x4, y4 = get_power_dists(binary_image, cx, cy, 4)
414
+ X4, Y4 = np.meshgrid(x4, y4)
415
+ m4x, m4y = get_var(mo, binary_image, X4, Y4)
416
+ return get_skewness_kurtosis(m4x, m4y, sx, sy, 4)
417
+
418
+
419
+ @njit()
420
+ def get_inertia_axes(mo: dict) -> Tuple[float, float, float, float, float]:
421
+ """
422
+ Calculate the inertia axes of a moment object.
423
+
424
+ This function computes the barycenters, central moments,
425
+ and the lengths of the major and minor axes, as well as
426
+ their orientation.
427
+
428
+ Parameters
429
+ ----------
430
+ mo : dict
431
+ Dictionary containing moments, which should include keys:
432
+ 'm00', 'm10', 'm01', 'm20', and 'm11'.
433
+
434
+ Returns
435
+ -------
436
+ tuple
437
+ A tuple containing:
438
+ - cx : float
439
+ The x-coordinate of the barycenter.
440
+ - cy : float
441
+ The y-coordinate of the barycenter.
442
+ - major_axis_len : float
443
+ The length of the major axis.
444
+ - minor_axis_len : float
445
+ The length of the minor axis.
446
+ - axes_orientation : float
447
+ The orientation of the axes in radians.
448
+
449
+ Notes
450
+ -----
451
+ This function uses Numba's @njit decorator for performance.
452
+ The moments in the input dictionary should be computed from
453
+ the same image region.
454
+
455
+ Examples
456
+ --------
457
+ >>> mo = {'m00': 1.0, 'm10': 2.0, 'm01': 3.0, 'm20': 4.0, 'm11': 5.0}
458
+ >>> get_inertia_axes(mo)
459
+ (2.0, 3.0, 9.165151389911677, 0.8421875803239, 0.7853981633974483)
460
+
461
+ """
462
+ #L. Rocha, L. Velho and P.C.P. Calvalho (2002)
463
+ #http://sibgrapi.sid.inpe.br/col/sid.inpe.br/banon/2002/10.23.11.34/doc/35.pdf
464
+ # http://raphael.candelier.fr/?blog=Image%20Moments
465
+
466
+ # Calculate barycenters
467
+ cx = mo["m10"] / mo["m00"]
468
+ cy = mo["m01"] / mo["m00"]
469
+ # Calculate central moments
470
+ c20 = (mo["m20"] / mo["m00"]) - np.square(cx)
471
+ c02 = (mo["m02"] / mo["m00"]) - np.square(cy)
472
+ c11 = (mo["m11"] / mo["m00"]) - (cx * cy)
473
+ # Calculate major and minor axi lengths OK
474
+ major_axis_len = np.sqrt(6 * (c20 + c02 + np.sqrt(np.square(2 * c11) + np.square(c20 - c02))))
475
+ minor_axis_len = np.sqrt(6 * (c20 + c02 - np.sqrt(np.square(2 * c11) + np.square(c20 - c02))))
476
+ if (c20 - c02) != 0:
477
+ axes_orientation = (0.5 * np.arctan((2 * c11) / (c20 - c02))) + ((c20 < c02) * (np.pi /2))
478
+ else:
479
+ axes_orientation = 0.
480
+ return cx, cy, major_axis_len, minor_axis_len, axes_orientation
481
+
482
+
483
+ def eudist(v1, v2) -> float:
484
+ """
485
+ Calculate the Euclidean distance between two points in n-dimensional space.
486
+
487
+ Parameters
488
+ ----------
489
+ v1 : iterable of float
490
+ The coordinates of the first point.
491
+ v2 : iterable of float
492
+ The coordinates of the second point.
493
+
494
+ Returns
495
+ -------
496
+ float
497
+ The Euclidean distance between `v1` and `v2`.
498
+
499
+ Raises
500
+ ------
501
+ ValueError
502
+ If `v1` and `v2` do not have the same length.
503
+
504
+ Notes
505
+ -----
506
+ The Euclidean distance is calculated using the standard formula:
507
+ √((x2 − x1)^2 + (y2 − y1)^2 + ...).
508
+
509
+ Examples
510
+ --------
511
+ >>> v1 = [1.0, 2.0]
512
+ >>> v2 = [4.0, 6.0]
513
+ >>> eudist(v1, v2)
514
+ 5.0
515
+
516
+ >>> v1 = [1.0, 2.0, 3.0]
517
+ >>> v2 = [4.0, 6.0, 8.0]
518
+ >>> eudist(v1, v2)
519
+ 7.0710678118654755
520
+ """
521
+ dist = [(a - b)**2 for a, b in zip(v1, v2)]
522
+ dist = np.sqrt(np.sum(dist))
523
+ return dist
524
+
525
+
526
+ def moving_average(vector: NDArray, step: int) -> NDArray[float]:
527
+ """
528
+ Calculate the moving average of a given vector with specified step size.
529
+
530
+ Computes the moving average of input `vector` using specified `step`
531
+ size. NaN values are treated as zeros in the calculation to allow
532
+ for continuous averaging.
533
+
534
+ Parameters
535
+ ----------
536
+ vector : ndarray
537
+ Input vector for which to calculate the moving average.
538
+ step : int
539
+ Size of the window for computing the moving average.
540
+
541
+ Returns
542
+ -------
543
+ numpy.ndarray
544
+ Vector containing the moving averages of the input vector.
545
+
546
+ Raises
547
+ ------
548
+ ValueError
549
+ If `step` is less than 1.
550
+ ValueError
551
+ If the input vector has no valid (non-NaN) elements.
552
+
553
+ Notes
554
+ -----
555
+ - The function considers NaN values as zeros during the averaging process.
556
+ - If `step` is greater than or equal to the length of the vector, a warning will be raised.
557
+
558
+ Examples
559
+ --------
560
+ >>> import numpy as np
561
+ >>> vector = np.array([1.0, 2.0, np.nan, 4.0, 5.0])
562
+ >>> step = 3
563
+ >>> result = moving_average(vector, step)
564
+ >>> print(result)
565
+ [1.5 2.33333333 3.66666667 4. nan]
566
+ """
567
+ substep = np.array((- int(np.floor((step - 1) / 2)), int(np.ceil((step - 1) / 2))))
568
+ sums = np.zeros(vector.shape)
569
+ n_okays = deepcopy(sums)
570
+ true_numbers = np.logical_not(np.isnan(vector))
571
+ vector[np.logical_not(true_numbers)] = 0
572
+ for step_i in np.arange(substep[1] + 1):
573
+ sums[step_i: (sums.size - step_i)] = sums[step_i: (sums.size - step_i)] + vector[(2 * step_i):]
574
+ n_okays[step_i: (sums.size - step_i)] = n_okays[step_i: (sums.size - step_i)] + true_numbers[(2 * step_i):]
575
+ if np.logical_and(step_i > 0, step_i < np.absolute(substep[0])):
576
+ sums[step_i: (sums.size - step_i)] = sums[step_i: (sums.size - step_i)] + vector[:(sums.size - (2 * step_i)):]
577
+ n_okays[step_i: (sums.size - step_i)] = n_okays[step_i: (sums.size - step_i)] + true_numbers[:(
578
+ true_numbers.size - (2 * step_i))]
579
+ vector = sums / n_okays
580
+ return vector
581
+
582
+
583
+ def find_common_coord(array1: NDArray[int], array2: NDArray[int]) -> NDArray[bool]:
584
+ """Find common coordinates between two arrays.
585
+
586
+ This function compares the given 2D `array1` and `array2`
587
+ to determine if there are any common coordinates.
588
+
589
+ Parameters
590
+ ----------
591
+ array1 : ndarray of int
592
+ A 2D numpy ndarray.
593
+ array2 : ndarray of int
594
+ Another 2D numpy ndarray.
595
+
596
+ Returns
597
+ -------
598
+ out : ndarray of bool
599
+ A boolean numpy ndarray where True indicates common
600
+ coordinates.
601
+
602
+ Examples
603
+ --------
604
+ >>> array1 = np.array([[1, 2], [3, 4]])
605
+ >>> array2 = np.array([[5, 6], [1, 2]])
606
+ >>> result = find_common_coord(array1, array2)
607
+ >>> print(result)
608
+ array([ True, False])"""
609
+ return (array1[:, None, :] == array2[None, :, :]).all(-1).any(-1)
610
+
611
+
612
+ def find_duplicates_coord(array1: NDArray[int]) -> NDArray[bool]:
613
+ """
614
+ Find duplicate rows in a 2D array and return their coordinate indices.
615
+
616
+ Given a 2D NumPy array, this function identifies rows that are duplicated (i.e., appear more than once) and returns a boolean array indicating their positions.
617
+
618
+ Parameters
619
+ ----------
620
+ array1 : ndarray of int
621
+ Input 2D array of shape (n_rows, n_columns) from which to find duplicate rows.
622
+
623
+ Returns
624
+ -------
625
+ duplicates : ndarray of bool
626
+ Boolean array of shape (n_rows,), where `True` indicates that the corresponding row in `array1` is a duplicate.
627
+
628
+ Examples
629
+ --------
630
+ >>> import numpy as np
631
+ >>> array1 = np.array([[1, 2], [3, 4], [1, 2], [5, 6]])
632
+ >>> find_duplicates_coord(array1)
633
+ array([ True, False, True, False])"""
634
+ unique_rows, inverse_indices = np.unique(array1, axis=0, return_inverse=True)
635
+ counts = np.bincount(inverse_indices)
636
+ # A row is duplicate if its count > 1
637
+ return counts[inverse_indices] > 1