rapidtide 3.0.11__py3-none-any.whl → 3.1__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 (139) hide show
  1. rapidtide/Colortables.py +492 -27
  2. rapidtide/OrthoImageItem.py +1049 -46
  3. rapidtide/RapidtideDataset.py +1533 -86
  4. rapidtide/_version.py +3 -3
  5. rapidtide/calccoherence.py +196 -29
  6. rapidtide/calcnullsimfunc.py +191 -40
  7. rapidtide/calcsimfunc.py +245 -42
  8. rapidtide/correlate.py +1210 -393
  9. rapidtide/data/examples/src/testLD +56 -0
  10. rapidtide/data/examples/src/testalign +1 -1
  11. rapidtide/data/examples/src/testdelayvar +0 -1
  12. rapidtide/data/examples/src/testfmri +19 -1
  13. rapidtide/data/examples/src/testglmfilt +5 -5
  14. rapidtide/data/examples/src/testhappy +25 -3
  15. rapidtide/data/examples/src/testppgproc +17 -0
  16. rapidtide/data/examples/src/testrolloff +11 -0
  17. rapidtide/data/models/model_cnn_pytorch/best_model.pth +0 -0
  18. rapidtide/data/models/model_cnn_pytorch/loss.png +0 -0
  19. rapidtide/data/models/model_cnn_pytorch/loss.txt +1 -0
  20. rapidtide/data/models/model_cnn_pytorch/model.pth +0 -0
  21. rapidtide/data/models/model_cnn_pytorch/model_meta.json +68 -0
  22. rapidtide/decorators.py +91 -0
  23. rapidtide/dlfilter.py +2225 -108
  24. rapidtide/dlfiltertorch.py +4843 -0
  25. rapidtide/externaltools.py +327 -12
  26. rapidtide/fMRIData_class.py +79 -40
  27. rapidtide/filter.py +1899 -810
  28. rapidtide/fit.py +2004 -574
  29. rapidtide/genericmultiproc.py +93 -18
  30. rapidtide/happy_supportfuncs.py +2044 -171
  31. rapidtide/helper_classes.py +584 -43
  32. rapidtide/io.py +2363 -370
  33. rapidtide/linfitfiltpass.py +341 -75
  34. rapidtide/makelaggedtcs.py +211 -20
  35. rapidtide/maskutil.py +423 -53
  36. rapidtide/miscmath.py +827 -121
  37. rapidtide/multiproc.py +210 -22
  38. rapidtide/patchmatch.py +234 -33
  39. rapidtide/peakeval.py +32 -30
  40. rapidtide/ppgproc.py +2203 -0
  41. rapidtide/qualitycheck.py +352 -39
  42. rapidtide/refinedelay.py +422 -57
  43. rapidtide/refineregressor.py +498 -184
  44. rapidtide/resample.py +671 -185
  45. rapidtide/scripts/applyppgproc.py +28 -0
  46. rapidtide/simFuncClasses.py +1052 -77
  47. rapidtide/simfuncfit.py +260 -46
  48. rapidtide/stats.py +540 -238
  49. rapidtide/tests/happycomp +9 -0
  50. rapidtide/tests/test_dlfiltertorch.py +627 -0
  51. rapidtide/tests/test_findmaxlag.py +24 -8
  52. rapidtide/tests/test_fullrunhappy_v1.py +0 -2
  53. rapidtide/tests/test_fullrunhappy_v2.py +0 -2
  54. rapidtide/tests/test_fullrunhappy_v3.py +1 -0
  55. rapidtide/tests/test_fullrunhappy_v4.py +2 -2
  56. rapidtide/tests/test_fullrunrapidtide_v7.py +1 -1
  57. rapidtide/tests/test_simroundtrip.py +8 -8
  58. rapidtide/tests/utils.py +9 -8
  59. rapidtide/tidepoolTemplate.py +142 -38
  60. rapidtide/tidepoolTemplate_alt.py +165 -44
  61. rapidtide/tidepoolTemplate_big.py +189 -52
  62. rapidtide/util.py +1217 -118
  63. rapidtide/voxelData.py +684 -37
  64. rapidtide/wiener.py +19 -12
  65. rapidtide/wiener2.py +113 -7
  66. rapidtide/wiener_doc.py +255 -0
  67. rapidtide/workflows/adjustoffset.py +105 -3
  68. rapidtide/workflows/aligntcs.py +85 -2
  69. rapidtide/workflows/applydlfilter.py +87 -10
  70. rapidtide/workflows/applyppgproc.py +522 -0
  71. rapidtide/workflows/atlasaverage.py +210 -47
  72. rapidtide/workflows/atlastool.py +100 -3
  73. rapidtide/workflows/calcSimFuncMap.py +294 -64
  74. rapidtide/workflows/calctexticc.py +201 -9
  75. rapidtide/workflows/ccorrica.py +97 -4
  76. rapidtide/workflows/cleanregressor.py +168 -29
  77. rapidtide/workflows/delayvar.py +163 -10
  78. rapidtide/workflows/diffrois.py +81 -3
  79. rapidtide/workflows/endtidalproc.py +144 -4
  80. rapidtide/workflows/fdica.py +195 -15
  81. rapidtide/workflows/filtnifti.py +70 -3
  82. rapidtide/workflows/filttc.py +74 -3
  83. rapidtide/workflows/fitSimFuncMap.py +206 -48
  84. rapidtide/workflows/fixtr.py +73 -3
  85. rapidtide/workflows/gmscalc.py +113 -3
  86. rapidtide/workflows/happy.py +801 -199
  87. rapidtide/workflows/happy2std.py +144 -12
  88. rapidtide/workflows/happy_parser.py +138 -9
  89. rapidtide/workflows/histnifti.py +118 -2
  90. rapidtide/workflows/histtc.py +84 -3
  91. rapidtide/workflows/linfitfilt.py +117 -4
  92. rapidtide/workflows/localflow.py +328 -28
  93. rapidtide/workflows/mergequality.py +79 -3
  94. rapidtide/workflows/niftidecomp.py +322 -18
  95. rapidtide/workflows/niftistats.py +174 -4
  96. rapidtide/workflows/pairproc.py +88 -2
  97. rapidtide/workflows/pairwisemergenifti.py +85 -2
  98. rapidtide/workflows/parser_funcs.py +1421 -40
  99. rapidtide/workflows/physiofreq.py +137 -11
  100. rapidtide/workflows/pixelcomp.py +208 -5
  101. rapidtide/workflows/plethquality.py +103 -21
  102. rapidtide/workflows/polyfitim.py +151 -11
  103. rapidtide/workflows/proj2flow.py +75 -2
  104. rapidtide/workflows/rankimage.py +111 -4
  105. rapidtide/workflows/rapidtide.py +272 -15
  106. rapidtide/workflows/rapidtide2std.py +98 -2
  107. rapidtide/workflows/rapidtide_parser.py +109 -9
  108. rapidtide/workflows/refineDelayMap.py +143 -33
  109. rapidtide/workflows/refineRegressor.py +682 -93
  110. rapidtide/workflows/regressfrommaps.py +152 -31
  111. rapidtide/workflows/resamplenifti.py +85 -3
  112. rapidtide/workflows/resampletc.py +91 -3
  113. rapidtide/workflows/retrolagtcs.py +98 -6
  114. rapidtide/workflows/retroregress.py +165 -9
  115. rapidtide/workflows/roisummarize.py +173 -5
  116. rapidtide/workflows/runqualitycheck.py +71 -3
  117. rapidtide/workflows/showarbcorr.py +147 -4
  118. rapidtide/workflows/showhist.py +86 -2
  119. rapidtide/workflows/showstxcorr.py +160 -3
  120. rapidtide/workflows/showtc.py +159 -3
  121. rapidtide/workflows/showxcorrx.py +184 -4
  122. rapidtide/workflows/showxy.py +185 -15
  123. rapidtide/workflows/simdata.py +262 -36
  124. rapidtide/workflows/spatialfit.py +77 -2
  125. rapidtide/workflows/spatialmi.py +251 -27
  126. rapidtide/workflows/spectrogram.py +305 -32
  127. rapidtide/workflows/synthASL.py +154 -3
  128. rapidtide/workflows/tcfrom2col.py +76 -2
  129. rapidtide/workflows/tcfrom3col.py +74 -2
  130. rapidtide/workflows/tidepool.py +2969 -130
  131. rapidtide/workflows/utils.py +19 -14
  132. rapidtide/workflows/utils_doc.py +293 -0
  133. rapidtide/workflows/variabilityizer.py +116 -3
  134. {rapidtide-3.0.11.dist-info → rapidtide-3.1.dist-info}/METADATA +3 -2
  135. {rapidtide-3.0.11.dist-info → rapidtide-3.1.dist-info}/RECORD +139 -122
  136. {rapidtide-3.0.11.dist-info → rapidtide-3.1.dist-info}/entry_points.txt +1 -0
  137. {rapidtide-3.0.11.dist-info → rapidtide-3.1.dist-info}/WHEEL +0 -0
  138. {rapidtide-3.0.11.dist-info → rapidtide-3.1.dist-info}/licenses/LICENSE +0 -0
  139. {rapidtide-3.0.11.dist-info → rapidtide-3.1.dist-info}/top_level.txt +0 -0
