rapidtide 2.9.6__py3-none-any.whl → 3.1.3__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 (405) hide show
  1. cloud/gmscalc-HCPYA +1 -1
  2. cloud/mount-and-run +2 -0
  3. cloud/rapidtide-HCPYA +3 -3
  4. rapidtide/Colortables.py +538 -38
  5. rapidtide/OrthoImageItem.py +1094 -51
  6. rapidtide/RapidtideDataset.py +1709 -114
  7. rapidtide/__init__.py +0 -8
  8. rapidtide/_version.py +4 -4
  9. rapidtide/calccoherence.py +242 -97
  10. rapidtide/calcnullsimfunc.py +240 -140
  11. rapidtide/calcsimfunc.py +314 -129
  12. rapidtide/correlate.py +1211 -389
  13. rapidtide/data/examples/src/testLD +56 -0
  14. rapidtide/data/examples/src/test_findmaxlag.py +2 -2
  15. rapidtide/data/examples/src/test_mlregressallt.py +32 -17
  16. rapidtide/data/examples/src/testalign +1 -1
  17. rapidtide/data/examples/src/testatlasaverage +35 -7
  18. rapidtide/data/examples/src/testboth +21 -0
  19. rapidtide/data/examples/src/testcifti +11 -0
  20. rapidtide/data/examples/src/testdelayvar +13 -0
  21. rapidtide/data/examples/src/testdlfilt +25 -0
  22. rapidtide/data/examples/src/testfft +35 -0
  23. rapidtide/data/examples/src/testfileorfloat +37 -0
  24. rapidtide/data/examples/src/testfmri +92 -42
  25. rapidtide/data/examples/src/testfuncs +3 -3
  26. rapidtide/data/examples/src/testglmfilt +8 -6
  27. rapidtide/data/examples/src/testhappy +84 -51
  28. rapidtide/data/examples/src/testinitdelay +19 -0
  29. rapidtide/data/examples/src/testmodels +33 -0
  30. rapidtide/data/examples/src/testnewrefine +26 -0
  31. rapidtide/data/examples/src/testnoiseamp +2 -2
  32. rapidtide/data/examples/src/testppgproc +17 -0
  33. rapidtide/data/examples/src/testrefineonly +22 -0
  34. rapidtide/data/examples/src/testretro +26 -13
  35. rapidtide/data/examples/src/testretrolagtcs +16 -0
  36. rapidtide/data/examples/src/testrolloff +11 -0
  37. rapidtide/data/examples/src/testsimdata +45 -28
  38. rapidtide/data/models/model_cnn_pytorch/loss.png +0 -0
  39. rapidtide/data/models/model_cnn_pytorch/loss.txt +1 -0
  40. rapidtide/data/models/model_cnn_pytorch/model.pth +0 -0
  41. rapidtide/data/models/model_cnn_pytorch/model_meta.json +68 -0
  42. rapidtide/data/models/model_cnn_pytorch_fulldata/loss.png +0 -0
  43. rapidtide/data/models/model_cnn_pytorch_fulldata/loss.txt +1 -0
  44. rapidtide/data/models/model_cnn_pytorch_fulldata/model.pth +0 -0
  45. rapidtide/data/models/model_cnn_pytorch_fulldata/model_meta.json +80 -0
  46. rapidtide/data/models/model_cnnbp_pytorch_fullldata/loss.png +0 -0
  47. rapidtide/data/models/model_cnnbp_pytorch_fullldata/loss.txt +1 -0
  48. rapidtide/data/models/model_cnnbp_pytorch_fullldata/model.pth +0 -0
  49. rapidtide/data/models/model_cnnbp_pytorch_fullldata/model_meta.json +138 -0
  50. rapidtide/data/models/model_cnnfft_pytorch_fulldata/loss.png +0 -0
  51. rapidtide/data/models/model_cnnfft_pytorch_fulldata/loss.txt +1 -0
  52. rapidtide/data/models/model_cnnfft_pytorch_fulldata/model.pth +0 -0
  53. rapidtide/data/models/model_cnnfft_pytorch_fulldata/model_meta.json +128 -0
  54. rapidtide/data/models/model_ppgattention_pytorch_w128_fulldata/loss.png +0 -0
  55. rapidtide/data/models/model_ppgattention_pytorch_w128_fulldata/loss.txt +1 -0
  56. rapidtide/data/models/model_ppgattention_pytorch_w128_fulldata/model.pth +0 -0
  57. rapidtide/data/models/model_ppgattention_pytorch_w128_fulldata/model_meta.json +49 -0
  58. rapidtide/data/models/model_revised_tf2/model.keras +0 -0
  59. rapidtide/data/models/{model_serdar → model_revised_tf2}/model_meta.json +1 -1
  60. rapidtide/data/models/model_serdar2_tf2/model.keras +0 -0
  61. rapidtide/data/models/{model_serdar2 → model_serdar2_tf2}/model_meta.json +1 -1
  62. rapidtide/data/models/model_serdar_tf2/model.keras +0 -0
  63. rapidtide/data/models/{model_revised → model_serdar_tf2}/model_meta.json +1 -1
  64. rapidtide/data/reference/HCP1200v2_MTT_2mm.nii.gz +0 -0
  65. rapidtide/data/reference/HCP1200v2_binmask_2mm.nii.gz +0 -0
  66. rapidtide/data/reference/HCP1200v2_csf_2mm.nii.gz +0 -0
  67. rapidtide/data/reference/HCP1200v2_gray_2mm.nii.gz +0 -0
  68. rapidtide/data/reference/HCP1200v2_graylaghist.json +7 -0
  69. rapidtide/data/reference/HCP1200v2_graylaghist.tsv.gz +0 -0
  70. rapidtide/data/reference/HCP1200v2_laghist.json +7 -0
  71. rapidtide/data/reference/HCP1200v2_laghist.tsv.gz +0 -0
  72. rapidtide/data/reference/HCP1200v2_mask_2mm.nii.gz +0 -0
  73. rapidtide/data/reference/HCP1200v2_maxcorr_2mm.nii.gz +0 -0
  74. rapidtide/data/reference/HCP1200v2_maxtime_2mm.nii.gz +0 -0
  75. rapidtide/data/reference/HCP1200v2_maxwidth_2mm.nii.gz +0 -0
  76. rapidtide/data/reference/HCP1200v2_negmask_2mm.nii.gz +0 -0
  77. rapidtide/data/reference/HCP1200v2_timepercentile_2mm.nii.gz +0 -0
  78. rapidtide/data/reference/HCP1200v2_white_2mm.nii.gz +0 -0
  79. rapidtide/data/reference/HCP1200v2_whitelaghist.json +7 -0
  80. rapidtide/data/reference/HCP1200v2_whitelaghist.tsv.gz +0 -0
  81. rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1-seg2.xml +131 -0
  82. rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1-seg2_regions.txt +60 -0
  83. rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1-seg2_space-MNI152NLin6Asym_2mm.nii.gz +0 -0
  84. rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1_space-MNI152NLin2009cAsym_2mm.nii.gz +0 -0
  85. rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1_space-MNI152NLin2009cAsym_2mm_mask.nii.gz +0 -0
  86. rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL1_space-MNI152NLin6Asym_2mm_mask.nii.gz +0 -0
  87. rapidtide/data/reference/JHU-ArterialTerritoriesNoVent-LVL2_space-MNI152NLin6Asym_2mm_mask.nii.gz +0 -0
  88. rapidtide/data/reference/MNI152_T1_1mm_Brain_FAST_seg.nii.gz +0 -0
  89. rapidtide/data/reference/MNI152_T1_1mm_Brain_Mask.nii.gz +0 -0
  90. rapidtide/data/reference/MNI152_T1_2mm_Brain_FAST_seg.nii.gz +0 -0
  91. rapidtide/data/reference/MNI152_T1_2mm_Brain_Mask.nii.gz +0 -0
  92. rapidtide/decorators.py +91 -0
  93. rapidtide/dlfilter.py +2553 -414
  94. rapidtide/dlfiltertorch.py +5201 -0
  95. rapidtide/externaltools.py +328 -13
  96. rapidtide/fMRIData_class.py +108 -92
  97. rapidtide/ffttools.py +168 -0
  98. rapidtide/filter.py +2704 -1462
  99. rapidtide/fit.py +2361 -579
  100. rapidtide/genericmultiproc.py +197 -0
  101. rapidtide/happy_supportfuncs.py +3255 -548
  102. rapidtide/helper_classes.py +587 -1116
  103. rapidtide/io.py +2569 -468
  104. rapidtide/linfitfiltpass.py +784 -0
  105. rapidtide/makelaggedtcs.py +267 -97
  106. rapidtide/maskutil.py +555 -25
  107. rapidtide/miscmath.py +835 -144
  108. rapidtide/multiproc.py +217 -44
  109. rapidtide/patchmatch.py +752 -0
  110. rapidtide/peakeval.py +32 -32
  111. rapidtide/ppgproc.py +2205 -0
  112. rapidtide/qualitycheck.py +353 -40
  113. rapidtide/refinedelay.py +854 -0
  114. rapidtide/refineregressor.py +939 -0
  115. rapidtide/resample.py +725 -204
  116. rapidtide/scripts/__init__.py +1 -0
  117. rapidtide/scripts/{adjustoffset → adjustoffset.py} +7 -2
  118. rapidtide/scripts/{aligntcs → aligntcs.py} +7 -2
  119. rapidtide/scripts/{applydlfilter → applydlfilter.py} +7 -2
  120. rapidtide/scripts/applyppgproc.py +28 -0
  121. rapidtide/scripts/{atlasaverage → atlasaverage.py} +7 -2
  122. rapidtide/scripts/{atlastool → atlastool.py} +7 -2
  123. rapidtide/scripts/{calcicc → calcicc.py} +7 -2
  124. rapidtide/scripts/{calctexticc → calctexticc.py} +7 -2
  125. rapidtide/scripts/{calcttest → calcttest.py} +7 -2
  126. rapidtide/scripts/{ccorrica → ccorrica.py} +7 -2
  127. rapidtide/scripts/delayvar.py +28 -0
  128. rapidtide/scripts/{diffrois → diffrois.py} +7 -2
  129. rapidtide/scripts/{endtidalproc → endtidalproc.py} +7 -2
  130. rapidtide/scripts/{fdica → fdica.py} +7 -2
  131. rapidtide/scripts/{filtnifti → filtnifti.py} +7 -2
  132. rapidtide/scripts/{filttc → filttc.py} +7 -2
  133. rapidtide/scripts/{fingerprint → fingerprint.py} +20 -16
  134. rapidtide/scripts/{fixtr → fixtr.py} +7 -2
  135. rapidtide/scripts/{gmscalc → gmscalc.py} +7 -2
  136. rapidtide/scripts/{happy → happy.py} +7 -2
  137. rapidtide/scripts/{happy2std → happy2std.py} +7 -2
  138. rapidtide/scripts/{happywarp → happywarp.py} +8 -4
  139. rapidtide/scripts/{histnifti → histnifti.py} +7 -2
  140. rapidtide/scripts/{histtc → histtc.py} +7 -2
  141. rapidtide/scripts/{glmfilt → linfitfilt.py} +7 -4
  142. rapidtide/scripts/{localflow → localflow.py} +7 -2
  143. rapidtide/scripts/{mergequality → mergequality.py} +7 -2
  144. rapidtide/scripts/{pairproc → pairproc.py} +7 -2
  145. rapidtide/scripts/{pairwisemergenifti → pairwisemergenifti.py} +7 -2
  146. rapidtide/scripts/{physiofreq → physiofreq.py} +7 -2
  147. rapidtide/scripts/{pixelcomp → pixelcomp.py} +7 -2
  148. rapidtide/scripts/{plethquality → plethquality.py} +7 -2
  149. rapidtide/scripts/{polyfitim → polyfitim.py} +7 -2
  150. rapidtide/scripts/{proj2flow → proj2flow.py} +7 -2
  151. rapidtide/scripts/{rankimage → rankimage.py} +7 -2
  152. rapidtide/scripts/{rapidtide → rapidtide.py} +7 -2
  153. rapidtide/scripts/{rapidtide2std → rapidtide2std.py} +7 -2
  154. rapidtide/scripts/{resamplenifti → resamplenifti.py} +7 -2
  155. rapidtide/scripts/{resampletc → resampletc.py} +7 -2
  156. rapidtide/scripts/retrolagtcs.py +28 -0
  157. rapidtide/scripts/retroregress.py +28 -0
  158. rapidtide/scripts/{roisummarize → roisummarize.py} +7 -2
  159. rapidtide/scripts/{runqualitycheck → runqualitycheck.py} +7 -2
  160. rapidtide/scripts/{showarbcorr → showarbcorr.py} +7 -2
  161. rapidtide/scripts/{showhist → showhist.py} +7 -2
  162. rapidtide/scripts/{showstxcorr → showstxcorr.py} +7 -2
  163. rapidtide/scripts/{showtc → showtc.py} +7 -2
  164. rapidtide/scripts/{showxcorr_legacy → showxcorr_legacy.py} +8 -8
  165. rapidtide/scripts/{showxcorrx → showxcorrx.py} +7 -2
  166. rapidtide/scripts/{showxy → showxy.py} +7 -2
  167. rapidtide/scripts/{simdata → simdata.py} +7 -2
  168. rapidtide/scripts/{spatialdecomp → spatialdecomp.py} +7 -2
  169. rapidtide/scripts/{spatialfit → spatialfit.py} +7 -2
  170. rapidtide/scripts/{spatialmi → spatialmi.py} +7 -2
  171. rapidtide/scripts/{spectrogram → spectrogram.py} +7 -2
  172. rapidtide/scripts/stupidramtricks.py +238 -0
  173. rapidtide/scripts/{synthASL → synthASL.py} +7 -2
  174. rapidtide/scripts/{tcfrom2col → tcfrom2col.py} +7 -2
  175. rapidtide/scripts/{tcfrom3col → tcfrom3col.py} +7 -2
  176. rapidtide/scripts/{temporaldecomp → temporaldecomp.py} +7 -2
  177. rapidtide/scripts/{testhrv → testhrv.py} +1 -1
  178. rapidtide/scripts/{threeD → threeD.py} +7 -2
  179. rapidtide/scripts/{tidepool → tidepool.py} +7 -2
  180. rapidtide/scripts/{variabilityizer → variabilityizer.py} +7 -2
  181. rapidtide/simFuncClasses.py +2113 -0
  182. rapidtide/simfuncfit.py +312 -108
  183. rapidtide/stats.py +579 -247
  184. rapidtide/tests/.coveragerc +27 -6
  185. rapidtide-2.9.6.data/scripts/fdica → rapidtide/tests/cleanposttest +4 -6
  186. rapidtide/tests/happycomp +9 -0
  187. rapidtide/tests/resethappytargets +1 -1
  188. rapidtide/tests/resetrapidtidetargets +1 -1
  189. rapidtide/tests/resettargets +1 -1
  190. rapidtide/tests/runlocaltest +3 -3
  191. rapidtide/tests/showkernels +1 -1
  192. rapidtide/tests/test_aliasedcorrelate.py +4 -4
  193. rapidtide/tests/test_aligntcs.py +1 -1
  194. rapidtide/tests/test_calcicc.py +1 -1
  195. rapidtide/tests/test_cleanregressor.py +184 -0
  196. rapidtide/tests/test_congrid.py +70 -81
  197. rapidtide/tests/test_correlate.py +1 -1
  198. rapidtide/tests/test_corrpass.py +4 -4
  199. rapidtide/tests/test_delayestimation.py +54 -59
  200. rapidtide/tests/test_dlfiltertorch.py +437 -0
  201. rapidtide/tests/test_doresample.py +2 -2
  202. rapidtide/tests/test_externaltools.py +69 -0
  203. rapidtide/tests/test_fastresampler.py +9 -5
  204. rapidtide/tests/test_filter.py +96 -57
  205. rapidtide/tests/test_findmaxlag.py +50 -19
  206. rapidtide/tests/test_fullrunhappy_v1.py +15 -10
  207. rapidtide/tests/test_fullrunhappy_v2.py +19 -13
  208. rapidtide/tests/test_fullrunhappy_v3.py +28 -13
  209. rapidtide/tests/test_fullrunhappy_v4.py +30 -11
  210. rapidtide/tests/test_fullrunhappy_v5.py +62 -0
  211. rapidtide/tests/test_fullrunrapidtide_v1.py +61 -7
  212. rapidtide/tests/test_fullrunrapidtide_v2.py +26 -14
  213. rapidtide/tests/test_fullrunrapidtide_v3.py +28 -8
  214. rapidtide/tests/test_fullrunrapidtide_v4.py +16 -8
  215. rapidtide/tests/test_fullrunrapidtide_v5.py +15 -6
  216. rapidtide/tests/test_fullrunrapidtide_v6.py +142 -0
  217. rapidtide/tests/test_fullrunrapidtide_v7.py +114 -0
  218. rapidtide/tests/test_fullrunrapidtide_v8.py +66 -0
  219. rapidtide/tests/test_getparsers.py +158 -0
  220. rapidtide/tests/test_io.py +59 -18
  221. rapidtide/tests/{test_glmpass.py → test_linfitfiltpass.py} +10 -10
  222. rapidtide/tests/test_mi.py +1 -1
  223. rapidtide/tests/test_miscmath.py +1 -1
  224. rapidtide/tests/test_motionregress.py +5 -5
  225. rapidtide/tests/test_nullcorr.py +6 -9
  226. rapidtide/tests/test_padvec.py +216 -0
  227. rapidtide/tests/test_parserfuncs.py +101 -0
  228. rapidtide/tests/test_phaseanalysis.py +1 -1
  229. rapidtide/tests/test_rapidtideparser.py +59 -53
  230. rapidtide/tests/test_refinedelay.py +296 -0
  231. rapidtide/tests/test_runmisc.py +5 -5
  232. rapidtide/tests/test_sharedmem.py +60 -0
  233. rapidtide/tests/test_simroundtrip.py +132 -0
  234. rapidtide/tests/test_simulate.py +1 -1
  235. rapidtide/tests/test_stcorrelate.py +4 -2
  236. rapidtide/tests/test_timeshift.py +2 -2
  237. rapidtide/tests/test_valtoindex.py +1 -1
  238. rapidtide/tests/test_zRapidtideDataset.py +5 -3
  239. rapidtide/tests/utils.py +10 -9
  240. rapidtide/tidepoolTemplate.py +88 -70
  241. rapidtide/tidepoolTemplate.ui +60 -46
  242. rapidtide/tidepoolTemplate_alt.py +88 -53
  243. rapidtide/tidepoolTemplate_alt.ui +62 -52
  244. rapidtide/tidepoolTemplate_alt_qt6.py +921 -0
  245. rapidtide/tidepoolTemplate_big.py +1125 -0
  246. rapidtide/tidepoolTemplate_big.ui +2386 -0
  247. rapidtide/tidepoolTemplate_big_qt6.py +1129 -0
  248. rapidtide/tidepoolTemplate_qt6.py +793 -0
  249. rapidtide/util.py +1389 -148
  250. rapidtide/voxelData.py +1048 -0
  251. rapidtide/wiener.py +138 -25
  252. rapidtide/wiener2.py +114 -8
  253. rapidtide/workflows/adjustoffset.py +107 -5
  254. rapidtide/workflows/aligntcs.py +86 -3
  255. rapidtide/workflows/applydlfilter.py +231 -89
  256. rapidtide/workflows/applyppgproc.py +540 -0
  257. rapidtide/workflows/atlasaverage.py +309 -48
  258. rapidtide/workflows/atlastool.py +130 -9
  259. rapidtide/workflows/calcSimFuncMap.py +490 -0
  260. rapidtide/workflows/calctexticc.py +202 -10
  261. rapidtide/workflows/ccorrica.py +123 -15
  262. rapidtide/workflows/cleanregressor.py +415 -0
  263. rapidtide/workflows/delayvar.py +1268 -0
  264. rapidtide/workflows/diffrois.py +84 -6
  265. rapidtide/workflows/endtidalproc.py +149 -9
  266. rapidtide/workflows/fdica.py +197 -17
  267. rapidtide/workflows/filtnifti.py +71 -4
  268. rapidtide/workflows/filttc.py +76 -5
  269. rapidtide/workflows/fitSimFuncMap.py +578 -0
  270. rapidtide/workflows/fixtr.py +74 -4
  271. rapidtide/workflows/gmscalc.py +116 -6
  272. rapidtide/workflows/happy.py +1242 -480
  273. rapidtide/workflows/happy2std.py +145 -13
  274. rapidtide/workflows/happy_parser.py +277 -59
  275. rapidtide/workflows/histnifti.py +120 -4
  276. rapidtide/workflows/histtc.py +85 -4
  277. rapidtide/workflows/{glmfilt.py → linfitfilt.py} +128 -14
  278. rapidtide/workflows/localflow.py +329 -29
  279. rapidtide/workflows/mergequality.py +80 -4
  280. rapidtide/workflows/niftidecomp.py +323 -19
  281. rapidtide/workflows/niftistats.py +178 -8
  282. rapidtide/workflows/pairproc.py +99 -5
  283. rapidtide/workflows/pairwisemergenifti.py +86 -3
  284. rapidtide/workflows/parser_funcs.py +1488 -56
  285. rapidtide/workflows/physiofreq.py +139 -12
  286. rapidtide/workflows/pixelcomp.py +211 -9
  287. rapidtide/workflows/plethquality.py +105 -23
  288. rapidtide/workflows/polyfitim.py +159 -19
  289. rapidtide/workflows/proj2flow.py +76 -3
  290. rapidtide/workflows/rankimage.py +115 -8
  291. rapidtide/workflows/rapidtide.py +1785 -1858
  292. rapidtide/workflows/rapidtide2std.py +101 -3
  293. rapidtide/workflows/rapidtide_parser.py +590 -389
  294. rapidtide/workflows/refineDelayMap.py +249 -0
  295. rapidtide/workflows/refineRegressor.py +1215 -0
  296. rapidtide/workflows/regressfrommaps.py +308 -0
  297. rapidtide/workflows/resamplenifti.py +86 -4
  298. rapidtide/workflows/resampletc.py +92 -4
  299. rapidtide/workflows/retrolagtcs.py +442 -0
  300. rapidtide/workflows/retroregress.py +1501 -0
  301. rapidtide/workflows/roisummarize.py +176 -7
  302. rapidtide/workflows/runqualitycheck.py +72 -7
  303. rapidtide/workflows/showarbcorr.py +172 -16
  304. rapidtide/workflows/showhist.py +87 -3
  305. rapidtide/workflows/showstxcorr.py +161 -4
  306. rapidtide/workflows/showtc.py +172 -10
  307. rapidtide/workflows/showxcorrx.py +250 -62
  308. rapidtide/workflows/showxy.py +186 -16
  309. rapidtide/workflows/simdata.py +418 -112
  310. rapidtide/workflows/spatialfit.py +83 -8
  311. rapidtide/workflows/spatialmi.py +252 -29
  312. rapidtide/workflows/spectrogram.py +306 -33
  313. rapidtide/workflows/synthASL.py +157 -6
  314. rapidtide/workflows/tcfrom2col.py +77 -3
  315. rapidtide/workflows/tcfrom3col.py +75 -3
  316. rapidtide/workflows/tidepool.py +3829 -666
  317. rapidtide/workflows/utils.py +45 -19
  318. rapidtide/workflows/utils_doc.py +293 -0
  319. rapidtide/workflows/variabilityizer.py +118 -5
  320. {rapidtide-2.9.6.dist-info → rapidtide-3.1.3.dist-info}/METADATA +30 -223
  321. rapidtide-3.1.3.dist-info/RECORD +393 -0
  322. {rapidtide-2.9.6.dist-info → rapidtide-3.1.3.dist-info}/WHEEL +1 -1
  323. rapidtide-3.1.3.dist-info/entry_points.txt +65 -0
  324. rapidtide-3.1.3.dist-info/top_level.txt +2 -0
  325. rapidtide/calcandfitcorrpairs.py +0 -262
  326. rapidtide/data/examples/src/testoutputsize +0 -45
  327. rapidtide/data/models/model_revised/model.h5 +0 -0
  328. rapidtide/data/models/model_serdar/model.h5 +0 -0
  329. rapidtide/data/models/model_serdar2/model.h5 +0 -0
  330. rapidtide/data/reference/ASPECTS_nlin_asym_09c_2mm.nii.gz +0 -0
  331. rapidtide/data/reference/ASPECTS_nlin_asym_09c_2mm_mask.nii.gz +0 -0
  332. rapidtide/data/reference/ATTbasedFlowTerritories_split_nlin_asym_09c_2mm.nii.gz +0 -0
  333. rapidtide/data/reference/ATTbasedFlowTerritories_split_nlin_asym_09c_2mm_mask.nii.gz +0 -0
  334. rapidtide/data/reference/HCP1200_binmask_2mm_2009c_asym.nii.gz +0 -0
  335. rapidtide/data/reference/HCP1200_lag_2mm_2009c_asym.nii.gz +0 -0
  336. rapidtide/data/reference/HCP1200_mask_2mm_2009c_asym.nii.gz +0 -0
  337. rapidtide/data/reference/HCP1200_negmask_2mm_2009c_asym.nii.gz +0 -0
  338. rapidtide/data/reference/HCP1200_sigma_2mm_2009c_asym.nii.gz +0 -0
  339. rapidtide/data/reference/HCP1200_strength_2mm_2009c_asym.nii.gz +0 -0
  340. rapidtide/glmpass.py +0 -434
  341. rapidtide/refine_factored.py +0 -641
  342. rapidtide/scripts/retroglm +0 -23
  343. rapidtide/workflows/glmfrommaps.py +0 -202
  344. rapidtide/workflows/retroglm.py +0 -643
  345. rapidtide-2.9.6.data/scripts/adjustoffset +0 -23
  346. rapidtide-2.9.6.data/scripts/aligntcs +0 -23
  347. rapidtide-2.9.6.data/scripts/applydlfilter +0 -23
  348. rapidtide-2.9.6.data/scripts/atlasaverage +0 -23
  349. rapidtide-2.9.6.data/scripts/atlastool +0 -23
  350. rapidtide-2.9.6.data/scripts/calcicc +0 -22
  351. rapidtide-2.9.6.data/scripts/calctexticc +0 -23
  352. rapidtide-2.9.6.data/scripts/calcttest +0 -22
  353. rapidtide-2.9.6.data/scripts/ccorrica +0 -23
  354. rapidtide-2.9.6.data/scripts/diffrois +0 -23
  355. rapidtide-2.9.6.data/scripts/endtidalproc +0 -23
  356. rapidtide-2.9.6.data/scripts/filtnifti +0 -23
  357. rapidtide-2.9.6.data/scripts/filttc +0 -23
  358. rapidtide-2.9.6.data/scripts/fingerprint +0 -593
  359. rapidtide-2.9.6.data/scripts/fixtr +0 -23
  360. rapidtide-2.9.6.data/scripts/glmfilt +0 -24
  361. rapidtide-2.9.6.data/scripts/gmscalc +0 -22
  362. rapidtide-2.9.6.data/scripts/happy +0 -25
  363. rapidtide-2.9.6.data/scripts/happy2std +0 -23
  364. rapidtide-2.9.6.data/scripts/happywarp +0 -350
  365. rapidtide-2.9.6.data/scripts/histnifti +0 -23
  366. rapidtide-2.9.6.data/scripts/histtc +0 -23
  367. rapidtide-2.9.6.data/scripts/localflow +0 -23
  368. rapidtide-2.9.6.data/scripts/mergequality +0 -23
  369. rapidtide-2.9.6.data/scripts/pairproc +0 -23
  370. rapidtide-2.9.6.data/scripts/pairwisemergenifti +0 -23
  371. rapidtide-2.9.6.data/scripts/physiofreq +0 -23
  372. rapidtide-2.9.6.data/scripts/pixelcomp +0 -23
  373. rapidtide-2.9.6.data/scripts/plethquality +0 -23
  374. rapidtide-2.9.6.data/scripts/polyfitim +0 -23
  375. rapidtide-2.9.6.data/scripts/proj2flow +0 -23
  376. rapidtide-2.9.6.data/scripts/rankimage +0 -23
  377. rapidtide-2.9.6.data/scripts/rapidtide +0 -23
  378. rapidtide-2.9.6.data/scripts/rapidtide2std +0 -23
  379. rapidtide-2.9.6.data/scripts/resamplenifti +0 -23
  380. rapidtide-2.9.6.data/scripts/resampletc +0 -23
  381. rapidtide-2.9.6.data/scripts/retroglm +0 -23
  382. rapidtide-2.9.6.data/scripts/roisummarize +0 -23
  383. rapidtide-2.9.6.data/scripts/runqualitycheck +0 -23
  384. rapidtide-2.9.6.data/scripts/showarbcorr +0 -23
  385. rapidtide-2.9.6.data/scripts/showhist +0 -23
  386. rapidtide-2.9.6.data/scripts/showstxcorr +0 -23
  387. rapidtide-2.9.6.data/scripts/showtc +0 -23
  388. rapidtide-2.9.6.data/scripts/showxcorr_legacy +0 -536
  389. rapidtide-2.9.6.data/scripts/showxcorrx +0 -23
  390. rapidtide-2.9.6.data/scripts/showxy +0 -23
  391. rapidtide-2.9.6.data/scripts/simdata +0 -23
  392. rapidtide-2.9.6.data/scripts/spatialdecomp +0 -23
  393. rapidtide-2.9.6.data/scripts/spatialfit +0 -23
  394. rapidtide-2.9.6.data/scripts/spatialmi +0 -23
  395. rapidtide-2.9.6.data/scripts/spectrogram +0 -23
  396. rapidtide-2.9.6.data/scripts/synthASL +0 -23
  397. rapidtide-2.9.6.data/scripts/tcfrom2col +0 -23
  398. rapidtide-2.9.6.data/scripts/tcfrom3col +0 -23
  399. rapidtide-2.9.6.data/scripts/temporaldecomp +0 -23
  400. rapidtide-2.9.6.data/scripts/threeD +0 -236
  401. rapidtide-2.9.6.data/scripts/tidepool +0 -23
  402. rapidtide-2.9.6.data/scripts/variabilityizer +0 -23
  403. rapidtide-2.9.6.dist-info/RECORD +0 -359
  404. rapidtide-2.9.6.dist-info/top_level.txt +0 -86
  405. {rapidtide-2.9.6.dist-info → rapidtide-3.1.3.dist-info/licenses}/LICENSE +0 -0
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env python
2
2
  # -*- coding: utf-8 -*-
