cellects 0.1.0.dev1__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 (46) 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 +154 -0
  5. cellects/core/__init__.py +0 -0
  6. cellects/core/cellects_paths.py +30 -0
  7. cellects/core/cellects_threads.py +1464 -0
  8. cellects/core/motion_analysis.py +1931 -0
  9. cellects/core/one_image_analysis.py +1065 -0
  10. cellects/core/one_video_per_blob.py +679 -0
  11. cellects/core/program_organizer.py +1347 -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 +789 -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 +1909 -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/extract_exif.py +61 -0
  29. cellects/image_analysis/fractal_analysis.py +184 -0
  30. cellects/image_analysis/fractal_functions.py +108 -0
  31. cellects/image_analysis/image_segmentation.py +272 -0
  32. cellects/image_analysis/morphological_operations.py +867 -0
  33. cellects/image_analysis/network_functions.py +1244 -0
  34. cellects/image_analysis/one_image_analysis_threads.py +289 -0
  35. cellects/image_analysis/progressively_add_distant_shapes.py +246 -0
  36. cellects/image_analysis/shape_descriptors.py +981 -0
  37. cellects/utils/__init__.py +0 -0
  38. cellects/utils/formulas.py +881 -0
  39. cellects/utils/load_display_save.py +1016 -0
  40. cellects/utils/utilitarian.py +516 -0
  41. cellects-0.1.0.dev1.dist-info/LICENSE.odt +0 -0
  42. cellects-0.1.0.dev1.dist-info/METADATA +131 -0
  43. cellects-0.1.0.dev1.dist-info/RECORD +46 -0
  44. cellects-0.1.0.dev1.dist-info/WHEEL +5 -0
  45. cellects-0.1.0.dev1.dist-info/entry_points.txt +2 -0
  46. cellects-0.1.0.dev1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,881 @@
