rapidtide 3.0a9__py3-none-any.whl → 3.0a11__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.
@@ -30,7 +30,6 @@ import pandas as pd
30
30
  import pyqtgraph as pg
31
31
  from nibabel.affines import apply_affine
32
32
  from pyqtgraph.Qt import QtCore, QtGui, QtWidgets
33
- from statsmodels.robust.scale import mad
34
33
 
35
34
  import rapidtide.util as tide_util
36
35
  from rapidtide.Colortables import *
@@ -88,7 +87,7 @@ def _get_parser():
88
87
  "--dataset",
89
88
  nargs="*",
90
89
  help=(
91
- "Use this dataset root name (skip initial selection step). The root name is the entire path "
90
+ "Specify one or more dataset root names (skip initial selection step). The root name is the entire path "
92
91
  "to the rapidtide output data (including the underscore) that precedes 'desc-maxtime_map.nii.gz'"
93
92
  ),
94
93
  dest="datafileroot",
@@ -107,8 +106,12 @@ def _get_parser():
107
106
  "--uistyle",
108
107
  action="store",
109
108
  type=str,
110
- choices=["normal", "old", "big"],
111
- help="Set the window layout style. Default is 'normal'.",
109
+ choices=["normal", "big"],
110
+ help=(
111
+ "Set the window layout style. The 'normal' uistyle loads 8 data maps into display panes, "
112
+ "and fits comfortably on the screen of a 14in MacbookPro screen. The 'big' uistyle has 16 display "
113
+ "panes, and fits on a 16in MBP screen. Default is 'normal'."
114
+ ),
112
115
  default="normal",
113
116
  )
114
117
  parser.add_argument(
@@ -121,7 +124,7 @@ def _get_parser():
121
124
  )