3
3
  #
4
- # Copyright 2016-2024 Blaise Frederick
4
+ # Copyright 2016-2025 Blaise Frederick
5
5
  #
6
6
  # Licensed under the Apache License, Version 2.0 (the "License");
7
7
  # you may not use this file except in compliance with the License.
@@ -19,9 +19,11 @@
19
19
  import copy
20
20
  import os
21
21
  import sys
22
+ from typing import Any, Callable
22
23
 
23
24
  import nibabel as nib
24
25
  import numpy as np
26
+ from numpy.typing import NDArray
25
27
 
26
28
  import rapidtide.filter as tide_filt
27
29
  import rapidtide.io as tide_io
@@ -29,31 +31,150 @@ import rapidtide.miscmath as tide_math
29
31
  import rapidtide.stats as tide_stats
30
32
  import rapidtide.util as tide_util
31
33
  from rapidtide.Colortables import *
34
+ from rapidtide.stats import neglogpfromr_interpolator
32
35
 
33
36
  atlases = {
34
37
  "ASPECTS": {"atlasname": "ASPECTS"},
35
38
  "ATT": {"atlasname": "ATTbasedFlowTerritories_split"},
36
- "JHU1": {"atlasname": "JHU-ArterialTerritoriesNoVent-LVL1_space-MNI152NLin6Asym"},
37
- "JHU2": {"atlasname": "JHU-ArterialTerritoriesNoVent-LVL2_space-MNI152NLin6Asym"},
39
+ "JHU1": {"atlasname": "JHU-ArterialTerritoriesNoVent-LVL1"},
40
+ "JHU2": {"atlasname": "JHU-ArterialTerritoriesNoVent-LVL2"},
38
41
  }
