Home
mrVista WorkFLow
Scanning
Post Scanning
fMRI Data Analysis
Original Lab Manual
Other Resources

 

fMRI Data Analysis

mrLoadRet Programmer's Guide

General rules:
  • Come and talk to me before getting started on a mrLoadRet hacking project. You should always touch base with me about what you are planning to do and I can help steer you to some of the relevant functions and data structures. You should come up with an informal spec for the code and get my approval on it before you get started, and then check in with me frequently as you progress. The reason for this is in part to enforce as much as possible a uniform style. But also to avoid inefficiencies, for example, to avoid having functions with different names that do essentially the same thing!
  • Do development work in your home directory. Install it in the mrLoadRet directory only after the code has been debugged and tested. And only after you have consulted with me about it. You may have to copy some of the mrLoadRet files into your home directory to make changes to them along the way, in addition to the new code that you are writing. Just keep track of those changes so that you and I can integrate them back into the mrLoadRet source when you are done.
  • Start with existing code and modify it. Try to make your code look as much as possible like my code (even if you would prefer to do things differently) because it is much easier to maintain when it is all done using a similar style.
Programming conventions:
  • No function should be more than 2 pages long. If it is longer than that then it should be split into smaller functions in a modular fashion.
  • No code segment should be duplicated. Even if its just a couple of lines, if it appears to two different functions, then move it out into its own function and have each of those functions call it.
  • All operations that can be done from the user interface must also be doable in a script by calling the relevant functions without having to open an actual window. Use hiddenInplane, hiddenVolume, hiddenGray, & hiddenFlat structures for writing such scripts. These structures are like the full blown INPLANE (etc) structures except that they don't have a ui substructure.
  • User interface code should be separated from analysis code, so that all operations can be done using the hiddenViews without a ui. The user interface functions themselves should be triggered only from the callbacks, never from code that computes things.
  • Global variables (only) are in all caps. Copies of a global variable that are local to a given function are not in caps.
  • All operations (data analysis steps) should be implemented to work for any of the viewTypes (Inplane, Volume/Gray, Flat).
  • Use the accessor functions (see below) rather than grabbing stuff directly from the structures. That way, when the data structures are modified, we need only modify the accessor functions rather than having to make a bunch of changes all over the place.
  • Groups of functions have been written to parallel one another (e.g., computeCorAnal, computeStdMap, computeMeanMap, computeResStdMap). If you make a change to any one of these functions, you must copy that change to all of them. If a function is part of such a group of functions, then this should be mentioned in the comment at the top of the file.
  • Many/most functions are written as follows: view = functionName (view, other arguments). Matlab isn't really an object oriented programming language, but we are pretending that it is. So you pass in a view (either inplane or gray, for example), modify that data structure, and then return it. Inside the function, use switch view.viewType to handle the different view types ( 'Inplane', 'Volume', 'Gray', 'Flat') differently.
  • Avoid using cd or chdir to change directories. Instead, use fullfile to construct the the full pathstring to the file.
  • How to deal with Matlab bugs.We occassionally run into problems with Matlab functions, but these bugs are often fixed in the next release of Matlab. So when this happens, we need to have a temporary replacement function that reminds us to check when a new Matlab version has been installed. Write a new function called <matlabFnName>Replacement.m (e.g., fooReplacement would be used to replace the function foo) that takes the same args as the original matlab function. The first line of this function should check the matlab release number and issue a warning to check if the original Matlab function has been fixed when a new version is installed:
    • expectedVersionNum = 6;
      version = ver('Matlab');
      versionNum = str2num(version.Version);
      if versionNum ~= expectedVersionNum
        disp(['Function fooReplacement is intended for Matlab 6. You are running Matlab ',version.Version,'. Check the if the function foo now works properly.']);
      end


    Then when the bug is fixed, it is easy to find all occurrences of fooReplacement and change them to foo.

Useful functions (that you should use):