122
125
  parser.add_argument(
123
126
  "--ignoredimmatch",
124
- help="Do not check to see if dataset sizes match",
127
+ help="Do not check to see if dataset sizes match. This is almost certainly a terrible idea.",
125
128
  dest="ignoredimmatch",
126
129
  action="store_true",
127
130
  default=False,
@@ -130,7 +133,86 @@ def _get_parser():
130
133
  return parser
131
134
 
132
135
 
133
- def selectFile():
136
+ def addDataset(
137
+ thisdatafileroot,
138
+ anatname=None,
139
+ geommaskname=None,
140
+ userise=False,
141
+ usecorrout=True,
142
+ useatlas=False,
143
+ forcetr=False,
144
+ forceoffset=False,
145
+ offsettime=0.0,
146
+ ignoredimmatch=False,
147
+ ):
148
+ global currentdataset, thesubjects, whichsubject, datafileroots
149
+ global verbosity
150
+
151
+ print("Loading", thisdatafileroot)
152
+ thissubject = RapidtideDataset(
153
+ "main",
154
+ thisdatafileroot,
155
+ anatname=anatname,
156
+ geommaskname=geommaskname,
157
+ userise=userise,
158
+ usecorrout=usecorrout,
159
+ useatlas=useatlas,
160
+ forcetr=forcetr,
161
+ forceoffset=forceoffset,
162
+ offsettime=offsettime,
163
+ verbose=verbosity,
164
+ )
165
+ if len(thesubjects) > 0:
166
+ # check to see that the dimensions match
167
+ dimmatch, sizematch, spacematch, affinematch = check_rt_spatialmatch(
168
+ thissubject, thesubjects[0]
169
+ )
170
+ if dimmatch or ignoredimmatch:
171
+ thesubjects.append(thissubject)
172
+ else:
173
+ print(f"dataset {thisdatafileroot} does not match loaded data - skipping")
174
+ else:
175
+ thesubjects.append(thissubject)
176
+
177
+ # list the datasets
178
+ for idx, subject in enumerate(thesubjects):
179
+ print(f"subject {idx}: {subject.fileroot}")
180
+
181
+
182
+ def updateFileMenu():
183
+ global thesubjects, whichsubject
184
+ global fileMenu, sel_open
185
+ global sel_files
186
+
187
+ if pyqtversion == 5:
188
+ qactionfunc = QtWidgets.QAction
189
+ else:
190
+ qactionfunc = QtGui.QAction
191
+
192
+ # scrub file menu
193
+ if sel_files is not None:
194
+ for sel_file in sel_files:
195
+ fileMenu.removeAction(sel_file)
196
+ del sel_file
197
+
198
+ # now build it back
199
+ if len(thesubjects) > 0:
200
+ sel_files = []
201
+ for idx, subject in enumerate(thesubjects):
202
+ if idx == whichsubject:
203
+ indicator = "\u2714 "
204
+ else:
205
+ indicator = " "
206
+ sel_files.append(qactionfunc(indicator + subject.fileroot, win))
207
+ sel_files[-1].triggered.connect(partial(selectDataset, idx))
208
+ fileMenu.addAction(sel_files[-1])
209
+
210
+
211
+ def datasetPicker():
212
+ global currentdataset, thesubjects, whichsubject, datafileroots
213
+ global ui, win, defaultdict, overlagGraphicsViews
214
+ global verbosity
215
+
134
216
  mydialog = QtWidgets.QFileDialog()
135
217
  if pyqtversion == 5:
136
218
  options = mydialog.Options()
@@ -146,7 +228,36 @@ def selectFile():
146
228
  datafileroot = str(lagfilename[:bidsstartloc])
147
229
  else:
148
230
  datafileroot = str(lagfilename[: lagfilename.find("lagtimes.nii.gz")])
149
- return datafileroot
231
+ datafileroots.append(datafileroot)
232
+ addDataset(datafileroots[-1])
233
+ whichsubject = len(thesubjects) - 1
234
+ selectDataset(whichsubject)
235
+
236
+ # update the file menu
237
+ updateFileMenu()
238
+
239
+
240
+ def selectDataset(thesubject):
241
+ global currentdataset, thesubjects, whichsubject, datafileroots
242
+ global ui, win, defaultdict, overlagGraphicsViews
243
+ global verbosity, uiinitialized
244
+
245
+ whichsubject = thesubject
246
+ if uiinitialized:
247
+ thesubjects[whichsubject].setfocusregressor(currentdataset.focusregressor)
248
+ thesubjects[whichsubject].setfocusmap(currentdataset.focusmap)
249
+ currentdataset = thesubjects[whichsubject]
250
+ activateDataset(
251
+ currentdataset,
252
+ ui,
253
+ win,
254
+ defaultdict,
255
+ overlayGraphicsViews,
256
+ verbosity=verbosity,
257
+ )
258
+
259
+ # update the file menu
260
+ updateFileMenu()
150
261
 
151
262
 
152
263
  class xyztlocation(QtWidgets.QWidget):
@@ -314,10 +425,17 @@ class xyztlocation(QtWidgets.QWidget):
314
425
  # print('resetting T spinbox values')
315
426
  if self.TPosSpinBox is not None:
316
427
  self.TPosSpinBox.setValue(self.tpos)
428
+ self.TPosSpinBox.setRange(0, self.tdim - 1)
317
429
  if self.TCoordSpinBox is not None:
318
430
  self.TCoordSpinBox.setValue(self.tcoord)
431
+ tllcoord = self.tr2real(0)
432
+ tulcoord = self.tr2real(self.tdim - 1)
433
+ tmin = np.min([tllcoord, tulcoord])
434
+ tmax = np.max([tllcoord, tulcoord])
435
+ self.TCoordSpinBox.setRange(tmin, tmax)
319
436
  if self.TimeSlider is not None:
320
437
  self.TimeSlider.setValue((self.tpos))
438
+ self.TimeSlider.setRange(0, self.tdim - 1)
321
439
  # print('done resetting T spinbox values')
322
440
  self.updatedT.emit()
323
441
 
@@ -349,6 +467,8 @@ class xyztlocation(QtWidgets.QWidget):
349
467
  self.updateXYZValues(emitsignal=emitsignal)
350
468
 
351
469
  def setTpos(self, tpos):
470
+ if tpos > self.tdim:
471
+ tpos = self.tdim
352
472
  if self.tpos != tpos:
353
473
  self.tpos = tpos
354
474
  self.tcoord = self.tr2real(self.tpos)
@@ -469,77 +589,7 @@ class xyztlocation(QtWidgets.QWidget):
469
589
  self.movieTimer.start(int(self.frametime))
470
590
 
471
591
 
472
- """class KeyPressWindow(QtWidgets.QMainWindow):
473
- sigKeyPress = QtCore.pyqtSignal(object)
474
-
475
- def __init__(self, *args, **kwargs):
476
- super().__init__(*args, **kwargs)
477
-
478
- def keyPressEvent(self, ev):
479
- self.sigKeyPress.emit(ev)"""
480
-
481
-
482
- def nextFileButtonPressed():
483
- global currentdataset, thesubjects, whichsubject
484
- global defaultdict, overlayGraphicsViews
485
- numsubjects = len(thesubjects)
486
- whichsubject = (whichsubject + 1) % numsubjects
487
- print(f"subject number set to {whichsubject}")
488
- thesubjects[whichsubject].setfocusregressor(currentdataset.focusregressor)
489
- thesubjects[whichsubject].setfocusmap(currentdataset.focusmap)
490
- currentdataset = thesubjects[whichsubject]
491
- activatedataset(
492
- currentdataset,
493
- ui,
494
- win,
495
- defaultdict,
496
- overlayGraphicsViews,
497
- verbosity=verbosity,
498
- doinit=False,
499
- )
500
- updateRegressor()
501
- updateRegressorSpectrum()
502
- updateUI(
503
- callingfunc="nextFileButtonPressed",
504
- orthoimages=True,
505
- histogram=True,
506
- focusvals=True,
507
- )
508
-
509
-
510
- """def keyPressed(evt):
511
- global currentsubject, thesubjects, whichsubject
512
- global defaultdict, overlayGraphicsViews
513
- numsubjects = len(thesubjects)
514
- if evt.key() == QtCore.Qt.Key.Key_F:
515
- whichsubject = (whichsubject + 1) % numsubjects
516
- print("Key_Up")
517
- elif evt.key() == QtCore.Qt.Key.Key_B:
518
- whichsubject = (whichsubject - 1) % numsubjects
519
- print("Key_Down")
520
- elif evt.key() == QtCore.Qt.Key.Key_Left:
521
- whichsubject = (whichsubject - 1) % numsubjects
522
- print("Key_Left")
523
- elif evt.key() == QtCore.Qt.Key.Key_Right:
524
- whichsubject = (whichsubject + 1) % numsubjects
525
- print("Key_Right")
526
- else:
527
- print(evt.key())
528
- print(f"subject number set to {whichsubject}")
529
- currentdataset = thesubjects[whichsubject]
530
- activatedataset(
531
- currentdataset,
532
- ui,
533
- win,
534
- defaultdict,
535
- overlayGraphicsViews,
536
- verbosity=verbosity,
537
- doinit=False,
538
- )
539
- updateOrthoImages()"""
540
-
541
-
542
- def logstatus(thetextbox, thetext):
592
+ def logStatus(thetextbox, thetext):
543
593
  if pyqtversion == 5:
544
594
  thetextbox.moveCursor(QtGui.QTextCursor.End)
545
595
  thetextbox.insertPlainText(thetext + "\n")
@@ -871,7 +921,7 @@ def updateAveragingMode():
871
921
  print("in updateAveragingMode")
872
922
  if ("atlas" in overlays) and (not atlasaveragingdone):
873
923
  calcAtlasStats()
874
- set_atlasmask()
924
+ setAtlasMask()
875
925
  if ("atlas" in overlays) and False:
876
926
  updateAtlasStats()
877
927
  if averagingmode is not None:
@@ -938,7 +988,7 @@ def MAD_radioButton_clicked(enabled):
938
988
  updateAveragingMode()
939
989
 
940
990
 
941
- def transparency_checkbox_clicked():
991
+ def transparencyCheckboxClicked():
942
992
  global LUT_alpha, LUT_endalpha, ui, overlays, currentdataset
943
993
  global verbosity
944
994
 
@@ -1034,7 +1084,7 @@ def rainbow_radioButton_clicked(enabled):
1034
1084
  updateLUT()
1035
1085
 
1036
1086
 
1037
- def set_mask(maskname):
1087
+ def setMask(maskname):
1038
1088
  global overlays, loadedfuncmaps, ui, atlasaveragingdone, currentdataset
1039
1089
  maskinfodicts = {}
1040
1090
  maskinfodicts["nomask"] = {
@@ -1049,6 +1099,10 @@ def set_mask(maskname):
1049
1099
  "msg": "Using valid fit points as functional mask",
1050
1100
  "label": "Valid mask",
1051
1101
  }
1102
+ maskinfodicts["brainmask"] = {
1103
+ "msg": "Externally provided brain mask",
1104
+ "label": "Brain mask",
1105
+ }
1052
1106
  maskinfodicts["refinemask"] = {
1053
1107
  "msg": "Voxel refinement mask",
1054
1108
  "label": "Refine mask",
@@ -1064,6 +1118,7 @@ def set_mask(maskname):
1064
1118
  }
1065
1119
  print(maskinfodicts[maskname]["msg"])
1066
1120
  ui.setMask_Button.setText(maskinfodicts[maskname]["label"])
1121
+ currentdataset.setFuncMaskName(maskname)
1067
1122
  for themap in currentdataset.loadedfuncmaps:
1068
1123
  if maskname == "nomask":
1069
1124
  overlays[themap].setFuncMask(None)
@@ -1071,16 +1126,16 @@ def set_mask(maskname):
1071
1126
  overlays[themap].setFuncMask(overlays[maskname].data)
1072
1127
  atlasaveragingdone = False
1073
1128
  updateAveragingMode()
1074
- updateUI(callingfunc=f"set_mask({maskname})", orthoimages=True, histogram=True)
1129
+ updateUI(callingfunc=f"setMask({maskname})", orthoimages=True, histogram=True)
1075
1130
 
1076
1131
 
1077
- def set_atlasmask():
1132
+ def setAtlasMask():
1078
1133
  global overlays, loadedfuncmaps, ui, currentdataset
1079
1134
  print("Using all defined atlas regions as functional mask")
1080
1135
  ui.setMask_Button.setText("Valid mask")
1081
1136
  for themap in currentdataset.loadedfuncmaps:
1082
1137
  overlays[themap].setFuncMask(overlays["atlasmask"].data)
1083
- updateUI(callingfunc="set_atlasmask", orthoimages=True, histogram=True)
1138
+ updateUI(callingfunc="setAtlasMask", orthoimages=True, histogram=True)
1084
1139
 
1085
1140
 
1086
1141
  def overlay_radioButton_clicked(which, enabled):
@@ -1096,17 +1151,22 @@ def overlay_radioButton_clicked(which, enabled):
1096
1151
  currentdataset.setfocusmap(panetomap[which] + "_atlasstat")
1097
1152
  else:
1098
1153
  currentdataset.setfocusmap(panetomap[which])
1154
+ thedispmin = overlays[currentdataset.focusmap].dispmin
1155
+ thedispmax = overlays[currentdataset.focusmap].dispmax
1099
1156
  if verbosity > 1:
1100
- print("currentdataset.focusmap set to ", currentdataset.focusmap)
1101
- if overlays[currentdataset.focusmap].lut_state == gen_gray_state():
1157
+ print(f"currentdataset.focusmap set to {currentdataset.focusmap}")
1158
+ print(
1159
+ f"overlays[currentdataset.focusmap].LUTname set to {overlays[currentdataset.focusmap].LUTname}"
1160
+ )
1161
+ if overlays[currentdataset.focusmap].LUTname == "gray":
1102
1162
  ui.gray_radioButton.setChecked(True)
1103
- elif overlays[currentdataset.focusmap].lut_state == gen_thermal_state():
1163
+ elif overlays[currentdataset.focusmap].LUTname == "thermal":
1104
1164
  ui.thermal_radioButton.setChecked(True)
1105
- elif overlays[currentdataset.focusmap].lut_state == gen_plasma_state():
1165
+ elif overlays[currentdataset.focusmap].LUTname == "plasma":
1106
1166
  ui.plasma_radioButton.setChecked(True)
1107
- elif overlays[currentdataset.focusmap].lut_state == gen_viridis_state():
1167
+ elif overlays[currentdataset.focusmap].LUTname == "viridis":
1108
1168
  ui.viridis_radioButton.setChecked(True)
1109
- elif overlays[currentdataset.focusmap].lut_state == gen_turbo_state():
1169
+ elif overlays[currentdataset.focusmap].LUTname == "turbo":
1110
1170
  ui.turbo_radioButton.setChecked(True)
1111
1171
  else:
1112
1172
  ui.rainbow_radioButton.setChecked(True)
@@ -1122,7 +1182,9 @@ def overlay_radioButton_clicked(which, enabled):
1122
1182
  overlays[currentdataset.focusmap].tr,
1123
1183
  overlays[currentdataset.focusmap].toffset,
1124
1184
  )