39
42
 
40
43
 
44
+ def check_rt_spatialmatch(dataset1: Any, dataset2: Any) -> tuple[bool, bool, bool, bool]:
45
+ """
46
+ Check spatial matching between two datasets for dimension, size, space, and affine properties.
47
+
48
+ This function compares four key spatial attributes between two datasets to determine
49
+ if they are spatially compatible for further processing or analysis.
50
+
51
+ Parameters
52
+ ----------
53
+ dataset1 : Any
54
+ First dataset object containing spatial attributes xdim, ydim, zdim, xsize, ysize,
55
+ zsize, space, and affine.
56
+ dataset2 : Any
57
+ Second dataset object containing the same spatial attributes as dataset1.
58
+
59
+ Returns
60
+ -------
61
+ tuple[bool, bool, bool, bool]
62
+ A tuple of four boolean values representing:
63
+ - dimmatch: True if all spatial dimensions (xdim, ydim, zdim) match
64
+ - sizematch: True if all spatial sizes (xsize, ysize, zsize) match
65
+ - spacematch: True if spatial coordinate systems (space) match
66
+ - affinematch: True if affine transformation matrices (affine) match
67
+
68
+ Notes
69
+ -----
70
+ The function performs element-wise comparison of spatial attributes. For affine matrices,
71
+ the comparison uses Python's default equality operator, which may be sensitive to
72
+ floating-point precision differences.
73
+
74
+ Examples
75
+ --------
76
+ >>> dimmatch, sizematch, spacematch, affinematch = check_rt_spatialmatch(dataset1, dataset2)
77
+ >>> if dimmatch and sizematch:
78
+ ... print("Datasets have matching dimensions and sizes")
79
+ """
80
+ if (
81
+ (dataset1.xdim == dataset2.xdim)
82
+ and (dataset1.ydim == dataset2.ydim)
83
+ and (dataset1.zdim == dataset2.zdim)
84
+ ):
85
+ dimmatch = True
86
+ else:
87
+ dimmatch = False
88
+ if (
89
+ (dataset1.xsize == dataset2.xsize)
90
+ and (dataset1.ysize == dataset2.ysize)
91
+ and (dataset1.zsize == dataset2.zsize)
92
+ ):
93
+ sizematch = True
94
+ else:
95
+ sizematch = False
96
+ if dataset1.space == dataset2.space:
97
+ spacematch = True
98
+ else:
99
+ spacematch = False
100
+ if dataset1.affine == dataset2.affine:
101
+ affinematch = True
102
+ else:
103
+ affinematch = False
104
+ return dimmatch, sizematch, spacematch, affinematch
105
+
106
+
41
107
  class Timecourse:
42
108
  "Store a timecourse and some information about it"
43
109
 
44
110
  def __init__(
45
111
  self,
46
- name,
47
- filename,
48
- namebase,
49
- samplerate,
50
- displaysamplerate,
51
- starttime=0.0,
52
- label=None,
53
- report=False,
54
- isbids=False,
55
- verbose=0,
56
- ):
112
+ name: str,
113
+ filename: str,
114
+ namebase: str,
115
+ samplerate: float,
116
+ displaysamplerate: float,
117
+ starttime: float = 0.0,
118
+ label: str | None = None,
119
+ report: bool = False,
120
+ isbids: bool = False,
121
+ limits: tuple[float, float] | None = None,
122
+ verbose: int = 0,
123
+ ) -> None:
124
+ """
125
+ Initialize a Timecourse object for reading and managing time series data.
126
+
127
+ This constructor sets up the basic properties of a timecourse and reads the
128
+ time series data from the specified file.
129
+
130
+ Parameters
131
+ ----------
132
+ name : str
133
+ The name of the timecourse, used for identification
134
+ filename : str
135
+ The full path to the data file containing the time series
136
+ namebase : str
137
+ The base name of the file (without path)
138
+ samplerate : float
139
+ The sampling rate of the time series data in Hz
140
+ displaysamplerate : float
141
+ The sampling rate used for display purposes in Hz
142
+ starttime : float, default=0.0
143
+ The start time of the time series in seconds
144
+ label : str, optional
145
+ The label to use for display. If None, defaults to the name parameter
146
+ report : bool, default=False
147
+ Whether to generate a report during initialization
148
+ isbids : bool, default=False
149
+ Whether the data follows BIDS (Brain Imaging Data Structure) format
150
+ limits : tuple of float, optional
151
+ The (min, max) value limits for the time series data
152
+ verbose : int, default=0
153
+ Verbosity level for logging output (0 = quiet, higher values = more verbose)
154
+
155
+ Returns
156
+ -------
157
+ None
158
+ This method initializes the object and does not return any value
159
+
160
+ Notes
161
+ -----
162
+ The method automatically reads the time series data using the readTimeData method
163
+ after setting all the internal attributes. If verbose level is greater than 1,
164
+ a message is printed indicating the file being read.
165
+
166
+ Examples
167
+ --------
168
+ >>> tc = Timecourse(
169
+ ... name="ECG",
170
+ ... filename="/data/ecg_data.dat",
171
+ ... namebase="ecg_data",
172
+ ... samplerate=1000.0,
173
+ ... displaysamplerate=100.0,
174
+ ... starttime=0.0,
175
+ ... label="Electrocardiogram"
176
+ ... )
177
+ """
57
178
  self.verbose = verbose
58
179
  self.name = name
59
180
  self.filename = filename
@@ -62,6 +183,7 @@ class Timecourse:
62
183
  self.displaysamplerate = displaysamplerate
63
184
  self.starttime = starttime
64
185
  self.isbids = isbids
186
+ self.limits = limits
65
187
 
66
188
  if label is None:
67
189
  self.label = name
@@ -72,9 +194,47 @@ class Timecourse:
72
194
  print("reading Timecourse ", self.name, " from ", self.filename, "...")
73
195
  self.readTimeData(self.label)
74
196
 
75
- def readTimeData(self, thename):
197
+ def readTimeData(self, thename: str) -> None:
198
+ """
199
+ Read time series data from a file and compute associated statistics and spectral properties.
200
+
201
+ This function reads time series data either from a BIDS-compatible TSV file or a vector file,
202
+ depending on whether the object is configured to use BIDS format. It computes the time axis,
203
+ spectral data, and statistical measures (kurtosis and skewness) for the selected column or
204
+ the entire dataset.
205
+
206
+ Parameters
207
+ ----------
208
+ thename : str
209
+ The name of the column to extract from the BIDS TSV file. Ignored if not using BIDS format.
210
+
211
+ Returns
212
+ -------
213
+ None
214
+ This function does not return a value but updates the following attributes of the object:
215
+ - `timedata`: The time series data as a numpy array.
216
+ - `length`: The length of the time series.
217
+ - `timeaxis`: The time axis corresponding to the data.
218
+ - `specaxis`: The frequency axis for the power spectrum.
219
+ - `specdata`: The power spectrum of the time series.
220
+ - `kurtosis`, `kurtosis_z`, `kurtosis_p`: Kurtosis statistics.
221
+ - `skewness`, `skewness_z`, `skewness_p`: Skewness statistics.
222
+
223
+ Notes
224
+ -----
225
+ If the `thename` column is not found in a BIDS TSV file, the function sets `timedata` to `None`
226
+ and returns early. The function uses `tide_io.readbidstsv` for BIDS files and `tide_io.readvec`
227
+ for non-BIDS files. Spectral analysis and statistical computations are performed using
228
+ `tide_filt.spectrum`, `tide_math.corrnormalize`, and `tide_stats.kurtosisstats`/`skewnessstats`.
229
+
230
+ Examples
231
+ --------
232
+ >>> obj.readTimeData('signal')
233
+ >>> print(obj.timedata)
234
+ >>> print(obj.specdata)
235
+ """
76
236
  if self.isbids:
77
- dummy, dummy, columns, indata, dummy, dummy = tide_io.readbidstsv(self.filename)
237
+ dummy, dummy, columns, indata, dummy, dummy, dummy = tide_io.readbidstsv(self.filename)
78
238
  try:
79
239
  self.timedata = indata[columns.index(thename), :]
80
240
  except ValueError:
@@ -88,11 +248,21 @@ class Timecourse:
88
248
  self.timeaxis = (
89
249
  np.linspace(0.0, self.length, num=self.length, endpoint=False) / self.samplerate
90
250
  ) - self.starttime
251
+ if self.limits is not None:
252
+ startpoint = np.max((int(np.round(self.limits[0] * self.samplerate, 0)), 0))
253
+ endpoint = np.min((int(np.round(self.limits[1] * self.samplerate, 0)), self.length))
254
+ else:
255
+ startpoint = 0
256
+ endpoint = self.length
91
257
  self.specaxis, self.specdata = tide_filt.spectrum(
92
- tide_math.corrnormalize(self.timedata), self.samplerate
258
+ tide_math.corrnormalize(self.timedata[startpoint:endpoint]), self.samplerate
259
+ )
260
+ self.kurtosis, self.kurtosis_z, self.kurtosis_p = tide_stats.kurtosisstats(
261
+ self.timedata[startpoint:endpoint]
262
+ )
263
+ self.skewness, self.skewness_z, self.skewness_p = tide_stats.skewnessstats(
264
+ self.timedata[startpoint:endpoint]
93
265
  )
94
- self.kurtosis, self.kurtosis_z, self.kurtosis_p = tide_stats.kurtosisstats(self.timedata)
95
- self.skewness, self.skewness_z, self.skewness_p = tide_stats.skewnessstats(self.timedata)
96
266
 
97
267
  if self.verbose > 1:
98
268
  print("Timecourse data range:", np.min(self.timedata), np.max(self.timedata))
@@ -105,7 +275,54 @@ class Timecourse:
105
275
 
106
276
  print()
107
277
 
108
- def summarize(self):
278
+ def summarize(self) -> None:
279
+ """
280
+ Print a summary of the timecourse properties.
281
+
282
+ This method outputs a formatted summary of various properties associated with
283
+ the timecourse object, including name, label, file information, sampling rate,
284
+ length, and statistical measures.
285
+
286
+ Parameters
287
+ ----------
288
+ self : object
289
+ The timecourse object instance containing the properties to be summarized.
290
+ Expected attributes include:
291
+ - name: str, the name of the timecourse
292
+ - label: str, the label associated with the timecourse
293
+ - filename: str, the filename of the timecourse data
294
+ - namebase: str, the base name of the file
295
+ - samplerate: float, the sampling rate of the timecourse
296
+ - length: int, the length of the timecourse
297
+ - kurtosis: float, the kurtosis value of the timecourse
298
+ - kurtosis_z: float, the z-score of the kurtosis
299
+ - kurtosis_p: float, the p-value of the kurtosis
300
+
301
+ Returns
302
+ -------
303
+ None
304
+ This method prints the summary information to stdout and does not return any value.
305
+
306
+ Notes
307
+ -----
308
+ The output is formatted for readability with consistent indentation and
309
+ descriptive labels for each property. This method is typically used for
310
+ debugging and quick inspection of timecourse properties.
311
+
312
+ Examples
313
+ --------
314
+ >>> timecourse = Timecourse(name="test_signal", label="test", filename="test.csv")
315
+ >>> timecourse.summarize()
316
+ Timecourse name: test_signal
317
+ label: test
318
+ filename: test.csv
319
+ namebase: test
320
+ samplerate: 100.0
321
+ length: 1000
322
+ kurtosis: 0.5
323
+ kurtosis_z: 1.2
324
+ kurtosis_p: 0.23
325
+ """
109
326
  print()
110
327
  print("Timecourse name: ", self.name)
111
328
  print(" label: ", self.label)
@@ -121,23 +338,90 @@ class Timecourse:
121
338
  class Overlay:
122
339
  "Store a data overlay and some information about it"
123
340
 