@@ -20,9 +20,11 @@
20
20
  A widget for orthographically displaying 3 and 4 dimensional data
21
21
  """
22
22
  import os
23
+ from typing import Any
23
24
 
24
25
  import numpy as np
25
26
  import pyqtgraph as pg
27
+ from numpy.typing import NDArray
26
28
  from pyqtgraph.Qt import QtCore, QtGui, QtWidgets
27
29
 
28
30
  try:
@@ -46,7 +48,55 @@ else:
46
48
  print(f"using {pyqtbinding=}")
47
49
 
48
50
 
49
- def newColorbar(left, top, impixpervoxx, impixpervoxy, imgsize):
51
+ def newColorbar(
52
+ left: float, top: float, impixpervoxx: float, impixpervoxy: float, imgsize: int
53
+ ) -> tuple[Any, Any, Any, NDArray[np.float64]]:
54
+ """
55
+ Create a colorbar widget with foreground and background image items for plotting.
56
+
57
+ This function generates a colorbar using PyGraphQt (pg) components, including
58
+ a foreground and background `ImageItem`, a `ViewBox` for layout control, and
59
+ a 2D array of color values. The colorbar is scaled and positioned according
60
+ to the provided parameters.
61
+
62
+ Parameters
63
+ ----------
64
+ left : float
65
+ The x-coordinate of the top-left corner of the colorbar in the scene.
66
+ top : float
67
+ The y-coordinate of the top-left corner of the colorbar in the scene.
68
+ impixpervoxx : float
69
+ Scaling factor for the horizontal axis (pixel per unit in x-direction).
70
+ impixpervoxy : float
71
+ Scaling factor for the vertical axis (pixel per unit in y-direction).
72
+ imgsize : int
73
+ The size of the colorbar image in pixels, used to determine dimensions.
74
+
75
+ Returns
76
+ -------
77
+ tuple[Any, Any, Any, NDArray[np.float64]]
78
+ A tuple containing:
79
+ - `thecolorbarfgwin`: The foreground `ImageItem` for the colorbar.
80
+ - `thecolorbarbgwin`: The background `ImageItem` for the colorbar.
81
+ - `theviewbox`: The `ViewBox` that contains the colorbar items.
82
+ - `colorbarvals`: A 2D NumPy array of shape `(cb_xdim, cb_ydim)` with
83
+ color values ranging from 0.0 to 1.0, used for rendering the colorbar.
84
+
85
+ Notes
86
+ -----
87
+ The colorbar uses a linear gradient from black (0.0) to white (1.0) along the
88
+ vertical axis. The horizontal dimension is set to 1/10th of `imgsize`, and
89
+ the vertical dimension equals `imgsize`. The `ViewBox` is configured to disable
90
+ auto-ranging and mouse interaction.
91
+
92
+ Examples
93
+ --------
94
+ >>> fg_item, bg_item, view_box, color_vals = newColorbar(
95
+ ... left=100, top=50, impixpervoxx=1.0, impixpervoxy=1.0, imgsize=256
96
+ ... )
97
+ >>> view_box.addItem(fg_item)
98
+ >>> view_box.addItem(bg_item)
99
+ """
50
100
  cb_xdim = imgsize // 10
51
101
  cb_ydim = imgsize
52
102
  theviewbox = pg.ViewBox(enableMouse=False)
@@ -80,14 +130,63 @@ def newColorbar(left, top, impixpervoxx, impixpervoxy, imgsize):
80
130
 
81
131
 
82
132
  def setupViewWindow(
83
- view,
84
- left,
85
- top,
86
- impixpervoxx,
87
- impixpervoxy,
88
- imgsize,
89
- enableMouse=False,
90
- ):
133
+ view: Any,
134
+ left: float,
135
+ top: float,
136
+ impixpervoxx: float,
137
+ impixpervoxy: float,
138
+ imgsize: int,
139
+ enableMouse: bool = False,
140
+ ) -> tuple[Any, Any, Any, Any, Any]:
141
+ """
142
+ Set up a view window with background and foreground image items, and crosshair lines.
143
+
144
+ This function configures a PyGraphQt view box with specified image transformation
145
+ parameters and adds background and foreground image items along with vertical and
146
+ horizontal crosshair lines for visualization purposes.
147
+
148
+ Parameters
149
+ ----------
150
+ view : Any
151
+ The parent view object to which the view box will be added.
152
+ left : float
153
+ The x-coordinate offset for the image transformation.
154
+ top : float
155
+ The y-coordinate offset for the image transformation.
156
+ impixpervoxx : float
157
+ The scaling factor for the horizontal axis of the image.
158
+ impixpervoxy : float
159
+ The scaling factor for the vertical axis of the image.
160
+ imgsize : int
161
+ The size of the image in pixels, used to set the view range.
162
+ enableMouse : bool, optional
163
+ Whether to enable mouse interaction with the view box. Default is False.
164
+
165
+ Returns
166
+ -------
167
+ tuple[Any, Any, Any, Any, Any]
168
+ A tuple containing:
169
+ - theviewfgwin: The foreground image item.
170
+ - theviewbgwin: The background image item.
171
+ - theviewvLine: The vertical crosshair line.
172
+ - theviewhLine: The horizontal crosshair line.
173
+ - theviewbox: The configured view box object.
174
+
175
+ Notes
176
+ -----
177
+ The view box is locked to a 1:1 aspect ratio and initialized with a gray background.
178
+ The transformation applied to both image items includes translation and scaling
179
+ to align the image properly within the view.
180
+
181
+ Examples
182
+ --------
183
+ >>> import pyqtgraph as pg
184
+ >>> from PyQt5 import QtCore, QtGui
185
+ >>> view = pg.GraphicsLayoutWidget()
186
+ >>> fgwin, bgwin, vline, hline, vbox = setupViewWindow(
187
+ ... view, 0, 0, 1.0, 1.0, 256, enableMouse=True
188
+ ... )
189
+ """
91
190
 
92
191
  theviewbox = view.addViewBox(enableMouse=enableMouse, enableMenu=False, lockAspect=1.0)
93
192
  theviewbox.setAspectLocked()
@@ -124,17 +223,69 @@ class OrthoImageItem(QtWidgets.QWidget):
124
223
 
125
224
  def __init__(
126
225
  self,
127
- map,
128
- axview,
129
- corview,
130
- sagview,
131
- enableMouse=False,
132
- button=None,
133
- imgsize=64,
134
- arrangement=0,
135
- bgmap=None,
136
- verbose=0,
137
- ):
226
+ map: Any,
227
+ axview: Any,
228
+ corview: Any,
229
+ sagview: Any,
230
+ enableMouse: bool = False,
231
+ button: Any | None = None,
232
+ imgsize: int = 64,
233
+ arrangement: int = 0,
234
+ bgmap: Any | None = None,
235
+ verbose: int = 0,
236
+ ) -> None:
237
+ """
238
+ Initialize the OrthoImageItem widget for displaying 3D medical images in orthogonal views.
239
+
240
+ This constructor sets up the necessary attributes and configurations for rendering
241
+ a 3D image volume in three orthogonal views (axial, coronal, and sagittal) using
242
+ PyQt and PySide. It handles coordinate transformations, view setup, and mouse interaction
243
+ if enabled.
244
+
245
+ Parameters
246
+ ----------
247
+ map : Any
248
+ The 3D image data map object containing image dimensions and voxel information.
249
+ axview : Any
250
+ The axial view widget (e.g., a PySide QGraphicsView).
251
+ corview : Any
252
+ The coronal view widget (e.g., a PySide QGraphicsView).
253
+ sagview : Any
254
+ The sagittal view widget (e.g., a PySide QGraphicsView).
255
+ enableMouse : bool, optional
256
+ Whether to enable mouse interaction for navigating the views, by default False.
257
+ button : Any | None, optional
258
+ Mouse button used for interaction, by default None.
259
+ imgsize : int, optional
260
+ Size of the image display in pixels, by default 64.
261
+ arrangement : int, optional
262
+ Layout arrangement for the views, by default 0.
263
+ bgmap : Any | None, optional
264
+ Background image map for overlay, by default None.
265
+ verbose : int, optional
266
+ Verbosity level for printing debug information, by default 0.
267
+
268
+ Returns
269
+ -------
270
+ None
271
+ This method initializes the object and does not return any value.
272
+
273
+ Notes
274
+ -----
275
+ The method performs coordinate transformations to map voxel indices to physical space
276
+ and sets up the view ranges and layouts for each of the three orthogonal views.
277
+ If `enableMouse` is True, mouse event handlers are attached to allow navigation.
278
+
279
+ Examples
280
+ --------
281
+ >>> ortho_item = OrthoImageItem(
282
+ ... map=volume_map,
283
+ ... axview=axial_view,
284
+ ... corview=coronal_view,
285
+ ... sagview=sagittal_view,
286
+ ... enableMouse=True
287
+ ... )
288
+ """
138
289
  QtWidgets.QWidget.__init__(self)
139
290
  self.map = map
140
291
  self.mapname = self.map.label
@@ -268,16 +419,128 @@ class OrthoImageItem(QtWidgets.QWidget):
268
419
  self.enableView()
269
420
  self.updateAllViews()
270
421
 
271
- def xvox2pix(self, xpos):
422
+ def xvox2pix(self, xpos: int) -> int:
423
+ """
424
+ Convert voxel position to pixel position along x-axis.
425
+
426
+ Parameters
427
+ ----------
428
+ xpos : int
429
+ Voxel position along x-axis to be converted to pixel coordinates.
430
+
431
+ Returns
432
+ -------
433
+ int
434
+ Corresponding pixel position along x-axis.
435
+
436
+ Notes
437
+ -----
438
+ This function performs a linear transformation from voxel coordinates to pixel coordinates
439
+ using the formula: pixel = offsetx + impixpervoxx * voxel_position
440
+
441
+ Examples
442
+ --------
443
+ >>> obj.xvox2pix(10)
444
+ 15
445
+ >>> obj.xvox2pix(0)
446
+ 5
447
+ """
272
448
  return int(np.round(self.offsetx + self.impixpervoxx * xpos))
273
449
 
274
- def yvox2pix(self, ypos):
450
+ def yvox2pix(self, ypos: int) -> int:
451
+ """
452
+ Convert voxel y-coordinate to pixel y-coordinate.
453
+
454
+ This function transforms a y-coordinate from voxel space to pixel space using
455
+ the transformation parameters stored in the object.
456
+
457
+ Parameters
458
+ ----------
459
+ ypos : int
460
+ Y-coordinate in voxel space to be converted to pixel space.
461
+
462
+ Returns
463
+ -------
464
+ int
465
+ Y-coordinate in pixel space corresponding to the input voxel y-coordinate.
466
+
467
+ Notes
468
+ -----
469
+ The conversion follows the formula: pixel_y = offsety + impixpervoxy * voxel_y
470
+ where offsety and impixpervoxy are attributes of the object.
471
+
472
+ Examples
473
+ --------
474
+ >>> obj = MyClass()
475
+ >>> obj.offsety = 10
476
+ >>> obj.impixpervoxy = 2.5
477
+ >>> obj.yvox2pix(4)
478
+ 20
479
+ """
275
480
  return int(np.round(self.offsety + self.impixpervoxy * ypos))
276
481
 
277
- def zvox2pix(self, zpos):
482
+ def zvox2pix(self, zpos: int) -> int:
483
+ """
484
+ Convert z-voxel position to pixel position.
485
+
486
+ This function transforms a z-coordinate in voxel space to its corresponding
487
+ position in pixel space using the camera's offset and pixel-per-voxel ratio.
488
+
489
+ Parameters
490
+ ----------
491
+ zpos : int
492
+ Z-coordinate in voxel space to be converted to pixel space.
493
+
494
+ Returns
495
+ -------
496
+ int
497
+ Corresponding z-position in pixel space.
498
+
499
+ Notes
500
+ -----
501
+ The conversion follows the formula: pixel_position = offsetz + impixpervoxz * zpos
502
+ where:
503
+ - offsetz: base offset in pixel space
504
+ - impixpervoxz: pixels per voxel in z-direction
505
+
506
+ Examples
507
+ --------
508
+ >>> zvox2pix(10)
509
+ 150
510
+ """
278
511
  return int(np.round(self.offsetz + self.impixpervoxz * zpos))
279
512
 
280
- def xpix2vox(self, xpix):
513
+ def xpix2vox(self, xpix: float) -> int:
514
+ """
515
+ Convert pixel coordinate to voxel coordinate in x-direction.
516
+
517
+ This function transforms a pixel coordinate in the x-direction to its
518
+ corresponding voxel coordinate, taking into account the image offset and
519
+ pixel-to-voxel conversion factors.
520
+
521
+ Parameters
522
+ ----------
523
+ xpix : float
524
+ The pixel coordinate in x-direction to be converted to voxel coordinate.
525
+
526
+ Returns
527
+ -------
528
+ int
529
+ The corresponding voxel coordinate in x-direction, clamped to the
530
+ valid range [0, self.xdim-1].
531
+
532
+ Notes
533
+ -----
534
+ The conversion is performed using the formula: voxel = (pixel - offset) / pixels_per_voxel.
535
+ Edge cases are handled by clamping values to the valid voxel range.
536
+
537
+ Examples
538
+ --------
539
+ >>> # Assuming self.offsetx = 10, self.impixpervoxx = 2.0, self.xdim = 100
540
+ >>> result = self.xpix2vox(20.0)
541
+ >>> print(result)
542
+ 5
543
+ """
281
544
  thepos = (xpix - self.offsetx) / self.impixpervoxx
282
545
  if thepos > self.xdim - 1:
283
546
  thepos = self.xdim - 1
@@ -285,7 +548,36 @@ class OrthoImageItem(QtWidgets.QWidget):
285
548
  thepos = 0
286
549
  return int(np.round(thepos))
287
550
 
288
- def ypix2vox(self, ypix):
551
+ def ypix2vox(self, ypix: float) -> int:
552
+ """
553
+ Convert y pixel coordinate to voxel coordinate.
554
+
555
+ This function transforms a y pixel coordinate in the image space to
556
+ the corresponding voxel coordinate in the volume space, taking into
557
+ account the image offset and pixel spacing.
558
+
559
+ Parameters
560
+ ----------
561
+ ypix : float
562
+ Y pixel coordinate in image space
563
+
564
+ Returns
565
+ -------
566
+ int
567
+ Corresponding y voxel coordinate in volume space
568
+
569
+ Notes
570
+ -----
571
+ The conversion uses the formula: voxel = (pixel - offset) / pixels_per_voxel
572
+ Boundary conditions are enforced to ensure the result stays within valid
573
+ voxel range [0, ydim-1].
574
+
575
+ Examples
576
+ --------
577
+ >>> # Assuming self.offsety = 10, self.impixpervoxy = 2.0, self.ydim = 100
578
+ >>> ypix2vox(12) # Returns 1
579
+ >>> ypix2vox(200) # Returns 99 (clamped to maximum valid voxel)
580
+ """
289
581
  thepos = (ypix - self.offsety) / self.impixpervoxy
290
582
  if thepos > self.ydim - 1:
291
583
  thepos = self.ydim - 1
@@ -293,7 +585,40 @@ class OrthoImageItem(QtWidgets.QWidget):
293
585
  thepos = 0
294
586
  return int(np.round(thepos))
295
587
 
296
- def zpix2vox(self, zpix):
588
+ def zpix2vox(self, zpix: float) -> int:
589
+ """
590
+ Convert z-pixel coordinate to z-voxel coordinate.
591
+
592
+ This function transforms a z-pixel coordinate to the corresponding z-voxel
593
+ coordinate by applying the inverse transformation using the offset and
594
+ pixel-per-voxel parameters.
595
+
596
+ Parameters
597
+ ----------
598
+ zpix : float
599
+ Z-pixel coordinate to be converted to voxel coordinate.
600
+
601
+ Returns
602
+ -------
603
+ int
604
+ Corresponding z-voxel coordinate. The result is clamped to the
605
+ valid range [0, self.zdim-1].
606
+
607
+ Notes
608
+ -----
609
+ The conversion is performed using the formula:
610
+ voxel = (zpix - offsetz) / impixpervoxz
611
+
612
+ If the resulting voxel coordinate exceeds the valid range [0, self.zdim-1],
613
+ it is clamped to the nearest boundary value.
614
+
615
+ Examples
616
+ --------
617
+ >>> # Assuming self.offsetz = 10, self.impixpervoxz = 2, self.zdim = 100
618
+ >>> zpix2vox(12) # Returns 1
619
+ >>> zpix2vox(10) # Returns 0
620
+ >>> zpix2vox(200) # Returns 99 (clamped to max)
621
+ """
297
622
  thepos = (zpix - self.offsetz) / self.impixpervoxz
298
623
  if thepos > self.zdim - 1:
299
624
  thepos = self.zdim - 1
@@ -301,7 +626,35 @@ class OrthoImageItem(QtWidgets.QWidget):
301
626
  thepos = 0
302
627
  return int(np.round(thepos))
303
628
 
304
- def updateAllViews(self):
629
+ def updateAllViews(self) -> None:
630
+ """
631
+ Update all three views (axial, coronal, and sagittal) of the visualization.
632
+
633
+ This function updates the axial, coronal, and sagittal views based on the current
634
+ position settings (`xpos`, `ypos`, `zpos`) and time index (`tpos`), using the
635
+ underlying data, mask, and background map if available. It also updates the
636
+ position lines in each view to reflect the current voxel coordinates.
637
+
638
+ Notes
639
+ -----
640
+ The function handles both 2D and 3D data depending on the value of `self.tdim`.
641
+ If `self.tdim == 1`, the data is treated as 2D; otherwise, it is treated as 3D
642
+ with a time dimension.
643
+
644
+ Parameters
645
+ ----------
646
+ None
647
+
648
+ Returns
649
+ -------
650
+ None
651
+ This function does not return any value.
652
+
653
+ Examples
654
+ --------
655
+ >>> updateAllViews()
656
+ Updates all three views (axial, coronal, sagittal) with current data and position.
657
+ """
305
658
  if self.tdim == 1:
306
659
  axdata = self.map.maskeddata[:, :, self.zpos]
307
660
  else:
@@ -354,18 +707,123 @@ class OrthoImageItem(QtWidgets.QWidget):
354
707
  self.sagviewvLine.setValue(self.yvox2pix(self.ypos))
355
708
  self.sagviewhLine.setValue(self.zvox2pix(self.zpos))
356
709
 
357
- def updateOneView(self, data, mask, background, theLUT, thefgwin, thebgwin):
710
+ def updateOneView(
711
+ self,
712
+ data: NDArray,
713
+ mask: NDArray,
714
+ background: NDArray | None,
715
+ theLUT: NDArray,
716
+ thefgwin: Any,
717
+ thebgwin: Any,
718
+ ) -> None:
719
+ """
720
+ Update the visualization view with processed data and optional background.
721
+
722
+ This function applies a lookup table to the input data, displays it in the
723
+ foreground window, and optionally displays a background image in the background window.
724
+
725
+ Parameters
726
+ ----------
727
+ data : NDArray
728
+ The main data array to be processed and displayed.
729
+ mask : NDArray
730
+ The mask array used for data processing.
731
+ background : NDArray | None
732
+ The background data array to be displayed, or None if no background.
733
+ theLUT : NDArray
734
+ The lookup table array used for color mapping.
735
+ thefgwin : Any
736
+ The foreground window object where the processed data will be displayed.
737
+ thebgwin : Any
738
+ The background window object where the background data will be displayed.
739
+
740
+ Returns
741
+ -------
742
+ None
743
+ This function does not return any value.
744
+
745
+ Notes
746
+ -----
747
+ The function applies the lookup table using `self.applyLUT` method and sets
748
+ the image in the foreground window with float data type. If background is
749
+ provided, it is displayed in the background window with automatic level
750
+ adjustment enabled.
751
+
752
+ Examples
753
+ --------
754
+ >>> updateOneView(data, mask, background, theLUT, fg_window, bg_window)
755
+ """
358
756
  im = self.applyLUT(data, mask, theLUT, self.map.dispmin, self.map.dispmax)
359
757
  thefgwin.setImage(im.astype("float"))
360
758
  if background is not None:
361
759
  thebgwin.setImage(background.astype("float"), autoLevels=True)
362
760
 
363
- def setMap(self, themap):
761
+ def setMap(self, themap: Any) -> None:
762
+ """
763
+ Set the map attribute and update related properties.
764
+
765
+ This method assigns the provided map to the instance and updates
766
+ the dimensionality and label properties based on the map's attributes.
767
+
768
+ Parameters
769
+ ----------
770
+ themap : Any
771
+ The map object to be assigned to the instance. Expected to have
772
+ attributes 'tdim' (dimensionality) and 'label' (name/label).
773
+
774
+ Returns
775
+ -------
776
+ None
777
+ This method does not return any value.
778
+
779
+ Notes
780
+ -----
781
+ The method assumes that the input map object has 'tdim' and 'label'
782
+ attributes. If these attributes are not present, an AttributeError
783
+ will be raised.
784
+
785
+ Examples
786
+ --------
787
+ >>> instance.setMap(my_map)
788
+ >>> print(instance.tdim)
789
+ 2
790
+ >>> print(instance.mapname)
791
+ 'my_map_label'
792
+ """
364
793
  self.map = themap
365
794
  self.tdim = self.map.tdim
366
795
  self.mapname = self.map.label
367
796
 
368
- def enableView(self):
797
+ def enableView(self) -> None:
798
+ """
799
+ Enable and display all view components.
800
+
801
+ This method enables the main button and displays all three view components
802
+ (axial, coronal, and sagittal) by setting their visibility to True.
803
+
804
+ Parameters
805
+ ----------
806
+ self : object
807
+ The instance of the class containing the view components and button.
808
+
809
+ Returns
810
+ -------
811
+ None
812
+ This method does not return any value.
813
+
814
+ Notes
815
+ -----
816
+ The method first checks if the button exists before attempting to modify it.
817
+ If the button exists, it updates the button text with the map label and enables
818
+ the button. All three view components (axview, corview, and sagview) are then
819
+ made visible.
820
+
821
+ Examples
822
+ --------
823
+ >>> viewer = Viewer()
824
+ >>> viewer.enableView()
825
+ >>> # All view components are now visible and button is enabled
826
+ """
369
827
  if self.button is not None:
370
828
  self.button.setText(self.map.label)
371
829
  self.button.setDisabled(False)
@@ -374,7 +832,47 @@ class OrthoImageItem(QtWidgets.QWidget):
374
832
  self.corview.show()
375
833
  self.sagview.show()
376
834
 
377
- def applyLUT(self, theimage, mask, theLUT, dispmin, dispmax):
835
+ def applyLUT(
836
+ self, theimage: NDArray, mask: NDArray, theLUT: NDArray, dispmin: float, dispmax: float
837
+ ) -> NDArray:
838
+ """
839
+ Apply a lookup table to an image with optional masking and scaling.
840
+
841
+ This function maps image values to colors using a lookup table, applying
842
+ scaling based on the display range and masking invalid regions.
843
+
844
+ Parameters
845
+ ----------
846
+ theimage : numpy.ndarray
847
+ Input image array to be mapped using the lookup table
848
+ mask : numpy.ndarray
849
+ Mask array where values less than 1 will be set to transparent (alpha = 0)
850
+ theLUT : numpy.ndarray
851
+ Lookup table array for color mapping, typically with shape (N, 4) for RGBA values
852
+ dispmin : float
853
+ Minimum display value for scaling the input image
854
+ dispmax : float
855
+ Maximum display value for scaling the input image
856
+
857
+ Returns
858
+ -------
859
+ numpy.ndarray
860
+ Mapped image array with the same shape as input image, with colors applied
861
+ from the lookup table and masked regions set to transparent
862
+
863
+ Notes
864
+ -----
865
+ The function performs the following operations:
866
+ 1. Scales input image values to index range of the lookup table
867
+ 2. Clamps scaled values to valid lookup table indices
868
+ 3. Maps image values to colors using the lookup table
869
+ 4. Applies mask to set transparent pixels where mask < 1
870
+
871
+ Examples
872
+ --------
873
+ >>> # Apply LUT to image with display range [0, 255]
874
+ >>> result = applyLUT(image, mask, lut, 0.0, 255.0)
875
+ """
378
876
  offset = dispmin
379
877
  if dispmax - dispmin > 0:
380
878
  scale = len(theLUT) / (dispmax - dispmin)
@@ -387,7 +885,48 @@ class OrthoImageItem(QtWidgets.QWidget):
387
885
  mappeddata[:, :, 3][np.where(mask < 1)] = 0
388
886
  return mappeddata
389
887
 
390
- def updateCursors(self):
888
+ def updateCursors(self) -> None:
889
+ """
890
+ Update cursor positions in all view axes based on voxel coordinates.
891
+
892
+ This method converts voxel coordinates to pixel coordinates for each view
893
+ and updates the corresponding cursor lines in the axial, coronal, and
894
+ sagittal views.
895
+
896
+ Parameters
897
+ ----------
898
+ self : object
899
+ The instance containing the cursor update functionality
900
+
901
+ Returns
902
+ -------
903
+ None
904
+ This method does not return any value
905
+
906
+ Notes
907
+ -----
908
+ The method uses the following coordinate conversion methods:
909
+ - xvox2pix: converts x voxel coordinate to x pixel coordinate
910
+ - yvox2pix: converts y voxel coordinate to y pixel coordinate
911
+ - zvox2pix: converts z voxel coordinate to z pixel coordinate
912
+
913
+ The cursor lines are updated in the following views:
914
+ - axviewvLine: axial view vertical line
915
+ - axviewhLine: axial view horizontal line
916
+ - corviewvLine: coronal view vertical line
917
+ - corviewhLine: coronal view horizontal line
918
+ - sagviewvLine: sagittal view vertical line
919
+ - sagviewhLine: sagittal view horizontal line
920
+
921
+ Examples
922
+ --------
923
+ >>> viewer = Viewer()
924
+ >>> viewer.xpos = 10
925
+ >>> viewer.ypos = 15
926
+ >>> viewer.zpos = 20
927
+ >>> viewer.updateCursors()
928
+ >>> # Cursor positions updated in all three views
929
+ """
391
930
  xpix = self.xvox2pix(self.xpos)
392
931
  ypix = self.yvox2pix(self.ypos)
393
932
  zpix = self.zvox2pix(self.zpos)
@@ -398,60 +937,332 @@ class OrthoImageItem(QtWidgets.QWidget):
398
937
  self.sagviewvLine.setValue(ypix)
399
938
  self.sagviewhLine.setValue(zpix)
400
939
 
401
- def handlemouseup(self, event):
940
+ def handlemouseup(self, event: Any) -> None:
941
+ """
942
+ Handle mouse button up event.
943
+
944
+ This method is called when a mouse button is released. It updates the internal
945
+ state to reflect that the button is no longer pressed and refreshes all views
946
+ to ensure proper cursor representation and visual feedback.
947
+
948
+ Parameters
949
+ ----------
950
+ event : Any
951
+ The mouse event object containing information about the mouse button release.
952
+ This typically includes coordinates and button information.
953
+
954
+ Returns
955
+ -------
956
+ None
957
+ This method does not return any value.
958
+
959
+ Notes
960
+ -----
961
+ This method updates the cursor state and triggers updates across all connected views
962
+ to ensure consistent visual representation of the mouse state.
963
+
964
+ Examples
965
+ --------
966
+ >>> widget.handlemouseup(event)
967
+ >>> # Mouse button state updated and views refreshed
968
+ """
402
969
  self.buttonisdown = False
403
970
  self.updateCursors()
404
971
  self.updateAllViews()
405
972
 
406
- def handleaxmousemove(self, event):
973
+ def handleaxmousemove(self, event: Any) -> None:
974
+ """
975
+ Handle mouse move events for axis navigation.
976
+
977
+ This method is called when the mouse is moved while a button is pressed,
978
+ updating the position coordinates and triggering view updates.
979
+
980
+ Parameters
981
+ ----------
982
+ event : Any
983
+ Mouse event object containing position information. The event object
984
+ should have a `pos()` method that returns the mouse position.
985
+
986
+ Returns
987
+ -------
988
+ None
989
+ This method does not return any value.
990
+
991
+ Notes
992
+ -----
993
+ The method only processes mouse movement when `self.buttonisdown` is True.
994
+ Position coordinates are converted from pixel to voxel space using
995
+ `xpix2vox` and `ypix2vox` conversion methods. The image size is used to
996
+ properly map y-coordinates from pixel space to voxel space.
997
+
998
+ Examples
999
+ --------
1000
+ >>> # This method is typically called internally by the GUI framework
1001
+ >>> # when mouse events occur
1002
+ >>> self.handleaxmousemove(mouse_event)
1003
+ >>> # Updates self.xpos and self.ypos coordinates
1004
+ >>> # Triggers view updates and emits updated signal
1005
+ """
407
1006
  if self.buttonisdown:
408
1007
  self.xpos = self.xpix2vox(event.pos().x() - 1)
409
1008
  self.ypos = self.ypix2vox(self.imgsize - event.pos().y() + 1)
410
1009
  self.updateAllViews()
411
1010
  self.updated.emit()
412
1011
 
413
- def handlecormousemove(self, event):
1012
+ def handlecormousemove(self, event: Any) -> None:
1013
+ """
1014
+ Handle mouse move events for correlation function view navigation.
1015
+
1016
+ This method updates the x and z position coordinates based on mouse movement
1017
+ when a button is pressed. It converts pixel coordinates to voxel coordinates
1018
+ and triggers view updates and signal emission.
1019
+
1020
+ Parameters
1021
+ ----------
1022
+ event : Any
1023
+ Mouse event object containing position information. Expected to have
1024
+ a `pos()` method that returns a position object with `x()` and `y()` methods.
1025
+
1026
+ Returns
1027
+ -------
1028
+ None
1029
+ This method does not return any value.
1030
+
1031
+ Notes
1032
+ -----
1033
+ The method only processes mouse movement when `self.buttonisdown` is True.
1034
+ Pixel coordinates are converted to voxel coordinates using:
1035
+ - x position: `xpix2vox(event.pos().x() - 1)`
1036
+ - z position: `zpix2vox(self.imgsize - event.pos().y() + 1)`
1037
+
1038
+ Examples
1039
+ --------
1040
+ >>> # This method is typically called internally by the GUI framework
1041
+ >>> # when mouse events occur in the correlative view
1042
+ >>> handlecormousemove(mouse_event)
1043
+ """
414
1044
  if self.buttonisdown:
415
1045
  self.xpos = self.xpix2vox(event.pos().x() - 1)
416
1046
  self.zpos = self.zpix2vox(self.imgsize - event.pos().y() + 1)
417
1047
  self.updateAllViews()
418
1048
  self.updated.emit()
419
1049
 
420
- def handlesagmousemove(self, event):
1050
+ def handlesagmousemove(self, event: Any) -> None:
1051
+ """
1052
+ Handle mouse move events for sagittal view navigation.
1053
+
1054
+ This method updates the y and z position coordinates when the mouse is moved
1055
+ while the button is pressed, and triggers view updates and signals.
1056
+
1057
+ Parameters
1058
+ ----------
1059
+ event : Any
1060
+ Mouse event object containing position information. Expected to have
1061
+ a `pos()` method that returns a position object with `x()` and `y()` methods.
1062
+
1063
+ Returns
1064
+ -------
1065
+ None
1066
+ This method does not return any value.
1067
+
1068
+ Notes
1069
+ -----
1070
+ The method only processes mouse movement when `self.buttonisdown` is True.
1071
+ Position coordinates are converted from pixel to voxel space using
1072
+ `self.ypix2vox()` and `self.zpix2vox()` conversion methods.
1073
+
1074
+ Examples
1075
+ --------
1076
+ >>> self.handlesagmousemove(mouse_event)
1077
+ # Updates position coordinates and triggers view updates
1078
+ """
421
1079
  if self.buttonisdown:
422
1080
  self.ypos = self.ypix2vox(event.pos().x() - 1)
423
1081
  self.zpos = self.zpix2vox(self.imgsize - event.pos().y() + 1)
424
1082
  self.updateAllViews()
425
1083
  self.updated.emit()
426
1084
 
427
- def handleaxkey(self, event):
1085
+ def handleaxkey(self, event: Any) -> None:
1086
+ """
1087
+ Handle axis key events and update views.
1088
+
1089
+ This method is called when an axis key event occurs. It prints the event
1090
+ if verbose mode is enabled (verbose > 1), updates all views in the
1091
+ application, and emits an updated signal.
1092
+
1093
+ Parameters
1094
+ ----------
1095
+ event : Any
1096
+ The axis key event object containing event information and data.
1097
+
1098
+ Returns
1099
+ -------
1100
+ None
1101
+ This method does not return any value.
1102
+
1103
+ Notes
1104
+ -----
1105
+ This method is typically used as an event handler for axis key events.
1106
+ The verbose flag controls whether event information is printed to stdout.
1107
+
1108
+ Examples
1109
+ --------
1110
+ >>> # Typically called internally by event system
1111
+ >>> self.handleaxkey(some_event_object)
1112
+ >>> # Output will be printed if self.verbose > 1
1113
+ """
428
1114
  if self.verbose > 1:
429
1115
  print(event)
430
1116
  self.updateAllViews()
431
1117
  self.updated.emit()
432
1118
 
433
- def handleaxclick(self, event):
1119
+ def handleaxclick(self, event: Any) -> None:
1120
+ """
1121
+ Handle mouse click events on the axis.
1122
+
1123
+ This method processes mouse click events to convert pixel coordinates to voxel coordinates,
1124
+ updates the button state, and triggers view updates.
1125
+
1126
+ Parameters
1127
+ ----------
1128
+ event : Any
1129
+ Mouse event object containing position information. Expected to have a `pos()` method
1130
+ that returns a position object with `x()` and `y()` methods.
1131
+
1132
+ Returns
1133
+ -------
1134
+ None
1135
+ This method does not return any value.
1136
+
1137
+ Notes
1138
+ -----
1139
+ The method converts pixel coordinates to voxel coordinates using the following transformations:
1140
+ - x-coordinate: xpix2vox(event.pos().x() - 1)
1141
+ - y-coordinate: ypix2vox(self.imgsize - event.pos().y() + 1)
1142
+
1143
+ The y-coordinate transformation accounts for the difference between pixel coordinate systems
1144
+ where (0,0) is typically at the top-left corner, and voxel coordinate systems where (0,0)
1145
+ is at the bottom-left corner.
1146
+
1147
+ Examples
1148
+ --------
1149
+ >>> handleaxclick(event)
1150
+ # Processes the mouse click event and updates internal state
1151
+ """
434
1152
  self.xpos = self.xpix2vox(event.pos().x() - 1)
435
1153
  self.ypos = self.ypix2vox(self.imgsize - event.pos().y() + 1)
436
1154
  self.buttonisdown = True
437
1155
  self.updateAllViews()
438
1156
  self.updated.emit()
439
1157
 
440
- def handlecorclick(self, event):
1158
+ def handlecorclick(self, event: Any) -> None:
1159
+ """
1160
+ Handle mouse click event for coordinate conversion and view update.
1161
+
1162
+ This method processes mouse click events to convert pixel coordinates to voxel coordinates,
1163
+ updates the button state, and triggers view updates and signals.
1164
+
1165
+ Parameters
1166
+ ----------
1167
+ event : Any
1168
+ Mouse event object containing position information. Expected to have a `pos()` method
1169
+ that returns a point with `x()` and `y()` coordinate methods.
1170
+
1171
+ Returns
1172
+ -------
1173
+ None
1174
+ This method does not return any value.
1175
+
1176
+ Notes
1177
+ -----
1178
+ The method converts pixel coordinates to voxel coordinates using:
1179
+ - x coordinate: `xpix2vox(event.pos().x() - 1)`
1180
+ - z coordinate: `zpix2vox(self.imgsize - event.pos().y() + 1)`
1181
+
1182
+ The coordinate transformation accounts for pixel indexing differences and image orientation.
1183
+
1184
+ Examples
1185
+ --------
1186
+ >>> # Typical usage in event handling context
1187
+ >>> self.handlecorclick(mouse_event)
1188
+ >>> # Updates self.xpos, self.zpos, self.buttonisdown and triggers updates
1189
+ """
441
1190
  self.xpos = self.xpix2vox(event.pos().x() - 1)
442
1191
  self.zpos = self.zpix2vox(self.imgsize - event.pos().y() + 1)
443
1192
  self.buttonisdown = True
444
1193
  self.updateAllViews()
445
1194
  self.updated.emit()
446
1195
 
447
- def handlesagclick(self, event):
1196
+ def handlesagclick(self, event: Any) -> None:
1197
+ """
1198
+ Handle mouse click events for sagittal view navigation.
1199
+
1200
+ This method processes mouse click events in the sagittal view, converting pixel
1201
+ coordinates to voxel coordinates and updating the view accordingly.
1202
+
1203
+ Parameters
1204
+ ----------
1205
+ event : Any
1206
+ Mouse event object containing position information. Expected to have a
1207
+ `pos()` method that returns a position object with `x()` and `y()` methods.
1208
+
1209
+ Returns
1210
+ -------
1211
+ None
1212
+ This method does not return any value.
1213
+
1214
+ Notes
1215
+ -----
1216
+ The method updates internal position variables (ypos, zpos) and triggers
1217
+ view updates through the updateAllViews() method and updated.emit() signal.
1218
+ The pixel coordinates are adjusted by subtracting 1 from x and adding 1 to y
1219
+ for proper coordinate system alignment.
1220
+
1221
+ Examples
1222
+ --------
1223
+ >>> viewer = ImageViewer()
1224
+ >>> event = MouseEvent(pos=QPoint(100, 150))
1225
+ >>> viewer.handlesagclick(event)
1226
+ >>> print(viewer.ypos, viewer.zpos)
1227
+ (0.5, 0.75)
1228
+ """
448
1229
  self.ypos = self.ypix2vox(event.pos().x() - 1)
449
1230
  self.zpos = self.zpix2vox(self.imgsize - event.pos().y() + 1)
450
1231
  self.buttonisdown = True
451
1232
  self.updateAllViews()
452
1233
  self.updated.emit()
453
1234
 
454
- def setXYZpos(self, xpos, ypos, zpos, emitsignal=True):
1235
+ def setXYZpos(self, xpos: int, ypos: int, zpos: int, emitsignal: bool = True) -> None:
1236
+ """
1237
+ Set the XYZ position coordinates and update views.
1238
+
1239
+ Parameters
1240
+ ----------
1241
+ xpos : int
1242
+ The x-coordinate position value.
1243
+ ypos : int
1244
+ The y-coordinate position value.
1245
+ zpos : int
1246
+ The z-coordinate position value.
1247
+ emitsignal : bool, optional
1248
+ If True, emit the updated signal after position change (default is True).
1249
+
1250
+ Returns
1251
+ -------
1252
+ None
1253
+ This method does not return any value.
1254
+
1255
+ Notes
1256
+ -----
1257
+ This method converts all position parameters to integers and updates
1258
+ all views through the updateAllViews() call. The updated signal is
1259
+ only emitted when emitsignal is True.
1260
+
1261
+ Examples
1262
+ --------
1263
+ >>> obj.setXYZpos(10, 20, 30)
1264
+ >>> obj.setXYZpos(5, 15, 25, emitsignal=False)
1265
+ """
455
1266
  self.xpos = int(xpos)
456
1267
  self.ypos = int(ypos)
457
1268
  self.zpos = int(zpos)
@@ -459,7 +1270,37 @@ class OrthoImageItem(QtWidgets.QWidget):
459
1270
  if emitsignal:
460
1271
  self.updated.emit()
461
1272
 
462
- def setTpos(self, tpos, emitsignal=True):
1273
+ def setTpos(self, tpos: int, emitsignal: bool = True) -> None:
1274
+ """
1275
+ Set the current time position and update all views.
1276
+
1277
+ This method updates the internal time position counter and triggers
1278
+ view updates. If emitsignal is True, it also emits the updated signal.
1279
+
1280
+ Parameters
1281
+ ----------
1282
+ tpos : int
1283
+ The new time position to set. If tpos exceeds the maximum allowed
1284
+ time position (self.tdim - 1), it will be clamped to the maximum value.
1285
+ emitsignal : bool, optional
1286
+ If True, emit the updated signal after updating the time position.
1287
+ Default is True.
1288
+
1289
+ Returns
1290
+ -------
1291
+ None
1292
+ This method does not return any value.
1293
+
1294
+ Notes
1295
+ -----
1296
+ The time position is automatically clamped to the valid range [0, self.tdim - 1].
1297
+ This ensures that the time position never exceeds the dimension limits.
1298
+
1299
+ Examples
1300
+ --------
1301
+ >>> obj.setTpos(5)
1302
+ >>> obj.setTpos(10, emitsignal=False)
1303
+ """
463
1304
  if tpos > self.tdim - 1:
464
1305
  self.tpos = int(self.tdim - 1)
465
1306
  else:
@@ -469,13 +1310,103 @@ class OrthoImageItem(QtWidgets.QWidget):
469
1310
  if emitsignal:
470
1311
  self.updated.emit()
471
1312
 
472
- def getFocusVal(self):
1313
+ def getFocusVal(self) -> float:
1314
+ """
1315
+ Get the focus value at the current position.
1316
+
1317
+ This method retrieves the data value from the masked data array at the
1318
+ current position coordinates. The method handles both 3D and 4D data arrays
1319
+ by checking the time dimension.
1320
+
1321
+ Parameters
1322
+ ----------
1323
+ self : object
1324
+ The instance containing the data and position attributes.
1325
+
1326
+ Returns
1327
+ -------
1328
+ float
1329
+ The focus value at the current position. Returns a scalar value
1330
+ from the masked data array.
1331
+
1332
+ Notes
1333
+ -----
1334
+ The method uses the following attributes from the instance:
1335
+ - self.tdim: Time dimension flag (1 for 3D, >1 for 4D)
1336
+ - self.map.maskeddata: The data array containing the values
1337
+ - self.xpos, self.ypos, self.zpos, self.tpos: Position coordinates
1338
+
1339
+ Examples
1340
+ --------
1341
+ >>> value = obj.getFocusVal()
1342
+ >>> print(value)
1343
+ 0.567
1344
+ """
473
1345
  if self.tdim > 1:
474
1346
  return self.map.maskeddata[self.xpos, self.ypos, self.zpos, self.tpos]
475
1347
  else:
476
1348
  return self.map.maskeddata[self.xpos, self.ypos, self.zpos]
477
1349
 
478
- def saveandcomposite(self, square_img, fg_img, bg_img, name, savedir, scalefach, scalefacv):
1350
+ def saveandcomposite(
1351
+ self,
1352
+ square_img: Any,
1353
+ fg_img: Any,
1354
+ bg_img: Any,
1355
+ name: str,
1356
+ savedir: str,
1357
+ scalefach: float,
1358
+ scalefacv: float,
1359
+ ) -> None:
1360
+ """
1361
+ Save and composite image layers into a final output file.
1362
+
1363
+ This function saves individual image layers (square, foreground, and background)
1364
+ and composites them into a final image. If PIL is available, it performs
1365
+ additional operations such as flipping, scaling, and saving the composite
1366
+ as a JPEG file. Temporary files are removed after processing.
1367
+
1368
+ Parameters
1369
+ ----------
1370
+ square_img : Any
1371
+ The square image to be saved.
1372
+ fg_img : Any
1373
+ The foreground image to be saved and composited.
1374
+ bg_img : Any
1375
+ The background image to be saved and composited.
1376
+ name : str
1377
+ Base name for the output files.
1378
+ savedir : str
1379
+ Directory where output files will be saved.
1380
+ scalefach : float
1381
+ Horizontal scaling factor for the final image.
1382
+ scalefacv : float
1383
+ Vertical scaling factor for the final image.
1384
+
1385
+ Returns
1386
+ -------
1387
+ None
1388
+ This function does not return any value.
1389
+
1390
+ Notes
1391
+ -----
1392
+ - If PIL is available, the function will save the images in PNG format
1393
+ and composite them into a JPEG file.
1394
+ - Temporary files are deleted after processing.
1395
+ - The function uses `Image.NEAREST` for resizing to preserve pixel integrity.
1396
+ - Verbose logging is enabled based on `self.verbose` level.
1397
+
1398
+ Examples
1399
+ --------
1400
+ >>> saveandcomposite(
1401
+ ... square_img=square,
1402
+ ... fg_img=foreground,
1403
+ ... bg_img=background,
1404
+ ... name="test_image",
1405
+ ... savedir="/path/to/save",
1406
+ ... scalefach=1.0,
1407
+ ... scalefacv=1.0
1408
+ ... )
1409
+ """
479
1410
  if PILexists:
480
1411
  if self.verbose > 1:
481
1412
  print("using PIL to save ", name)
@@ -524,7 +1455,55 @@ class OrthoImageItem(QtWidgets.QWidget):
524
1455
  fg_img.save(os.path.join(savedir, name + "_fg.png"))
525
1456
  bg_img.save(os.path.join(savedir, name + "_bg.png"))
526
1457
 
527
- def saveDisp(self):
1458
+ def saveDisp(self) -> None:
1459
+ """
1460
+ Save display windows for axial, coronal, and sagittal views of the image data.
1461
+
1462
+ This function saves three orthogonal views (axial, coronal, and sagittal) of the
1463
+ image data to the specified directory. It also saves a colorbar and writes
1464
+ display limits to a text file. The saved images are composed using the
1465
+ `saveandcomposite` method, and the colorbar is generated using `newColorbar`.
1466
+
1467
+ Parameters
1468
+ ----------
1469
+ self : object
1470
+ The instance of the class containing this method. Expected to have attributes:
1471
+ - `verbose`: int, controls verbosity of output.
1472
+ - `map`: object with attributes:
1473
+ - `namebase`: str, base name for output files.
1474
+ - `name`: str, name of the map.
1475
+ - `theLUT`: lookup table for color mapping.
1476
+ - `dispmin`: float, minimum display value.
1477
+ - `dispmax`: float, maximum display value.
1478
+ - `impixpervoxx`, `impixpervoxy`, `impixpervoxz`: float, voxel sizes in each dimension.
1479
+ - `xdim`, `ydim`, `zdim`: int, dimensions of the image in each axis.
1480
+ - `xsize`, `ysize`, `zsize`: float, physical size per voxel in each axis.
1481
+ - `axviewwin`, `axviewbgwin`, `corviewwin`, `corviewbgwin`, `sagviewwin`, `sagviewbgwin`:
1482
+ ImageItem objects for the respective views.
1483
+ - `applyLUT`: method to apply lookup table to data.
1484
+ - `saveandcomposite`: method to composite and save image views.
1485
+
1486
+ Returns
1487
+ -------
1488
+ None
1489
+ This function does not return any value.
1490
+
1491
+ Notes
1492
+ -----
1493
+ - The function uses Qt bindings (PyQt5, PyQt6, or PySide6) to open a file dialog
1494
+ for selecting the output directory.
1495
+ - The saved images are named with the base name from `self.map.namebase` and
1496
+ appended with `_ax`, `_cor`, and `_sag` for the respective views.
1497
+ - A colorbar is generated but currently commented out in the code.
1498
+ - The display limits are saved to a file named `<namebase><name>_lims.txt`.
1499
+
1500
+ Examples
1501
+ --------
1502
+ Assuming `obj` is an instance of the class containing this method:
1503
+
1504
+ >>> obj.saveDisp()
1505
+ # Saves axial, coronal, and sagittal views to the selected directory.
1506
+ """
528
1507
  if self.verbose > 1:
529
1508
  print("saving main window")
530
1509
  mydialog = QtWidgets.QFileDialog()
@@ -617,7 +1596,31 @@ class OrthoImageItem(QtWidgets.QWidget):
617
1596
  FILE.writelines(str(self.map.dispmin) + "\t" + str(self.map.dispmax))
618
1597
  # img_colorbar.save(thedir + self.map.name + '_colorbar.png')
619
1598
 
620
- def summarize(self):
1599
+ def summarize(self) -> None:
1600
+ """
1601
+ Summarize the orthoimage item information.
1602
+
1603
+ This method performs a summary operation on the orthoimage item, typically
1604
+ used to validate or prepare the item for further processing. When a map is
1605
+ associated with the item, it may perform additional operations or validation.
1606
+
1607
+ Notes
1608
+ -----
1609
+ The method currently contains a placeholder implementation that only checks
1610
+ if a map is set. In a complete implementation, this method would likely
1611
+ generate summary statistics, validate data integrity, or prepare the item
1612
+ for display or export operations.
1613
+
1614
+ Examples
1615
+ --------
1616
+ >>> item = OrthoImageItem()
1617
+ >>> item.summarize()
1618
+ # Performs summary operation on the item
1619
+
1620
+ See Also
1621
+ --------
1622
+ OrthoImageItem : Main class for orthoimage items
1623
+ """
621
1624
  if self.map is not None:
622
1625
  # print('OrthoImageItem[', self.map.name, ']: map is set')
623
1626
  pass