rapidtide 3.0.10__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 (141) hide show
  1. rapidtide/Colortables.py +492 -27
  2. rapidtide/OrthoImageItem.py +1053 -47
  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 +30 -1
  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/data/reference/JHU-ArterialTerritoriesNoVent-LVL1_space-MNI152NLin2009cAsym_2mm.nii.gz +0 -0
  23. rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1_space-MNI152NLin2009cAsym_2mm_mask.nii.gz +0 -0
  24. rapidtide/decorators.py +91 -0
  25. rapidtide/dlfilter.py +2225 -108
  26. rapidtide/dlfiltertorch.py +4843 -0
  27. rapidtide/externaltools.py +327 -12
  28. rapidtide/fMRIData_class.py +79 -40
  29. rapidtide/filter.py +1899 -810
  30. rapidtide/fit.py +2004 -574
  31. rapidtide/genericmultiproc.py +93 -18
  32. rapidtide/happy_supportfuncs.py +2044 -171
  33. rapidtide/helper_classes.py +584 -43
  34. rapidtide/io.py +2363 -370
  35. rapidtide/linfitfiltpass.py +341 -75
  36. rapidtide/makelaggedtcs.py +211 -20
  37. rapidtide/maskutil.py +423 -53
  38. rapidtide/miscmath.py +827 -121
  39. rapidtide/multiproc.py +210 -22
  40. rapidtide/patchmatch.py +234 -33
  41. rapidtide/peakeval.py +32 -30
  42. rapidtide/ppgproc.py +2203 -0
  43. rapidtide/qualitycheck.py +352 -39
  44. rapidtide/refinedelay.py +422 -57
  45. rapidtide/refineregressor.py +498 -184
  46. rapidtide/resample.py +671 -185
  47. rapidtide/scripts/applyppgproc.py +28 -0
  48. rapidtide/simFuncClasses.py +1052 -77
  49. rapidtide/simfuncfit.py +260 -46
  50. rapidtide/stats.py +540 -238
  51. rapidtide/tests/happycomp +9 -0
  52. rapidtide/tests/test_dlfiltertorch.py +627 -0
  53. rapidtide/tests/test_findmaxlag.py +24 -8
  54. rapidtide/tests/test_fullrunhappy_v1.py +0 -2
  55. rapidtide/tests/test_fullrunhappy_v2.py +0 -2
  56. rapidtide/tests/test_fullrunhappy_v3.py +1 -0
  57. rapidtide/tests/test_fullrunhappy_v4.py +2 -2
  58. rapidtide/tests/test_fullrunrapidtide_v7.py +1 -1
  59. rapidtide/tests/test_simroundtrip.py +8 -8
  60. rapidtide/tests/utils.py +9 -8
  61. rapidtide/tidepoolTemplate.py +142 -38
  62. rapidtide/tidepoolTemplate_alt.py +165 -44
  63. rapidtide/tidepoolTemplate_big.py +189 -52
  64. rapidtide/util.py +1217 -118
  65. rapidtide/voxelData.py +684 -37
  66. rapidtide/wiener.py +19 -12
  67. rapidtide/wiener2.py +113 -7
  68. rapidtide/wiener_doc.py +255 -0
  69. rapidtide/workflows/adjustoffset.py +105 -3
  70. rapidtide/workflows/aligntcs.py +85 -2
  71. rapidtide/workflows/applydlfilter.py +87 -10
  72. rapidtide/workflows/applyppgproc.py +522 -0
  73. rapidtide/workflows/atlasaverage.py +210 -47
  74. rapidtide/workflows/atlastool.py +100 -3
  75. rapidtide/workflows/calcSimFuncMap.py +294 -64
  76. rapidtide/workflows/calctexticc.py +201 -9
  77. rapidtide/workflows/ccorrica.py +97 -4
  78. rapidtide/workflows/cleanregressor.py +168 -29
  79. rapidtide/workflows/delayvar.py +163 -10
  80. rapidtide/workflows/diffrois.py +81 -3
  81. rapidtide/workflows/endtidalproc.py +144 -4
  82. rapidtide/workflows/fdica.py +195 -15
  83. rapidtide/workflows/filtnifti.py +70 -3
  84. rapidtide/workflows/filttc.py +74 -3
  85. rapidtide/workflows/fitSimFuncMap.py +206 -48
  86. rapidtide/workflows/fixtr.py +73 -3
  87. rapidtide/workflows/gmscalc.py +113 -3
  88. rapidtide/workflows/happy.py +813 -201
  89. rapidtide/workflows/happy2std.py +144 -12
  90. rapidtide/workflows/happy_parser.py +149 -8
  91. rapidtide/workflows/histnifti.py +118 -2
  92. rapidtide/workflows/histtc.py +84 -3
  93. rapidtide/workflows/linfitfilt.py +117 -4
  94. rapidtide/workflows/localflow.py +328 -28
  95. rapidtide/workflows/mergequality.py +79 -3
  96. rapidtide/workflows/niftidecomp.py +322 -18
  97. rapidtide/workflows/niftistats.py +174 -4
  98. rapidtide/workflows/pairproc.py +88 -2
  99. rapidtide/workflows/pairwisemergenifti.py +85 -2
  100. rapidtide/workflows/parser_funcs.py +1421 -40
  101. rapidtide/workflows/physiofreq.py +137 -11
  102. rapidtide/workflows/pixelcomp.py +208 -5
  103. rapidtide/workflows/plethquality.py +103 -21
  104. rapidtide/workflows/polyfitim.py +151 -11
  105. rapidtide/workflows/proj2flow.py +75 -2
  106. rapidtide/workflows/rankimage.py +111 -4
  107. rapidtide/workflows/rapidtide.py +272 -15
  108. rapidtide/workflows/rapidtide2std.py +98 -2
  109. rapidtide/workflows/rapidtide_parser.py +109 -9
  110. rapidtide/workflows/refineDelayMap.py +143 -33
  111. rapidtide/workflows/refineRegressor.py +682 -93
  112. rapidtide/workflows/regressfrommaps.py +152 -31
  113. rapidtide/workflows/resamplenifti.py +85 -3
  114. rapidtide/workflows/resampletc.py +91 -3
  115. rapidtide/workflows/retrolagtcs.py +98 -6
  116. rapidtide/workflows/retroregress.py +165 -9
  117. rapidtide/workflows/roisummarize.py +173 -5
  118. rapidtide/workflows/runqualitycheck.py +71 -3
  119. rapidtide/workflows/showarbcorr.py +147 -4
  120. rapidtide/workflows/showhist.py +86 -2
  121. rapidtide/workflows/showstxcorr.py +160 -3
  122. rapidtide/workflows/showtc.py +159 -3
  123. rapidtide/workflows/showxcorrx.py +184 -4
  124. rapidtide/workflows/showxy.py +185 -15
  125. rapidtide/workflows/simdata.py +262 -36
  126. rapidtide/workflows/spatialfit.py +77 -2
  127. rapidtide/workflows/spatialmi.py +251 -27
  128. rapidtide/workflows/spectrogram.py +305 -32
  129. rapidtide/workflows/synthASL.py +154 -3
  130. rapidtide/workflows/tcfrom2col.py +76 -2
  131. rapidtide/workflows/tcfrom3col.py +74 -2
  132. rapidtide/workflows/tidepool.py +2972 -133
  133. rapidtide/workflows/utils.py +19 -14
  134. rapidtide/workflows/utils_doc.py +293 -0
  135. rapidtide/workflows/variabilityizer.py +116 -3
  136. {rapidtide-3.0.10.dist-info → rapidtide-3.1.dist-info}/METADATA +10 -9
  137. {rapidtide-3.0.10.dist-info → rapidtide-3.1.dist-info}/RECORD +141 -122
  138. {rapidtide-3.0.10.dist-info → rapidtide-3.1.dist-info}/entry_points.txt +1 -0
  139. {rapidtide-3.0.10.dist-info → rapidtide-3.1.dist-info}/WHEEL +0 -0
  140. {rapidtide-3.0.10.dist-info → rapidtide-3.1.dist-info}/licenses/LICENSE +0 -0
  141. {rapidtide-3.0.10.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,19 +223,72 @@ 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
291
+ self.mapname = self.map.label
140
292
  self.bgmap = bgmap
141
293
  self.axview = axview
142
294
  self.corview = corview
@@ -180,6 +332,7 @@ class OrthoImageItem(QtWidgets.QWidget):
180
332
 
181
333
  if self.verbose > 1:
182
334
  print("OrthoImageItem initialization:")
335
+ print(" Map name:", self.mapname)
183
336
  print(" Dimensions:", self.xdim, self.ydim, self.zdim)
184
337
  print(" Voxel sizes:", self.xsize, self.ysize, self.zsize)
185
338
  print(" FOVs:", self.xfov, self.yfov, self.zfov)
@@ -266,16 +419,128 @@ class OrthoImageItem(QtWidgets.QWidget):
266
419
  self.enableView()
267
420
  self.updateAllViews()
268
421
 
269
- 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
+ """
270
448
  return int(np.round(self.offsetx + self.impixpervoxx * xpos))
271
449
 
272
- 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
+ """
273
480
  return int(np.round(self.offsety + self.impixpervoxy * ypos))
274
481
 
275
- 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
+ """
276
511
  return int(np.round(self.offsetz + self.impixpervoxz * zpos))
277
512
 
278
- 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
+ """
279
544
  thepos = (xpix - self.offsetx) / self.impixpervoxx
280
545
  if thepos > self.xdim - 1:
281
546
  thepos = self.xdim - 1
@@ -283,7 +548,36 @@ class OrthoImageItem(QtWidgets.QWidget):
283
548
  thepos = 0
284
549
  return int(np.round(thepos))
285
550
 
286
- 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
+ """
287
581
  thepos = (ypix - self.offsety) / self.impixpervoxy
288
582
  if thepos > self.ydim - 1:
289
583
  thepos = self.ydim - 1
@@ -291,7 +585,40 @@ class OrthoImageItem(QtWidgets.QWidget):
291
585
  thepos = 0
292
586
  return int(np.round(thepos))
293
587
 
294
- 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
+ """
295
622
  thepos = (zpix - self.offsetz) / self.impixpervoxz
296
623
  if thepos > self.zdim - 1:
297
624
  thepos = self.zdim - 1
@@ -299,7 +626,35 @@ class OrthoImageItem(QtWidgets.QWidget):
299
626
  thepos = 0
300
627
  return int(np.round(thepos))
301
628
 
302
- 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
+ """
303
658
  if self.tdim == 1:
304
659
  axdata = self.map.maskeddata[:, :, self.zpos]
305
660
  else:
@@ -352,17 +707,123 @@ class OrthoImageItem(QtWidgets.QWidget):
352
707
  self.sagviewvLine.setValue(self.yvox2pix(self.ypos))
353
708
  self.sagviewhLine.setValue(self.zvox2pix(self.zpos))
354
709
 
355
- 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
+ """
356
756
  im = self.applyLUT(data, mask, theLUT, self.map.dispmin, self.map.dispmax)
357
757
  thefgwin.setImage(im.astype("float"))
358
758
  if background is not None:
359
759
  thebgwin.setImage(background.astype("float"), autoLevels=True)
360
760
 
361
- 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
+ """
362
793
  self.map = themap
363
794
  self.tdim = self.map.tdim
364
-
365
- def enableView(self):
795
+ self.mapname = self.map.label
796
+
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
+ """
366
827
  if self.button is not None:
367
828
  self.button.setText(self.map.label)
368
829
  self.button.setDisabled(False)
@@ -371,7 +832,47 @@ class OrthoImageItem(QtWidgets.QWidget):
371
832
  self.corview.show()
372
833
  self.sagview.show()
373
834
 
374
- 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
+ """
375
876
  offset = dispmin
376
877
  if dispmax - dispmin > 0:
377
878
  scale = len(theLUT) / (dispmax - dispmin)
@@ -384,7 +885,48 @@ class OrthoImageItem(QtWidgets.QWidget):
384
885
  mappeddata[:, :, 3][np.where(mask < 1)] = 0
385
886
  return mappeddata
386
887
 
387
- 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
+ """
388
930
  xpix = self.xvox2pix(self.xpos)
389
931
  ypix = self.yvox2pix(self.ypos)
390
932
  zpix = self.zvox2pix(self.zpos)
@@ -395,60 +937,332 @@ class OrthoImageItem(QtWidgets.QWidget):
395
937
  self.sagviewvLine.setValue(ypix)
396
938
  self.sagviewhLine.setValue(zpix)
397
939
 
398
- 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
+ """
399
969
  self.buttonisdown = False
400
970
  self.updateCursors()
401
971
  self.updateAllViews()
402
972
 
403
- 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
+ """
404
1006
  if self.buttonisdown:
405
1007
  self.xpos = self.xpix2vox(event.pos().x() - 1)
406
1008
  self.ypos = self.ypix2vox(self.imgsize - event.pos().y() + 1)
407
1009
  self.updateAllViews()
408
1010
  self.updated.emit()
409
1011
 
410
- 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
+ """
411
1044
  if self.buttonisdown:
412
1045
  self.xpos = self.xpix2vox(event.pos().x() - 1)
413
1046
  self.zpos = self.zpix2vox(self.imgsize - event.pos().y() + 1)
414
1047
  self.updateAllViews()
415
1048
  self.updated.emit()
416
1049
 
417
- 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
+ """
418
1079
  if self.buttonisdown:
419
1080
  self.ypos = self.ypix2vox(event.pos().x() - 1)
420
1081
  self.zpos = self.zpix2vox(self.imgsize - event.pos().y() + 1)
421
1082
  self.updateAllViews()
422
1083
  self.updated.emit()
423
1084
 
424
- 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
+ """
425
1114
  if self.verbose > 1:
426
1115
  print(event)
427
1116
  self.updateAllViews()
428
1117
  self.updated.emit()
429
1118
 
430
- 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
+ """
431
1152
  self.xpos = self.xpix2vox(event.pos().x() - 1)
432
1153
  self.ypos = self.ypix2vox(self.imgsize - event.pos().y() + 1)
433
1154
  self.buttonisdown = True
434
1155
  self.updateAllViews()
435
1156
  self.updated.emit()
436
1157
 
437
- 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
+ """
438
1190
  self.xpos = self.xpix2vox(event.pos().x() - 1)
439
1191
  self.zpos = self.zpix2vox(self.imgsize - event.pos().y() + 1)
440
1192
  self.buttonisdown = True
441
1193
  self.updateAllViews()
442
1194
  self.updated.emit()
443
1195
 
444
- 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
+ """
445
1229
  self.ypos = self.ypix2vox(event.pos().x() - 1)
446
1230
  self.zpos = self.zpix2vox(self.imgsize - event.pos().y() + 1)
447
1231
  self.buttonisdown = True
448
1232
  self.updateAllViews()
449
1233
  self.updated.emit()
450
1234
 
451
- 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
+ """
452
1266
  self.xpos = int(xpos)
453
1267
  self.ypos = int(ypos)
454
1268
  self.zpos = int(zpos)
@@ -456,7 +1270,37 @@ class OrthoImageItem(QtWidgets.QWidget):
456
1270
  if emitsignal:
457
1271
  self.updated.emit()
458
1272
 
459
- 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
+ """
460
1304
  if tpos > self.tdim - 1:
461
1305
  self.tpos = int(self.tdim - 1)
462
1306
  else:
@@ -466,13 +1310,103 @@ class OrthoImageItem(QtWidgets.QWidget):
466
1310
  if emitsignal:
467
1311
  self.updated.emit()
468
1312
 
469
- 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
+ """
470
1345
  if self.tdim > 1:
471
1346
  return self.map.maskeddata[self.xpos, self.ypos, self.zpos, self.tpos]
472
1347
  else:
473
1348
  return self.map.maskeddata[self.xpos, self.ypos, self.zpos]
474
1349
 
475
- 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
+ """
476
1410
  if PILexists:
477
1411
  if self.verbose > 1:
478
1412
  print("using PIL to save ", name)
@@ -521,7 +1455,55 @@ class OrthoImageItem(QtWidgets.QWidget):
521
1455
  fg_img.save(os.path.join(savedir, name + "_fg.png"))
522
1456
  bg_img.save(os.path.join(savedir, name + "_bg.png"))
523
1457
 
524
- 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
+ """
525
1507
  if self.verbose > 1:
526
1508
  print("saving main window")
527
1509
  mydialog = QtWidgets.QFileDialog()
@@ -614,7 +1596,31 @@ class OrthoImageItem(QtWidgets.QWidget):
614
1596
  FILE.writelines(str(self.map.dispmin) + "\t" + str(self.map.dispmax))
615
1597
  # img_colorbar.save(thedir + self.map.name + '_colorbar.png')
616
1598
 
617
- 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
+ """
618
1624
  if self.map is not None:
619
1625
  # print('OrthoImageItem[', self.map.name, ']: map is set')
620
1626
  pass