341
+ LUTname = None
342
+
124
343
  def __init__(
125
344
  self,
126
- name,
127
- filespec,
128
- namebase,
129
- funcmask=None,
130
- geommask=None,
131
- label=None,
132
- report=False,
133
- lut_state=gen_gray_state(),
134
- alpha=128,
135
- endalpha=0,
136
- display_state=True,
137
- isaMask=False,
138
- init_LUT=True,
139
- verbose=1,
140
- ):
345
+ name: str,
346
+ filespec: str,
347
+ namebase: str,
348
+ funcmask: NDArray | None = None,
349
+ geommask: NDArray | None = None,
350
+ label: str | None = None,
351
+ report: bool = False,
352
+ lut_state: dict = gen_gray_state(),
353
+ alpha: int = 128,
354
+ endalpha: int = 0,
355
+ display_state: bool = True,
356
+ invertonload: bool = False,
357
+ isaMask: bool = False,
358
+ init_LUT: bool = True,
359
+ verbose: int = 1,
360
+ ) -> None:
361
+ """
362
+ Initialize an overlay object for rapidtide image data visualization.
363
+
364
+ This constructor initializes an overlay by loading image data from a file,
365
+ applying functional and geometric masks, and setting up display properties
366
+ including lookup tables and affine transformations.
367
+
368
+ Parameters
369
+ ----------
370
+ name : str
371
+ Name of the overlay.
372
+ filespec : str
373
+ File specification string used to locate and load the image data.
374
+ namebase : str
375
+ Base name for the overlay, used in file naming and labeling.
376
+ funcmask : NDArray | None, optional
377
+ Functional mask to apply to the data. Default is None.
378
+ geommask : NDArray | None, optional
379
+ Geometric mask to apply to the data. Default is None.
380
+ label : str | None, optional
381
+ Label for the overlay. If None, defaults to the value of `name`. Default is None.
382
+ report : bool, optional
383
+ If True, enables reporting mode. Default is False.
384
+ lut_state : dict, optional
385
+ Lookup table state dictionary. Default is ``gen_gray_state()``.
386
+ alpha : int, optional
387
+ Initial alpha value for display. Default is 128.
388
+ endalpha : int, optional
389
+ End alpha value for display. Default is 0.
390
+ display_state : bool, optional
391
+ If True, initializes display state. Default is True.
392
+ invertonload : bool, optional
393
+ If True, inverts the data on load. Default is False.
394
+ isaMask : bool, optional
395
+ If True, treats the data as a mask. Default is False.
396
+ init_LUT : bool, optional
397
+ If True, initializes the lookup table. Default is True.
398
+ verbose : int, optional
399
+ Verbosity level. Default is 1.
400
+
401
+ Returns
402
+ -------
403
+ None
404
+ This method initializes the object in-place and does not return a value.
405
+
406
+ Notes
407
+ -----
408
+ The constructor performs the following steps:
409
+ 1. Loads image data using `tide_io.processnamespec`.
410
+ 2. Applies functional and geometric masks.
411
+ 3. Sets up display parameters such as `dispmin` and `dispmax`.
412
+ 4. Initializes lookup table if `init_LUT` is True.
413
+ 5. Determines the spatial coordinate system and affine transformation matrix.
414
+ 6. Determines the orientation (neurological or radiological) based on the affine matrix.
415
+
416
+ Examples
417
+ --------
418
+ >>> overlay = Overlay(
419
+ ... name="my_overlay",
420
+ ... filespec="/path/to/image.nii",
421
+ ... namebase="overlay_base",
422
+ ... verbose=2
423
+ ... )
424
+ """
141
425
  self.verbose = verbose
142
426
  self.name = name
143
427
  if label is None:
@@ -151,6 +435,8 @@ class Overlay:
151
435
  self.namebase = namebase
152
436
  if self.verbose > 1:
153
437
  print("reading map ", self.name, " from ", self.filename, "...")
438
+ self.maskhash = 0
439
+ self.invertonload = invertonload
154
440
  self.readImageData(isaMask=isaMask)
155
441
  self.mask = None
156
442
  self.maskeddata = None
@@ -158,6 +444,8 @@ class Overlay:
158
444
  self.setGeomMask(geommask, maskdata=False)
159
445
  self.maskData()
160
446
  self.updateStats()
447
+ self.dispmin = self.robustmin
448
+ self.dispmax = self.robustmax
161
449
  if init_LUT:
162
450
  self.gradient = getagradient()
163
451
  self.lut_state = lut_state
@@ -218,7 +506,41 @@ class Overlay:
218
506
  if self.verbose > 0:
219
507
  self.summarize()
220
508
 
221
- def duplicate(self, newname, newlabel):
509
+ def duplicate(self, newname: str, newlabel: str, init_LUT: bool = True) -> Any:
510
+ """
511
+ Create a duplicate of the current overlay with new name and label.
512
+
513
+ Parameters
514
+ ----------
515
+ newname : str
516
+ The name for the new overlay instance.
517
+ newlabel : str
518
+ The label for the new overlay instance.
519
+ init_LUT : bool, optional
520
+ Whether to initialize the lookup table for the new overlay.
521
+ Default is True.
522
+
523
+ Returns
524
+ -------
525
+ Any
526
+ A new Overlay instance with the specified name and label,
527
+ inheriting all properties from the current overlay.
528
+
529
+ Notes
530
+ -----
531
+ This method creates a shallow copy of the current overlay with
532
+ updated name and label attributes. The new overlay maintains
533
+ references to the original data files and masks.
534
+
535
+ Examples
536
+ --------
537
+ >>> overlay = Overlay("original", "file.nii", "base")
538
+ >>> new_overlay = overlay.duplicate("copy", "Copy Label")
539
+ >>> print(new_overlay.name)
540
+ 'copy'
541
+ >>> print(new_overlay.label)
542
+ 'Copy Label'
543
+ """
222
544
  return Overlay(
223
545
  newname,
224
546
  self.filename,
@@ -227,12 +549,45 @@ class Overlay:
227
549
  geommask=self.geommask,
228
550
  label=newlabel,
229
551
  report=self.report,
230
- init_LUT=self.init_LUT,
231
- lut_state=self.lut_state,
552
+ init_LUT=init_LUT,
553
+ verbose=self.verbose,
232
554
  )
233
555
 
234
- def updateStats(self):
556
+ def updateStats(self) -> None:
557
+ """
558
+ Update statistical properties of the masked data.
559
+
560
+ This method calculates various statistical measures from the masked data,
561
+ including min/max values, quartiles, robust statistics, and histogram data.
562
+ The results are stored as instance attributes for later use.
563
+
564
+ Parameters
565
+ ----------
566
+ None
567
+
568
+ Returns
569
+ -------
570
+ None
571
+ This method does not return a value but updates instance attributes
572
+ with statistical calculations.
573
+
574
+ Notes
575
+ -----
576
+ The method uses the mask to filter data points where mask != 0.
577
+ Statistical calculations include:
578
+ - Minimum and maximum values
579
+ - Robust statistics (0.02, 0.25, 0.5, 0.75, 0.98 percentiles)
580
+ - Histogram data with 200 bins
581
+ - Quartiles (25th, 50th, 75th percentiles)
582
+
583
+ Examples
584
+ --------
585
+ >>> obj.updateStats()
586
+ >>> print(obj.minval, obj.maxval)
587
+ >>> print(obj.quartiles)
588
+ """
235
589
  calcmaskeddata = self.data[np.where(self.mask != 0)]
590
+
236
591
  self.minval = calcmaskeddata.min()
237
592
  self.maxval = calcmaskeddata.max()
238
593
  (
@@ -242,12 +597,11 @@ class Overlay:
242
597
  self.pct75,
243
598
  self.robustmax,
244
599
  ) = tide_stats.getfracvals(calcmaskeddata, [0.02, 0.25, 0.5, 0.75, 0.98], nozero=False)
245
- self.dispmin = self.robustmin
246
- self.dispmax = self.robustmax
247
600
  self.histy, self.histx = np.histogram(
248
601
  calcmaskeddata, bins=np.linspace(self.minval, self.maxval, 200)
249
602
  )
250
603
  self.quartiles = [self.pct25, self.pct50, self.pct75]
604
+
251
605
  if self.verbose > 1:
252
606
  print(
253
607
  self.name,
@@ -259,17 +613,92 @@ class Overlay:
259
613
  self.quartiles,
260
614
  )
261
615
 
262
- def setData(self, data, isaMask=False):
616
+ def setData(self, data: NDArray, isaMask: bool = False) -> None:
617
+ """
618
+ Set the data array and optionally convert it to a binary mask.
619
+
620
+ This method assigns the provided data array to the internal data attribute
621
+ and optionally converts it to a binary mask where values less than 0.5
622
+ are set to 0.0 and values greater than 0.5 are set to 1.0.
623
+
624
+ Parameters
625
+ ----------
626
+ data : NDArray
627
+ The input data array to be set. A copy of this array is stored internally.
628
+ isaMask : bool, optional
629
+ If True, converts the data to a binary mask. Values less than 0.5 become 0.0,
630
+ and values greater than 0.5 become 1.0. Default is False.
631
+
632
+ Returns
633
+ -------
634
+ None
635
+ This method does not return any value.
636
+
637
+ Notes
638
+ -----
639
+ The data is stored as a copy to prevent external modifications from affecting
640
+ the internal state. The mask conversion is performed using numpy's where function
641
+ for efficient element-wise operations.
642
+
643
+ Examples
644
+ --------
645
+ >>> obj.setData(np.array([0.2, 0.7, 0.3, 0.8]))
646
+ >>> obj.setData(np.array([0.2, 0.7, 0.3, 0.8]), isaMask=True)
647
+ """
263
648
  self.data = data.copy()
264
649
  if isaMask:
265
650
  self.data[np.where(self.data < 0.5)] = 0.0
266
651
  self.data[np.where(self.data > 0.5)] = 1.0
267
652
  self.updateStats()
268
653
 
269
- def readImageData(self, isaMask=False):
654
+ def readImageData(self, isaMask: bool = False) -> None:
655
+ """
656
+ Read image data from a NIfTI file and process it based on specified flags.
657
+
658
+ This function loads image data from a NIfTI file using `tide_io.readfromnifti`,
659
+ applies optional inversion and masking operations, and extracts dimension and
660
+ spacing information from the header.
661
+
662
+ Parameters
663
+ ----------
664
+ isaMask : bool, optional
665
+ If True, process the data as a binary mask. For non-mask files, values
666
+ less than 0.5 are set to 0, and values greater than 0.5 are set to 1.
667
+ For mask files with `filevals` defined, the data is converted to a binary
668
+ mask based on matching values in `filevals`. Default is False.
669
+
670
+ Returns
671
+ -------
672
+ None
673
+ This function does not return a value but updates the instance attributes
674
+ `nim`, `data`, `header`, `dims`, `sizes`, `xdim`, `ydim`, `zdim`, `tdim`,
675
+ `xsize`, `ysize`, `zsize`, `tr`, and `toffset`.
676
+
677
+ Notes
678
+ -----
679
+ - If `invertonload` is True, the data is multiplied by -1.0.
680
+ - The function prints data range and header information if `verbose > 1`.
681
+ - Dimension and spacing information is parsed using `tide_io.parseniftidims` and
682
+ `tide_io.parseniftisizes`.
683
+
684
+ Examples
685
+ --------
686
+ >>> reader = ImageReader()
687
+ >>> reader.filename = "example.nii"
688
+ >>> reader.invertonload = True
689
+ >>> reader.verbose = 2
690
+ >>> reader.readImageData(isaMask=True)
691
+ Overlay data range: -1.0 1.0
692
+ header {'toffset': 0.0, ...}
693
+ Overlay dims: 64 64 32 1
694
+ Overlay sizes: 3.0 3.0 3.0 2.0
695
+ Overlay toffset: 0.0
696
+ """
270
697
  self.nim, self.data, self.header, self.dims, self.sizes = tide_io.readfromnifti(
271
698
  self.filename
272
699
  )
700
+ if self.invertonload:
701
+ self.data *= -1.0
273
702
  if isaMask:
274
703
  if self.filevals is None:
275
704
  self.data[np.where(self.data < 0.5)] = 0.0
@@ -290,16 +719,97 @@ class Overlay:
290
719
  print("Overlay sizes:", self.xsize, self.ysize, self.zsize, self.tr)
291
720
  print("Overlay toffset:", self.toffset)
292
721
 
293
- def setLabel(self, label):
722
+ def setLabel(self, label: str) -> None:
723
+ """
724
+ Set the label for the object.
725
+
726
+ Parameters
727
+ ----------
728
+ label : str
729
+ The label to assign to the object.
730
+
731
+ Returns
732
+ -------
733
+ None
734
+ This method does not return any value.
735
+
736
+ Notes
737
+ -----
738
+ This method directly assigns the provided label to the object's label attribute.
739
+ The label is typically used for identification or display purposes.
740
+
741
+ Examples
742
+ --------
743
+ >>> obj = MyClass()
744
+ >>> obj.setLabel("New Label")
745
+ >>> print(obj.label)
746
+ 'New Label'
747
+ """
294
748
  self.label = label
295
749
 
296
- def real2tr(self, time):
750
+ def real2tr(self, time: float) -> float:
751
+ """
752
+ Convert real time to trigger time.
753
+
754
+ Convert a real time value to its corresponding trigger time value by applying
755
+ the time offset and trigger period parameters.
756
+
757
+ Parameters
758
+ ----------
759
+ time : float
760
+ The real time value to be converted to trigger time.
761
+
762
+ Returns
763
+ -------
764
+ float
765
+ The converted trigger time value, rounded to the nearest integer.
766
+
767
+ Notes
768
+ -----
769
+ The conversion is performed using the formula: ``round((time - toffset) / tr)``
770
+ where ``toffset`` is the time offset and ``tr`` is the trigger period.
771
+
772
+ Examples
773
+ --------
774
+ >>> obj.real2tr(10.5)
775
+ 2.0
776
+ >>> obj.real2tr(5.0)
777
+ 0.0
778
+ """
297
779
  return np.round((time - self.toffset) / self.tr, 0)
298
780
 
299
- def tr2real(self, tpos):
781
+ def tr2real(self, tpos: int) -> float:
300
782
  return self.toffset + self.tr * tpos
301
783
 
302
- def real2vox(self, xcoord, ycoord, zcoord, time):
784
+ def real2vox(
785
+ self, xcoord: float, ycoord: float, zcoord: float, time: float
786
+ ) -> tuple[int, int, int, int]:
787
+ """
788
+ Convert a time position to a real time value.
789
+
790
+ Parameters
791
+ ----------
792
+ tpos : int
793
+ Time position index to convert to real time value.
794
+
795
+ Returns
796
+ -------
797
+ float
798
+ The corresponding real time value calculated as `toffset + tr * tpos`.
799
+
800
+ Notes
801
+ -----
802
+ This function performs a linear transformation from discrete time positions
803
+ to continuous time values using the instance's time offset and time rate
804
+ parameters.
805
+
806
+ Examples
807
+ --------
808
+ >>> obj.tr2real(0)
809
+ 10.0
810
+ >>> obj.tr2real(5)
811
+ 15.0
812
+ """
303
813
  x, y, z = nib.apply_affine(self.invaffine, [xcoord, ycoord, zcoord])
304
814
  t = self.real2tr(time)
305
815
  return (
@@ -309,30 +819,183 @@ class Overlay:
309
819
  int(np.round(t, 0)),
310
820
  )
311
821
 
312
- def vox2real(self, xpos, ypos, zpos, tpos):
822
+ def vox2real(self, xpos: int, ypos: int, zpos: int, tpos: int) -> NDArray:
823
+ """
824
+ Convert voxel coordinates to real-world coordinates.
825
+
826
+ This function transforms voxel coordinates (x, y, z, t) to real-world coordinates
827
+ using the affine transformation matrix and temporal transformation.
828
+
829
+ Parameters
830
+ ----------
831
+ xpos : int
832
+ X coordinate in voxel space
833
+ ypos : int
834
+ Y coordinate in voxel space
835
+ zpos : int
836
+ Z coordinate in voxel space
837
+ tpos : int
838
+ T coordinate in voxel space (temporal dimension)
839
+
840
+ Returns
841
+ -------
842
+ NDArray
843
+ Array containing real-world coordinates [x_real, y_real, z_real, t_real]
844
+
845
+ Notes
846
+ -----
847
+ The conversion uses nibabel's apply_affine function for spatial transformation
848
+ and self.tr2real for temporal transformation. The result includes both
849
+ spatial and temporal coordinates in real-world units.
850
+
851
+ Examples
852
+ --------
853
+ >>> vox2real(10, 20, 30, 5)
854
+ array([12.5, 25.0, 37.5, 2.5])
855
+ """
313
856
  return np.concatenate(
314
857
  (nib.apply_affine(self.affine, [xpos, ypos, zpos]), [self.tr2real(tpos)]),
315
858
  axis=0,
316
859
  )