1
+ #!/usr/bin/env python3
2
+ """ This script contains formula functions,
3
+ they mainly are simple mathematical expressions, used many times by Cellects.
4
+ This is part of the lower level of the software. When possible, these functions are optimized using Numba's decorator
5
+ @njit.
6
+ - linear_model
7
+ - get_divisor
8
+ - eudist
9
+ - cart2pol
10
+ - pol2cart
11
+ - get_peak_number
12
+ - cohen_d_95
13
+ - cohen_d
14
+ - SlopeDeviation
15
+ - acf_fft
16
+ - moving_average
17
+ - max_cum_sum_from_rolling_window
18
+ """
19
+ from copy import deepcopy
20
+ from numba import njit
21
+ import numpy as np
22
+
23
+
24
+ @njit()
25
+ def sum_of_abs_differences(array1, array2):
26
+ """
27
+ Calculate the sum of absolute differences between two NumPy arrays.
28
+
29
+ Parameters
30
+ ----------
31
+ array1 : array_like
32
+ First input array.
33
+ array2 : array_like
34
+ Second input array.
35
+
36
+ Returns
37
+ -------
38
+ scalar
39
+ Sum of absolute differences between the two arrays.
40
+ """
41
+ return np.sum(np.absolute(array1 - array2))
42
+
43
+
44
+ @njit()
45
+ def to_uint8(an_array):
46
+ """
47
+ Convert an array to unsigned 8-bit integers.
48
+
49
+ Parameters
50
+ ----------
51
+ an_array : numpy.ndarray
52
+ Input array to be converted. It can be of any numeric dtype.
53
+
54
+ Returns
55
+ -------
56
+ numpy.ndarray
57
+ The input array rounded to the nearest integer and then cast to
58
+ unsigned 8-bit integers.
59
+
60
+ Raises
61
+ ------
62
+ TypeError
63
+ If `an_array` is not a numpy.ndarray.
64
+
65
+ Notes
66
+ -----
67
+ This function uses Numba's `@njit` decorator for performance optimization.
68
+
69
+ Examples
70
+ --------
71
+ >>> import numpy as np
72
+ >>> result = to_uint8(np.array([1.2, 2.5, -3.7]))
73
+ >>> print(result)
74
+ [1 3 0]
75
+ """
76
+ out = np.empty_like(an_array)
77
+ return np.round(an_array, 0, out).astype(np.uint8)
78
+
79
+
80
+ @njit()
81
+ def bracket_to_uint8_image_contrast(image):
82
+ """
83
+ Convert an image with bracket contrast values to uint8 type.
84
+
85
+ This function normalizes an input image by scaling the minimum and maximum
86
+ values of the image to the range [0, 255] and then converts it to uint8
87
+ data type.
88
+
89
+ Parameters
90
+ ----------
91
+ image : np.ndarray
92
+ Input image as a numpy array with floating-point values.
93
+
94
+ Returns
95
+ -------
96
+ np.ndarray
97
+ Output image converted to uint8 type after normalization.
98
+ """
99
+ image -= np.min(image)
100
+ return to_uint8(255 * (image / np.max(image)))
101
+
102
+
103
+ @njit()
104
+ def linear_model(x, a, b):
105
+ """
106
+ Perform a linear transformation on input data using slope and intercept.
107
+
108
+ Parameters
109
+ ----------
110
+ x : array_like
111
+ Input data.
112
+ a : float
113
+ Slope coefficient.
114
+ b : float
115
+ Intercept.
116
+
117
+ Returns
118
+ -------
119
+ float
120
+ Resulting value from linear transformation: `a` * `x` + `b`.
121
+
122
+ Examples
123
+ --------
124
+ >>> result = linear_model(5, 2.0, 1.5)
125
+ >>> print(result) # doctest: +SKIP
126
+ 11.5
127
+
128
+ Notes
129
+ -----
130
+ This function uses Numba's @njit decorator for performance.
131
+ """
132
+ return a * x + b
133
+
134
+
135
+ @njit()
136
+ def get_power_dists(binary_image, cx, cy, n):
137
+ """
138
+ Calculate the power distributions based on the given center coordinates and exponent.
139
+
140
+ This function computes the `n`th powers of x and y distances from
141
+ a given center point `(cx, cy)` for each pixel in the binary image.
142
+
143
+ Parameters
144
+ ----------
145
+ binary_image : np.ndarray
146
+ A 2D array (binary image) where the power distributions are calculated.
147
+ cx : float
148
+ The x-coordinate of the center point.
149
+ cy : float
150
+ The y-coordinate of the center point.
151
+ n : int
152
+ The exponent for power distribution calculation.
153
+
154
+ Returns
155
+ -------
156
+ tuple[np.ndarray, np.ndarray]
157
+ A tuple containing two arrays:
158
+ - The first array contains the `n`th power of x distances from the center.
159
+ - The second array contains the `n`th power of y distances from the center.
160
+
161
+ Notes
162
+ -----
163
+ This function uses Numba's `@njit` decorator for performance optimization.
164
+ Ensure that `binary_image` is a NumPy ndarray to avoid type issues.
165
+
166
+ Examples
167
+ --------
168
+ >>> binary_image = np.zeros((10, 10))
169
+ >>> xn, yn = get_power_dists(binary_image, 5.0, 5.0, 2)
170
+ >>> print(xn.shape), print(yn.shape
171
+ (10,) (10,)
172
+
173
+ """
174
+ xn = (np.arange(binary_image.shape[1]) - cx) ** n
175
+ yn = (np.arange(binary_image.shape[0]) - cy) ** n
176
+ return xn, yn
177
+
178
+
179
+ @njit()
180
+ def get_var(mo, binary_image, Xn, Yn):
181
+ """
182
+ Compute the center of mass in 2D space.
183
+
184
+ This function calculates the weighted average position (centroid) of
185
+ a binary image using given pixel coordinates and moments.
186
+
187
+ Parameters
188
+ ----------
189
+ mo : dict
190
+ Image moments dictionary with keys 'm00', 'm10', and 'm20'.
191
+ binary_image : ndarray
192
+ 2D binary image where non-zero pixels are considered.
193
+ Xn : ndarray
194
+ Array of x-coordinates for each pixel in `binary_image`.
195
+ Yn : ndarray
196
+ Array of y-coordinates for each pixel in `binary_image`.
197
+
198
+ Returns
199
+ -------
200
+ tuple
201
+ A tuple of two floats `(vx, vy)` representing the centroid coordinates.
202
+
203
+ Raises
204
+ ------
205
+ ZeroDivisionError
206
+ If `mo['m00']` is zero, indicating no valid pixels in the image.
207
+ The function raises a `ZeroDivisionError`.
208
+
209
+ Notes
210
+ -----
211
+ Performance considerations: This function uses Numba's `@njit` decorator for performance.
212
+ """
213
+ vx = np.sum(binary_image * Xn) / mo["m00"]
214
+ vy = np.sum(binary_image * Yn) / mo["m00"]
215
+ return vx, vy
216
+
217
+ @njit()
218
+ def get_skewness_kurtosis(mnx, mny, sx, sy, n):
219
+ """
220
+ Calculates skewness and kurtosis of a distribution.
221
+
222
+ This function computes the skewness and kurtosis from given statistical
223
+ moments, standard deviations, and order of moments.
224
+
225
+ Parameters
226
+ ----------
227
+ mnx : float
228
+ The third moment about the mean for x.
229
+ mny : float
230
+ The fourth moment about the mean for y.
231
+ sx : float
232
+ The standard deviation of x.
233
+ sy : float
234
+ The standard deviation of y.
235
+ n : int
236
+ Order of the moment (3 for skewness, 4 for kurtosis).
237
+
238
+ Returns
239
+ -------
240
+ skewness : float
241
+ The computed skewness.
242
+ kurtosis : float
243
+ The computed kurtosis.
244
+
245
+ Notes
246
+ -----
247
+ This function uses Numba's `@njit` decorator for performance.
248
+ Ensure that the values of `mnx`, `mny`, `sx`, and `sy` are non-zero to avoid division by zero.
249
+ If `n = 3`, the function calculates skewness. If `n = 4`, it calculates kurtosis.
250
+
251
+ Examples
252
+ --------
253
+ >>> skewness, kurtosis = get_skewness_kurtosis(1.5, 2.0, 0.5, 0.75, 3)
254
+ >>> print("Skewness:", skewness)
255
+ Skewness: 8.0
256
+ >>> print("Kurtosis:", kurtosis)
257
+ Kurtosis: nan
258
+
259
+ """
260
+ return mnx / sx ** n, mny / sy ** n
261
+
262
+
263
+ def get_standard_deviations(mo, binary_image, cx, cy):
264
+ """
265
+ Return spatial standard deviations for a given moment and binary image.
266
+
267
+ This function computes the square root of variances along `x` (horizontal)
268
+ and `y` (vertical) axes for the given binary image and moment.
269
+
270
+ Parameters
271
+ ----------
272
+ mo : ndarray of float64
273
+ The moment matrix computed from the binary image.
274
+ binary_image : ndarray of bool or int8
275
+ The binary input image where the moments are computed.
276
+ cx : float64
277
+ X-coordinate of center of mass (horizontal position).
278
+ cy : float64
279
+ Y-coordinate of center of mass (vertical position).
280
+
281
+ Returns
282
+ -------
283
+ tuple[ndarray of float64, ndarray of float64]
284
+ Tuple containing the standard deviations along the x and y axes.
285
+
286
+ Raises
287
+ ------
288
+ ValueError
289
+ If `binary_image` is not a binary image or has an invalid datatype.
290
+
291
+ Notes
292
+ -----
293
+ This function uses the `get_power_dists` and `get_var` functions to compute
294
+ the distributed variances, which are then transformed into standard deviations.
295
+
296
+ Examples
297
+ --------
298
+ >>> import numpy as np
299
+ >>> binary_image = np.array([[0, 1], [1, 0]], dtype=np.int8)
300
+ >>> mo = np.array([[2.0], [3.0]])
301
+ >>> cx, cy = 1.5, 1.5
302
+ >>> stdx, stdy = get_standard_deviations(mo, binary_image, cx, cy)
303
+ >>> print(stdx)
304
+ [1.1]
305
+ >>> print(stdy)
306
+ [0.8366600265...]
307
+ """
308
+ x2, y2 = get_power_dists(binary_image, cx, cy, 2)
309
+ X2, Y2 = np.meshgrid(x2, y2)
310
+ vx, vy = get_var(mo, binary_image, X2, Y2)
311
+ return np.sqrt(vx), np.sqrt(vy)
312
+
313
+
314
+ def get_skewness(mo, binary_image, cx, cy, sx, sy):
315
+ """
316
+ Calculate the skewness of a moment image.
317
+
318
+ Parameters
319
+ ----------
320
+ mo : ndarray
321
+ Moment matrix.
322
+ binary_image : ndarray
323
+ Binary image of the object.
324
+ cx, cy : int
325
+ Center coordinates of the moment calculation.
326
+ sx, sy : float or int
327
+ Standard deviation in x and y directions.
328
+
329
+ Returns
330
+ -------
331
+ float
332
+ Skewness value. If the values are not defined, returns `None`.
333
+
334
+ Examples
335
+ --------
336
+ >>> import numpy as np
337
+ >>> mo = np.array([[1, 2, 3], [4, 5, 6]]) # Example moment matrix
338
+ >>> binary_image = np.array([[0, 1], [1, 0]]) # Example binary image
339
+ >>> cx = 1
340
+ >>> cy = 0
341
+ >>> sx = 2.5
342
+ >>> sy = 1.8
343
+
344
+ >>> result = get_skewness(mo, binary_image, cx, cy, sx, sy)
345
+ >>> print(result) # Expected output may vary based on the input data
346
+ None
347
+ """
348
+ x3, y3 = get_power_dists(binary_image, cx, cy, 3)
349
+ X3, Y3 = np.meshgrid(x3, y3)
350
+ m3x, m3y = get_var(mo, binary_image, X3, Y3)
351
+ return get_skewness_kurtosis(m3x, m3y, sx, sy, 3)
352
+
353
+
354
+ def get_kurtosis(mo, binary_image, cx, cy, sx, sy):
355
+ """
356
+ Calculate the kurtosis of a binary image.
357
+
358
+ The function calculates the fourth moment (kurtosis) of the given
359
+ binary image around the specified center coordinates with an option
360
+ to specify the size of the square window.
361
+
362
+ Parameters
363
+ ----------
364
+ mo : np.ndarray
365
+ A 2D numpy ndarray of moments calculated from the image.
366
+ binary_image : np.ndarray
367
+ A 2D numpy ndarray representing a binary image.
368
+ cx : int or float
369
+ The x-coordinate of the center point of the square window.
370
+ cy : int or float
371
+ The y-coordinate of the center point of the square window.
372
+ sx : int or float
373
+ The x-length of the square window (width).
374
+ sy : int or float
375
+ The y-length of the square window (height).
376
+
377
+ Returns
378
+ -------
379
+ float
380
+ The kurtosis value calculated from the moments.
381
+
382
+ Examples
383
+ --------
384
+ >>> mo = np.array([[0, 1], [2, 3]])
385
+ >>> binary_image = np.array([[1, 0], [0, 1]])
386
+ >>> cx = 2
387
+ >>> cy = 3
388
+ >>> sx = 5
389
+ >>> sy = 6
390
+ >>> result = get_kurtosis(mo, binary_image, cx, cy, sx, sy)
391
+ >>> print(result)
392
+ expected output
393
+ """
394
+ x4, y4 = get_power_dists(binary_image, cx, cy, 4)
395
+ X4, Y4 = np.meshgrid(x4, y4)
396
+ m4x, m4y = get_var(mo, binary_image, X4, Y4)
397
+ return get_skewness_kurtosis(m4x, m4y, sx, sy, 4)
398
+
399
+
400
+ @njit()
401
+ def get_inertia_axes(mo):
402
+ """
403
+ Calculate the inertia axes of a moment object.
404
+
405
+ This function computes the barycenters, central moments,
406
+ and the lengths of the major and minor axes, as well as
407
+ their orientation.
408
+
409
+ Parameters
410
+ ----------
411
+ mo : dict
412
+ Dictionary containing moments, which should include keys:
413
+ 'm00', 'm10', 'm01', 'm20', and 'm11'.
414
+
415
+ Returns
416
+ -------
417
+ tuple
418
+ A tuple containing:
419
+ - cx : float
420
+ The x-coordinate of the barycenter.
421
+ - cy : float
422
+ The y-coordinate of the barycenter.
423
+ - major_axis_len : float
424
+ The length of the major axis.
425
+ - minor_axis_len : float
426
+ The length of the minor axis.
427
+ - axes_orientation : float
428
+ The orientation of the axes in radians.
429
+
430
+ Notes
431
+ -----
432
+ This function uses Numba's @njit decorator for performance.
433
+ The moments in the input dictionary should be computed from
434
+ the same image region.
435
+
436
+ Examples
437
+ --------
438
+ >>> mo = {'m00': 1.0, 'm10': 2.0, 'm01': 3.0, 'm20': 4.0, 'm11': 5.0}
439
+ >>> get_inertia_axes(mo)
440
+ (2.0, 3.0, 9.165151389911677, 0.8421875803239, 0.7853981633974483)
441
+
442
+ """
443
+ #L. Rocha, L. Velho and P.C.P. Calvalho (2002)
444
+ #http://sibgrapi.sid.inpe.br/col/sid.inpe.br/banon/2002/10.23.11.34/doc/35.pdf
445
+ # http://raphael.candelier.fr/?blog=Image%20Moments
446
+
447
+ # Calculate barycenters
448
+ cx = mo["m10"] / mo["m00"]
449
+ cy = mo["m01"] / mo["m00"]
450
+ # Calculate central moments
451
+ c20 = (mo["m20"] / mo["m00"]) - np.square(cx)
452
+ c02 = (mo["m02"] / mo["m00"]) - np.square(cy)
453
+ c11 = (mo["m11"] / mo["m00"]) - (cx * cy)
454
+ # Calculate major and minor axi lengths OK
455
+ major_axis_len = np.sqrt(6 * (c20 + c02 + np.sqrt(np.square(2 * c11) + np.square(c20 - c02))))
456
+ minor_axis_len = np.sqrt(6 * (c20 + c02 - np.sqrt(np.square(2 * c11) + np.square(c20 - c02))))
457
+ if (c20 - c02) != 0:
458
+ axes_orientation = (0.5 * np.arctan((2 * c11) / (c20 - c02))) + ((c20 < c02) * (np.pi /2))
459
+ else:
460
+ axes_orientation = 0
461
+ return cx, cy, major_axis_len, minor_axis_len, axes_orientation
462
+
463
+
464
+ def eudist(v1, v2):
465
+ """
466
+ Calculate the Euclidean distance between two points in n-dimensional space.
467
+
468
+ Parameters
469
+ ----------
470
+ v1 : iterable of float
471
+ The coordinates of the first point.
472
+ v2 : iterable of float
473
+ The coordinates of the second point.
474
+
475
+ Returns
476
+ -------
477
+ float
478
+ The Euclidean distance between `v1` and `v2`.
479
+
480
+ Raises
481
+ ------
482
+ ValueError
483
+ If `v1` and `v2` do not have the same length.
484
+
485
+ Notes
486
+ -----
487
+ The Euclidean distance is calculated using the standard formula:
488
+ √((x2 − x1)^2 + (y2 − y1)^2 + ...).
489
+
490
+ Examples
491
+ --------
492
+ >>> v1 = [1.0, 2.0]
493
+ >>> v2 = [4.0, 6.0]
494
+ >>> eudist(v1, v2)
495
+ 5.0
496
+
497
+ >>> v1 = [1.0, 2.0, 3.0]
498
+ >>> v2 = [4.0, 6.0, 8.0]
499
+ >>> eudist(v1, v2)
500
+ 7.0710678118654755
501
+ """
502
+ dist = [(a - b)**2 for a, b in zip(v1, v2)]
503
+ dist = np.sqrt(np.sum(dist))
504
+ return dist
505
+
506
+
507
+ def cart2pol(x, y):
508
+ """
509
+ Convert Cartesian coordinates to polar coordinates.
510
+
511
+ Given kartesian coordinates x and y, return the corresponding
512
+ polar coordinates rho and phi. This is done by using the formula for
513
+ conversion from Cartesian to Polar.
514
+
515
+ Parameters
516
+ ----------
517
+ x : float
518
+ The x-coordinate of the point in Cartesian space.
519
+ y : float
520
+ The y-coordinate of the point in Cartesian space.
521
+
522
+ Returns
523
+ -------
524
+ tuple[float, float]
525
+ A tuple containing (rho, phi) where rho is the radial distance
526
+ and phi is the angle in radians.
527
+
528
+ Examples
529
+ --------
530
+ >>> cart2pol(1, 0)
531
+ (1.0, 0.0)
532
+
533
+ >>> cart2pol(0, 1)
534
+ (1.0, 1.5707963267948966)
535
+
536
+ >>> cart2pol(-1, 0)
537
+ (1.0, 3.141592653589793)
538
+ """
539
+ rho = np.sqrt(x**2 + y**2)
540
+ phi = np.arctan2(y, x)
541
+ return(rho, phi)
542
+
543
+
544
+ def pol2cart(rho, phi):
545
+ """
546
+ Convert from polar to Cartesian coordinates.
547
+
548
+ Given a point in polar coordinates (rho, phi), this function
549
+ calculates the corresponding Cartesian coordinates (x, y).
550
+
551
+ Parameters
552
+ ----------
553
+ rho : float
554
+ The radius in polar coordinates.
555
+ phi : float
556
+ The angle in radians in polar coordinates.
557
+
558
+ Returns
559
+ -------
560
+ tuple[float, float]
561
+ A tuple containing the x and y coordinates in Cartesian
562
+ representation.
563
+
564
+ Notes
565
+ -----
566
+ This function assumes the input values for phi are in radians.
567
+ If they are provided in degrees, convert them using
568
+ `np.radians(phi)` before calling this function.
569
+
570
+ Examples
571
+ --------
572
+ >>> pol2cart(1.0, 0)
573
+ (1.0, 0.0)
574
+
575
+ >>> pol2cart(5.0, np.pi / 4)
576
+ (3.5355339059327378, 3.5355339059327373)
577
+ """
578
+ x = rho * np.cos(phi)
579
+ y = rho * np.sin(phi)
580
+ return x, y
581
+
582
+
583
+ def cohen_d_95(vector_1, vector_2, nbboot=100000):
584
+ """
585
+ Calculate Cohen's d with a 95% confidence interval through bootstrapping.
586
+
587
+ Performs bootstrapping on the provided data vectors to calculate Cohen's d
588
+ effect size along with its 95% confidence interval.
589
+
590
+ Parameters
591
+ ----------
592
+ vector_1 : array_like
593
+ The first data vector.
594
+ vector_2 : array_like
595
+ The second data vector.
596
+ nbboot : int, optional
597
+ Number of bootstrap iterations. Default is ``100000``.
598
+
599
+ Returns
600
+ -------
601
+ ndarray
602
+ An array containing Cohen's d effect size and its 95% confidence interval.
603
+ The first element is the Cohen's d value, followed by the lower and upper
604
+ bounds of the confidence interval.
605
+
606
+ Raises
607
+ ------
608
+ ValueError
609
+ If `vector_1` and `vector_2` are not of the same length.
610
+ TypeError
611
+ If `vector_1` or `vector_2` are not array-like.
612
+
613
+ Notes
614
+ -----
615
+ This function uses bootstrapping to estimate the 95% confidence interval for
616
+ Cohen's d. The calculation of Cohen’s d assumes equal population variances.
617
+
618
+ Examples
619
+ --------
620
+ >>> vector_1 = np.array([2.3, 3.4, 5.6, 7.8])
621
+ >>> vector_2 = np.array([1.1, 4.3, 9.8])
622
+ >>> result = cohen_d_95(vector_1, vector_2)
623
+ >>> print(result)
624
+ [ 0.73864592 -1.46522 1.88307 ]
625
+ """
626
+ boot = np.zeros(nbboot, dtype=int)
627
+ n1 = len(vector_1)
628
+ n2 = len(vector_2)
629
+ for i in np.arange(nbboot):
630
+ v1bis = np.random.choice(vector_1, size=n1, replace=True)
631
+ v2bis = np.random.choice(vector_2, size=n2, replace=True)
632
+ boot[i] = cohen_d(v1bis,v2bis)
633
+ effect_low_top = np.append(cohen_d(vector_1, vector_2), np.quantile(boot, (0.025, 0.975)))
634
+ return effect_low_top
635
+
636
+
637
+ def cohen_d(vector_1, vector_2):
638
+ """
639
+ Calculate Cohen's d effect size between two independent groups.
640
+
641
+ Parameters
642
+ ----------
643
+ vector_1 : array_like
644
+ First group's data.
645
+ vector_2 : array_like
646
+ Second group's data.
647
+
648
+ Returns
649
+ -------
650
+ float
651
+ Cohen's d effect size statistic between the two groups.
652
+
653
+ Notes
654
+ -----
655
+ Cohen's d is a measure of the difference between two means in terms
656
+ of standard deviation units. It can be used to compare the mean difference
657
+ between two groups, normalized by pooled standard deviation.
658
+
659
+ Examples
660
+ --------
661
+ >>> vector_1 = [2.3, 4.5, 6.7]
662
+ >>> vector_2 = [5.3, 7.8, 9.1]
663
+ >>> result = cohen_d(vector_1, vector_2)
664
+ >>> print(result)
665
+ 0.864
666
+ """
667
+ m1 = np.mean(vector_1)
668
+ m2 = np.mean(vector_2)
669
+ s1 = np.std(vector_1)
670
+ s2 = np.std(vector_2)
671
+ n1 = len(vector_1)
672
+ n2 = len(vector_2)
673
+ spooled = np.sqrt(((n2 - 1) * s2 ** 2 + (n1 - 1) * s1 ** 2) / (n1 + n2 - 2))
674
+ return (m2 - m1) / spooled
675
+
676
+
677
+ def moving_average(vector, step):
678
+ """
679
+ Calculate the moving average of a given vector with specified step size.
680
+
681
+ Computes the moving average of input `vector` using specified `step`
682
+ size. NaN values are treated as zeros in the calculation to allow
683
+ for continuous averaging.
684
+
685
+ Parameters
686
+ ----------
687
+ vector : numpy.ndarray
688
+ Input vector for which to calculate the moving average.
689
+ step : int
690
+ Size of the window for computing the moving average.
691
+
692
+ Returns
693
+ -------
694
+ numpy.ndarray
695
+ Vector containing the moving averages of the input vector.
696
+
697
+ Raises
698
+ ------
699
+ ValueError
700
+ If `step` is less than 1.
701
+ ValueError
702
+ If the input vector has no valid (non-NaN) elements.
703
+
704
+ Notes
705
+ -----
706
+ - The function considers NaN values as zeros during the averaging process.
707
+ - If `step` is greater than or equal to the length of the vector, a warning will be raised.
708
+
709
+ Examples
710
+ --------
711
+ >>> import numpy as np
712
+ >>> vector = np.array([1.0, 2.0, np.nan, 4.0, 5.0])
713
+ >>> step = 3
714
+ >>> result = moving_average(vector, step)
715
+ >>> print(result)
716
+ [1.5 2.33333333 3.66666667 4. nan]
717
+ """
718
+ substep = np.array((- int(np.floor((step - 1) / 2)), int(np.ceil((step - 1) / 2))))
719
+ sums = np.zeros(vector.shape)
720
+ n_okays = deepcopy(sums)
721
+ true_numbers = np.logical_not(np.isnan(vector))
722
+ vector[np.logical_not(true_numbers)] = 0
723
+ for step_i in np.arange(substep[1] + 1):
724
+ sums[step_i: (sums.size - step_i)] = sums[step_i: (sums.size - step_i)] + vector[(2 * step_i):]
725
+ n_okays[step_i: (sums.size - step_i)] = n_okays[step_i: (sums.size - step_i)] + true_numbers[(2 * step_i):]
726
+ if np.logical_and(step_i > 0, step_i < np.absolute(substep[0])):
727
+ sums[step_i: (sums.size - step_i)] = sums[step_i: (sums.size - step_i)] + vector[:(sums.size - (2 * step_i)):]
728
+ n_okays[step_i: (sums.size - step_i)] = n_okays[step_i: (sums.size - step_i)] + true_numbers[:(
729
+ true_numbers.size - (2 * step_i))]
730
+ vector = sums / n_okays
731
+ return vector
732
+
733
+
734
+ def max_cum_sum_from_rolling_window(side_length, window_step):
735
+ """
736
+ Calculate the maximum cumulative sum from a rolling window.
737
+
738
+ Parameters
739
+ ----------
740
+ side_length : int
741
+ The length of the side of the square window.
742
+ window_step : int
743
+ The step size for rolling the window.
744
+
745
+ Returns
746
+ -------
747
+ int
748
+ The maximum cumulative sum calculated from the rolling window.
749
+
750
+ Raises
751
+ ------
752
+ ValueError
753
+ If `side_length` or `window_step` are not positive integers.
754
+
755
+ Notes
756
+ -----
757
+ - The function assumes that `side_length` and `window_step` are both positive integers.
758
+ - This function uses NumPy's ceiling function to handle non-integer division results.
759
+
760
+ Examples
761
+ --------
762
+ >>> result = max_cum_sum_from_rolling_window(10, 2)
763
+ >>> print(result)
764
+ 9
765
+
766
+ """
767
+ return np.square(np.ceil(side_length / window_step))
768
+
769
+
770
+ def find_common_coord(array1, array2):
771
+ """
772
+ Find common coordinates between two arrays.
773
+
774
+ Given two 2D arrays, this function finds the indices where all corresponding
775
+ elements are equal.
776
+
777
+ Parameters
778
+ ----------
779
+ array1 : array_like
780
+ First 2D array of shape (M, N).
781
+ array2 : array_like
782
+ Second 2D array of shape (P, N).
783
+
784
+ Returns
785
+ -------
786
+ bool_array : ndarray
787
+ A 2D boolean array of shape (M, P) where each element indicates
788
+ whether the corresponding rows in `array1` and `array2` are equal.
789
+
790
+ Examples
791
+ --------
792
+ >>> array1 = np.array([[1, 2], [3, 4]])
793
+ >>> array2 = np.array([[5, 6], [1, 2]])
794
+ >>> result = find_common_coord(array1, array2)
795
+ >>> print(result)
796
+ array([ True, False])"""
797
+ return (array1[:, None, :] == array2[None, :, :]).all(-1).any(-1)
798
+
799
+
800
+ def find_duplicates_coord(array1):
801
+ """
802
+ Find duplicate rows in a 2D array and return their coordinate indices.
803
+
804
+ 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.
805
+
806
+ Parameters
807
+ ----------
808
+ array1 : ndarray
809
+ Input 2D array of shape (n_rows, n_columns) from which to find duplicate rows.
810
+
811
+ Returns
812
+ -------
813
+ duplicates : ndarray
814
+ Boolean array of shape (n_rows,), where `True` indicates that the corresponding row in `array1` is a duplicate.
815
+
816
+ Examples
817
+ --------
818
+ >>> import numpy as np
819
+ >>> array1 = np.array([[1, 2], [3, 4], [1, 2], [5, 6]])
820
+ >>> find_duplicates_coord(array1)
821
+ array([ True, False, True, False])"""
822
+ unique_rows, inverse_indices = np.unique(array1, axis=0, return_inverse=True)
823
+ counts = np.bincount(inverse_indices)
824
+ # A row is duplicate if its count > 1
825
+ return counts[inverse_indices] > 1
826
+
827
+ def remove_excedent_duplicates_coord(array1):
828
+ """
829
+ Remove duplicate rows in a 2D array based on coordinate order.
830
+
831
+ This function removes all but the first occurrence of duplicate rows in a 2D array.
832
+ The removal is based on the order of appearance (coordinates) in the input array.
833
+
834
+ Parameters
835
+ ----------
836
+ array1 : numpy.ndarray
837
+ A 2D array of shape (n, m) containing rows to be deduplicated.
838
+
839
+ Other Parameters
840
+ ----------------
841
+ None
842
+
843
+ Returns
844
+ -------
845
+ numpy.ndarray
846
+ A 2D array with duplicate rows removed.
847
+
848
+ Raises
849
+ ------
850
+ None
851
+
852
+ Notes
853
+ -----
854
+ This function uses NumPy's `np.unique` for performance and efficiency.
855
+
856
+ Examples
857
+ --------
858
+ >>> array1 = np.array([[1, 2], [3, 4], [1, 2]])
859
+ >>> result = remove_excedent_duplicates_coord(array1)
860
+ >>> print(result)
861
+ [[1 2]
862
+ [3 4]]
863
+
864
+ >>> array1 = np.array([[5, 6], [7, 8], [9, 0], [5, 6]])
865
+ >>> result = remove_excedent_duplicates_coord(array1)
866
+ >>> print(result)
867
+ [[5 6]
868
+ [7 8]
869
+ [9 0]]
870
+ """
871
+ # np.unique(array1, axis=0)
872
+ unique_rows, inverse_indices = np.unique(array1, axis=0, return_inverse=True)
873
+ to_remove = []
874
+ seen_indices = []
875
+ for i in inverse_indices:
876
+ if i in seen_indices:
877
+ to_remove.append(True)
878
+ else:
879
+ to_remove.append(False)
880
+ seen_indices.append(i)
881
+ return np.delete(array1, to_remove, 0)