1125
-
1185
+ overlays[currentdataset.focusmap].dispmin = thedispmin
1186
+ overlays[currentdataset.focusmap].dispmax = thedispmax
1187
+ updateDispLimits()
1126
1188
  updateUI(
1127
1189
  callingfunc="overlay_radioButton_clicked",
1128
1190
  histogram=True,
@@ -1275,7 +1337,7 @@ def printfocusvals():
1275
1337
  global ui, overlays, currentdataset
1276
1338
  global currentloc
1277
1339
  global simfuncFitter
1278
- logstatus(
1340
+ logStatus(
1279
1341
  ui.logOutput,
1280
1342
  "\n\nValues at location "
1281
1343
  + "{0},{1},{2}".format(currentloc.xpos, currentloc.ypos, currentloc.zpos),
@@ -1297,7 +1359,7 @@ def printfocusvals():
1297
1359
  + str(":")
1298
1360
  + "{:.3f}".format(round(focusval, 3))
1299
1361
  )
1300
- logstatus(ui.logOutput, outstring)
1362
+ logStatus(ui.logOutput, outstring)
1301
1363
  else:
1302
1364
  if focusval > 0.0:
1303
1365
  if simfuncFitter is not None:
@@ -1308,7 +1370,7 @@ def printfocusvals():
1308
1370
  + str(":\n\t ")
1309
1371
  + failstring.replace(", ", "\n\t ")
1310
1372
  )
1311
- logstatus(ui.logOutput, outstring)
1373
+ logStatus(ui.logOutput, outstring)
1312
1374
  else:
1313
1375
  outstring = (
1314
1376
  indentstring
@@ -1316,7 +1378,7 @@ def printfocusvals():
1316
1378
  + str(":")
1317
1379
  + str(currentdataset.atlaslabels[int(focusval) - 1])
1318
1380
  )
1319
- logstatus(ui.logOutput, outstring)
1381
+ logStatus(ui.logOutput, outstring)
1320
1382
 
1321
1383
 
1322
1384
  def regressor_radioButton_clicked(theregressor, enabled):
@@ -1326,15 +1388,22 @@ def regressor_radioButton_clicked(theregressor, enabled):
1326
1388
  updateRegressorSpectrum()
1327
1389
 
1328
1390
 
1329
- def activatedataset(
1330
- currentdataset, ui, win, defaultdict, overlayGraphicsViews, verbosity=0, doinit=False
1331
- ):
1391
+ def activateDataset(currentdataset, ui, win, defaultdict, overlayGraphicsViews, verbosity=0):
1332
1392
  global regressors, overlays
1333
1393
  global mainwin
1334
1394
  global xdim, ydim, zdim, tdim, xpos, ypos, zpos, tpos
1335
1395
  global timeaxis
1336
1396
  global usecorrout
1337
1397
  global orthoimagedict
1398
+ global panesinitialized, uiinitialized
1399
+ global currentloc
1400
+
1401
+ if uiinitialized:
1402
+ currentloc.xdim = currentdataset.xdim
1403
+ currentloc.ydim = currentdataset.ydim
1404
+ currentloc.xdim = currentdataset.zdim
1405
+ currentloc.tdim = currentdataset.tdim
1406
+ currentloc.setTpos(currentloc.tpos)
1338
1407
 
1339
1408
  if verbosity > 1:
1340
1409
  print("getting regressors")
@@ -1502,13 +1571,14 @@ def activatedataset(
1502
1571
  overlays["atlas"].setGeomMask(thegeommask)
1503
1572
  overlays["atlas"].setFuncMask(overlays["atlasmask"].data)
1504
1573
 
1505
- if verbosity > 0:
1506
- for theoverlay in overlays:
1507
- overlays[theoverlay].summarize()
1574
+ if not panesinitialized:
1575
+ if verbosity > 0:
1576
+ for theoverlay in overlays:
1577
+ overlays[theoverlay].summarize()
1508
1578
 
1509
1579
  if verbosity > 1:
1510
1580
  print("focusmap is:", currentdataset.focusmap, "bgmap is:", bgmap)
1511
- if doinit:
1581
+ if not panesinitialized:
1512
1582
  if bgmap is None:
1513
1583
  mainwin = OrthoImageItem(
1514
1584
  overlays[currentdataset.focusmap],
@@ -1533,12 +1603,12 @@ def activatedataset(
1533
1603
  else:
1534
1604
  mainwin.setMap(overlays[currentdataset.focusmap])
1535
1605
 
1536
- if verbosity > 1:
1537
- print("loading panes")
1538
1606
  availablepanes = len(overlayGraphicsViews)
1607
+ if verbosity > 0:
1608
+ print(f"loading {availablepanes} available panes")
1539
1609
  numnotloaded = 0
1540
1610
  numloaded = 0
1541
- if doinit:
1611
+ if not panesinitialized:
1542
1612
  orthoimagedict = {}
1543
1613
  for idx, themap in enumerate(currentdataset.dispmaps):
1544
1614
  if overlays[themap].display_state:
@@ -1546,11 +1616,15 @@ def activatedataset(
1546
1616
  (numloaded > availablepanes - 2) and (themap != "corrout")
1547
1617
  ):
1548
1618
  if verbosity > 1:
1549
- print("skipping map ", themap, "(", idx, "): out of display panes")
1619
+ print(
1620
+ f"skipping map {themap}({idx}): out of display panes ({numloaded=}, {availablepanes=})"
1621
+ )
1550
1622
  numnotloaded += 1
1551
1623
  else:
1552
1624
  if verbosity > 1:
1553
- print("loading map ", themap, "(", idx, ") into pane ", numloaded)
1625
+ print(
1626
+ f"loading map {themap}=({idx}) into pane {numloaded} of {availablepanes}"
1627
+ )
1554
1628
  if bgmap is None:
1555
1629
  loadpane(
1556
1630
  overlays[themap],
@@ -1572,7 +1646,7 @@ def activatedataset(
1572
1646
  bgmap=overlays[bgmap],
1573
1647
  sm_imgsize=sm_imgsize,
1574
1648
  )
1575
- numloaded += 1
1649
+ numloaded += 1
1576
1650
  else:
1577
1651
  if verbosity > 1:
1578
1652
  print("not loading map ", themap, "(", idx, "): display_state is False")
@@ -1588,6 +1662,26 @@ def activatedataset(
1588
1662
  if numnotloaded > 0:
1589
1663
  print("WARNING:", numnotloaded, "maps could not be loaded - not enough panes")
1590
1664
 
1665
+ # record that we've been through once
1666
+ panesinitialized = True
1667
+
1668
+ if uiinitialized:
1669
+ # update the windows
1670
+ updateUI(
1671
+ callingfunc="activateDataset",
1672
+ orthoimages=True,
1673
+ histogram=True,
1674
+ )
1675
+
1676
+ # update the regressor
1677
+ updateRegressor()
1678
+ updateRegressorSpectrum()
1679
+
1680
+ # update the mask menu
1681
+ if currentdataset.funcmaskname is not None:
1682
+ print(f"updating the mask menu to {currentdataset.funcmaskname}")
1683
+ setMask(currentdataset.funcmaskname)
1684
+
1591
1685
 
1592
1686
  def loadpane(
1593
1687
  themap,
@@ -1627,6 +1721,7 @@ def loadpane(
1627
1721
  def tidepool(args):
1628
1722
  global vLine
1629
1723
  global ui, win
1724
+ global fileMenu, sel_open, sel_files
1630
1725
  global movierunning
1631
1726
  global focusmap, bgmap, focusregressor
1632
1727
  global maps
@@ -1643,9 +1738,10 @@ def tidepool(args):
1643
1738
  global imageadj
1644
1739
  global harvestcolormaps
1645
1740
  global atlasaveragingdone
1646
- global currentdataset, thesubjects, whichsubject
1741
+ global currentdataset, thesubjects, whichsubject, datafileroots
1647
1742
  global defaultdict, overlayGraphicsViews
1648
1743
  global verbosity
1744
+ global panesinitialized, uiinitialized
1649
1745
  global simfuncFitter
1650
1746
  global simfunc_ax, simfuncCurve, simfuncfitCurve, simfuncTLine, simfuncPeakMarker, simfuncCurvePoint, simfuncCaption
1651
1747
 
@@ -1671,6 +1767,10 @@ def tidepool(args):
1671
1767
  tpos = 0
1672
1768
  verbosity = 0
1673
1769
  simfuncFitter = None
1770
+ datafileroots = []
1771
+ panesinitialized = False
1772
+ uiinitialized = False
1773
+ sel_files = None
1674
1774
 
1675
1775
  if pyqtversion == 5:
1676
1776
  if args.uistyle == "normal":
@@ -1702,7 +1802,6 @@ def tidepool(args):
1702
1802
  else:
1703
1803
  geommaskname = None
1704
1804
 
1705
- datafileroots = []
1706
1805
  if args.datafileroot is not None:
1707
1806
  print("using ", args.datafileroot, " as the root file name list")
1708
1807
  datafileroots = args.datafileroot
@@ -1729,34 +1828,25 @@ def tidepool(args):
1729
1828
  # make the main window
1730
1829
  app = QtWidgets.QApplication([])
1731
1830
  print("setting up output window")
1732
- # win = KeyPressWindow()
1733
- # win.sigKeyPress.connect(keyPressed)
1734
1831
  win = QtWidgets.QMainWindow()
1735
1832
  ui = uiTemplate.Ui_MainWindow()
1736
1833
  ui.setupUi(win)
1737
1834
  win.show()
1738
1835
  win.setWindowTitle("TiDePool")
1739
1836
 
1740
- """"# create the menu bar
1837
+ # create the menu bar
1741
1838
  print("creating menu bar")
1742
1839
  menuBar = win.menuBar()
1743
- fileMenu = QtWidgets.QMenu(win)
1840
+ fileMenu = menuBar.addMenu("File")
1744
1841
  if pyqtversion == 5:
1745
1842
  qactionfunc = QtWidgets.QAction
1746
1843
  else:
1747
1844
  qactionfunc = QtGui.QAction
1748
- sel_open = qactionfunc("Open", win)
1749
- sel_open.triggered.connect(selectFile())
1845
+ sel_open = qactionfunc("Add dataset...", win)
1846
+ sel_open.triggered.connect(datasetPicker)
1750
1847
  fileMenu.addAction(sel_open)
1751
- win.setMenuBar(menuBar)
1752
- print("done creating menu bar")"""
1753
-
1754
- # get inputfile root name if necessary
1755
- if len(datafileroots) == 0:
1756
- datafileroots.append(selectFile())
1757
- if len(datafileroots) == 0:
1758
- print("No input file specified - exiting.")
1759
- sys.exit()
1848
+ fileMenu.addSeparator()
1849
+ print("done creating menu bar")
1760
1850
 
1761
1851
  # wire up the ortho image windows for mouse interaction
1762
1852
  vb_colorbar = pg.ViewBox(enableMouse=False)
@@ -1784,6 +1874,10 @@ def tidepool(args):
1784
1874
  if harvestcolormaps:
1785
1875
  ui.largeimage_horizontalLayout.addWidget(imageadj)
1786
1876
 
1877
+ if args.uistyle == "big":
1878
+ extramaps = True
1879
+ else:
1880
+ extramaps = False
1787
1881
  defaultdict = {
1788
1882
  "lagmask": {
1789
1883
  "colormap": gen_gray_state(),
@@ -1815,6 +1909,12 @@ def tidepool(args):
1815
1909
  "display": False,
1816
1910
  "funcmask": None,
1817
1911
  },
1912
+ "brainmask": {
1913
+ "colormap": gen_gray_state(),
1914
+ "label": "Brain mask",
1915
+ "display": False,
1916
+ "funcmask": None,
1917
+ },
1818
1918
  "p_lt_0p050_mask": {
1819
1919
  "colormap": gen_gray_state(),
1820
1920
  "label": "p<0.05",
@@ -1890,12 +1990,42 @@ def tidepool(args):
1890
1990
  "MTT": {
1891
1991
  "colormap": gen_spectrum_state(),
1892
1992
  "label": "MTT",
1893
- "display": True,
1993
+ "display": extramaps,
1894
1994
  "funcmask": "p_lt_0p050_mask",
1895
1995
  },
1896
1996
  "R2": {
1897
1997
  "colormap": gen_thermal_state(),
1898
- "label": "Fit R2",
1998
+ "label": "GLM Fit R2",
1999
+ "display": extramaps,
2000
+ "funcmask": "p_lt_0p050_mask",
2001
+ },
2002
+ "CoV": {
2003
+ "colormap": gen_thermal_state(),
2004
+ "label": "Coefficient of variation",
2005
+ "display": True,
2006
+ "funcmask": "p_lt_0p050_mask",
2007
+ },
2008
+ "confoundR2": {
2009
+ "colormap": gen_thermal_state(),
2010
+ "label": "Confound Fit R2",
2011
+ "display": extramaps,
2012
+ "funcmask": "p_lt_0p050_mask",
2013
+ },
2014
+ "varBefore": {
2015
+ "colormap": gen_thermal_state(),
2016
+ "label": "LFO variance before GLM",
2017
+ "display": extramaps,
2018
+ "funcmask": "p_lt_0p050_mask",
2019
+ },
2020
+ "varAfter": {
2021
+ "colormap": gen_thermal_state(),
2022
+ "label": "LFO variance after GLM",
2023
+ "display": extramaps,
2024
+ "funcmask": "p_lt_0p050_mask",
2025
+ },
2026
+ "varChange": {
2027
+ "colormap": gen_thermal_state(),
2028
+ "label": "LFO variance decrease %",
1899
2029
  "display": True,
1900
2030
  "funcmask": "p_lt_0p050_mask",
1901
2031
  },
@@ -1908,7 +2038,7 @@ def tidepool(args):
1908
2038
  "fitNorm": {
1909
2039
  "colormap": gen_thermal_state(),
1910
2040
  "label": "fitNorm",
1911
- "display": True,
2041
+ "display": False,
1912
2042
  "funcmask": "p_lt_0p050_mask",
1913
2043
  },
1914
2044
  "gaussout": {
@@ -1920,7 +2050,7 @@ def tidepool(args):
1920
2050
  "failimage": {
1921
2051
  "colormap": gen_spectrum_state(),
1922
2052
  "label": "Fit failure reason",
1923
- "display": False,
2053
+ "display": extramaps,
1924
2054
  "funcmask": None,
1925
2055
  },
1926
2056
  "anatomic": {
@@ -1944,7 +2074,7 @@ def tidepool(args):
1944
2074
  "neglog10p": {
1945
2075
  "colormap": gen_thermal_state(),
1946
2076
  "label": "Correlation fit -log10p",
1947
- "display": False,
2077
+ "display": extramaps,
1948
2078
  "funcmask": "None",
1949
2079
  },
1950
2080
  "delayoffset": {
@@ -1999,7 +2129,7 @@ def tidepool(args):
1999
2129
  ui.rainbow_radioButton.clicked.connect(rainbow_radioButton_clicked)
2000
2130
 
2001
2131
  # wire up the transparency checkbox
2002
- ui.transparency_checkBox.stateChanged.connect(transparency_checkbox_clicked)
2132
+ ui.transparency_checkBox.stateChanged.connect(transparencyCheckboxClicked)
2003
2133
 
2004
2134
  overlaybuttons = [
2005
2135
  ui.overlay_radioButton_01,
@@ -2058,13 +2188,14 @@ def tidepool(args):
2058
2188
  theview.hide()
2059
2189
 
2060
2190
  # define things for the popup mask menu
2061
- popMenu = QtWidgets.QMenu(win)
2191
+ popMaskMenu = QtWidgets.QMenu(win)
2062
2192
  if pyqtversion == 5:
2063
2193
  qactionfunc = QtWidgets.QAction
2064
2194
  else:
2065
2195
  qactionfunc = QtGui.QAction
2066
2196
  sel_nomask = qactionfunc("No mask", win)
2067
2197
  sel_lagmask = qactionfunc("Valid fit", win)
2198
+ sel_brainmask = qactionfunc("Externally provided brain mask", win)
2068
2199
  sel_refinemask = qactionfunc("Voxels used in refine", win)
2069
2200
  sel_meanmask = qactionfunc("Voxels used in mean regressor calculation", win)
2070
2201
  sel_preselectmask = qactionfunc(
@@ -2075,24 +2206,38 @@ def tidepool(args):
2075
2206
  sel_0p005 = qactionfunc("p<0.005", win)
2076
2207
  sel_0p001 = qactionfunc("p<0.001", win)
2077
2208
 
2078
- sel_nomask.triggered.connect(partial(set_mask, "nomask"))
2079
- sel_lagmask.triggered.connect(partial(set_mask, "lagmask"))
2080
- sel_refinemask.triggered.connect(partial(set_mask, "refinemask"))
2081
- sel_meanmask.triggered.connect(partial(set_mask, "meanmask"))
2082
- sel_preselectmask.triggered.connect(partial(set_mask, "preselectmask"))
2083
- sel_0p05.triggered.connect(partial(set_mask, "p_lt_0p050_mask"))
2084
- sel_0p01.triggered.connect(partial(set_mask, "p_lt_0p010_mask"))
2085
- sel_0p005.triggered.connect(partial(set_mask, "p_lt_0p005_mask"))
2086
- sel_0p001.triggered.connect(partial(set_mask, "p_lt_0p001_mask"))
2087
- popMenu.addAction(sel_nomask)
2209
+ sel_nomask.triggered.connect(partial(setMask, "nomask"))
2210
+ sel_lagmask.triggered.connect(partial(setMask, "lagmask"))
2211
+ sel_brainmask.triggered.connect(partial(setMask, "brainmask"))
2212
+ sel_refinemask.triggered.connect(partial(setMask, "refinemask"))
2213
+ sel_meanmask.triggered.connect(partial(setMask, "meanmask"))
2214
+ sel_preselectmask.triggered.connect(partial(setMask, "preselectmask"))
2215
+ sel_0p05.triggered.connect(partial(setMask, "p_lt_0p050_mask"))
2216
+ sel_0p01.triggered.connect(partial(setMask, "p_lt_0p010_mask"))
2217
+ sel_0p005.triggered.connect(partial(setMask, "p_lt_0p005_mask"))
2218
+ sel_0p001.triggered.connect(partial(setMask, "p_lt_0p001_mask"))
2219
+ popMaskMenu.addAction(sel_nomask)
2088
2220
  numspecial = 0
2089
2221
 
2090
- def on_context_menu(point):
2222
+ # configure the mask selection popup menu
2223
+ def on_mask_context_menu(point):
2091
2224
  # show context menu
2092
- popMenu.exec(ui.setMask_Button.mapToGlobal(point))
2225
+ popMaskMenu.exec(ui.setMask_Button.mapToGlobal(point))
2093
2226
 
2094
2227
  ui.setMask_Button.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.CustomContextMenu)
2095
- ui.setMask_Button.customContextMenuRequested.connect(on_context_menu)
2228
+ ui.setMask_Button.customContextMenuRequested.connect(on_mask_context_menu)
2229
+
2230
+ # configure the file selection popup menu
2231
+ def on_file_context_menu(point):
2232
+ # show context menu
2233
+ popMaskMenu.exec(ui.setFile_Button.mapToGlobal(point))
2234
+
2235
+ try:
2236
+ ui.setFile_Button.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.CustomContextMenu)
2237
+ ui.setFile_Button.customContextMenuRequested.connect(on_file_context_menu)
2238
+ setfilebuttonexists = True
2239
+ except AttributeError:
2240
+ setfilebuttonexists = False
2096
2241
 
2097
2242
  # wire up the regressor selection radio buttons
2098
2243
  regressorbuttons = [
@@ -2116,52 +2261,41 @@ def tidepool(args):
2116
2261
 
2117
2262
  # read in all the datasets
2118
2263
  thesubjects = []
2119
-
2120
- print("loading datasets...")
2121
- for thisdatafileroot in datafileroots:
2122
- print("Loading", thisdatafileroot)
2123
- thissubject = RapidtideDataset(
2124
- "main",
2125
- thisdatafileroot,
2126
- anatname=anatname,
2127
- geommaskname=geommaskname,
2128
- userise=userise,
2129
- usecorrout=usecorrout,
2130
- useatlas=useatlas,
2131
- forcetr=forcetr,
2132
- forceoffset=forceoffset,
2133
- offsettime=offsettime,
2134
- verbose=verbosity,
2135
- )
2136
- if len(thesubjects) > 0:
2137
- # check to see that the dimensions match
2138
- dimmatch, sizematch, spacematch, affinematch = check_rt_spatialmatch(
2139
- thissubject, thesubjects[0]
2140
- )
2141
- if dimmatch or args.ignoredimmatch:
2142
- thesubjects.append(thissubject)
2143
- else:
2144
- print(f"dataset {thisdatafileroot} does not match loaded data - skipping")
2145
- else:
2146
- thesubjects.append(thissubject)
2147
2264
  whichsubject = 0
2148
- currentdataset = thesubjects[whichsubject]
2149
- activatedataset(
2150
- currentdataset,
2151
- ui,
2152
- win,
2153
- defaultdict,
2154
- overlayGraphicsViews,
2155
- verbosity=verbosity,
2156
- doinit=True,
2157
- )
2265
+ if len(datafileroots) > 0:
2266
+ print("loading prespecified datasets...")
2267
+ for thisdatafileroot in datafileroots:
2268
+ addDataset(
2269
+ thisdatafileroot,
2270
+ anatname=anatname,
2271
+ geommaskname=geommaskname,
2272
+ userise=userise,
2273
+ usecorrout=usecorrout,
2274
+ useatlas=useatlas,
2275
+ forcetr=forcetr,
2276
+ forceoffset=forceoffset,
2277
+ offsettime=offsettime,
2278
+ ignoredimmatch=args.ignoredimmatch,
2279
+ )
2280
+ currentdataset = thesubjects[whichsubject]
2281
+ activateDataset(
2282
+ currentdataset,
2283
+ ui,
2284
+ win,
2285
+ defaultdict,
2286
+ overlayGraphicsViews,
2287
+ verbosity=verbosity,
2288
+ )
2289
+ # update the file menu
2290
+ updateFileMenu()
2291
+ else:
2292
+ # get inputfile root name if necessary
2293
+ datasetPicker()
2158
2294
 
2159
- for thebutton in [ui.nextFile_Button]:
2160
- if len(thesubjects) == 1:
2161
- thebutton.setDisabled(True)
2162
- thebutton.hide()
2163
- else:
2164
- thebutton.clicked.connect(nextFileButtonPressed)
2295
+ # check to see that something is loaded
2296
+ if len(thesubjects) == 0:
2297
+ print("No input datasets specified - exiting.")
2298
+ sys.exit()
2165
2299
 
2166
2300
  # wire up the display range controls
2167
2301
  ui.resetDispLimits_Button.clicked.connect(resetDispLimits)
@@ -2263,29 +2397,32 @@ def tidepool(args):
2263
2397
  if verbosity > 1:
2264
2398
  print("loadedfuncmasks", currentdataset.loadedfuncmasks)
2265
2399
  if len(currentdataset.loadedfuncmasks) > 0:
2266
- popMenu.addSeparator()
2400
+ popMaskMenu.addSeparator()
2267
2401
  if "lagmask" in currentdataset.loadedfuncmasks:
2268
- popMenu.addAction(sel_lagmask)
2402
+ popMaskMenu.addAction(sel_lagmask)
2403
+ numspecial += 1
2404
+ if "brainmask" in currentdataset.loadedfuncmasks:
2405
+ popMaskMenu.addAction(sel_brainmask)
2269
2406
  numspecial += 1
2270
2407
  if "refinemask" in currentdataset.loadedfuncmasks:
2271
- popMenu.addAction(sel_refinemask)
2408
+ popMaskMenu.addAction(sel_refinemask)
2272
2409
  numspecial += 1
2273
2410
  if "meanmask" in currentdataset.loadedfuncmasks:
2274
- popMenu.addAction(sel_meanmask)
2411
+ popMaskMenu.addAction(sel_meanmask)
2275
2412
  numspecial += 1
2276
2413
  if "preselectmask" in currentdataset.loadedfuncmasks:
2277
- popMenu.addAction(sel_preselectmask)
2414
+ popMaskMenu.addAction(sel_preselectmask)
2278
2415
  numspecial += 1
2279
2416
  if numspecial > 0:
2280
- popMenu.addSeparator()
2417
+ popMaskMenu.addSeparator()
2281
2418
  if "p_lt_0p050_mask" in currentdataset.loadedfuncmasks:
2282
- popMenu.addAction(sel_0p05)
2419
+ popMaskMenu.addAction(sel_0p05)
2283
2420
  if "p_lt_0p010_mask" in currentdataset.loadedfuncmasks:
2284
- popMenu.addAction(sel_0p01)
2421
+ popMaskMenu.addAction(sel_0p01)
2285
2422
  if "p_lt_0p005_mask" in currentdataset.loadedfuncmasks:
2286
- popMenu.addAction(sel_0p005)
2423
+ popMaskMenu.addAction(sel_0p005)
2287
2424
  if "p_lt_0p001_mask" in currentdataset.loadedfuncmasks:
2288
- popMenu.addAction(sel_0p001)
2425
+ popMaskMenu.addAction(sel_0p001)
2289
2426
 
2290
2427
  # initialize the location picker
2291
2428
  global currentloc
@@ -2331,5 +2468,12 @@ def tidepool(args):
2331
2468
 
2332
2469
  updateUI(callingfunc="main thread", orthoimages=True, focusvals=True)
2333
2470
  updateRegressor()
2471
+ updateRegressorSpectrum()
2472
+ uiinitialized = True
2473
+
2474
+ # for profiling
2475
+ """for i in range(20):
2476
+ selectDataset((i + 1) % 2)
2477
+ sys.exit(0)"""
2334
2478
 
2335
2479
  QtWidgets.QApplication.instance().exec()