317
860
 
318
- def setXYZpos(self, xpos, ypos, zpos):
861
+ def setXYZpos(self, xpos: int, ypos: int, zpos: int) -> None:
862
+ """
863
+ Set the 3D position coordinates of the object.
864
+
865
+ Parameters
866
+ ----------
867
+ xpos : int
868
+ The x-coordinate position value.
869
+ ypos : int
870
+ The y-coordinate position value.
871
+ zpos : int
872
+ The z-coordinate position value.
873
+
874
+ Returns
875
+ -------
876
+ None
877
+ This method does not return any value.
878
+
879
+ Notes
880
+ -----
881
+ All position values are converted to integers before assignment.
882
+
883
+ Examples
884
+ --------
885
+ >>> obj = MyClass()
886
+ >>> obj.setXYZpos(10, 20, 30)
887
+ >>> print(obj.xpos, obj.ypos, obj.zpos)
888
+ 10 20 30
889
+ """
319
890
  self.xpos = int(xpos)
320
891
  self.ypos = int(ypos)
321
892
  self.zpos = int(zpos)
322
893
 
323
- def setTpos(self, tpos):
894
+ def setTpos(self, tpos: int) -> None:
895
+ """
896
+ Set the temporal position attribute with bounds checking.
897
+
898
+ Parameters
899
+ ----------
900
+ tpos : int
901
+ The temporal position to set. If greater than self.tdim - 1,
902
+ it will be clamped to self.tdim - 1.
903
+
904
+ Returns
905
+ -------
906
+ None
907
+ This method modifies the instance in-place and does not return a value.
908
+
909
+ Notes
910
+ -----
911
+ The temporal position is bounded by the dimensionality of the temporal
912
+ space (self.tdim). If the input tpos exceeds this limit, it will be
913
+ automatically adjusted to the maximum valid position (self.tdim - 1).
914
+
915
+ Examples
916
+ --------
917
+ >>> obj = MyClass()
918
+ >>> obj.tdim = 5
919
+ >>> obj.setTpos(3)
920
+ >>> obj.tpos
921
+ 3
922
+ >>> obj.setTpos(10)
923
+ >>> obj.tpos
924
+ 4
925
+ """
324
926
  if tpos > self.tdim - 1:
325
927
  self.tpos = int(self.tdim - 1)
326
928
  else:
327
929
  self.tpos = int(tpos)
328
930
 
329
- def getFocusVal(self):
931
+ def getFocusVal(self) -> float:
932
+ """
933
+ Get the focus value at the current position.
934
+
935
+ This method retrieves the data value from the masked data array at the
936
+ current position coordinates. The method handles both 3D and 4D data arrays
937
+ by checking the time dimension.
938
+
939
+ Parameters
940
+ ----------
941
+ self : object
942
+ The instance of the class containing the masked data and position
943
+ coordinates.
944
+
945
+ Returns
946
+ -------
947
+ float
948
+ The data value at the current position. For 4D data (tdim > 1), returns
949
+ the value at [xpos, ypos, zpos, tpos]. For 3D data (tdim <= 1), returns
950
+ the value at [xpos, ypos, zpos].
951
+
952
+ Notes
953
+ -----
954
+ The method assumes that the instance has the following attributes:
955
+ - maskeddata: numpy array containing the data
956
+ - xpos, ypos, zpos, tpos: integer coordinates
957
+ - tdim: integer representing the time dimension
958
+
959
+ Examples
960
+ --------
961
+ >>> value = obj.getFocusVal()
962
+ >>> print(value)
963
+ 0.5
964
+ """
330
965
  if self.tdim > 1:
331
966
  return self.maskeddata[self.xpos, self.ypos, self.zpos, self.tpos]
332
967
  else:
333
968
  return self.maskeddata[self.xpos, self.ypos, self.zpos]
334
969
 
335
- def setFuncMask(self, funcmask, maskdata=True):
970
+ def setFuncMask(self, funcmask: NDArray | None, maskdata: bool = True) -> None:
971
+ """
972
+ Set the functional mask for the object.
973
+
974
+ Parameters
975
+ ----------
976
+ funcmask : array-like, optional
977
+ The functional mask to be set. If None, a default mask is created based on
978
+ the dimensionality of the data. If provided, a copy of the mask is stored.
979
+ maskdata : bool, default=True
980
+ If True, calls maskData() method after setting the functional mask.
981
+
982
+ Returns
983
+ -------
984
+ None
985
+ This method modifies the object in-place and does not return any value.
986
+
987
+ Notes
988
+ -----
989
+ When funcmask is None, the method creates a default mask:
990
+ - For 1D data (tdim == 1): creates a mask with the same shape as self.data
991
+ - For higher dimensional data: creates a mask with shape (self.data.shape[0], self.data.shape[1], self.data.shape[2], 1)
992
+
993
+ Examples
994
+ --------
995
+ >>> obj.setFuncMask(None)
996
+ >>> obj.setFuncMask(np.ones((10, 10)))
997
+ >>> obj.setFuncMask(None, maskdata=False)
998
+ """
336
999
  self.funcmask = funcmask
337
1000
  if self.funcmask is None:
338
1001
  if self.tdim == 1:
@@ -344,7 +1007,35 @@ class Overlay:
344
1007
  if maskdata:
345
1008
  self.maskData()
346
1009
 
347
- def setGeomMask(self, geommask, maskdata=True):
1010
+ def setGeomMask(self, geommask: NDArray | None, maskdata: bool = True) -> None:
1011
+ """
1012
+ Set the geometric mask for the object and optionally mask the data.
1013
+
1014
+ Parameters
1015
+ ----------
1016
+ geommask : ndarray or None
1017
+ Geometric mask array. If None, a default mask is created based on the
1018
+ object's dimensions. If not None, the provided mask is copied and used.
1019
+ maskdata : bool, default=True
1020
+ If True, applies the mask to the data by calling maskData() method.
1021
+ If False, only sets the geometric mask without masking the data.
1022
+
1023
+ Returns
1024
+ -------
1025
+ None
1026
+ This method modifies the object in-place and does not return any value.
1027
+
1028
+ Notes
1029
+ -----
1030
+ When geommask is None and tdim == 1, a mask of ones with the same shape as
1031
+ self.data is created. Otherwise, a mask of ones with the shape of
1032
+ self.data[:, :, :, 0] is created.
1033
+
1034
+ Examples
1035
+ --------
1036
+ >>> obj.setGeomMask(None)
1037
+ >>> obj.setGeomMask(mask_array, maskdata=False)
1038
+ """
348
1039
  self.geommask = geommask
349
1040
  if self.geommask is None:
350
1041
  if self.tdim == 1:
@@ -356,22 +1047,180 @@ class Overlay:
356
1047
  if maskdata:
357
1048
  self.maskData()
358
1049
 
359
- def maskData(self):
1050
+ def maskData(self) -> None:
1051
+ """
1052
+ Apply mask to data and update statistics if mask has changed.
1053
+
1054
+ This method combines geometric and functional masks to create a final mask,
1055
+ then checks if the mask has changed since the last update. If the mask has
1056
+ changed, it applies the mask to the data, sets masked values to zero, and
1057
+ updates the statistics.
1058
+
1059
+ Parameters
1060
+ ----------
1061
+ None
1062
+
1063
+ Returns
1064
+ -------
1065
+ None
1066
+ This method modifies the instance in-place and does not return any value.
1067
+
1068
+ Notes
1069
+ -----
1070
+ The method uses a hash-based approach to efficiently detect when the mask
1071
+ has changed, avoiding expensive operations when the mask remains the same.
1072
+ The mask is applied by setting values to zero where the combined mask is
1073
+ less than 0.5.
1074
+
1075
+ Examples
1076
+ --------
1077
+ >>> obj.maskData()
1078
+ # Applies mask and updates statistics if mask has changed
1079
+ """
360
1080
  self.mask = self.geommask * self.funcmask
361
- self.maskeddata = self.data.copy()
362
- self.maskeddata[np.where(self.mask < 0.5)] = 0.0
363
- self.updateStats()
364
-
365
- def setReport(self, report):
1081
+ maskhash = hash(self.mask.tobytes())
1082
+ # these operations are expensive, so only do them if the mask is changed
1083
+ if (maskhash == self.maskhash) and (self.verbose > 1):
1084
+ print("mask has not changed")
1085
+ else:
1086
+ if self.verbose > 1:
1087
+ print("mask changed - recalculating")
1088
+ self.maskeddata = self.data.copy()
1089
+ self.maskeddata[np.where(self.mask < 0.5)] = 0.0
1090
+ self.updateStats()
1091
+ self.maskhash = maskhash
1092
+
1093
+ def setReport(self, report: bool) -> None:
1094
+ """
1095
+ Set the report flag for the object.
1096
+
1097
+ Parameters
1098
+ ----------
1099
+ report : bool
1100
+ Flag indicating whether reporting is enabled or disabled.
1101
+
1102
+ Returns
1103
+ -------
1104
+ None
1105
+ This method does not return any value.
1106
+
1107
+ Notes
1108
+ -----
1109
+ This method assigns the provided boolean value to the internal `report` attribute
1110
+ of the object. The attribute can be accessed later to check the current reporting state.
1111
+
1112
+ Examples
1113
+ --------
1114
+ >>> obj = MyClass()
1115
+ >>> obj.setReport(True)
1116
+ >>> obj.report
1117
+ True
1118
+ >>> obj.setReport(False)
1119
+ >>> obj.report
1120
+ False
1121
+ """
366
1122
  self.report = report
367
1123
 
368
- def setTR(self, trval):
1124
+ def setTR(self, trval: float) -> None:
1125
+ """
1126
+ Set the TR (repetition time) value for the object.
1127
+
1128
+ Parameters
1129
+ ----------
1130
+ trval : float
1131
+ The repetition time value to be set. This parameter represents the
1132
+ time interval between successive MRI pulse sequences in seconds.
1133
+
1134
+ Returns
1135
+ -------
1136
+ None
1137
+ This method does not return any value.
1138
+
1139
+ Notes
1140
+ -----
1141
+ This method directly assigns the provided value to the internal `tr` attribute
1142
+ of the object. The TR value is commonly used in MRI data processing and
1143
+ represents the time between the start of one pulse sequence and the start
1144
+ of the next.
1145
+
1146
+ Examples
1147
+ --------
1148
+ >>> obj = MyClass()
1149
+ >>> obj.setTR(2.0)
1150
+ >>> print(obj.tr)
1151
+ 2.0
1152
+ """
369
1153
  self.tr = trval
370
1154
 
371
- def settoffset(self, toffset):
1155
+ def settoffset(self, toffset: float) -> None:
1156
+ """
1157
+ Set the time offset value.
1158
+
1159
+ Parameters
1160
+ ----------
1161
+ toffset : float
1162
+ The time offset value to set.
1163
+
1164
+ Returns
1165
+ -------
1166
+ None
1167
+ This method does not return any value.
1168
+
1169
+ Notes
1170
+ -----
1171
+ This method assigns the provided time offset value to the instance variable
1172
+ `self.toffset`. The time offset is typically used to adjust timing references
1173
+ in time-series data processing or temporal calculations.
1174
+
1175
+ Examples
1176
+ --------
1177
+ >>> obj = MyClass()
1178
+ >>> obj.settoffset(5.0)
1179
+ >>> print(obj.toffset)
1180
+ 5.0
1181
+ """
372
1182
  self.toffset = toffset
373
1183
 
374
- def setLUT(self, lut_state, alpha=255, endalpha=128):
1184
+ def setLUT(self, lut_state: dict, alpha: int = 255, endalpha: int = 128) -> None:
1185
+ """
1186
+ Set the lookup table (LUT) state with optional alpha blending adjustments.
1187
+
1188
+ This function configures the lookup table state for gradient visualization,
1189
+ applying alpha transparency adjustments to the color ticks and restoring
1190
+ the gradient state with the updated LUT.
1191
+
1192
+ Parameters
1193
+ ----------
1194
+ lut_state : dict
1195
+ Dictionary containing the lookup table state with keys:
1196
+ - "ticks": list of tuples representing color stops
1197
+ - "mode": color mapping mode
1198
+ - "name": name of the LUT
1199
+ alpha : int, optional
1200
+ Alpha value (0-255) to apply to intermediate color ticks, by default 255
1201
+ endalpha : int, optional
1202
+ Alpha value (0-255) to apply to the end color ticks, by default 128
1203
+
1204
+ Returns
1205
+ -------
1206
+ None
1207
+ This function modifies the instance state in-place and does not return anything.
1208
+
1209
+ Notes
1210
+ -----
1211
+ The function applies alpha blending to intermediate color ticks while preserving
1212
+ the original alpha values of the first and last ticks. When verbose mode is enabled
1213
+ (verbose > 1), the modified tick values are printed to the console.
1214
+
1215
+ Examples
1216
+ --------
1217
+ >>> lut_state = {
1218
+ ... "ticks": [(0, (0, 0, 0, 255)), (128, (128, 128, 128, 255)), (255, (255, 255, 255, 255))],
1219
+ ... "mode": "RGB",
1220
+ ... "name": "grayscale"
1221
+ ... }
1222
+ >>> setLUT(lut_state, alpha=128, endalpha=64)
1223
+ """
375
1224
  if alpha is not None:
376
1225
  theticks = [lut_state["ticks"][0]]
377
1226
  for theelement in lut_state["ticks"][1:-1]:
@@ -389,11 +1238,82 @@ class Overlay:
389
1238
  self.lut_state = setendalpha(lut_state, endalpha)
390
1239
  self.gradient.restoreState(self.lut_state)
391
1240
  self.theLUT = self.gradient.getLookupTable(512, alpha=True)
392
-
393
- def setisdisplayed(self, display_state):
1241
+ self.LUTname = lut_state["name"]
1242
+
1243
+ def setisdisplayed(self, display_state: bool) -> None:
1244
+ """
1245
+ Set the display state of the object.
1246
+
1247
+ Parameters
1248
+ ----------
1249
+ display_state : bool
1250
+ The display state to set. True indicates the object should be displayed,
1251
+ False indicates it should be hidden.
1252
+
1253
+ Returns
1254
+ -------
1255
+ None
1256
+ This method does not return any value.
1257
+
1258
+ Notes
1259
+ -----
1260
+ This method directly assigns the provided display state to the internal
1261
+ `display_state` attribute of the object. The display state controls whether
1262
+ the object is visible in the user interface or not.
1263
+
1264
+ Examples
1265
+ --------
1266
+ >>> obj = MyClass()
1267
+ >>> obj.setisdisplayed(True)
1268
+ >>> print(obj.display_state)
1269
+ True
1270
+ >>> obj.setisdisplayed(False)
1271
+ >>> print(obj.display_state)
1272
+ False
1273
+ """
394
1274
  self.display_state = display_state