Accessor functions:

  • viewSize (view): Returns the full size of the view, i.e., used to xform coordinates from one viewType to another. For Inplane views, this is the size of the cropped inplane anatomies [#rows #cols #slices]. For Volume views, this is the size of the vAnatomy [#rows #cols #slices]. For Flat views, this is the size of the flat map images [#rows #cols 2].
  • dataSize (view,[scan]): Returns the size of the data arrays, i.e., size of 'co' for a single scan. For Inplane views, the first two dimensions will typically be smaller (1/2 or 1/4) than viewSize(view) because the inplane functional images are smaller than the inplane anatomies. The3rd dimension is the same as that for viewSize (i.e., counting all inplane slices) even if the functionals were restricted to a subset of the slices; the data array has to be of that size (filled with NaNs where there are no data) to make it easy to transform it to the volume/gray. For Gray views, this returns the number of gray nodes because the data are stored in a vector of that length. For Flat views, this is the same as viewSize, that is the size of the flat map.
  • sliceDims (view,[scan]): Returns the size for a single slice of the data array, i.e., corresponding to a single frame from a tSeries file. Inplanes/Flats: same as the first 2 dims of dataSize. Volumes/Grays: number of gray nodes, same as dataSize.
  • numScans (view):
  • numSlices (view,scan): number of inplane anatomy slices
  • sliceList (view,scan): which of the inplane anatomy slices were included in the functional scan
  • numFrames (view,scan):
  • numCycles (view,scan):
  • frameRate (view,scan):
  • getCurScan (view):
  • view = setCurScan (view):
  • getCurSlice (view):
  • view = setCurSlice (view):
  • coords = getCurROICoords (view): Gets ROI.coords from currently selected ROI.

Analysis:

  • subdata = getCurDataROI (view, fieldname, scanNum, ROIcoords): This is how to get data (co, amp, ph, or map) for given scan and ROI.  Returns a vector of length equal to the number of pixels/voxels in the ROI.
  • data = getCurData (view, fieldname, scanNum): Returns either co, amp, or ph for given scan number, returned as a 3d array. Warning: If you do this on a volume or gray view beware that you will get a 3d array that is the size of the vAnatomy.
  • subtSeries = getTSeriesROI (view,ROIcoords): Extract subtSeries from view.tSeries for given ROI..
  • mapVolROIs :
  • analyzeSessions :
  • analyzeConditions :
  • vectorMean , vectorMeans :
  • view = restrictROI (view,refScan,cothresh,phWindow,mapWindow,[ROInum])

File:

  • homeDir (view): returns path string to the view (e.g., mrSESSION.homedir/Inplane or /Flat-fovea). For flat views, this depends on the unfold (there are multiple Flat subdirs, one for each unfold).
  • dataDir (view): returns path string to the data (e.g., corAnal), depends on dataType
  • roiDir (view): returns path string to the ROI subdirectory
  • tSeriesDir (view): returns path string to the tSeries
  • loadSession This is the preferred way for loading mrSESSION
  • saveSession This is the preferred way for saving mrSESSION
  • tSeries = loadtSeries (view,scan,slice): Loads the tSeries corresponding to the specified scan & slice and returns it.
  • view = percentTSeries (view,scan,slice): This is the preferred way for loading a tSeries file. If you have the urge to load the file directly using 'load(filename)' then you are doing something wrong.
  • savetSeries (tSeries,view,scan,slice): This is the preferred way to save a tSeries file.
  • view = loadCorAnal (view): This is the only way that you should ever load data from a corAnal file. If you have the urge to load the file directly using 'load(filename)' then you are doing something wrong.
  • saveCorAnal (view): This is the only way that you should ever save data to a corAnal file
  • view = loadROI (view,[filename],[select],[color]): This is the only way that you should ever load an ROI from a file.
  • saveROI (view,ROI): This is the only way that you should ever save an ROI.
  • getAnatomyPath (subjectname)
  • view = loadAnat (view): This is the only way that you should load the anatomy images.
  • cleanGray : Deletes all the data files from the Gray subdirectory to install/re-install a segmentation
  • cleanFlat, cleanAllFlats : Deletes data files from the Flat subdir(s) to install/re-install an unfold.
  • cleanDataType (dataTypeName): Deletes data files from all view subdir(s) corresponding to data type.

View:

  • initHiddenInplane, initHiddenVolume, initHiddenGray, initHiddenFlat: These functions are very useful for writing scripts that do a whole bunch of operations (e.g., computeCorAnal and map to one or more flat views) without having to open any windows. The hiddenInplanes are like full blown INPLANE structures except that they don't have the ui subsstructure (likewise for hiddenVolumes, etc.)
  • getSelectedInplane, getSelectedVolume, getSelectedGray, getSelectedFlat: Returns the currently selected inplane view (or likewise for the other viewTypes). If there is no currently selected view of that type, returns [].
  • checkSelectedInplane, checkSelectedVolume, checkSelectedGray, checkSelectedFlat: Calls getSelected* and returns the currently selected view of that type, or signals an error if there is no currently selected view of that type. Useful in callbacks where the view type must exist.
  • checkTypes (view1,view2): Checks that the two views have the same data type, e.g., before transforming data from one to the other.
  • found = existDataType (dataTypeName): Returns the data type's number, i.e., mrSESSION.dataTypes(found)
  • dataTypeName = getDataTypeName (view): Returns the current data type for the view.
  • view = selectDataType (view,n):

Utilities:

  • myErrorDlg:
  • myWarnDlg:
  • countDirs:
  • countFiles:
  • getPathStrDialog: Opens a dialog box that prompts user to choose an existing file.
  • putPathStrDialog: Opens a dialog box that prompts user to enter a filename for a file that doesn't necessarily exist.
  • intersectCols:

Data Structures:

mrSESSION
Structure that hold parameters about the scanning session, loaded from mrSESSION.mat file, with the following fields:
  • mrLoadRetVersion:
  • sessionCode:
  • description: text string that can be used to identify the project
  • subject: text string, should correspond to <anatomy directory>/<subject>
  • examNum: from scanner
  • alignment.inplane2VolXform: 4 x 4 homogeneous transform matrix
  • inplanes, structure describing the inplane anatomy images with the following fields
    • FOV
    • cropSize: [ydim xdim]
    • crop: 2x2 matrix [ystart xstart; yend xend]
    • fullSize: [ydim ydim], same as matrix size in scanner protocol
    • voxelSize: [ysize xsize thickness] in mm, computed from FOV and matrix size
    • nSlices: number
  • functionals, struct array (1 x numScans) describing each of the functional scans with the following fields:
    • PfileName: string, e.g., 'P46080'
    • totalFrames: total number of temporal frames (for each slice)
    • junkFirstFrames: frames to dump at the beginning
    • nFrames: number of frames to keep. This will typically be totalFrames - junkFirstFrames, but might be less than that if you junk some frames at the end as well. Note that junkEndFrames is not a field in this structure because it would be redundant with the other 3 fields.
    • slices: vector listing which slices were included in this scan. Note that each scan can use a different subset of the inplane slices. Typically, slices = [1:nSlices].
    • fullSize: [ydim xdim], power of 2 size that images are recon'd at
    • cropSize: [ydim xdim]
    • crop: 2x2 matrix
    • voxelSize: [ysize xsize thickness] in mm, computed as:
      • reconParams.FOV / fullsize
    • effectiveResolution: [ysize xsize thickness] in mm, computed as:
      • reconParams.FOV / reconParams.freqEncodeMatSize
    • framePeriod (sec): TR * # interleaves = seconds per acquisition
    • reconParams, from Pfile header, structure with the following fields:
      • date: string (e.g., '04/21/101')
      • time: string (e.g., '18:55')
      • nSlices: number
      • necho:
      • nAvs:
      • totalShots: numInterleavs * totalFrames
      • frameSize: size of recon'd images (e.g., 128 or 256)
      • totalFrames: number of frames (same as mrSESSION.functionals(s).totalFrames)
      • freqEncodeMatrixSize: number specifying the effective spatial sampling resolution. Note that images are recon'd up to the next highest power of 2.
      • numInterleaves: number of interleaves/shots per image
      • sliceThickness: thickness of each slice (mm)
      • FOV: field of view
      • sliceSpacing: spacing between slices (mm)
      • TR: repetition time (msec)
      • TE: echo time (msec)
      • psd: string specifying pulse sequence, e.g., 'sprl831'
dateTYPES
Struct array (1 x number of data types) with the following fields:
  • name: string (e.g., 'Original')
  • scanParams, struct array (1 x numScans) with the following fields:
    • annotation: string, optional description of this scan that appears near the top of the mrLoadRet window
    • nFrames: number of temporal frames. For 'Original' data type, this is copied from mrSESSION.functionals(s).nFrames
    • framePeriod (sec): time for each acquistion. For 'Original' data type, this is copied from mrSESSION.functionals(s).framePeriod
    • slices: vector listing which slices were included in this scan. Note that each scan can use a different subset of the inplane slices. Typically, slices = [1:nSlices]. For 'Original' data type, this is copied from mrSESSION.functionals(s).slices
    • cropSize: [ydim xdim]. for 'Original' data type, this is copied from mrSESSION.functionals(s).cropSize
  • blockedAnalysisParams, struct array (1 x numScans) with the following fields:
    • blockedAnalysis: 1 if this is a blocked scan
    • detrend, specifies detrending as follows:
      • 0: no detrending
      • 1: highpass filter
      • 2: subtract best-fit quartic polynomial
      • -1: subtract best-fit line
    • inhomoCorrect, specifies method of inhomogeneity correction that is used to convert from raw intensity units to percent signal change:
      • 0: divide by mean separately for each pixel
      • 1: divide by spatial gradient estimate (robust polynomial fit to the mean)
    • nCycles: number of block alternation cycles (cycles/scan)
  • eventAnalysisParams, struct array (1 x numScans) with the following fields:
    • Ress: do this


INPLANE
Cell array (each cell corresponds to an inplane view/window), each with the following fields:

  • name = 'INPLANE{n}', used to make eval strings in callbacks
  • viewType = 'Inplane', used to switch on different view types
  • subdir = 'Inplane', subdirectory for inplane data files
  • refreshFn = 'refreshView', specifies function that gets called by refreshScreen.
  • anat: inplane anatomies, 3d array (y,x,z)
  • co:  correlation maps, cell array (each cell corresponds to a scan) of 3d arrays (y,x,z)
  • amp:  response amplitudes, cell array of 3d arrays
  • ph:  response phase, cell array of 3d arrays
  • map: user defined parameter map, cell array of 3d arrays
  • mapName: string, corresponding to a name for the parameter map
  • tSeries: currently loaded detrended percent tSeries (set by percentTSeries), nFrames-by-nPixels
  • tSeriesScan: scan number of the currently loaded tSeries
  • tSeriesSlice: slice number of the currently loaded tSeries
  • curDataType: number of the data type, corresponding to mrSESSION.dataTypes(n)
  • ROIs: struct array with fields:
    • viewType: for book keeping to make sure that it is an ROI that corresponds to this view (e.g., 'Inplane')
    • name: ROI name and filename string (e.g., 'V1')
    • color: color when not the selected ROI
    • coords: 3xN array of coordinates for the N pixels in the ROI.
  • selectedROI: integer indicating the currently selected ROI (initialized to 0 meaning no ROI selected).
  • prevCoords: holds previous coords of selected ROI, used to undo last modification to the selected ROI.
  • ui: user interface substructure
    • figNum
    • windowHandle
    • mainAxisHandle
    • colorbarHandle: handle for colorbar axes
    • image: uint8 array stored because it doesn't always have to be recomputed.
    • cbarRange: range of values in overlay image, used to set the tick labels on the color bar.
    • displayMode: see refreshScreen
    • anatMode: displayMode for anatomy
      • clipMode: 'auto' or [clipMin clipMax], see refreshScreen.
      • numGrays: number of grays in the cmap
      • numColors: number of colors in the cmap
      • cmap: color map, Nx3 matrix of color map entries
    • coMode: displayMode for correlation (with same sub-fields as anatMode)
    • ampMode: displayMode for amplitude (with same sub-fields as anatMode)
    • phMode: displayMode for phase (with same sub-fields as anatMode)
    • mapMode: displayMode for parameter map (with same sub-fields as anatMode)
    • dataType: data type popup
      • name: 'dataType'
      • popHandle
      • labelHandle
    • ROI: ROI popup (with same sub-fields as dataType)
    • slice: slice slider
      • name: 'slice'
      • sliderHandle
      • labelHandel
      • textHandle
    • scan: scan slider (with same sub-fields as slice)
    • cothresh: cothresh slider structure (see setSlider)
      • sliderHandle: handle for slider itself
      • labelHandle: handle for text label
      • name = 'cothresh'
    • phWinMin, phWinMax: phase window sliders (each with same sub-fields as cothresh)
    • mapWinMax, mapWinMin: parameter map sliders (each with same sub-fields as cothresh)
    • anatMin, anatMax: anatomy sliders (each with same sub-fields as cothresh)
    • showROIs: 0=hide ROIs, 1=show selected ROI, 2=show all ROIs, -1=show selected perimeter, -2=show all perimeters.
    • image: holds the image (anat + overlay) currently being displayed to avoid having to recompute it when possible.
VOLUME
Most fields are the same as INPLANE with the following differences:
  • name = 'VOLUME{n}'
  • viewType = 'Volume' or 'Gray'
  • subdir = 'Volume' or 'Gray'
  • coords: 3 x nVoxels array of (y,x,z) of coordinates. For volumes, these coords are all the volume voxels that intersect with the inplanes. For grays, these coords are all the segmented gray nodes that intersect with the inplanes.
  • co: cell array (each cell corresponds to a scan) of vectors. Each vector has length nVoxels where nVoxels=size(volume.coords,2)
  • amp: cell array, same format as co
  • ph: cell array, same format as co
  • map: cell array, same format as co
  • leftPath (gray views only): path to left hemisphere gray class file (e.g., below /usr/local/mri/anatomy/<subject>/left/). This is for book-keeping purposes only. The file should never need to be reloaded.
  • rightPath (gray views only): path to right hemisphere gray class file.
  • nodes, edges (gray views only): subset of nodes/edges that intersect with the inplanes.
  • allLeftNodes, allLeftEdges, allRightNodes, allRightEdges (gray views only): full sets of nodes/edges loaded from the gray class file.
  • ui:
    • sliceOriButtons: cell array of button handles (sag=1, cor=2, axi=3)
    • sliceNumFields: cell array of editable text handles (sag=1, cor=2, axi=3) that specify sliceNum


FLAT
Most fields are the same as INPLANE with the following differences:

  • name = 'FLAT{n}'
  • viewType = 'Flat'
  • subdir = 'Flat-*' (which can be any number of subdirectories corresponding to different unfolds from the same segmentation).
  • coords: cell array containing 2 subarrays (one for each hemisphere) each 2 x nVoxels of (y,x) coordinates in the flat view.
  • grayCoords: cell array containing 2 subarrays (one for each hemisphere) each 3 x nVoxels of (y,x,z) coordinates.
  • anat: 3d array (y,z,hemisphere)
  • co: cell array (each cell corresponds to a scan) of 3d arrays (y,x,hemisphere) with NaNs where there's no data.
  • amp: "
  • ph: "
  • map: "
  • leftPath: path to left hemisphere flat file (e.g., below /usr/local/mri/anatomy/<subject>/left/). This is for book-keeping purposes only. The file should never need to be reloaded.
  • rightPath: path to right hemisphere flat file.
  • ui:
    • imSize: size of the displayed flat images.
    • mask: imSize x 2 array of two mask images (one for each hemisphere) filled with NaNs at pixels that do not correspond to gray nodes. Used to mask out the the displayed (e.g., co) images where there's no data.

 

Home | mrVista WorkFlow | Scanning| Post Scanning|fMRI Data Analysis |Original Lab manual |Other Resources

Stanford Vision, Imaging Science and Technology Laboratory
Department of Psychology, Jordan Hall, Building 420
Stanford University, Stanford, CA 94305-2130

Send email to : vista@white.stanford.edu
Copyright © 2003. All Rights Reserved