395
1275
 
396
- def summarize(self):
1276
+ def summarize(self) -> None:
1277
+ """
1278
+ Print a summary of the overlay's properties and metadata.
1279
+
1280
+ This method outputs a formatted summary of the overlay's key attributes,
1281
+ including name, label, file information, dimensions, orientation, and
1282
+ data statistics. It also indicates whether geometric and functional masks
1283
+ are set.
1284
+
1285
+ Notes
1286
+ -----
1287
+ The output is printed directly to the console and does not return any value.
1288
+ This method is intended for debugging or inspection purposes.
1289
+
1290
+ Examples
1291
+ --------
1292
+ >>> overlay = Overlay(...)
1293
+ >>> overlay.summarize()
1294
+ Overlay name: my_overlay
1295
+ label: My Overlay
1296
+ filename: /path/to/my_overlay.nii
1297
+ namebase: my_overlay
1298
+ xdim: 64
1299
+ ydim: 64
1300
+ zdim: 32
1301
+ tdim: 100
1302
+ space: MNI
1303
+ orientation: radiological
1304
+ toffset: 0.0
1305
+ tr: 2.0
1306
+ min: -1.5
1307
+ max: 2.0
1308
+ robustmin: -1.0
1309
+ robustmax: 1.5
1310
+ dispmin: -1.5
1311
+ dispmax: 2.0
1312
+ data shape: (64, 64, 32, 100)
1313
+ masked data shape: (64, 64, 32, 100)
1314
+ geometric mask is set
1315
+ functional mask not set
1316
+ """
397
1317
  print()
398
1318
  print("Overlay name: ", self.name)
399
1319
  print(" label: ", self.label)
@@ -432,6 +1352,8 @@ class Overlay:
432
1352
 
433
1353
  class RapidtideDataset:
434
1354
  "Store all the data associated with a rapidtide dataset"
1355
+
1356
+ fileroot = None
435
1357
  focusregressor = None
436
1358
  regressorfilterlimits = None
437
1359
  regressorsimcalclimits = None
@@ -451,31 +1373,100 @@ class RapidtideDataset:
451
1373
  ysize = 0.0
452
1374
  zsize = 0.0
453
1375
  tr = 0.0
1376
+ space = None
1377
+ affine = None
454
1378
 
455
1379
  def __init__(
456
1380
  self,
457
- name,
458
- fileroot,
459
- anatname=None,
460
- geommaskname=None,
461
- graymaskspec=None,
462
- whitemaskspec=None,
463
- userise=False,
464
- usecorrout=False,
465
- useatlas=False,
466
- minimal=False,
467
- forcetr=False,
468
- forceoffset=False,
469
- coordinatespace="unspecified",
470
- offsettime=0.0,
471
- init_LUT=True,
472
- verbose=1,
473
- ):
1381
+ name: str,
1382
+ fileroot: str,
1383
+ anatname: str | None = None,
1384
+ geommaskname: str | None = None,
1385
+ funcmaskname: str | None = None,
1386
+ graymaskspec: str | None = None,
1387
+ whitemaskspec: str | None = None,
1388
+ userise: bool = False,
1389
+ usecorrout: bool = False,
1390
+ useatlas: bool = False,
1391
+ minimal: bool = False,
1392
+ forcetr: bool = False,
1393
+ forceoffset: bool = False,
1394
+ coordinatespace: str = "unspecified",
1395
+ offsettime: float = 0.0,
1396
+ init_LUT: bool = True,
1397
+ verbose: int = 0,
1398
+ ) -> None:
1399
+ """
1400
+ Initialize a RapidtideDataset object for processing neuroimaging data.
1401
+
1402
+ This constructor sets up the dataset configuration based on provided parameters,
1403
+ determines the naming convention used by the dataset (BIDS or legacy), and
1404
+ initializes internal structures for regressor and overlay handling.
1405
+
1406
+ Parameters
1407
+ ----------
1408
+ name : str
1409
+ Name of the dataset.
1410
+ fileroot : str
1411
+ Root path to the dataset files.
1412
+ anatname : str, optional
1413
+ Path to the anatomical image file. Default is None.
1414
+ geommaskname : str, optional
1415
+ Path to the geometric mask file. Default is None.
1416
+ funcmaskname : str, optional
1417
+ Path to the functional mask file. Default is None.
1418
+ graymaskspec : str, optional
1419
+ Specification for gray matter mask. Default is None.
1420
+ whitemaskspec : str, optional
1421
+ Specification for white matter mask. Default is None.
1422
+ userise : bool, optional
1423
+ Whether to use RISE (reconstruction of instantaneous signal estimates). Default is False.
1424
+ usecorrout : bool, optional
1425
+ Whether to use corrected output. Default is False.
1426
+ useatlas : bool, optional
1427
+ Whether to use atlas-based processing. Default is False.
1428
+ minimal : bool, optional
1429
+ Whether to run in minimal mode. Default is False.
1430
+ forcetr : bool, optional
1431
+ Whether to force TR (repetition time) correction. Default is False.
1432
+ forceoffset : bool, optional
1433
+ Whether to force offset correction. Default is False.
1434
+ coordinatespace : str, optional
1435
+ Coordinate space of the data. Default is "unspecified".
1436
+ offsettime : float, optional
1437
+ Time offset to apply. Default is 0.0.
1438
+ init_LUT : bool, optional
1439
+ Whether to initialize lookup tables. Default is True.
1440
+ verbose : int, optional
1441
+ Verbosity level. Default is 0.
1442
+
1443
+ Returns
1444
+ -------
1445
+ None
1446
+ This method initializes the object and does not return any value.
1447
+
1448
+ Notes
1449
+ -----
1450
+ The function automatically detects whether the dataset uses BIDS-style naming
1451
+ conventions by checking for the presence of specific files like
1452
+ ``<fileroot>desc-maxtime_map.nii.gz``. If not found, it checks for legacy naming
1453
+ patterns such as ``<fileroot>fitmask.nii.gz``.
1454
+
1455
+ Examples
1456
+ --------
1457
+ >>> dataset = RapidtideDataset(
1458
+ ... name="test_dataset",
1459
+ ... fileroot="/path/to/data",
1460
+ ... anatname="/path/to/anat.nii.gz",
1461
+ ... verbose=1
1462
+ ... )
1463
+ """
474
1464
  self.verbose = verbose
475
1465
  self.name = name
476
1466
  self.fileroot = fileroot
477
1467
  self.anatname = anatname
478
1468
  self.geommaskname = geommaskname
1469
+ self.funcmaskname = funcmaskname
479
1470
  self.graymaskspec = graymaskspec
480
1471
  self.whitemaskspec = whitemaskspec
481
1472
  self.userise = userise
@@ -509,7 +1500,47 @@ class RapidtideDataset:
509
1500
  self.setupregressors()
510
1501
  self.setupoverlays()
511
1502
 
512
- def _loadregressors(self):
1503
+ def _loadregressors(self) -> None:
1504
+ """
1505
+ Load regressor timecourses from specified files.
1506
+
1507
+ This method iterates through the list of regressor specifications (`self.regressorspecs`)
1508
+ and attempts to load each regressor from the corresponding file. If a file exists, it is
1509
+ read into a `Timecourse` object and stored in `self.regressors`. If no regressor is
1510
+ successfully loaded, the first one in the list is set as the focus regressor.
1511
+
1512
+ Parameters
1513
+ ----------
1514
+ self : object
1515
+ The instance of the class containing the method. Expected to have the following
1516
+ attributes:
1517
+ - `regressorspecs`: list of tuples specifying regressor files and parameters.
1518
+ - `fileroot`: string, base path for regressor files.
1519
+ - `regressors`: dict, to store loaded regressors.
1520
+ - `focusregressor`: str, name of the currently focused regressor.
1521
+ - `verbose`: int, level of verbosity for logging.
1522
+ - `bidsformat`: bool, flag indicating BIDS format usage.
1523
+ - `regressorsimcalclimits`: tuple, limits for regressor calculation.
1524
+ - `isbids`: bool, flag indicating BIDS format usage (likely a typo for `bidsformat`).
1525
+
1526
+ Returns
1527
+ -------
1528
+ None
1529
+ This method modifies the instance's attributes in place and does not return any value.
1530
+
1531
+ Notes
1532
+ -----
1533
+ - If a regressor file does not exist and the corresponding flag in `regressorspecs` is True,
1534
+ a `FileNotFoundError` is raised.
1535
+ - If a regressor file does not exist and the flag is False, the file is skipped with a message.
1536
+ - The first successfully loaded regressor is set as the `focusregressor` if none is already set.
1537
+
1538
+ Examples
1539
+ --------
1540
+ >>> loader = MyLoader()
1541
+ >>> loader._loadregressors()
1542
+ # Loads regressors specified in `loader.regressorspecs` into `loader.regressors`.
1543
+ """
513
1544
  self.focusregressor = None
514
1545
  for thisregressor in self.regressorspecs:
515
1546
  if os.path.isfile(self.fileroot + thisregressor[2]):
@@ -525,6 +1556,7 @@ class RapidtideDataset:
525
1556
  label=thisregressor[1],
526
1557
  starttime=thisregressor[5],
527
1558
  isbids=self.bidsformat,
1559
+ limits=self.regressorsimcalclimits,
528
1560
  verbose=self.verbose,
529
1561
  )
530
1562
  if theregressor.timedata is not None:
@@ -534,14 +1566,59 @@ class RapidtideDataset:
534
1566
  if self.focusregressor is None:
535
1567
  self.focusregressor = thisregressor[0]
536
1568
  else:
537
- if self.verbose > 1:
538
- print(
539
- "file: ",
540
- self.fileroot + thisregressor[2],
541
- " does not exist - skipping...",
1569
+ if thisregressor[6]:
1570
+ raise FileNotFoundError(
1571
+ f"regressor file {self.fileroot + thisregressor[2]} does not exist"
542
1572
  )
543
-
544
- def _loadfuncmaps(self):
1573
+ else:
1574
+ if self.verbose > 1:
1575
+ print(
1576
+ "file: ",
1577
+ self.fileroot + thisregressor[2],
1578
+ " does not exist - skipping...",
1579
+ )
1580
+
1581
+ def _loadfuncmaps(self) -> None:
1582
+ """
1583
+ Load functional maps from NIfTI files and initialize overlays.
1584
+
1585
+ This function iterates through the list of functional maps specified in
1586
+ `self.funcmaps`, loads each map from a NIfTI file (if it exists), and
1587
+ initializes an `Overlay` object for each. It ensures that all loaded
1588
+ maps have consistent dimensions and voxel sizes. If a map is listed in
1589
+ `mapstoinvert`, it will be inverted upon loading.
1590
+
1591
+ Parameters
1592
+ ----------
1593
+ None
1594
+
1595
+ Returns
1596
+ -------
1597
+ None
1598
+ This function does not return a value but updates the following
1599
+ instance attributes:
1600
+ - `self.overlays`: Dictionary mapping map names to `Overlay` objects.
1601
+ - `self.loadedfuncmaps`: List of successfully loaded map names.
1602
+
1603
+ Notes
1604
+ -----
1605
+ - The function checks for the existence of `.nii.gz` files before attempting
1606
+ to load them.
1607
+ - If dimensions or voxel sizes of the loaded maps do not match, the program
1608
+ will exit with an error message.
1609
+ - Map names in `mapstoinvert` (currently only "varChange") will be inverted
1610
+ during loading.
1611
+
1612
+ Examples
1613
+ --------
1614
+ Assuming `self.funcmaps` contains entries like:
1615
+ [("varChange", "varchange_map"), ("tstat", "tstat_map")]
1616
+
1617
+ And the corresponding files exist, this function will load these maps and
1618
+ store them in `self.overlays` with appropriate inversion applied where
1619
+ needed.
1620
+ """
1621
+ mapstoinvert = ["varChange"]
545
1622
  self.loadedfuncmaps = []
546
1623
  xdim = 0
547
1624
  ydim = 0
@@ -557,12 +1634,17 @@ class RapidtideDataset:
557
1634
  " exists - reading...",
558
1635
  )
559
1636
  thepath, thebase = os.path.split(self.fileroot)
1637
+ if mapname in mapstoinvert:
1638
+ invertthismap = True
1639
+ else:
1640
+ invertthismap = False
560
1641
  self.overlays[mapname] = Overlay(
561
1642
  mapname,
562
1643
  self.fileroot + mapfilename + ".nii.gz",
563
1644
  thebase,
564
1645
  init_LUT=self.init_LUT,
565
1646
  report=True,
1647
+ invertonload=invertthismap,
566
1648
  verbose=self.verbose,
567
1649
  )
568
1650
  if xdim == 0:
@@ -596,7 +1678,53 @@ class RapidtideDataset:
596
1678
  if self.verbose > 1:
597
1679
  print("functional maps loaded:", self.loadedfuncmaps)
598
1680
 
599
- def _loadfuncmasks(self):
1681
+ def _loadfuncmasks(self) -> None:
1682
+ """
1683
+ Load functional masks from specified files and create overlay objects.
1684
+
1685
+ This method iterates through the functional masks defined in `self.funcmasks`
1686
+ and attempts to load each mask file. If a mask file exists, it creates an
1687
+ Overlay object and stores it in `self.overlays` with the mask name as key.
1688
+
1689
+ Parameters
1690
+ ----------
1691
+ self : object
1692
+ The instance containing the following attributes:
1693
+ - funcmasks : list of tuples
1694
+ List of (maskname, maskfilename) pairs to load
1695
+ - fileroot : str
1696
+ Root directory path for mask files
1697
+ - overlays : dict
1698
+ Dictionary to store loaded overlay objects
1699
+ - verbose : int
1700
+ Verbosity level for printing status messages
1701
+ - init_LUT : bool, optional
1702
+ Flag to initialize lookup table for overlays
1703
+ - loadedfuncmasks : list
1704
+ List to store names of successfully loaded masks
1705
+
1706
+ Returns
1707
+ -------
1708
+ None
1709
+ This method modifies instance attributes in-place and does not return a value.
1710
+
1711
+ Notes
1712
+ -----
1713
+ - Mask files are expected to have .nii.gz extension
1714
+ - Only masks that exist at the constructed file path are loaded
1715
+ - Progress information is printed based on verbosity level
1716
+ - Successfully loaded mask names are stored in `self.loadedfuncmasks`
1717
+
1718
+ Examples
1719
+ --------
1720
+ >>> # Assuming self.funcmasks = [('mask1', 'mask1_file'), ('mask2', 'mask2_file')]
1721
+ >>> # and mask files exist at self.fileroot + maskfilename + ".nii.gz"
1722
+ >>> _loadfuncmasks()
1723
+ >>> print(self.loadedfuncmasks)
1724
+ ['mask1', 'mask2']
1725
+ >>> print(self.overlays['mask1'])
1726
+ <Overlay object at 0x...>
1727
+ """
600
1728
  self.loadedfuncmasks = []
601
1729
  for maskname, maskfilename in self.funcmasks:
602
1730
  if self.verbose > 1:
@@ -622,7 +1750,91 @@ class RapidtideDataset:
622
1750
  if self.verbose > 1:
623
1751
  print(self.loadedfuncmasks)
624
1752
 
625
- def _loadgeommask(self):
1753
+ def _genpmasks(self, pvals: list[float] = [0.05, 0.01, 0.005, 0.001]) -> None:
1754
+ """
1755
+ Generate binary masks for specified p-value thresholds from negative log10 p-values.
1756
+
1757
+ This function creates binary masks based on negative log10 p-values stored in
1758
+ self.overlays["neglog10p"]. Each mask represents regions where the negative
1759
+ log10 p-values exceed the specified threshold.
1760
+
1761
+ Parameters
1762
+ ----------
1763
+ pvals : list of float, optional
1764
+ List of p-value thresholds for mask generation. Default is [0.05, 0.01, 0.005, 0.001].
1765
+ Each threshold is converted to a mask name format "p_lt_{threshold}_mask".
1766
+
1767
+ Returns
1768
+ -------
1769
+ None
1770
+ This function modifies the instance's overlays and loadedfuncmasks attributes
1771
+ in-place and does not return any value.
1772
+
1773
+ Notes
1774
+ -----
1775
+ - Mask names are formatted to replace "0.0" with "0p0" (e.g., "0.05" becomes "0p05")
1776
+ - The function uses the last loaded functional mask as the base for duplication
1777
+ - Generated masks are stored in self.overlays dictionary with corresponding names
1778
+ - The function updates self.loadedfuncmasks with the names of newly created masks
1779
+
1780
+ Examples
1781
+ --------
1782
+ >>> _genpmasks([0.05, 0.01])
1783
+ # Generates masks for p-values 0.05 and 0.01 based on neglog10p data
1784
+
1785
+ >>> _genpmasks()
1786
+ # Generates masks for default p-values [0.05, 0.01, 0.005, 0.001]
1787
+ """
1788
+ for thepval in pvals:
1789
+ maskname = f"p_lt_{thepval:.3f}_mask".replace("0.0", "0p0")
1790
+ nlpthresh = -np.log10(thepval)
1791
+ if self.verbose > 1:
1792
+ print(f"generating {maskname} from neglog10p")
1793
+ self.overlays[maskname] = self.overlays[self.loadedfuncmasks[-1]].duplicate(
1794
+ maskname, None, self.init_LUT
1795
+ )
1796
+ self.overlays[maskname].setData(
1797
+ np.where(self.overlays["neglog10p"].data > nlpthresh, 1.0, 0.0), isaMask=True
1798
+ )
1799
+ self.loadedfuncmasks.append(maskname)
1800
+ if self.verbose > 1:
1801
+ print(self.loadedfuncmasks)
1802
+
1803
+ def _loadgeommask(self) -> bool:
1804
+ """
1805
+ Load a geometric mask based on configuration settings and available files.
1806
+
1807
+ This function attempts to load a geometric mask either from a user-specified
1808
+ file or from a default location based on the coordinate space and voxel size.
1809
+ The mask is stored in `self.overlays["geommask"]` if successfully loaded.
1810
+
1811
+ Returns
1812
+ -------
1813
+ bool
1814
+ True if a geometric mask was successfully loaded, False otherwise.
1815
+
1816
+ Notes
1817
+ -----
1818
+ - If `self.geommaskname` is set, the function attempts to load the mask from that file.
1819
+ - If `self.coordinatespace` is "MNI152", the function searches for a default mask
1820
+ based on the voxel size (`xsize`, `ysize`, `zsize`).
1821
+ - The function uses the FSL directory to locate default masks when available.
1822
+ - Verbose output is printed if `self.verbose` is greater than 1.
1823
+
1824
+ Examples
1825
+ --------
1826
+ >>> loader = SomeClass()
1827
+ >>> loader.geommaskname = "/path/to/custom_mask.nii.gz"
1828
+ >>> loader._loadgeommask()
1829
+ True
1830
+
1831
+ >>> loader.coordinatespace = "MNI152"
1832
+ >>> loader.xsize = 2.0
1833
+ >>> loader.ysize = 2.0
1834
+ >>> loader.zsize = 2.0
1835
+ >>> loader._loadgeommask()
1836
+ True # if default mask is found
1837
+ """
626
1838
  if self.geommaskname is not None:
627
1839
  if os.path.isfile(self.geommaskname):
628
1840
  thepath, thebase = os.path.split(self.geommaskname)
@@ -677,7 +1889,46 @@ class RapidtideDataset:
677
1889
  print("no geometric mask loaded")
678
1890
  return False
679
1891
 
680
- def _loadanatomics(self):
1892
+ def _loadanatomics(self) -> bool:
1893
+ """
1894
+ Load anatomic image data based on available files and coordinate space settings.
1895
+
1896
+ This method attempts to load anatomic images from various possible sources,
1897
+ prioritizing user-specified files, high-resolution templates, MNI templates,
1898
+ and mean-based images. The loaded image is stored in `self.overlays["anatomic"]`.
1899
+
1900
+ Returns
1901
+ -------
1902
+ bool
1903
+ True if anatomic image was successfully loaded, False otherwise.
1904
+
1905
+ Notes
1906
+ -----
1907
+ The method checks for the following files in order:
1908
+ 1. User-specified anatomic file (`self.anatname`)
1909
+ 2. High-resolution head image: `highres_head.nii.gz`
1910
+ 3. High-resolution image: `highres.nii.gz`
1911
+ 4. MNI152 template based on resolution (`xsize`, `ysize`, `zsize`)
1912
+ 5. MNI152NLin2009cAsym template based on resolution
1913
+ 6. Mean image: `mean.nii.gz`
1914
+ 7. Mean value image: `meanvalue.nii.gz`
1915
+ 8. Described mean image: `desc-unfiltmean_map.nii.gz`
1916
+ 9. Described mean image: `desc-mean_map.nii.gz`
1917
+
1918
+ If `FSLDIR` environment variable is set, it is used to locate MNI152 templates
1919
+ with 2mm resolution.
1920
+
1921
+ Examples
1922
+ --------
1923
+ >>> loader = MyLoader()
1924
+ >>> loader.fileroot = "/path/to/data/"
1925
+ >>> loader.coordinatespace = "MNI152"
1926
+ >>> loader.xsize = 2.0
1927
+ >>> loader.ysize = 2.0
1928
+ >>> loader.zsize = 2.0
1929
+ >>> loader._loadanatomics()
1930
+ True
1931
+ """
681
1932
  try:
682
1933
  fsldir = os.environ["FSLDIR"]
683
1934
  except KeyError:
@@ -815,6 +2066,23 @@ class RapidtideDataset:
815
2066
  print("using ", self.fileroot + "meanvalue.nii.gz", " as background")
816
2067
  # allloadedmaps.append('anatomic')
817
2068
  return True
2069
+ elif os.path.isfile(self.fileroot + "desc-unfiltmean_map.nii.gz"):
2070
+ thepath, thebase = os.path.split(self.fileroot)
2071
+ self.overlays["anatomic"] = Overlay(
2072
+ "anatomic",
2073
+ self.fileroot + "desc-unfiltmean_map.nii.gz",
2074
+ thebase,
2075
+ init_LUT=self.init_LUT,
2076
+ verbose=self.verbose,
2077
+ )
2078
+ if self.verbose > 1:
2079
+ print(
2080
+ "using ",
2081
+ self.fileroot + "desc-unfiltmean_map.nii.gz",
2082
+ " as background",
2083
+ )
2084
+ # allloadedmaps.append('anatomic')
2085
+ return True
818
2086
  elif os.path.isfile(self.fileroot + "desc-mean_map.nii.gz"):
819
2087
  thepath, thebase = os.path.split(self.fileroot)
820
2088
  self.overlays["anatomic"] = Overlay(
@@ -837,7 +2105,33 @@ class RapidtideDataset:
837
2105
  print("no anatomic image loaded")
838
2106
  return False
839
2107
 
840
- def _loadgraymask(self):
2108
+ def _loadgraymask(self) -> bool:
2109
+ """
2110
+ Load gray matter mask from specification.
2111
+
2112
+ Load a gray matter mask from the file specification stored in `self.graymaskspec`.
2113
+ If successful, the mask is stored in `self.overlays["graymask"]` and the function
2114
+ returns True. If no mask specification is provided or the file doesn't exist,
2115
+ the function returns False.
2116
+
2117
+ Returns
2118
+ -------
2119
+ bool
2120
+ True if gray matter mask was successfully loaded, False otherwise.
2121
+
2122
+ Notes
2123
+ -----
2124
+ This function checks if `self.graymaskspec` is not None and if the specified
2125
+ file exists. If both conditions are met, it creates an Overlay object for the
2126
+ gray mask and stores it in `self.overlays["graymask"]`. The function also
2127
+ prints verbose messages when loading or skipping the mask.
2128
+
2129
+ Examples
2130
+ --------
2131
+ >>> loaded = self._loadgraymask()
2132
+ >>> print(loaded)
2133
+ True
2134
+ """
841
2135
  if self.graymaskspec is not None:
842
2136
  filename, dummy = tide_io.parsefilespec(self.graymaskspec)
843
2137
  if os.path.isfile(filename):
@@ -859,7 +2153,39 @@ class RapidtideDataset:
859
2153
  print("no gray mask loaded")
860
2154
  return False
861
2155
 
862
- def _loadwhitemask(self):
2156
+ def _loadwhitemask(self) -> bool:
2157
+ """
2158
+ Load white matter mask from specification if available.
2159
+
2160
+ This method attempts to load a white matter mask from the specification
2161
+ stored in `self.whitemaskspec`. If the specification is valid and the
2162
+ corresponding file exists, it creates an Overlay object for the white
2163
+ matter mask and stores it in `self.overlays["whitemask"]`.
2164
+
2165
+ Parameters
2166
+ ----------
2167
+ self : object
2168
+ The instance containing the white matter mask specification and
2169
+ overlay storage.
2170
+
2171
+ Returns
2172
+ -------
2173
+ bool
2174
+ True if white matter mask was successfully loaded, False otherwise.
2175
+
2176
+ Notes
2177
+ -----
2178
+ The method checks if `self.whitemaskspec` is not None and if the
2179
+ specified file exists before attempting to load it. If successful,
2180
+ the mask is stored in `self.overlays["whitemask"]` and a verbose
2181
+ message is printed if `self.verbose` is greater than 1.
2182
+
2183
+ Examples
2184
+ --------
2185
+ >>> loaded = self._loadwhitemask()
2186
+ >>> print(loaded)
2187
+ True
2188
+ """
863
2189
  if self.whitemaskspec is not None:
864
2190
  filename, dummy = tide_io.parsefilespec(self.whitemaskspec)
865
2191
  if os.path.isfile(filename):
@@ -881,7 +2207,42 @@ class RapidtideDataset:
881
2207
  print("no white mask loaded")
882
2208
  return False
883
2209
 
884
- def setupregressors(self):
2210
+ def setupregressors(self) -> None:
2211
+ """
2212
+ Set up regressor specifications and load regressor data.
2213
+
2214
+ This method initializes the regressor specifications based on the BIDS format
2215
+ and the run options, and loads the corresponding regressor data. It handles
2216
+ various configuration parameters such as filter limits, sampling frequencies,
2217
+ and similarity metrics, and prepares a list of regressor specifications for
2218
+ use in subsequent processing steps.
2219
+
2220
+ Parameters
2221
+ ----------
2222
+ None
2223
+
2224
+ Returns
2225
+ -------
2226
+ None
2227
+ This method does not return any value but updates the instance attributes
2228
+ `regressors`, `regressorfilterlimits`, `fmrifreq`, `inputfreq`,
2229
+ `inputstarttime`, `oversampfactor`, `similaritymetric`, `regressorsimcalclimits`,
2230
+ `numberofpasses`, and `regressorspecs`.
2231
+
2232
+ Notes
2233
+ -----
2234
+ - The method reads run options from a file specified by `self.fileroot + "desc-runoptions_info"`.
2235
+ - If `self.bidsformat` is True, the regressor files are named according to BIDS conventions.
2236
+ - The method determines the number of passes and sets up the regressor specifications accordingly.
2237
+ - The `regressorspecs` list contains information for loading regressors at different stages:
2238
+ pre-filtered, post-filtered, and multiple passes, with associated file names, frequencies,
2239
+ and time offsets.
2240
+
2241
+ Examples
2242
+ --------
2243
+ >>> setupregressors()
2244
+ # Updates instance attributes with regressor configurations and loads data.
2245
+ """
885
2246
  # load the regressors
886
2247
  self.regressors = {}
887
2248
  self.therunoptions = tide_io.readoptionsfile(self.fileroot + "desc-runoptions_info")
@@ -942,6 +2303,7 @@ class RapidtideDataset:
942
2303
  self.inputfreq,
943
2304
  self.inputfreq,
944
2305
  self.inputstarttime,
2306
+ True,
945
2307
  ],
946
2308
  [
947
2309
  "postfilt",
@@ -950,6 +2312,7 @@ class RapidtideDataset:
950
2312
  self.inputfreq,
951
2313
  self.inputfreq,
952
2314
  self.inputstarttime,
2315
+ True,
953
2316
  ],
954
2317
  [
955
2318
  "pass1",
@@ -958,6 +2321,7 @@ class RapidtideDataset:
958
2321
  self.fmrifreq * self.oversampfactor,
959
2322
  self.fmrifreq,
960
2323
  0.0,
2324
+ True,
961
2325
  ],
962
2326
  [
963
2327
  "pass2",
@@ -966,6 +2330,7 @@ class RapidtideDataset:
966
2330
  self.fmrifreq * self.oversampfactor,
967
2331
  self.fmrifreq,
968
2332
  0.0,
2333
+ False,
969
2334
  ],
970
2335
  [
971
2336
  "pass3",
@@ -974,6 +2339,7 @@ class RapidtideDataset:
974
2339
  self.fmrifreq * self.oversampfactor,
975
2340
  self.fmrifreq,
976
2341
  0.0,
2342
+ False,
977
2343
  ],
978
2344
  [
979
2345
  "pass4",
@@ -982,6 +2348,7 @@ class RapidtideDataset:
982
2348
  self.fmrifreq * self.oversampfactor,
983
2349
  self.fmrifreq,
984
2350
  0.0,
2351
+ False,
985
2352
  ],
986
2353
  ]
987
2354
  else:
@@ -993,6 +2360,7 @@ class RapidtideDataset:
993
2360
  self.inputfreq,
994
2361
  self.inputfreq,
995
2362
  self.inputstarttime,
2363
+ True,
996
2364
  ],
997
2365
  [
998
2366
  "postfilt",
@@ -1001,6 +2369,7 @@ class RapidtideDataset:
1001
2369
  self.inputfreq,
1002
2370
  self.inputfreq,
1003
2371
  self.inputstarttime,
2372
+ True,
1004
2373
  ],
1005
2374
  [
1006
2375
  "pass1",
@@ -1009,6 +2378,7 @@ class RapidtideDataset:
1009
2378
  self.fmrifreq * self.oversampfactor,
1010
2379
  self.fmrifreq,
1011
2380
  0.0,
2381
+ True,
1012
2382
  ],
1013
2383
  [
1014
2384
  "pass2",
@@ -1017,6 +2387,7 @@ class RapidtideDataset:
1017
2387
  self.fmrifreq * self.oversampfactor,
1018
2388
  self.fmrifreq,
1019
2389
  0.0,
2390
+ False,
1020
2391
  ],
1021
2392
  [
1022
2393
  "pass3",
@@ -1025,6 +2396,7 @@ class RapidtideDataset:
1025
2396
  self.fmrifreq * self.oversampfactor,
1026
2397
  self.fmrifreq,
1027
2398
  0.0,
2399
+ False,
1028
2400
  ],
1029
2401
  [
1030
2402
  "pass4",
@@ -1033,17 +2405,139 @@ class RapidtideDataset:
1033
2405
  self.fmrifreq * self.oversampfactor,
1034
2406
  self.fmrifreq,
1035
2407
  0.0,
2408
+ False,
1036
2409
  ],
1037
2410
  ]
1038
2411
  self._loadregressors()
1039
2412
 
1040
- def getregressors(self):
2413
+ def getregressors(self) -> dict:
2414
+ """
2415
+ Return the regressors stored in the object.
2416
+
2417
+ Returns
2418
+ -------
2419
+ dict
2420
+ A dictionary containing the regressors. The keys are typically
2421
+ regressor names and the values are the corresponding regressor objects.
2422
+
2423
+ Notes
2424
+ -----
2425
+ This method provides access to the internal regressors dictionary
2426
+ that stores all regression models used by the object.
2427
+
2428
+ Examples
2429
+ --------
2430
+ >>> model = MyRegressionModel()
2431
+ >>> regressors = model.getregressors()
2432
+ >>> print(regressors)
2433
+ {'linear_reg': LinearRegression(), 'ridge_reg': Ridge()}
2434
+ """
1041
2435
  return self.regressors
1042
2436
 
1043
- def setfocusregressor(self, whichregressor):
1044
- self.focusregressor = whichregressor
1045
-
1046
- def setupoverlays(self):
2437
+ def setfocusregressor(self, whichregressor: str) -> None:
2438
+ """
2439
+ Set the focus regressor for the current instance.
2440
+
2441
+ This method sets the focus regressor to the specified regressor name if it exists
2442
+ in the regressors dictionary. If the specified regressor does not exist, it defaults
2443
+ to "prefilt".
2444
+
2445
+ Parameters
2446
+ ----------
2447
+ whichregressor : str
2448
+ The name of the regressor to set as the focus regressor. This should be a key
2449
+ present in the instance's regressors dictionary.
2450
+
2451
+ Returns
2452
+ -------
2453
+ None
2454
+ This method does not return any value.
2455
+
2456
+ Notes
2457
+ -----
2458
+ If the specified regressor name is not found in self.regressors, the method will
2459
+ automatically fall back to setting the focus regressor to "prefilt".
2460
+
2461
+ Examples
2462
+ --------
2463
+ >>> instance.setfocusregressor("regressor1")
2464
+ >>> print(instance.focusregressor)
2465
+ 'regressor1'
2466
+
2467
+ >>> instance.setfocusregressor("nonexistent")
2468
+ >>> print(instance.focusregressor)
2469
+ 'prefilt'
2470
+ """
2471
+ try:
2472
+ testregressor = self.regressors[whichregressor]
2473
+ self.focusregressor = whichregressor
2474
+ except KeyError:
2475
+ self.focusregressor = "prefilt"
2476
+
2477
+ def setupoverlays(self) -> None:
2478
+ """
2479
+ Set up and load all overlays for functional and anatomical data.
2480
+
2481
+ This function initializes the overlays dictionary and loads various functional
2482
+ maps, masks, and anatomical data based on the configuration parameters such as
2483
+ BIDS format, use of correlation outputs, and coordinate space. It also handles
2484
+ setting TR and time offset values for the loaded maps, and loads additional
2485
+ data such as atlases and tissue masks if applicable.
2486
+
2487
+ Parameters
2488
+ ----------
2489
+ self : object
2490
+ The instance of the class containing this method. Expected to have the
2491
+ following attributes:
2492
+
2493
+ - bidsformat : bool
2494
+ Indicates whether the data is in BIDS format.
2495
+ - usecorrout : bool
2496
+ Whether to include correlation output maps.
2497
+ - newstylenames : bool
2498
+ Whether to use new-style naming conventions for maps.
2499
+ - userise : bool
2500
+ Whether to include rise time-related maps.
2501
+ - forcetr : bool
2502
+ Whether to force TR value for loaded maps.
2503
+ - forceoffset : bool
2504
+ Whether to force time offset for loaded maps.
2505
+ - trval : float
2506
+ The TR value to be set if `forcetr` is True.
2507
+ - offsettime : float
2508
+ The time offset to be set if `forceoffset` is True.
2509
+ - verbose : int
2510
+ Verbosity level for output messages.
2511
+ - referencedir : str
2512
+ Directory containing reference data such as atlases.
2513
+ - init_LUT : bool
2514
+ Whether to initialize lookup tables for overlays.
2515
+ - useatlas : bool
2516
+ Whether to load atlas data.
2517
+ - coordinatespace : str
2518
+ The coordinate space of the data (e.g., "MNI152", "MNI152NLin2009cAsym").
2519
+
2520
+ Returns
2521
+ -------
2522
+ None
2523
+ This function does not return any value. It modifies the instance's
2524
+ attributes in place.
2525
+
2526
+ Notes
2527
+ -----
2528
+ - Functional maps are loaded based on the BIDS format and naming conventions.
2529
+ - The function dynamically builds lists of functional maps and masks depending
2530
+ on the configuration.
2531
+ - If an atlas is to be used and the coordinate space is compatible, it will be
2532
+ loaded and added to the overlays.
2533
+ - The function sets up several instance variables such as `xdim`, `ydim`, `zdim`,
2534
+ `tdim`, `xsize`, `ysize`, `zsize`, and `tr` from the focus map.
2535
+
2536
+ Examples
2537
+ --------
2538
+ >>> setupoverlays()
2539
+ # Loads all overlays and sets up the instance for further processing.
2540
+ """
1047
2541
  # load the overlays
1048
2542
  self.overlays = {}
1049
2543
 
@@ -1051,13 +2545,22 @@ class RapidtideDataset:
1051
2545
  if self.bidsformat:
1052
2546
  self.funcmaps = [
1053
2547
  ["lagtimes", "desc-maxtime_map"],
2548
+ ["lagtimesrefined", "desc-maxtimerefined_map"],
1054
2549
  ["timepercentile", "desc-timepercentile_map"],
1055
2550
  ["lagstrengths", "desc-maxcorr_map"],
2551
+ ["lagstrengthsrefined", "desc-maxcorrrefined_map"],
1056
2552
  ["lagsigma", "desc-maxwidth_map"],
1057
2553
  ["MTT", "desc-MTT_map"],
1058
2554
  ["R2", "desc-lfofilterR2_map"],
2555
+ ["CoV", "desc-CoV_map"],
2556
+ ["confoundR2", "desc-confoundfilterR2_map"],
2557
+ ["varBefore", "desc-lfofilterInbandVarianceBefore_map"],
2558
+ ["varAfter", "desc-lfofilterInbandVarianceAfter_map"],
2559
+ ["varChange", "desc-lfofilterInbandVarianceChange_map"],
1059
2560
  ["fitNorm", "desc-lfofilterNorm_map"],
1060
2561
  ["fitcoff", "desc-lfofilterCoeff_map"],
2562
+ ["neglog10p", "desc-neglog10p_map"],
2563
+ ["delayoffset", "desc-delayoffset_map"],
1061
2564
  ]
1062
2565
  if self.usecorrout:
1063
2566
  self.funcmaps += [["corrout", "desc-corrout_info"]]
@@ -1146,12 +2649,17 @@ class RapidtideDataset:
1146
2649
  ["lagmask", "desc-corrfit_mask"],
1147
2650
  ["refinemask", "desc-refine_mask"],
1148
2651
  ["meanmask", "desc-globalmean_mask"],
2652
+ ["brainmask", "desc-brainmask_mask"],
1149
2653
  ["preselectmask", "desc-globalmeanpreselect_mask"],
1150
- ["p_lt_0p050_mask", "desc-plt0p050_mask"],
1151
- ["p_lt_0p010_mask", "desc-plt0p010_mask"],
1152
- ["p_lt_0p005_mask", "desc-plt0p005_mask"],
1153
- ["p_lt_0p001_mask", "desc-plt0p001_mask"],
1154
2654
  ]
2655
+ if not ("neglog10p" in self.loadedfuncmaps):
2656
+ # load p maps manually
2657
+ self.funcmasks += [
2658
+ ["p_lt_0p050_mask", "desc-plt0p050_mask"],
2659
+ ["p_lt_0p010_mask", "desc-plt0p010_mask"],
2660
+ ["p_lt_0p005_mask", "desc-plt0p005_mask"],
2661
+ ["p_lt_0p001_mask", "desc-plt0p001_mask"],
2662
+ ]
1155
2663
  else:
1156
2664
  if self.newstylenames:
1157
2665
  self.funcmasks = [
@@ -1174,6 +2682,9 @@ class RapidtideDataset:
1174
2682
  ["p_lt_0p001_mask", "p_lt_0p001_mask"],
1175
2683
  ]
1176
2684
  self._loadfuncmasks()
2685
+ if "neglog10p" in self.loadedfuncmaps:
2686
+ # generate p maps on the fly
2687
+ self._genpmasks()
1177
2688
 
1178
2689
  # then the geometric masks
1179
2690
  if self._loadgeommask():
@@ -1190,8 +2701,7 @@ class RapidtideDataset:
1190
2701
  or (self.coordinatespace == "MNI152NLin6")
1191
2702
  or (self.coordinatespace == "MNI152NLin2009cAsym")
1192
2703
  ):
1193
- # atlasname = 'ASPECTS'
1194
- self.atlasshortname = "ATT"
2704
+ self.atlasshortname = "JHU1"
1195
2705
  self.atlasname = atlases[self.atlasshortname]["atlasname"]
1196
2706
  self.atlaslabels = tide_io.readlabels(
1197
2707
  os.path.join(self.referencedir, self.atlasname + "_regions.txt")
@@ -1200,19 +2710,20 @@ class RapidtideDataset:
1200
2710
  print(self.atlaslabels)
1201
2711
  self.atlasniftiname = None
1202
2712
  if self.coordinatespace == "MNI152":
2713
+ spacename = "_space-MNI152NLin6Asym"
1203
2714
  if self.xsize == 2.0 and self.ysize == 2.0 and self.zsize == 2.0:
1204
2715
  self.atlasniftiname = os.path.join(
1205
- self.referencedir, self.atlasname + "_2mm.nii.gz"
2716
+ self.referencedir, self.atlasname + spacename + "_2mm.nii.gz"
1206
2717
  )
1207
2718
  self.atlasmaskniftiname = os.path.join(
1208
- self.referencedir, self.atlasname + "_2mm_mask.nii.gz"
2719
+ self.referencedir, self.atlasname + spacename + "_2mm_mask.nii.gz"
1209
2720
  )
1210
2721
  if self.xsize == 3.0 and self.ysize == 3.0 and self.zsize == 3.0:
1211
2722
  self.atlasniftiname = os.path.join(
1212
- self.referencedir, self.atlasname + "_3mm.nii.gz"
2723
+ self.referencedir, self.atlasname + spacename + "_3mm.nii.gz"
1213
2724
  )
1214
2725
  self.atlasmaskniftiname = os.path.join(
1215
- self.referencedir, self.atlasname + "_3mm_mask.nii.gz"
2726
+ self.referencedir, self.atlasname + spacename + "_3mm_mask.nii.gz"
1216
2727
  )
1217
2728
  else:
1218
2729
  pass
@@ -1256,8 +2767,92 @@ class RapidtideDataset:
1256
2767
  if self.verbose > 1:
1257
2768
  print("done")
1258
2769
 
1259
- def getoverlays(self):
2770
+ def getoverlays(self) -> dict:
2771
+ """
2772
+ Return the overlays dictionary.
2773
+
2774
+ Returns
2775
+ -------
2776
+ dict
2777
+ A dictionary containing the overlays data.
2778
+
2779
+ Notes
2780
+ -----
2781
+ This method provides access to the internal overlays attribute.
2782
+ The returned dictionary contains all overlay data managed by this instance.
2783
+
2784
+ Examples
2785
+ --------
2786
+ >>> overlays = obj.getoverlays()
2787
+ >>> print(overlays)
2788
+ {'overlay1': <OverlayObject>, 'overlay2': <OverlayObject>}
2789
+ """
1260
2790
  return self.overlays
1261
2791
 
1262
- def setfocusmap(self, whichmap):
1263
- self.focusmap = whichmap
2792
+ def setfocusmap(self, whichmap: str) -> None:
2793
+ """
2794
+ Set the focus map to the specified map name.
2795
+
2796
+ This method sets the current focus map to the specified map name if it exists
2797
+ in the overlays dictionary. If the specified map does not exist, it defaults
2798
+ to setting the focus map to "lagtimes".
2799
+
2800
+ Parameters
2801
+ ----------
2802
+ whichmap : str
2803
+ The name of the map to set as the focus map. This should correspond to
2804
+ a key in the self.overlays dictionary.
2805
+
2806
+ Returns
2807
+ -------
2808
+ None
2809
+ This method does not return any value.
2810
+
2811
+ Notes
2812
+ -----
2813
+ If the specified `whichmap` is not found in `self.overlays`, the method
2814
+ will automatically fall back to setting the focus map to "lagtimes".
2815
+
2816
+ Examples
2817
+ --------
2818
+ >>> obj.setfocusmap("temperature")
2819
+ >>> obj.focusmap
2820
+ 'temperature'
2821
+
2822
+ >>> obj.setfocusmap("nonexistent")
2823
+ >>> obj.focusmap
2824
+ 'lagtimes'
2825
+ """
2826
+ try:
2827
+ testmap = self.overlays[whichmap]
2828
+ self.focusmap = whichmap
2829
+ except KeyError:
2830
+ self.focusmap = "lagtimes"
2831
+
2832
+ def setFuncMaskName(self, maskname: str) -> None:
2833
+ """
2834
+ Set the function mask name attribute.
2835
+
2836
+ Parameters
2837
+ ----------
2838
+ maskname : str
2839
+ The name to assign to the function mask attribute.
2840
+
2841
+ Returns
2842
+ -------
2843
+ None
2844
+ This method does not return any value.
2845
+
2846
+ Notes
2847
+ -----
2848
+ This method assigns the provided mask name to the internal `funcmaskname` attribute
2849
+ of the object instance.
2850
+
2851
+ Examples
2852
+ --------
2853
+ >>> obj = MyClass()
2854
+ >>> obj.setFuncMaskName("my_mask")
2855
+ >>> print(obj.funcmaskname)
2856
+ 'my_mask'
2857
+ """
2858
+ self.funcmaskname = maskname