OSCR

High-frequency, high-intensity electrical stimulation selectively activates human fast-spiking interneurons.

Code ↔ Paper

2 matches between paragraphs of the paper and lines of its authors' code, computed by the harvester (lexical-v1). Click a colored paragraph or line to see its counterpart.

The 2 matches
  1. [1] § Methods › Slice electrophysiology ↔ pvbs.m, lines 111–180 · score 0.75 · AP half width, AP amplitude, AP threshold, rising, detection, peak
  2. [2] § Methods › Data analysis and statistics ↔ pvbs.m, lines 544–586 · score 0.58 · Bessel filter, cutoff frequency, amplifier, injection, PVBS, voltage

Paper

Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC

The paper is loaded when this pane is shown.

The authors' code

MATLAB · 3,320 lines · 195 KB · GPL-3.0 · 2 matches

  1. %% PVBS: Prairie View Browsing Solution
  2. % (https://github.com/flosfor/pvbs)
  3. %
  4. % Copyright (C) 2022-2024, Jaeyoung Yoon.
  5. %
  6. % The use or modification of this software (PVBS) is consented only
  7. % under agreement to cite the developer and/or the original source code
  8. % (https://github.com/flosfor/pvbs) within the body of the published
  9. % work or presentation, wherein PVBS was used.
  10. %
  11. %
  12. % -------------------------- <!> Important <!> ---------------------------
  13. %
  14. % - Required Matlab Toolboxes:
  15. % 1) Statistics & Machine Learning
  16. % 2) Signal Processing
  17. %
  18. % - Import Settings:
  19. % Make sure the import settings are correctly defined to match YOUR data
  20. % before importing experiments, as they can be easily different across
  21. % setups; e.g. DAC gain, input channels, etc. To access import settings,
  22. % use the button on the GUI, or see function setDefaultParams() in the
  23. % code for default parameters.
  24. %
  25. % ------------------------------------------------------------------------
  26. %
  27. % - Supported experiment types:
  28. % 1) *.CSV (any data)
  29. % 2) *.ABF (from pClamp)
  30. % 3) *.XML (from Prairie View (PV))
  31. % 3-1) VoltageRecording
  32. % 3-2) LineScan (synchronized with VoltageRecording and/or MarkPoints)
  33. % 3-3) T-Series (of VoltageRecording type experiments)
  34. %
  35. % ------------------------------------------------------------------------
  36. %
  37. % - Import settings can be found and modified with the options button;
  38. % by default, PVBS assumes the following:
  39. % - timestamp present at column 1
  40. % - following columns represent sweeps (for i or V)
  41. % - ... or acquisition channels (for F)
  42. %
  43. % If metadata is available (from .abf, or .xml in the case of PV
  44. % experiments), PVBS will attempt to read correct signal definitions
  45. % from metadata.
  46. %
  47. % PVBS assumes that values are in units of: ms, mV, pA. This also
  48. % applies to display, even when metadata is available (see below).
  49. %
  50. % ------------------------------------------------------------------------
  51. %
  52. % - NB.
  53. %
  54. % Default settings (including display) were intended for i-clamp
  55. % experiments and positive peak direction (e.g. EPSP), but PVBS is
  56. % compatible with both i-clamp or V-clamp, or peaks in any direction.
  57. % PVBS attempts to read correct signal definition from metadata, but
  58. % in some cases, axis labels can be displayed incorrectly especially
  59. % when the signal definitions (type or channel) are inconsistent across
  60. % experiments loaded in the same instance of PVBS. Nevertheless, the
  61. % numerical values of data will still be correct even in such cases.
  62. %
  63. % To avoid confusion, it is recommended that a single instance of PVBS
  64. % is used for a set of experiments with consistent signal (axis)
  65. % definitions. For experiments with different signal definitions
  66. % (e.g. i-clamp and V-clamp), simply launch another instance of PVBS
  67. % to load them separately.
  68. %
  69. % ------------------------------------------------------------------------
  70. %
  71. %
  72. % ------------------------------------------------------------------------
  73. %% ------------------------------------------------------------------------
  74. function pvbs()
  75. % main window
  76. % version
  77. pvbsTitle = 'PVBS (Prairie View Browsing Solution)';
  78. pvbsLastMod = '2025.05.30';
  79. pvbsStage = '(c)';
  80. theGreatCorona = 2020; % best year ever
  81. pvbsVer = [num2str(str2num(pvbsLastMod(1:4)) - theGreatCorona), pvbsLastMod(5:end)]; % why not
  82. fpVer = '5.5'; % not the version of this code, but PV itself
  83. matlabVer = '2023a'; % with Statistics & Machine Learning Toolbox (v. 12.0) and Signal Processing Toolbox (v. 8.5)
  84. github = '(https://github.com/flosfor/pvbs)';
  85. copyright = 'Copyright (C) 2022-2024, ';
  86. yjy = 'Jaeyoung Yoon';
  87. % open and initialize
  88. fprintf('\n%s v.%s%s\n%s\n%s%s.\n\n\n', pvbsTitle, pvbsVer, pvbsStage, github, copyright, yjy);
  89. win = figure('Name', [pvbsTitle, ' // ', 'v. ', pvbsVer, ' ', pvbsStage, ' / (PV ', fpVer, ' & Matlab ', matlabVer, ')'], 'NumberTitle', 'off', 'MenuBar', 'none', 'Units', 'Normalized', 'Position', [0.075, 0.15, 0.9, 0.8]);
  90. win.WindowState = 'maximized';
  91. h = struct();
  92. %%{
  93. ui.aboutPVBS = uicontrol('Style', 'pushbutton', 'String', '?', 'foregroundcolor', [0.75, 0.75, 0.75], 'backgroundcolor', [0.95, 0.95, 0.95], 'Units', 'normalized', 'Position', [0.00, 0.995, 0.0025, 0.005], 'Callback', @aboutPVBS, 'interruptible', 'off');
  94. function aboutPVBS(src, ~)
  95. aboutButton = src;
  96. set(aboutButton, 'enable', 'off');
  97. aboutWin = figure('Name', 'About PVBS', 'NumberTitle', 'off', 'MenuBar', 'none', 'Units', 'Normalized', 'Position', [0.4, 0.4, 0.25, 0.25], 'resize', 'off', 'CloseRequestFcn', @closeAboutWin);
  98. aboutWinText1 = uicontrol('Parent', aboutWin, 'Style', 'text', 'string', ' PVBS : "Prairie View Browsing Solution"', 'fontweight', 'bold', 'horizontalalignment', 'center', 'Units', 'normalized', 'Position', [0.05, 0.85, 0.9, 0.1]);
  99. aboutWinText2 = uicontrol('Parent', aboutWin, 'Style', 'text', 'string', sprintf(' "mspaint made by an unfortunate graphics designer \n who is not a programmer and used to having Photoshop" \n \n\n v. %s \n Designed for Prairie View %s & Matlab %s \n (+ Statistics & Machine Learning Toolbox, Signal Processing Toolbox) \n\n (LF) "What does PVBS stand for?" \n (JY) "(PV BS)" \n\n', [pvbsVer, ' ', pvbsStage], fpVer, matlabVer), 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.05, 0.15, 0.8, 0.65]);
  100. aboutWinClose = uicontrol('Parent', aboutWin, 'Style', 'pushbutton', 'string', 'Che sfortuna!', 'horizontalalignment', 'center', 'backgroundcolor', [0.9, 0.9, 0.9], 'Units', 'normalized', 'Position', [0.3, 0.1, 0.4, 0.1], 'Callback', @closeAboutWin, 'interruptible', 'off');
  101. try
  102. set(h.ui.saveGUIButton, 'enable', 'on');
  103. catch ME
  104. end
  105. function closeAboutWin(src, ~)
  106. set(aboutButton, 'enable', 'on');
  107. delete(aboutWin);
  108. end
  109. end
  110. %}
  111. % load default parameters
  112. guidata(win, h);
  113. %params.defaultParams = struct();
  114. defaultParams = setDefaultParams(win); % default parameter set
  115. params.actualParams = defaultParams; % actual parameters to be used; initializing with defaults
  116. params.defaultParams = defaultParams; % store separately for access (e.g. to revert to defaults)
  117. % default parameters that can be hard-coded without much concern
  118. %params.defaultParams = struct(); % moved up
  119. params.analysisBaseline = [27, 44]; % baseline window; NB. choose ~ 16.67 ms to average out 60 Hz noise
  120. params.analysisWindow1 = [52, 202]; % analysis window 1
  121. params.analysisWindow2 = [60, 210]; % analysis window 2
  122. %params.analysisTargetList = {'(Target)', 'All Groups', 'Selected Groups', 'All Sweeps', 'Selected Sweeps'};
  123. %{
  124. params.analysisOptionList11 = {'(Dir.)', '+/-', '+', '-'};
  125. params.analysisOptionList12 = {'(Kin.)', '20-80', '10-90', 'Custom...'};
  126. params.analysisOptionList21 = {'(Dir.)', '+/-', '+', '-'};
  127. params.analysisOptionList22 = {'(Kin.)', '20-80', '10-90', 'Custom...'};
  128. %}
  129. %params.analysisPlotMenuList0 = {'(Experiment)', 'Current Experiment', 'All Experiments'};
  130. params.analysisPlotMenuList1 = {'(Signal)', 'S1', 'S2'};
  131. params.analysisPlotMenuList2 = {'(Window)', 'W1', 'W2'};
  132. params.analysisPlotMenuList3 = {'(Results)', '(Select Window # for options)'};
  133. params.analysisPlotMenuList31 = {'(Results)', 'Peak', 'Area', 'Mean', 'Time of Peak', 'Rise (time)', 'Decay (time)', 'Rise (slope)', 'Decay (slope)'};
  134. params.analysisPlotMenuList32 = {'(Results)', 'No. of Events', 'Event Peak Value', 'Event Amplitude', 'Event Time of Peak', 'Event Baseline'};
  135. params.analysisPlotMenuList33 = {'(Results)', 'AP Threshold', 'AP Amplitude', 'AP Time of Peak', 'AP Half-width', 'Max Depol', 'Max Repol', 'RMP'};
  136. params.analysisPlotMenuList4 = {'(Plot by...)', 'Swps.', 'Grps.'};
  137. params.analysisTypeList1 = {'(Type)', 'Peak / Area / Mean', 'Threshold Detection', 'Waveform'};
  138. params.analysisTypeList2 = {'(Type)', 'Peak / Area / Mean', 'Threshold Detection', 'Waveform'};
  139. params.analysisPresetList = {'(Select)', 'Uncaging w/ LineScan'};
  140. params.analysisBaselineColor = [0.4, 0.5, 0.6]; % baseline window color
  141. params.analysisWindow1Color = [0, 0.75, 0.75]; % analysis window 1 color
  142. params.analysisWindow2Color = [0, 0.6, 0.6]; % analysis window 2 color
  143. %params.intrinsicPropertiesAnalysis = struct(); % default analysis parameters for intrinsic membrane properties %%% moved under params.actualParams
  144. params.xRange = []; % x axis range for main trace display; leave this empty
  145. params.xRangeZoom = 2; % x range zooming factor
  146. params.xRangeMove = 0.166666667; % x range moving factor
  147. params.yRangeDefault = [-140, 20]; % y axis range for main trace display, for V
  148. params.yRange = params.yRangeDefault;
  149. params.yRangeZoom = 2; % y range zooming factor, for V
  150. params.yRangeMove = 0.083333334; % y range moving factor, for V
  151. params.y2RangeDefault = [-1, 4]; % y axis range for main trace display, for F
  152. params.y2Range = params.y2RangeDefault;
  153. params.y2RangeZoom = 2; % y range zooming factor, for F
  154. params.y2RangeMove = 0.083333334; % y range moving factor, for F
  155. params.y3RangeDefault = [-500, 400]; % y axis range for main trace display, for i
  156. params.y3Range = params.y3RangeDefault;
  157. params.y3RangeZoom = 2; % y range zooming factor, for i
  158. params.y3RangeMove = 0.083333334; % y range moving factor, for i
  159. params.traceColorInactive = [0.75, 0.75, 0.75]; % color for inactive traces
  160. params.traceColorActive = [1, 0, 0]; % color for active (selected) traces
  161. params.trace2ColorInactive = [0.9, 0.95, 0.9]; % secondary color for inactive traces
  162. params.trace2ColorActive = [0.6, 0.8, 0.6]; % secondary color for active (selected) traces
  163. params.selectionInterval = 1; % default sweep selection interval
  164. params.groupSelectionInterval = 1; % misleading name; previously default selection interval for grouping, now group every this number of sweeps
  165. params.groupSweepIdx = 0; % index of sweep to display within group
  166. %params.peakDirection = 0; % direction for peak detection (-1: negative, 0: absolute, 1: positive) - obsolete
  167. params.traceProcessingTargetList = {'Voltage / Current', 'Fluorescence'}; % obsolete, using params.analysisPlotMenuList1 instead
  168. %params.exportTarget = 1; % which signal to export - default to 1 - obsolete
  169. params.resultsPlot1YRange = []; % will be updated upon analysis
  170. params.resultsPlot2YRange = []; % will be updated upon analysis
  171. params.lastSweepDeleted = 0; % flag to indicate if last sweep had been deleted; for correct indexing
  172. params.firstRun = 1; % flag for first run
  173. % data structure
  174. exp.experimentCount = 0;
  175. exp.metadata = {}; % cell for tSeries metadata files
  176. % below are for easier access without having to dig into metadata
  177. exp.fileName = {}; % file name
  178. exp.filePath = {}; % file path
  179. exp.sweeps = {}; % total sweep count for each tSeries
  180. % actual data
  181. data.fileType = {}; % cell for file type identifier (PV? CSV? ABF?)
  182. data.VRec = {}; % VRec (.csv)
  183. data.VRecOriginal = {}; % VRec (.csv), to preserve original in case of postprocessing - again real lack of foresight
  184. data.VRecMetadata = {}; % metadata for each VRec (.xml)
  185. data.VOut = {}; % VOut (.xml) - may have to omit due to PV insanity in formatting these
  186. data.VOutName = {}; % VRec experiment type (e.g. "single stim") - VOut name will work most of the time
  187. %data.lineScanMetadata = {}; % metadata for each LScn (.xml) - obsolete, linescans don't have separate metadata per cycle
  188. data.lineScan = {}; % LScn (.tiff)
  189. data.lineScanDFF = {}; % LScn dF/F
  190. data.lineScanDFFOriginal = {}; % LScn dF/F, to preserve original in case of postprocessing - again real lack of foresight
  191. data.lineScanF = {}; % LScn F
  192. data.lineScanFChannel = {}; % LScn channel used for F, dF/F
  193. data.lineScanROI = {}; % LScn ROI
  194. data.lineScanBaseline = {}; % LScn baseline period (time)
  195. data.lineScanCSV = {}; % LScn profile (.csv)
  196. data.postprocessing = {}; % postprocessing info (e.g. downsampling)
  197. data.artifactRemoval = {}; % artifact removal info
  198. data.markPointsIdx = {}; % indices for MkPts
  199. data.markPointsMetadata = {}; % MkPts metadata (.xml)
  200. data.intrinsicProperties = {}; % intrinsic properties, analyzed from file below
  201. data.intrinsicPropertiesVRec = {}; % intrinsic properties VRec (.csv)
  202. data.intrinsicPropertiesVRecMetadata = {}; % metadata for intrinsic properties VRec (.xml)
  203. data.intrinsicPropertiesFileName = {}; % file path and name for intrinsic properties
  204. data.zStack = {}; % z-stack
  205. data.zStackFileName = {}; % file path and name for z-stack
  206. data.singleScan = {}; % single-scan image
  207. data.singleScanFileName = {}; % file path and name for single-scan
  208. data.sweepIdx = {}; % sweep indices
  209. data.sweepStr = {}; % sweep strings for display
  210. data.groupIdx = {}; % sweep grouping indices
  211. data.groupStr = {}; % sweep grouping indices in string format for display
  212. data.notes = {}; % notes
  213. exp.data = data; % meta-struct for VRec data
  214. % analysis results
  215. results = {};
  216. % more analysis results - another unplanned mess "resulting" in more of really stupid naming and structuring
  217. analysis = struct();
  218. % UI elements
  219. % experiment list
  220. ui.experimentTitle = uicontrol('Style', 'text', 'string', 'Experiments', 'fontweight', 'bold', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.015, 0.955, 0.09, 0.02]);
  221. ui.newMatButton = uicontrol('Style', 'pushbutton', 'visible', 'off', 'String', 'New Dataset', 'backgroundcolor', [0.875, 0.875, 0.9], 'Units', 'normalized', 'Position', [0.015, 0.92, 0.121, 0.03], 'Callback', @newMat, 'interruptible', 'off');
  222. ui.loadMatButton = uicontrol('Style', 'pushbutton', 'String', 'Load Dataset (.mat)', 'backgroundcolor', [0.875, 0.875, 0.9], 'Units', 'normalized', 'Position', [0.015, 0.92, 0.121, 0.03], 'Callback', @loadMat, 'interruptible', 'off');
  223. ui.saveMatButton = uicontrol('Style', 'pushbutton', 'String', 'Save Dataset (.mat)', 'backgroundcolor', [0.875, 0.875, 0.9], 'Units', 'normalized', 'Position', [0.015, 0.89, 0.121, 0.03], 'Callback', @saveMat, 'interruptible', 'off');
  224. ui.saveGUIButton = uicontrol('Style', 'pushbutton', 'enable', 'off', 'String', 'Save GUI for Debugging (.mat)', 'backgroundcolor', [0.875, 0.875, 0.9], 'Units', 'normalized', 'Position', [0, 0, 0.0025, 0.005], 'Callback', @saveGUI, 'interruptible', 'off');
  225. ui.defaultSettingsButton = uicontrol('Style', 'pushbutton', 'String', 'Import Settings', 'backgroundcolor', [0.875, 0.875, 0.9], 'Units', 'normalized', 'Position', [0.015, 0.84, 0.121, 0.03], 'Callback', @defaultSettingsCallback, 'interruptible', 'off');
  226. ui.loadExpButton = uicontrol('Style', 'pushbutton', 'String', 'Load Experiment (.abf, .xml, .csv)', 'backgroundcolor', [0.85, 0.85, 0.95], 'Units', 'normalized', 'Position', [0.015, 0.81, 0.121, 0.03], 'Callback', @loadExp, 'interruptible', 'off'); % will be used for both vRec or tSer
  227. ui.cellListDisplay = uicontrol('Style', 'listbox', 'Visible', 'on', 'Min', 0, 'Max', 1000, 'Units', 'normalized', 'Position', [0.015, 0.55, 0.12, 0.25], 'Callback', @cellListClick, 'interruptible', 'off'); % not cellist
  228. ui.cellList = {}; % experiment list items - in hindsight, this was very poorly named
  229. ui.cellListUp = uicontrol('Style', 'pushbutton', 'String', '^', 'Units', 'normalized', 'Position', [0.015, 0.51, 0.02, 0.03], 'Callback', @cellListUp, 'interruptible', 'off');
  230. ui.cellListDown = uicontrol('Style', 'pushbutton', 'String', 'v', 'Units', 'normalized', 'Position', [0.0345, 0.51, 0.02, 0.03], 'Callback', @cellListDown, 'interruptible', 'off');
  231. ui.cellListMerge = uicontrol('Style', 'pushbutton', 'String', 'Merge', 'Units', 'normalized', 'Position', [0.0555, 0.51, 0.025, 0.03], 'Callback', @cellListMerge, 'interruptible', 'off');
  232. ui.cellListDuplicate = uicontrol('Style', 'pushbutton', 'String', 'Duplicate', 'Units', 'normalized', 'Position', [0.08, 0.51, 0.035, 0.03], 'Callback', @cellListDuplicate, 'interruptible', 'off');
  233. ui.cellListDel = uicontrol('Style', 'pushbutton', 'String', 'X', 'Units', 'normalized', 'Position', [0.1155, 0.51, 0.02, 0.03], 'Callback', @cellListDel, 'interruptible', 'off');
  234. % main trace display window
  235. ui.traceDisplayTitle = uicontrol('Style', 'text', 'string', 'Traces', 'fontweight', 'bold', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.15, 0.955, 0.04, 0.02]);
  236. ui.traceDisplay = axes('Units', 'Normalized', 'Position', [0.19, 0.42, 0.57, 0.53], 'xminortick', 'on', 'yminortick', 'on', 'box', 'on');
  237. ui.traceDisplaySignalsButton = uicontrol('Style', 'pushbutton', 'enable', 'on', 'String', 'S#', 'backgroundcolor', [0.99, 0.99, 0.99], 'Units', 'normalized', 'Position', [0.735, 0.905, 0.015, 0.03], 'Callback', @traceDisplaySignals, 'interruptible', 'off');
  238. ui.traceDisplayXZoomIn = uicontrol('Style', 'pushbutton', 'String', '+', 'fontweight', 'bold', 'Units', 'normalized', 'Position', [0.5245, 0.361, 0.015, 0.03], 'Callback', @traceDisplayXZoomIn, 'interruptible', 'off');
  239. ui.traceDisplayXZoomOut = uicontrol('Style', 'pushbutton', 'String', '-', 'fontweight', 'bold', 'Units', 'normalized', 'Position', [0.4115, 0.361, 0.015, 0.03], 'Callback', @traceDisplayXZoomOut, 'interruptible', 'off');
  240. ui.traceDisplayXMoveRight = uicontrol('Style', 'pushbutton', 'String', '>', 'fontweight', 'bold', 'Units', 'normalized', 'Position', [0.695, 0.361, 0.015, 0.03], 'Callback', @traceDisplayXMoveRight, 'interruptible', 'off');
  241. ui.traceDisplayXMoveLeft = uicontrol('Style', 'pushbutton', 'String', '<', 'fontweight', 'bold', 'Units', 'normalized', 'Position', [0.241, 0.361, 0.015, 0.03], 'Callback', @traceDisplayXMoveLeft, 'interruptible', 'off');
  242. ui.traceDisplayXMoveToStart = uicontrol('Style', 'pushbutton', 'String', '<<', 'fontweight', 'bold', 'Units', 'normalized', 'Position', [0.212, 0.361, 0.015, 0.03], 'Callback', @traceDisplayXMoveToStart, 'interruptible', 'off');
  243. ui.traceDisplayXMoveToEnd = uicontrol('Style', 'pushbutton', 'String', '>>', 'fontweight', 'bold', 'Units', 'normalized', 'Position', [0.724, 0.361, 0.015, 0.03], 'Callback', @traceDisplayXMoveToEnd, 'interruptible', 'off');
  244. ui.traceDisplayYZoomIn = uicontrol('Style', 'pushbutton', 'String', '+', 'fontweight', 'bold', 'Units', 'normalized', 'Position', [0.15, 0.76, 0.015, 0.03], 'Callback', @traceDisplayYZoomIn, 'interruptible', 'off');
  245. ui.traceDisplayYZoomOut = uicontrol('Style', 'pushbutton', 'String', '-', 'fontweight', 'bold', 'Units', 'normalized', 'Position', [0.15, 0.58, 0.015, 0.03], 'Callback', @traceDisplayYZoomOut, 'interruptible', 'off');
  246. ui.traceDisplayYMoveUp = uicontrol('Style', 'pushbutton', 'String', '^', 'fontweight', 'bold', 'Units', 'normalized', 'Position', [0.15, 0.89, 0.015, 0.03], 'Callback', @traceDisplayYMoveUp, 'interruptible', 'off');
  247. ui.traceDisplayYMoveDown = uicontrol('Style', 'pushbutton', 'String', 'v', 'fontweight', 'bold', 'Units', 'normalized', 'Position', [0.15, 0.45, 0.015, 0.03], 'Callback', @traceDisplayYMoveDown, 'interruptible', 'off');
  248. ui.traceDisplayY2ZoomIn = uicontrol('Style', 'pushbutton', 'String', '+', 'fontweight', 'bold', 'foregroundcolor', [0, 0.5, 0], 'Units', 'normalized', 'Position', [0.785, 0.76, 0.015, 0.03], 'Callback', @traceDisplayY2ZoomIn, 'interruptible', 'off');
  249. ui.traceDisplayY2ZoomOut = uicontrol('Style', 'pushbutton', 'String', '-', 'fontweight', 'bold', 'foregroundcolor', [0, 0.5, 0], 'Units', 'normalized', 'Position', [0.785, 0.58, 0.015, 0.03], 'Callback', @traceDisplayY2ZoomOut, 'interruptible', 'off');
  250. ui.traceDisplayY2MoveUp = uicontrol('Style', 'pushbutton', 'String', '^', 'fontweight', 'bold', 'foregroundcolor', [0, 0.5, 0], 'Units', 'normalized', 'Position', [0.785, 0.89, 0.015, 0.03], 'Callback', @traceDisplayY2MoveUp, 'interruptible', 'off');
  251. ui.traceDisplayY2MoveDown = uicontrol('Style', 'pushbutton', 'String', 'v', 'fontweight', 'bold', 'foregroundcolor', [0, 0.5, 0], 'Units', 'normalized', 'Position', [0.785, 0.45, 0.015, 0.03], 'Callback', @traceDisplayY2MoveDown, 'interruptible', 'off');
  252. ui.traceDisplayReset = uicontrol('Style', 'pushbutton', 'String', 'O', 'fontweight', 'bold', 'Units', 'normalized', 'Position', [0.15, 0.361, 0.015, 0.03], 'Callback', @traceDisplayReset, 'interruptible', 'off');
  253. ui.traceDisplayReset2 = uicontrol('Style', 'pushbutton', 'String', 'O', 'fontweight', 'bold', 'foregroundcolor', [0, 0.5, 0], 'Units', 'normalized', 'Position', [0.785, 0.361, 0.015, 0.03], 'Callback', @traceDisplayReset2, 'interruptible', 'off');
  254. ui.traceDisplayYRange = params.yRange; % set to default Y range
  255. ui.traceDisplayY2Range = params.y2Range; % set to default Y range
  256. ui.traceDisplayXRange = params.xRange; % set to default X range
  257. ui.trace = {}; % traces, saved for sweep indexing
  258. ui.trace2 = {}; % traces (2), saved for sweep indexing
  259. % sweep and group list
  260. ui.sweepListTitle = uicontrol('Style', 'text', 'string', 'Sweeps ', 'fontweight', 'bold', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.815, 0.955, 0.045, 0.02]);
  261. ui.sweepListDisplay = uicontrol('Style', 'listbox', 'Visible', 'on', 'Min', 0, 'Max', 1000000, 'Units', 'normalized', 'Position', [0.815, 0.62, 0.04, 0.33], 'Callback', @sweepListClick, 'interruptible', 'off');
  262. ui.sweepList = {}; % sweep list items
  263. ui.groupListTitle = uicontrol('Style', 'text', 'string', 'Groups ', 'fontweight', 'bold', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.86, 0.955, 0.09, 0.02]);
  264. ui.groupListDisplay = uicontrol('Style', 'listbox', 'Visible', 'on', 'Min', 0, 'Max', 1000000, 'Units', 'normalized', 'Position', [0.86, 0.62, 0.072, 0.33], 'Callback', @groupListClick, 'interruptible', 'off');
  265. ui.groupList = {}; % group list items
  266. %ui.sweepSelectGroupText = uicontrol('Style', 'text', 'string', '(Sweeps)', 'fontweight', 'bold', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.936, 0.93, 0.045, 0.02]);
  267. ui.sweepSelectText = uicontrol('Style', 'text', 'string', 'Select Swps: ', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.936, 0.93, 0.09, 0.02]);
  268. ui.sweepSelectMod = uicontrol('Style', 'pushbutton', 'string', 'Interval:', 'Units', 'normalized', 'Position', [0.936, 0.9, 0.032, 0.03], 'Callback', @sweepSelectMod, 'interruptible', 'off');
  269. ui.sweepSelectModValue = uicontrol('Style', 'edit', 'string', num2str(params.selectionInterval), 'horizontalalignment', 'right', 'Units', 'normalized', 'Position', [0.9685, 0.901, 0.015, 0.028], 'Callback', @sweepSelectModValue, 'interruptible', 'off');
  270. ui.sweepSelectOdd = uicontrol('Style', 'pushbutton', 'string', 'Odd', 'Units', 'normalized', 'Position', [0.936, 0.87, 0.0165, 0.03], 'Callback', @sweepSelectOdd, 'interruptible', 'off');
  271. ui.sweepSelectEven = uicontrol('Style', 'pushbutton', 'string', 'Evn', 'Units', 'normalized', 'Position', [0.952, 0.87, 0.0165, 0.03], 'Callback', @sweepSelectEven, 'interruptible', 'off');
  272. ui.sweepSelectInvert = uicontrol('Style', 'pushbutton', 'string', 'Inv', 'Units', 'normalized', 'Position', [0.968, 0.87, 0.0165, 0.03], 'Callback', @sweepSelectInvert, 'interruptible', 'off');
  273. ui.sweepGroupText = uicontrol('Style', 'text', 'string', 'Grp. by: ', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.936, 0.71, 0.045, 0.02]);
  274. ui.groupSelected = uicontrol('Style', 'pushbutton', 'String', 'Sel.', 'Units', 'normalized', 'Position', [0.96, 0.71, 0.024, 0.03], 'Callback', @groupSelected, 'interruptible', 'off');
  275. ui.groupSelectedMod = uicontrol('Style', 'pushbutton', 'string', 'Swps', 'Units', 'normalized', 'Position', [0.96, 0.68, 0.024, 0.03], 'Callback', @groupSelectedMod, 'interruptible', 'off');
  276. ui.groupSelectedModValue = uicontrol('Style', 'edit', 'string', num2str(params.groupSelectionInterval), 'horizontalalignment', 'right', 'Units', 'normalized', 'Position', [0.94, 0.681, 0.02, 0.028], 'Callback', @groupSelectModValue, 'interruptible', 'off');
  277. %{
  278. ui.groupAuto1 = uicontrol('Style', 'pushbutton', 'String', 'VOut', 'Units', 'normalized', 'Position', [0.936, 0.65, 0.024, 0.03], 'Callback', @groupAutoVOut, 'interruptible', 'off');
  279. ui.groupAuto2 = uicontrol('Style', 'pushbutton', 'String', 'MkPts', 'Units', 'normalized', 'Position', [0.96, 0.65, 0.024, 0.03], 'Callback', @groupAutoMkPts, 'interruptible', 'off');
  280. %}
  281. ui.sweepProcessText = uicontrol('Style', 'text', 'string', 'Selected Swps: ', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.936, 0.84, 0.09, 0.02]);
  282. ui.sweepSegment = uicontrol('Style', 'pushbutton', 'String', 'Segm.', 'Units', 'normalized', 'Position', [0.936, 0.81, 0.024, 0.03], 'Callback', @sweepsSegmentation, 'interruptible', 'off');
  283. ui.sweepTrucante = uicontrol('Style', 'pushbutton', 'String', 'Trunc.', 'Units', 'normalized', 'Position', [0.96, 0.81, 0.024, 0.03], 'Callback', @sweepsTruncate, 'interruptible', 'off');
  284. ui.sweepAverage = uicontrol('Style', 'pushbutton', 'String', 'Avg.', 'Units', 'normalized', 'Position', [0.936, 0.78, 0.024, 0.03], 'Callback', @sweepsAverage, 'interruptible', 'off');
  285. %ui.sweepArithmetic = uicontrol('Style', 'pushbutton', 'String', '+ / -', 'Units', 'normalized', 'Position', [0.96, 0.78, 0.024, 0.03], 'Callback', @sweepsArithmetic, 'interruptible', 'off');
  286. ui.sweepAdd = uicontrol('Style', 'pushbutton', 'String', '+', 'Units', 'normalized', 'Position', [0.96, 0.78, 0.012, 0.03], 'Callback', @sweepsAdd, 'interruptible', 'off');
  287. ui.sweepSubtract = uicontrol('Style', 'pushbutton', 'String', '-', 'Units', 'normalized', 'Position', [0.972, 0.78, 0.012, 0.03], 'Callback', @sweepsSubtract, 'interruptible', 'off');
  288. ui.sweepConcatenate = uicontrol('Style', 'pushbutton', 'String', 'Concat.', 'Units', 'normalized', 'Position', [0.936, 0.75, 0.024, 0.03], 'Callback', @sweepsConcatenate, 'interruptible', 'off');
  289. ui.sweepDel = uicontrol('Style', 'pushbutton', 'String', 'X', 'Units', 'normalized', 'Position', [0.96, 0.75, 0.024, 0.03], 'Callback', @sweepsDelete, 'interruptible', 'off');
  290. %ui.groupText = uicontrol('Style', 'text', 'String', '(Groups)', 'fontweight', 'bold', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.936, 0.68, 0.03, 0.02], 'interruptible', 'off');
  291. ui.groupText = uicontrol('Style', 'text', 'String', 'Selected Grps:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.936, 0.65, 0.09, 0.02], 'interruptible', 'off');
  292. ui.groupListUp = uicontrol('Style', 'pushbutton', 'String', '^', 'Units', 'normalized', 'Position', [0.936, 0.62, 0.0165, 0.03], 'Callback', @groupListUp, 'interruptible', 'off');
  293. ui.groupListDown = uicontrol('Style', 'pushbutton', 'String', 'v', 'Units', 'normalized', 'Position', [0.936, 0.59, 0.0165, 0.03], 'Callback', @groupListDown, 'interruptible', 'off');
  294. ui.groupListInvert = uicontrol('Style', 'pushbutton', 'String', 'Inv', 'Units', 'normalized', 'Position', [0.968, 0.62, 0.0165, 0.03], 'Callback', @groupListInvert, 'interruptible', 'off');
  295. ui.groupListReverse = uicontrol('Style', 'pushbutton', 'String', 'Rev', 'Units', 'normalized', 'Position', [0.952, 0.62, 0.0165, 0.03], 'Callback', @groupListReverse, 'interruptible', 'off');
  296. ui.groupListMerge = uicontrol('Style', 'pushbutton', 'String', 'Mrg', 'Units', 'normalized', 'Position', [0.952, 0.59, 0.0165, 0.03], 'Callback', @groupListMerge, 'interruptible', 'off');
  297. ui.groupListDel = uicontrol('Style', 'pushbutton', 'String', 'X', 'Units', 'normalized', 'Position', [0.968, 0.59, 0.0165, 0.03], 'Callback', @groupListDel, 'interruptible', 'off');
  298. ui.groupSweepText = uicontrol('Style', 'text', 'string', 'Sweep #', 'horizontalalignment', 'center', 'Units', 'normalized', 'Position', [0.871, 0.592, 0.05, 0.02]);
  299. ui.groupSweepPrev = uicontrol('Style', 'pushbutton', 'String', '<', 'Units', 'normalized', 'Position', [0.86, 0.59, 0.015, 0.03], 'Callback', @groupSweepPrev, 'interruptible', 'off');
  300. ui.groupSweepNext = uicontrol('Style', 'pushbutton', 'String', '>', 'Units', 'normalized', 'Position', [0.917, 0.59, 0.015, 0.03], 'Callback', @groupSweepNext, 'interruptible', 'off');
  301. % analysis window
  302. ui.analysisTitle = uicontrol('Style', 'text', 'string', 'Analysis', 'fontweight', 'bold', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.815, 0.56, 0.09, 0.02]);
  303. ui.analysisBaselineText = uicontrol('Style', 'text', 'string', 'Bsln: ', 'foregroundcolor', params.analysisBaselineColor, 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.816, 0.532, 0.045, 0.02]);
  304. ui.analysisBaselineText2 = uicontrol('Style', 'text', 'string', '-', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.856, 0.532, 0.02, 0.02]);
  305. ui.analysisBaselineText3 = uicontrol('Style', 'text', 'string', '(ms)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.88, 0.532, 0.045, 0.02]);
  306. ui.analysisBaselineStart = uicontrol('Style', 'edit', 'string', num2str(params.analysisBaseline(1)), 'horizontalalignment', 'right', 'Units', 'normalized', 'Position', [0.835, 0.53, 0.02, 0.028], 'Callback', @baselineStart, 'interruptible', 'off');
  307. ui.analysisBaselineEnd = uicontrol('Style', 'edit', 'string', num2str(params.analysisBaseline(2)), 'horizontalalignment', 'right', 'Units', 'normalized', 'Position', [0.86, 0.53, 0.02, 0.028], 'Callback', @baselineEnd, 'interruptible', 'off');
  308. ui.analysisBaselineMedian = uicontrol('Style', 'checkbox', 'min', 0, 'max', 1, 'value', 1, 'string', 'Median', 'Units', 'normalized', 'Position', [0.895, 0.53, 0.037, 0.03], 'Callback', @baselineMedian, 'interruptible', 'off');
  309. ui.analysisWindow1Text = uicontrol('Style', 'text', 'string', 'Win 1: ', 'foregroundcolor', params.analysisWindow1Color, 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.816, 0.502, 0.045, 0.02]);
  310. ui.analysisWindow1Text2 = uicontrol('Style', 'text', 'string', '-', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.856, 0.502, 0.02, 0.02]);
  311. ui.analysisWindow1Text3 = uicontrol('Style', 'text', 'string', '(ms)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.88, 0.502, 0.045, 0.02]);
  312. ui.analysisWindow1Start = uicontrol('Style', 'edit', 'string', num2str(params.analysisWindow1(1)), 'horizontalalignment', 'right', 'Units', 'normalized', 'Position', [0.835, 0.50, 0.02, 0.028], 'Callback', @analysisWindow1Start, 'interruptible', 'off');
  313. ui.analysisWindow1End = uicontrol('Style', 'edit', 'string', num2str(params.analysisWindow1(2)), 'horizontalalignment', 'right', 'Units', 'normalized', 'Position', [0.86, 0.50, 0.02, 0.028], 'Callback', @analysisWindow1End, 'interruptible', 'off');
  314. ui.analysisWindow2Text = uicontrol('Style', 'text', 'string', 'Win 2: ', 'foregroundcolor', params.analysisWindow2Color, 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.816, 0.472, 0.045, 0.02]);
  315. ui.analysisWindow2Text2 = uicontrol('Style', 'text', 'string', '-', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.856, 0.472, 0.02, 0.02]);
  316. ui.analysisWindow2Text3 = uicontrol('Style', 'text', 'string', '(ms)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.88, 0.472, 0.045, 0.02]);
  317. ui.analysisWindow2Start = uicontrol('Style', 'edit', 'string', num2str(params.analysisWindow2(1)), 'horizontalalignment', 'right', 'Units', 'normalized', 'Position', [0.835, 0.47, 0.02, 0.028], 'Callback', @analysisWindow2Start, 'interruptible', 'off');
  318. ui.analysisWindow2End = uicontrol('Style', 'edit', 'string', num2str(params.analysisWindow2(2)), 'horizontalalignment', 'right', 'Units', 'normalized', 'Position', [0.86, 0.47, 0.02, 0.028], 'Callback', @analysisWindow2End, 'interruptible', 'off');
  319. ui.analysisWindowHandle = cell(1, 6); % handle for displaying analysis windows - somehow it is overly complicated to make this work
  320. % analysis parameters
  321. ui.analysisType1 = uicontrol('Style', 'popupmenu', 'string', params.analysisTypeList1, 'value', 2, 'foregroundcolor', params.analysisWindow1Color, 'Units', 'normalized', 'Position', [0.895, 0.497, 0.037, 0.03], 'Callback', @analysisTypeSel, 'interruptible', 'off');
  322. ui.analysisType2 = uicontrol('Style', 'popupmenu', 'string', params.analysisTypeList2, 'value', 2, 'foregroundcolor', params.analysisWindow2Color, 'Units', 'normalized', 'Position', [0.895, 0.467, 0.037, 0.03], 'Callback', @analysisTypeSel, 'interruptible', 'off'); % can use the same callback
  323. %ui.analysisTarget = uicontrol('Style', 'popupmenu', 'string', params.analysisTargetList, 'foregroundcolor', [0.25, 0.25, 0.375], 'Units', 'normalized', 'Position', [0.895, 0.527, 0.037, 0.03], 'Callback', @analysisTargetSel, 'interruptible', 'off');
  324. ui.analysisOptions = uicontrol('Style', 'pushbutton', 'string', 'Options', 'backgroundcolor', [0.9, 0.9, 0.95], 'Units', 'normalized', 'Position', [0.9365, 0.53, 0.0475, 0.025], 'Callback', @analysisOptions, 'interruptible', 'off');
  325. ui.analysisRun = uicontrol('Style', 'pushbutton', 'string', '>>', 'fontweight', 'bold', 'foregroundcolor', 'w', 'backgroundcolor', [0.5, 0.5, 0.75], 'Units', 'normalized', 'Position', [0.936, 0.4735, 0.048, 0.055], 'Callback', @runAnalysis, 'interruptible', 'off');
  326. ui.analysisPresetText = uicontrol('Style', 'text', 'string', 'Analysis Presets: ', 'foregroundcolor', [0.3, 0.3, 0.36], 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.845, 0.442, 0.09, 0.02]);
  327. ui.analysisPreset = uicontrol('Style', 'popupmenu', 'string', params.analysisPresetList, 'value', 2, 'foregroundcolor', [0.3, 0.3, 0.36], 'Units', 'normalized', 'Position', [0.895, 0.437, 0.037, 0.03], 'Callback', @analysisPresetSel, 'interruptible', 'off');
  328. ui.analysisRunPreset = uicontrol('Style', 'pushbutton', 'string', '>', 'fontweight', 'bold', 'foregroundcolor', 'w', 'backgroundcolor', [0.6, 0.6, 0.72], 'Units', 'normalized', 'Position', [0.936, 0.4435, 0.048, 0.025], 'Callback', @runAutoAnalysis, 'interruptible', 'off');
  329. % analysis results
  330. ui.analysisResultsTitle = uicontrol('Style', 'text', 'string', 'Results', 'fontweight', 'bold', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.815, 0.39, 0.09, 0.02]);
  331. ui.analysisPlot1 = axes('Units', 'Normalized', 'Position', [0.835, 0.255, 0.135, 0.13], 'xminortick', 'on', 'yminortick', 'on');
  332. ui.analysisPlot2 = axes('Units', 'Normalized', 'Position', [0.835, 0.05, 0.135, 0.13], 'xminortick', 'on', 'yminortick', 'on');
  333. ui.analysisPlot1Menu1 = uicontrol('Style', 'popupmenu', 'string', params.analysisPlotMenuList1, 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.855, 0.381, 0.032, 0.03], 'callback', @analysisPlotUpdateCall11, 'interruptible', 'off');
  334. ui.analysisPlot1Menu2 = uicontrol('Style', 'popupmenu', 'string', params.analysisPlotMenuList2, 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.888, 0.381, 0.03, 0.03], 'callback', @analysisPlotUpdateCall21, 'interruptible', 'off');
  335. ui.analysisPlot1Menu3 = uicontrol('Style', 'popupmenu', 'string', params.analysisPlotMenuList3, 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.919, 0.381, 0.032, 0.03], 'callback', @analysisPlotUpdateCall31, 'interruptible', 'off');
  336. ui.analysisPlot1Menu4 = uicontrol('Style', 'popupmenu', 'string', params.analysisPlotMenuList4, 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.952, 0.381, 0.032, 0.03], 'callback', @analysisPlotUpdateCall41, 'interruptible', 'off');
  337. ui.analysisPlot2Menu1 = uicontrol('Style', 'popupmenu', 'string', params.analysisPlotMenuList1, 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.855, 0.176, 0.032, 0.03], 'callback', @analysisPlotUpdateCall12, 'interruptible', 'off');
  338. ui.analysisPlot2Menu2 = uicontrol('Style', 'popupmenu', 'string', params.analysisPlotMenuList2, 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.888, 0.176, 0.03, 0.03], 'callback', @analysisPlotUpdateCall22, 'interruptible', 'off');
  339. ui.analysisPlot2Menu3 = uicontrol('Style', 'popupmenu', 'string', params.analysisPlotMenuList3, 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.919, 0.176, 0.032, 0.03], 'callback', @analysisPlotUpdateCall32, 'interruptible', 'off');
  340. ui.analysisPlot2Menu4 = uicontrol('Style', 'popupmenu', 'string', params.analysisPlotMenuList4, 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.952, 0.176, 0.032, 0.03], 'callback', @analysisPlotUpdateCall42, 'interruptible', 'off');
  341. ui.analysisPlot1MoveUp = uicontrol('Style', 'pushbutton', 'String', '^', 'Units', 'normalized', 'Position', [0.972, 0.36, 0.0125, 0.024], 'Callback', @resultsPlot1YMoveUp, 'interruptible', 'off');
  342. ui.analysisPlot1MoveDown = uicontrol('Style', 'pushbutton', 'String', 'v', 'Units', 'normalized', 'Position', [0.972, 0.255, 0.0125, 0.024], 'Callback', @resultsPlot1YMoveDown, 'interruptible', 'off');
  343. ui.analysisPlot1ZoomIn = uicontrol('Style', 'pushbutton', 'String', '+', 'Units', 'normalized', 'Position', [0.972, 0.335, 0.0125, 0.024], 'Callback', @resultsPlot1YZoomIn, 'interruptible', 'off');
  344. ui.analysisPlot1ZoomOut = uicontrol('Style', 'pushbutton', 'String', '-', 'Units', 'normalized', 'Position', [0.972, 0.28, 0.0125, 0.024], 'Callback', @resultsPlot1YZoomOut, 'interruptible', 'off');
  345. ui.analysisPlot1ZoomReset = uicontrol('Style', 'pushbutton', 'String', 'O', 'Units', 'normalized', 'Position', [0.972, 0.3075, 0.0125, 0.024], 'Callback', @resultsPlot1YReset, 'interruptible', 'off');
  346. ui.analysisPlot2MoveUp = uicontrol('Style', 'pushbutton', 'String', '^', 'Units', 'normalized', 'Position', [0.972, 0.155, 0.0125, 0.024], 'Callback', @resultsPlot2YMoveUp, 'interruptible', 'off');
  347. ui.analysisPlot2MoveDown = uicontrol('Style', 'pushbutton', 'String', 'v', 'Units', 'normalized', 'Position', [0.972, 0.05, 0.0125, 0.024], 'Callback', @resultsPlot2YMoveDown, 'interruptible', 'off');
  348. ui.analysisPlot2ZoomIn = uicontrol('Style', 'pushbutton', 'String', '+', 'Units', 'normalized', 'Position', [0.972, 0.13, 0.0125, 0.024], 'Callback', @resultsPlot2YZoomIn, 'interruptible', 'off');
  349. ui.analysisPlot2ZoomOut = uicontrol('Style', 'pushbutton', 'String', '-', 'Units', 'normalized', 'Position', [0.972, 0.075, 0.0125, 0.024], 'Callback', @resultsPlot2YZoomOut, 'interruptible', 'off');
  350. ui.analysisPlot2ZoomReset = uicontrol('Style', 'pushbutton', 'String', 'O', 'Units', 'normalized', 'Position', [0.972, 0.1025, 0.0125, 0.024], 'Callback', @resultsPlot2YReset, 'interruptible', 'off');
  351. % cell info
  352. ui.cellInfoTitle = uicontrol('Style', 'text', 'string', 'Cell Info', 'fontweight', 'bold', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.015, 0.48, 0.09, 0.02]);
  353. ui.cellInfoIntrinsic = uicontrol('Style', 'pushbutton', 'String', 'Intrinsic Properties (PV .xml)', 'backgroundcolor', [0.9, 0.9, 0.9], 'Units', 'normalized', 'Position', [0.015, 0.45, 0.095, 0.03], 'Callback', @loadIntrinsic, 'interruptible', 'off');
  354. ui.cellInfoIntrinsicOptions = uicontrol('Style', 'pushbutton', 'string', 'Options', 'backgroundcolor', [0.9, 0.9, 0.9], 'Units', 'normalized', 'Position', [0.11075, 0.45, 0.025, 0.03], 'Callback', @loadIntrinsicOptions, 'interruptible', 'off');
  355. ui.cellInfoZStack = uicontrol('Style', 'pushbutton', 'String', 'Z-Stack (.tif, ...)', 'backgroundcolor', [0.9, 0.9, 0.9], 'Units', 'normalized', 'Position', [0.015, 0.42, 0.06, 0.03], 'Callback', @loadZStack, 'interruptible', 'off');
  356. ui.cellInfoSingleScan = uicontrol('Style', 'pushbutton', 'String', 'Single-Scan (.tif, ...)', 'backgroundcolor', [0.9, 0.9, 0.9], 'Units', 'normalized', 'Position', [0.076, 0.42, 0.06, 0.03], 'Callback', @loadSingleScan, 'interruptible', 'off');
  357. % notes
  358. ui.notesTitle = uicontrol('Style', 'text', 'string', 'Notes', 'fontweight', 'bold', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.015, 0.39, 0.09, 0.02]);
  359. ui.notes = uicontrol('Style', 'edit', 'string', '', 'horizontalalignment', 'left', 'min', 1, 'max', 1000, 'Units', 'normalized', 'Position', [0.015, 0.33, 0.12, 0.06], 'Callback', @notesEdit);
  360. % trace processing
  361. ui.traceProcessingTitle = uicontrol('Style', 'text', 'string', 'Postprocessing', 'fontweight', 'bold', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.015, 0.30, 0.09, 0.02]);
  362. ui.traceProcessingTargetText = uicontrol('Style', 'text', 'string', 'Target Signal: ', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.02, 0.274, 0.09, 0.02]);
  363. ui.traceProcessingTarget = uicontrol('Style', 'popupmenu', 'string', params.analysisPlotMenuList1, 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.0775, 0.274, 0.0575, 0.025], 'Callback', @downsamplingSignalSelect, 'interruptible', 'off');
  364. ui.downsamplingButton = uicontrol('Style', 'checkbox', 'min', 0, 'max', 1, 'string', 'Boxcar: ', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.016, 0.242, 0.09, 0.03], 'Callback', @downsamplingBoxcarButton, 'interruptible', 'off');
  365. ui.downsamplingInput = uicontrol('Style', 'edit', 'string', num2str(params.actualParams.boxcarLength2), 'horizontalalignment', 'right', 'Units', 'normalized', 'Position', [0.08, 0.242, 0.016, 0.026], 'Callback', @downsamplingBoxcarInput, 'interruptible', 'off');
  366. ui.downsamplingText = uicontrol('Style', 'text', 'string', 'x', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.096, 0.242, 0.02, 0.02]);
  367. ui.lowPassFilterButton = uicontrol('Style', 'checkbox', 'min', 0, 'max', 1, 'string', 'Bessel LP: ', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.016, 0.212, 0.09, 0.03], 'Callback', @downsamplingBesselButton, 'interruptible', 'off');
  368. ui.lowPassFilterInput = uicontrol('Style', 'edit', 'string', num2str(params.actualParams.besselFreq2), 'horizontalalignment', 'right', 'Units', 'normalized', 'Position', [0.08, 0.212, 0.016, 0.026], 'Callback', @downsamplingBesselInput, 'interruptible', 'off');
  369. ui.lowPassFilterText = uicontrol('Style', 'text', 'string', '(kHz)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.096, 0.212, 0.02, 0.02]);
  370. ui.stimArtifactButton = uicontrol('Style', 'checkbox', 'enable', 'on', 'min', 0, 'max', 1, 'string', 'Remove artifact: ', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.016, 0.18, 0.09, 0.03], 'Callback', @stimArtifactButton, 'interruptible', 'off');
  371. ui.stimArtifactInput = uicontrol('Style', 'edit', 'string', num2str(params.actualParams.artifactLength), 'horizontalalignment', 'right', 'Units', 'normalized', 'Position', [0.08, 0.182, 0.016, 0.026], 'Callback', @stimArtifactLength, 'interruptible', 'off');
  372. ui.stimArtifactText = uicontrol('Style', 'text', 'string', '(ms)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.096, 0.182, 0.03, 0.02]);
  373. ui.stimArtifactText2 = uicontrol('Style', 'text', 'string', 'from', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.025, 0.152, 0.02, 0.02]);
  374. ui.stimArtifactInput2 = uicontrol('Style', 'edit', 'string', num2str(params.actualParams.artifactStart), 'horizontalalignment', 'right', 'Units', 'normalized', 'Position', [0.04, 0.152, 0.016, 0.026], 'Callback', @stimArtifactStart, 'interruptible', 'off');
  375. ui.stimArtifactText3 = uicontrol('Style', 'text', 'string', '(ms)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.056, 0.152, 0.02, 0.02]);
  376. ui.stimArtifactText4 = uicontrol('Style', 'text', 'string', 'x', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.073, 0.152, 0.01, 0.02]);
  377. ui.stimArtifactInput3 = uicontrol('Style', 'edit', 'string', num2str(params.actualParams.artifactCount), 'horizontalalignment', 'right', 'Units', 'normalized', 'Position', [0.08, 0.152, 0.016, 0.026], 'Callback', @stimArtifactCount, 'interruptible', 'off');
  378. ui.stimArtifactText5 = uicontrol('Style', 'text', 'string', 'at', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.096, 0.152, 0.03, 0.02]);
  379. ui.stimArtifactInput4 = uicontrol('Style', 'edit', 'string', num2str(params.actualParams.artifactFreq), 'horizontalalignment', 'right', 'Units', 'normalized', 'Position', [0.105, 0.152, 0.016, 0.026], 'Callback', @stimArtifactFreq, 'interruptible', 'off');
  380. ui.stimArtifactText6 = uicontrol('Style', 'text', 'string', '(Hz)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.121, 0.152, 0.02, 0.02]);
  381. % export
  382. ui.exportDisplayTitle = uicontrol('Style', 'text', 'string', 'Export', 'fontweight', 'bold', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.015, 0.12, 0.09, 0.02]);
  383. ui.exportTargetText = uicontrol('Style', 'text', 'string', 'Source (Plot / Axis): ', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.02, 0.09, 0.09, 0.02]);
  384. %ui.exportTarget = uicontrol('Style', 'popupmenu', 'string', params.analysisPlotMenuList1, 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.042, 0.09, 0.093, 0.025]);
  385. ui.exportTarget1 = uicontrol('Style', 'checkbox', 'min', 0, 'max', 1, 'value', 1, 'string', '1', 'Units', 'normalized', 'Position', [0.09, 0.09, 0.025, 0.025], 'callback', @exportTarget1, 'interruptible', 'off');
  386. ui.exportTarget2 = uicontrol('Style', 'checkbox', 'min', 0, 'max', 1, 'value', 1, 'string', '2', 'Units', 'normalized', 'Position', [0.11, 0.09, 0.025, 0.025], 'callback', @exportTarget2, 'interruptible', 'off');
  387. ui.exportTraceButton1 = uicontrol('Style', 'pushbutton', 'String', 'Traces (.csv)', 'backgroundcolor', [0.85, 0.85, 0.85], 'Units', 'normalized', 'Position', [0.015, 0.03, 0.06, 0.03], 'Callback', @exportTraces1, 'interruptible', 'off');
  388. ui.exportTraceButton2 = uicontrol('Style', 'pushbutton', 'String', 'Trace Display', 'backgroundcolor', [0.85, 0.85, 0.85], 'Units', 'normalized', 'Position', [0.015, 0.06, 0.06, 0.03], 'Callback', @exportTraces2, 'interruptible', 'off');
  389. ui.exportResultsButton1 = uicontrol('Style', 'pushbutton', 'String', 'Results (.csv)', 'backgroundcolor', [0.85, 0.85, 0.85], 'Units', 'normalized', 'Position', [0.076, 0.06, 0.06, 0.03], 'Callback', @exportResults1, 'interruptible', 'off');
  390. ui.exportResultsButton2 = uicontrol('Style', 'pushbutton', 'String', 'All Results (.mat)', 'backgroundcolor', [0.85, 0.85, 0.85], 'Units', 'normalized', 'Position', [0.076, 0.03, 0.06, 0.03], 'Callback', @exportResults2, 'interruptible', 'off');
  391. % intrinsic properties
  392. ui.intrinsicTitle = uicontrol('Style', 'text', 'string', 'Intrinsic Membrane Properties: ', 'fontweight', 'bold', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.15, 0.3, 0.12, 0.02]);
  393. ui.intrinsicFileName = uicontrol('Style', 'popupmenu', 'string', '(N/A)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.26, 0.298, 0.09, 0.025], 'callback', @copyTextFromPopup, 'interruptible', 'off');
  394. ui.intrinsicUseCurrentFile = uicontrol('Style', 'pushbutton', 'String', 'Use ^', 'Units', 'normalized', 'Position', [0.3525, 0.3, 0.02, 0.024], 'Callback', @intrinsicUseCurrent, 'interruptible', 'off');
  395. ui.intrinsicReanalyze = uicontrol('Style', 'pushbutton', 'String', 'Re-analyze', 'Units', 'normalized', 'Position', [0.3725, 0.3, 0.04, 0.024], 'Callback', @intrinsicReanalyze, 'interruptible', 'off');
  396. ui.intrinsicDel = uicontrol('Style', 'pushbutton', 'String', 'X', 'Units', 'normalized', 'Position', [0.412, 0.3, 0.012, 0.024], 'Callback', @intrinsicDel, 'interruptible', 'off');
  397. ui.intrinsicPlot1 = axes('Units', 'Normalized', 'Position', [0.19, 0.05, 0.11, 0.23], 'xminortick', 'on', 'yminortick', 'on', 'box', 'on');
  398. ui.intrinsicPlot2 = axes('Units', 'Normalized', 'Position', [0.325, 0.19, 0.1, 0.09], 'xminortick', 'on', 'yminortick', 'on');
  399. ui.intrinsicPlot3 = axes('Units', 'Normalized', 'Position', [0.325, 0.05, 0.1, 0.09], 'xminortick', 'on', 'yminortick', 'on');
  400. ui.intrinsicPlot1Enlarge = uicontrol('Style', 'pushbutton', 'String', '+', 'Units', 'normalized', 'Position', [0.288, 0.254, 0.012, 0.024], 'Callback', @intrinsicPlot1Enlarge, 'interruptible', 'off');
  401. ui.intrinsicPlot2Enlarge = uicontrol('Style', 'pushbutton', 'String', '+', 'Units', 'normalized', 'Position', [0.413, 0.254, 0.012, 0.024], 'Callback', @intrinsicPlot2Enlarge, 'interruptible', 'off');
  402. ui.intrinsicPlot3Enlarge = uicontrol('Style', 'pushbutton', 'String', '+', 'Units', 'normalized', 'Position', [0.413, 0.114, 0.012, 0.024], 'Callback', @intrinsicPlot3Enlarge, 'interruptible', 'off');
  403. ui.intrinsicRMP = uicontrol('Style', 'text', 'string', '', 'backgroundcolor', 'w', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.2425, 0.235, 0.055, 0.02]);
  404. ui.intrinsicRin = uicontrol('Style', 'text', 'string', '', 'backgroundcolor', 'w', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.2425, 0.215, 0.055, 0.02]);
  405. ui.intrinsicSag = uicontrol('Style', 'text', 'string', '', 'backgroundcolor', 'w', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.2425, 0.195, 0.055, 0.02]);
  406. % z-stack and single-scan images
  407. ui.zStackTitle = uicontrol('Style', 'text', 'string', 'Z-Stack: ', 'fontweight', 'bold', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.445, 0.3, 0.08, 0.02]);
  408. ui.zStackFileName = uicontrol('Style', 'popupmenu', 'string', '(N/A)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.505, 0.298, 0.055, 0.025], 'callback', @copyTextFromPopup, 'interruptible', 'off');
  409. ui.zStackDel = uicontrol('Style', 'pushbutton', 'String', 'X', 'Units', 'normalized', 'Position', [0.562, 0.3, 0.012, 0.024], 'Callback', @zStackDel, 'interruptible', 'off');
  410. ui.zStackEnlarge = uicontrol('Style', 'pushbutton', 'String', '+', 'Units', 'normalized', 'Position', [0.562, 0.2725, 0.012, 0.024], 'Callback', @zStackEnlarge, 'interruptible', 'off');
  411. ui.zStackDisplay = axes('Units', 'Normalized', 'Position', [0.445, 0.03, 0.13, 0.27], 'box', 'on', 'xtick', [], 'ytick', [], 'xcolor', [0.8, 0.8, 0.8], 'ycolor', [0.8, 0.8, 0.8], 'color', [0.95, 0.95, 0.95]);
  412. ui.singleScanTitle = uicontrol('Style', 'text', 'string', 'Single-Scan: ', 'fontweight', 'bold', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.58, 0.3, 0.08, 0.02]);
  413. ui.singleScanFileName = uicontrol('Style', 'popupmenu', 'string', '(N/A)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.64, 0.298, 0.055, 0.025], 'callback', @copyTextFromPopup, 'interruptible', 'off');
  414. ui.singleScanDel = uicontrol('Style', 'pushbutton', 'String', 'X', 'Units', 'normalized', 'Position', [0.697, 0.3, 0.012, 0.024], 'Callback', @singleScanDel, 'interruptible', 'off');
  415. ui.singleScanEnlarge = uicontrol('Style', 'pushbutton', 'String', '+', 'Units', 'normalized', 'Position', [0.697, 0.2725, 0.012, 0.024], 'Callback', @singleScanEnlarge, 'interruptible', 'off');
  416. ui.singleScanDisplay = axes('Units', 'Normalized', 'Position', [0.58, 0.03, 0.13, 0.27], 'box', 'on', 'xtick', [], 'ytick', [], 'xcolor', [0.8, 0.8, 0.8], 'ycolor', [0.8, 0.8, 0.8], 'color', [0.95, 0.95, 0.95]);
  417. % linescan
  418. ui.lineScanDisplayTitle = uicontrol('Style', 'text', 'string', 'Linescans: ', 'fontweight', 'bold', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.72, 0.3, 0.08, 0.02]);
  419. ui.lineScanRoiButton = uicontrol('Style', 'pushbutton', 'enable', 'off', 'string', '(ROI)', 'foregroundcolor', [0.2, 0.2, 1], 'horizontalalignment', 'center', 'Units', 'normalized', 'Position', [0.78, 0.3, 0.02, 0.024], 'callback', @lineScanRoiManualSelect, 'interruptible', 'off');
  420. ui.lineScan1Title = uicontrol('Style', 'text', 'string', 'Ch. 1', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.72, 0.27, 0.04, 0.02]);
  421. ui.lineScan2Title = uicontrol('Style', 'text', 'string', 'Ch. 2', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.761, 0.27, 0.04, 0.02]);
  422. ui.lineScan1Display = axes('Units', 'Normalized', 'Position', [0.72, 0.03, 0.038, 0.24], 'box', 'on', 'xtick', [], 'ytick', [], 'xcolor', [0.8, 0.8, 0.8], 'ycolor', [0.8, 0.8, 0.8], 'color', [0.95, 0.95, 0.95]);
  423. ui.lineScan2Display = axes('Units', 'Normalized', 'Position', [0.761, 0.03, 0.038, 0.24], 'box', 'on', 'xtick', [], 'ytick', [], 'xcolor', [0.8, 0.8, 0.8], 'ycolor', [0.8, 0.8, 0.8], 'color', [0.95, 0.95, 0.95]);
  424. % initialize display areas
  425. %{
  426. set(ui.traceDisplay, 'xtick', [], 'ytick', [], 'xlabel', [], 'ylabel', []);
  427. set(ui.analysisPlot1, 'xtick', [], 'ytick', [], 'xlabel', [], 'ylabel', []);
  428. set(ui.analysisPlot2, 'xtick', [], 'ytick', [], 'xlabel', [], 'ylabel', []);
  429. set(get(ui.traceDisplay, 'xlabel'), 'string', 't (ms)');
  430. set(get(ui.traceDisplay, 'ylabel'), 'string', 'V_m (mV)');
  431. %}
  432. axes(ui.intrinsicPlot1);
  433. xlabel('t (ms)');
  434. ylabel('V_m (mV)');
  435. xticks(''); yticks('');
  436. axes(ui.intrinsicPlot2);
  437. xlabel('i (pA)');
  438. ylabel('dV (mV)');
  439. xticks(''); yticks('');
  440. axes(ui.intrinsicPlot3);
  441. xlabel('i (pA)');
  442. ylabel('f (Hz)');
  443. xticks(''); yticks('');
  444. axes(ui.analysisPlot1);
  445. %xlabel('Sweep #');
  446. %xticks(''); %yticks('');
  447. axes(ui.analysisPlot2);
  448. %xlabel('Sweep #');
  449. %xticks(''); %yticks('');
  450. axes(ui.traceDisplay); % move focus to main display panel
  451. set(gca, 'layer', 'top');
  452. xlabel('t (ms)');
  453. %{
  454. yyaxis left; ylabel('V_m (mV)', 'color', 'k'); ylim(params.yRange); set(gca, 'ycolor', 'k', 'yminortick', 'on');
  455. yyaxis right; ylabel('dF/F', 'color', 'g'); ylim(params.y2Range); set(gca, 'ycolor', [0, 0.5, 0], 'yminortick', 'on');
  456. %}
  457. xlabel(' ', 'color', 'k'); xlim([-1, 0]);
  458. yyaxis left; ylabel(' ', 'color', 'k'); ylim([-10000, 10000]); set(gca, 'ycolor', 'k');
  459. yyaxis right; ylabel(' ', 'color', 'g'); ylim([-10000, 10000]); set(gca, 'ycolor', [0, 0.5, 0]);
  460. yyaxis left; % move focus back to left y axis to be safe
  461. % save
  462. h.exp = exp;
  463. h.results = results;
  464. h.analysis = analysis;
  465. h.params = params;
  466. h.ui = ui;
  467. guidata(win, h);
  468. % load default parameters - moved up
  469. %defaultParams = setDefaultParams(win); % this has to be done after guidata(win, h)
  470. %h.params.defaultParams = defaultParams;
  471. end
  472. %% Default Parameters
  473. function defaultParams = setDefaultParams(win);
  474. % load
  475. h = guidata(win);
  476. % gain settings
  477. % below are set for MC700B with Rf = 500 MO and usual gain settings for whole-cell recordings, in combination with PV
  478. % reminder: these are dependent on both acquisition hardware and software settings; make sure they are correct!
  479. pvbsVoltageScalingFactor = 100; % (mV/V); % 100 for P-IV (MIT MIBR 46-6178) and Rigs 1 & 2 (46-6190)
  480. pvbsCurrentScalingFactor = 2000; % (pA/V); % 2000 for P-IV (MIT MIBR 46-6178), or 10000 for Rigs 1 & 2 (46-6190) - 2022-07-19 JY
  481. % PV software conventions
  482. % below are set for single channel recording of V and i (in that order)
  483. % multiple-channel support pending %%% fixlater
  484. timeColumn = 1; % column 1: timestamp
  485. timeColumnAvailable = 1; % flag for timestamp availability
  486. pvbsVoltageColumn = 2; % column 2: voltage
  487. pvbsCurrentColumn = 3; % column 3: current
  488. csvOffsetRow = 1; % row 1: title
  489. csvOffsetColumn = 0; % no column offset
  490. csvColumnsAsSweeps = 1; % each column represents a sweep - set this to 0 if primarilily used for importing .csv saved directly from PV (not recommended; import .xls metadata instead for PV data)
  491. % voltage/current data
  492. analysisColumn = pvbsVoltageColumn; % column for analysis; NB. column 1 will usually be timestamp in the current code
  493. peakDirection1 = 0; % window 1 default peak direction (-1, 0, 1 : negative, absolute, positive)
  494. peakDirection2 = 0; % window 2 default peak direction (-1, 0, 1 : negative, absolute, positive)
  495. useMedian = 1; % use median instead of mean for baseline, "mean" (in peak analysis), etc., to be robust from noise
  496. riseDecay = [20, 80]; % low/high point for kinetics analysis (e.g. [20, 80] for 20-80 %)
  497. % fluorescence data
  498. lineScanChannel = 2; % primary channel for calcium imaging signal; e.g. for P4, 1: red, 2: green (primary)
  499. lineScanBaseline = [23, 40]; % (ms), baseline for F_0 in linescans, avoid starting from 0 to prevent possible contamination from shutter artifact
  500. lineScanROIDetectDuringBaseline = 1; % detect linescan ROI only during baseline window specified above (0: no, 1: yes), in order to prevent possible errors from uncaging artifact
  501. lineScanDownsamplingFactor = 1; % downsampling factor for fluorescence signals, for the dF/F to be robust to noise
  502. % NB. for best performance in ROI detection, use minimal (or zero) smoothing,
  503. % high threshold for ROI, and low (in terms of absolute value) threshold for background;
  504. % +/- 1 pixel, top 2% (roi), bottom 50% (background) seems best (2022-02-03)
  505. lineScanROISmoothing = 1; % will average over this many points before and after (not total) while detecting ROI to be robust from noise - obsolete with single ROI
  506. %lineScanROIThreshold = 2.32635; % (s.d.); z-score for 1st percentile
  507. lineScanROIThreshold = 2.05375; % (s.d.); z-score for 2nd percentile
  508. %lineScanROIThreshold = 1.64485; % (s.d.); z-score for 5th percentile
  509. %lineScanROIThreshold = 1.28125; % (s.d.); z-score for 10th percentile
  510. %lineScanROIThreshold = 0.67449; % (s.d.); z-score for 1st quartile
  511. %lineScanROIThreshold = 0.43991; % (s.d.); z-score for 33rd percentile
  512. lineScanBackgroundThreshold = -0; % (s.d.); z-score for 2nd quartile
  513. %lineScanBackgroundThreshold = -0.43991; % (s.d.); z-score for 67th percentile
  514. %lineScanBackgroundThreshold = -0.67449; % (s.d.); z-score for 3rd quartile
  515. %lineScanBackgroundThreshold = -1.28125; % (s.d.); z-score for 90th percentile
  516. %lineScanBackgroundThreshold = -2.05375; % (s.d.); z-score for 98th percentile
  517. lineScanColorMapRange = 0.8; % saturate displayed intensity for signals above this percentage of maximum
  518. offloadMarkPointsMetadata = 0; % delete markpoints metadata after retrieving point indices to save space (0: no, 1: yes)
  519. % signals to display
  520. signal1Type = 2; % current, voltage, fluorescence
  521. signal2Type = 3; % current, voltage, fluorescence
  522. signal1Channel = pvbsVoltageColumn; % corresponding to data column, but mind timestamp availability
  523. signal2Channel = lineScanChannel; % corresponding to data column, but mind timestamp availability
  524. % PV hardware error correction
  525. % Prairie (now Bruker) GPIO box (DAC) can quite unbelievably have bleedthrough across channels,
  526. % which has to be corrected if present; otherwise, it could lead to introducing
  527. % "phantom" DC offset error in data...
  528. % - DO NOT use if recordings DO have intentional baseline DC injection at the beginning!
  529. % - DO NOT confuse this with having an incorrect bias setting on the amplifier!
  530. % (e.g. RV2 for MC700B, or i_G for BVC700A)
  531. pvbsCurrentCorrectionFlag = 0; % set to 1 to correct, 0 to leave as is
  532. pvbsCurrentCorrectionDataPoints = 50; % this many points at the beginning will be used for baseline correction
  533. % data downsampling
  534. boxcarLength1 = 0; % boxcar length for Ch. 1 (e.g. V); 0 to disable by default
  535. %boxcarLength2 = 4; % boxcar length for Ch. 2 (e.g. dF/F); 0 to disable by default
  536. boxcarLength2 = 0; % boxcar length for Ch. 2 (e.g. dF/F); 0 to disable by default
  537. besselFreq1 = 0; % (kHz); Bessel filter cutoff frequency for Ch. 1; 0 to disable by default
  538. %besselFreq2 = 1; % (kHz); Bessel filter cutoff frequency for Ch. 2; 0 to disable by default
  539. besselFreq2 = 0; % (kHz); Bessel filter cutoff frequency for Ch. 2; 0 to disable by default
  540. besselOrder1 = 4; % reverse Bessel polynomial order for Ch. 1
  541. besselOrder2 = 4; % reverse Bessel polynomial order for Ch. 2
  542. % artifact removal
  543. artifactLength = 2; % (ms)
  544. artifactStart = 50; % (ms)
  545. artifactCount = 1;
  546. artifactFreq = 10; % (Hz)
  547. % sweep segmentation
  548. % for convenience with single spines - none of which should be necessary were PV not gap-free all the time
  549. segmentationLength = 200; % segment length (ms)
  550. segmentationOffset = 150; % segmentation initial offset (ms)
  551. % below was for convenience with 3 groups of spines
  552. %{
  553. segmentationLength = 400; % segment length (ms)
  554. segmentationOffset = 350; % segmentation initial offset (ms)
  555. %}
  556. segmentationTruncate = 1; % truncate remainder (0: no, 1: yes)
  557. segmentationCount = 0; % keep only this many segments and discard the rest (0 to disable)
  558. % analysis - intrinsic properties (to be reverse compatible with ancient code)
  559. % data format
  560. intrinsicPropertiesAnalysis = struct();
  561. intrinsicPropertiesAnalysisInput = [pvbsVoltageScalingFactor, pvbsCurrentScalingFactor, pvbsCurrentCorrectionFlag];
  562. intrinsicPropertiesAnalysis = setDefaultParamsIntrinsic(intrinsicPropertiesAnalysis, intrinsicPropertiesAnalysisInput);
  563. % event detection and waveform analysis
  564. eventAnalysis = struct();
  565. eventAnalysis.detectionThreshold = 0; % event detection threshold (e.g. 0 mV; do not confuse with AP threshold definition (e.g. 20 V/s))
  566. eventAnalysis.detectionRearm = -10; % event detection re-arm point (e.g. -10 mV)
  567. eventAnalysis.detectionDirection = 1; % (-1: negative, 1: positive); don't rename it to eventDirection to avoid confusion with variable with the same name from analysis results
  568. eventAnalysis.apThresholdDvdt = 20; % definition of AP threshold (e.g. 20 V/s)
  569. eventAnalysis.apThresholdInterpolate = 1; % interpolate data points to obtain AP threshold (0: no, 1: yes)
  570. eventAnalysis.apThresholdTakePrecedingPoint = 1; % take one data point preceding AP threshold definition for AP threshold - useful in case of low sampling rates (0: no, 1: yes)
  571. eventAnalysis.restingStateDuration = 100; % (ms); e.g. for RMP calculation
  572. % uncaging analysis - moved from auto analysis macro (messed up old code)
  573. uncagingAnalysis = struct();
  574. uncagingAnalysis.winV = 1; % analysis window for V (NB. do not confuse with signal channel)
  575. uncagingAnalysis.winF = 2; % analysis window for dF/F (NB. do not confuse with signal channel)
  576. uncagingAnalysis.pspMax = 35; % max PSP (mV) for threshold detection
  577. uncagingAnalysis.uncUnitSizeDefault = 1; % default assumption for unit size (in number of spines), only used when markpoints metadata is not available
  578. % sweep grouping
  579. autoGroup = 'Automatic'; % somewhat arbitrary but whatever - currently set to MarkPoints for LineScan and VoltageOutput for TSeries, see loadExpMain()
  580. % default directory
  581. dirSaveDefault = cd;
  582. dirLoadDefault = cd;
  583. % save
  584. defaultParams.pvbsVoltageScalingFactor = pvbsVoltageScalingFactor;
  585. defaultParams.pvbsCurrentScalingFactor = pvbsCurrentScalingFactor;
  586. defaultParams.timeColumn = timeColumn;
  587. defaultParams.timeColumnAvailable = timeColumnAvailable;
  588. defaultParams.pvbsVoltageColumn = pvbsVoltageColumn;
  589. defaultParams.pvbsCurrentColumn = pvbsCurrentColumn;
  590. defaultParams.csvOffsetRow = csvOffsetRow;
  591. defaultParams.csvOffsetColumn = csvOffsetColumn;
  592. defaultParams.csvColumnsAsSweeps = csvColumnsAsSweeps;
  593. defaultParams.signal1Type = signal1Type;
  594. defaultParams.signal2Type = signal2Type;
  595. defaultParams.signal1Channel = signal1Channel;
  596. defaultParams.signal2Channel = signal2Channel;
  597. defaultParams.analysisColumn = analysisColumn;
  598. defaultParams.peakDirection1 = peakDirection1;
  599. defaultParams.peakDirection2 = peakDirection2;
  600. defaultParams.useMedian = useMedian;
  601. defaultParams.riseDecay = riseDecay;
  602. defaultParams.autoGroup = autoGroup;
  603. defaultParams.lineScanChannel = lineScanChannel;
  604. defaultParams.lineScanBaseline = lineScanBaseline;
  605. defaultParams.lineScanROIDetectDuringBaseline = lineScanROIDetectDuringBaseline;
  606. defaultParams.lineScanDownsamplingFactor = lineScanDownsamplingFactor;
  607. defaultParams.lineScanROISmoothing = lineScanROISmoothing;
  608. defaultParams.lineScanROIThreshold = lineScanROIThreshold;
  609. defaultParams.lineScanBackgroundThreshold = lineScanBackgroundThreshold;
  610. defaultParams.lineScanColorMapRange = lineScanColorMapRange;
  611. defaultParams.offloadMarkPointsMetadata = offloadMarkPointsMetadata;
  612. defaultParams.pvbsCurrentCorrectionFlag = pvbsCurrentCorrectionFlag;
  613. defaultParams.pvbsCurrentCorrectionDataPoints = pvbsCurrentCorrectionDataPoints;
  614. defaultParams.boxcarLength1 = boxcarLength1;
  615. defaultParams.boxcarLength2 = boxcarLength2;
  616. defaultParams.besselFreq1 = besselFreq1;
  617. defaultParams.besselFreq2 = besselFreq2;
  618. defaultParams.besselOrder1 = besselOrder1;
  619. defaultParams.besselOrder2 = besselOrder2;
  620. defaultParams.artifactLength = artifactLength;
  621. defaultParams.artifactStart = artifactStart;
  622. defaultParams.artifactCount = artifactCount;
  623. defaultParams.artifactFreq = artifactFreq;
  624. defaultParams.segmentationLength = segmentationLength;
  625. defaultParams.segmentationOffset = segmentationOffset;
  626. defaultParams.segmentationTruncate = segmentationTruncate;
  627. defaultParams.segmentationCount = segmentationCount;
  628. defaultParams.intrinsicPropertiesAnalysis = intrinsicPropertiesAnalysis;
  629. defaultParams.eventAnalysis = eventAnalysis;
  630. defaultParams.uncagingAnalysis = uncagingAnalysis;
  631. %h.params.actualParams = actualParams;
  632. guidata(win, h);
  633. end
  634. function intrinsicPropertiesAnalysis = setDefaultParamsIntrinsic(intrinsicPropertiesAnalysis, intrinsicPropertiesAnalysisInput)
  635. % separated for access from elsewhere
  636. % relics
  637. pvbsVoltageScalingFactor = intrinsicPropertiesAnalysisInput(1);
  638. pvbsCurrentScalingFactor = intrinsicPropertiesAnalysisInput(2);
  639. pvbsCurrentCorrectionFlag = intrinsicPropertiesAnalysisInput(3);
  640. % actual stuff
  641. intrinsicPropertiesAnalysis.v_rec_gain = pvbsVoltageScalingFactor; % gain for V, defined above
  642. intrinsicPropertiesAnalysis.i_cmd_gain = pvbsCurrentScalingFactor; % gain for i, defined above
  643. intrinsicPropertiesAnalysis.voltage_signal_channel = 1; % V_m channel, from PV (NB. defined differently above as .csv comlumn index)
  644. intrinsicPropertiesAnalysis.data_length_unit = 100; % (ms); truncate data to a nice multiple of this (e.g. 17919 ms -> 17900 ms)
  645. intrinsicPropertiesAnalysis.data_voltage_samplingrate = 20; % (kHz); sampling rate (e.g. 20 kHz = 20 points/ms)
  646. intrinsicPropertiesAnalysis.data_voltage_interval = 1/intrinsicPropertiesAnalysis.data_voltage_samplingrate; % (ms); data point interval (e.g. 20 kHz = 20 points/ms)
  647. intrinsicPropertiesAnalysis.i_bsln_correction = pvbsCurrentCorrectionFlag; % GPIO error correction, defined above
  648. intrinsicPropertiesAnalysis.i_bsln_correction_window = 10; % GPIO error correction window (ms) (NB. defined differently above as datapoints)
  649. % long protocol
  650. %%{
  651. % segmentation (episodic transformation)
  652. intrinsicPropertiesAnalysis.data_segmentation_cutoff_first = 0; % (ms); discard this length of data at the beginning
  653. intrinsicPropertiesAnalysis.data_segment_length = 1000; % Sweep duration (ms), synonymous with inter-sweep interval because of absolutely stupid gap-free PV
  654. % detection window; for more than 2 windows, manually set them as n*3 arrays (start, end, direction) and pass them onto functions
  655. intrinsicPropertiesAnalysis.window_baseline_start = 0; % (ms); baseline start - this is not for main analysis window, but for intrinsic properties!
  656. intrinsicPropertiesAnalysis.window_baseline_end = 100; % (ms); baseline end
  657. intrinsicPropertiesAnalysis.window_n = 1; % number of detection windows (1 or 2)
  658. intrinsicPropertiesAnalysis.window_start = 100; % (ms); detection window start
  659. intrinsicPropertiesAnalysis.window_end = 600; % (ms); detection window end
  660. intrinsicPropertiesAnalysis.window_direction = 0; % (ms); detection window 1 direction (-1: negative, 0: either, 1: positive; e.g. for peak detection)
  661. %{
  662. intrinsicPropertiesAnalysis.window_n = 2; % number of detection windows (1 or 2)
  663. intrinsicPropertiesAnalysis.window_1_start = 100; % (ms); detection window 1 start
  664. intrinsicPropertiesAnalysis.window_1_end = 200; % (ms); detection window 1 end
  665. intrinsicPropertiesAnalysis.window_1_direction = 0; % (ms); detection window 1 direction (-1: negative, 0: either, 1: positive; e.g. for peak detection)
  666. intrinsicPropertiesAnalysis.window_2_start = 500; % (ms); analysis window 2 start
  667. intrinsicPropertiesAnalysis.window_2_end = 600; % (ms); analysis window 2 end
  668. intrinsicPropertiesAnalysis.window_2_direction = 0; % (ms); analysis window 2 direction (-1: negative, 0: either, 1: positive; e.g. for peak detection)
  669. %}
  670. % short protocol
  671. %{
  672. % segmentation (episodic transformation)
  673. intrinsicPropertiesAnalysis.data_segmentation_cutoff_first = 0; % (ms); discard this length of data at the beginning
  674. intrinsicPropertiesAnalysis.data_segment_length = 1000; % Sweep duration (ms), synonymous with inter-sweep interval because of absolutely stupid gap-free PV
  675. % detection window; for more than 2 windows, manually set them as n*3 arrays (start, end, direction) and pass them onto functions
  676. intrinsicPropertiesAnalysis.window_baseline_start = 0; % (ms); baseline start - this is not for main analysis window, but for intrinsic properties!
  677. intrinsicPropertiesAnalysis.window_baseline_end = 250; % (ms); baseline end
  678. intrinsicPropertiesAnalysis.window_n = 2; % number of detection windows (1 or 2)
  679. intrinsicPropertiesAnalysis.window_1_start = 250; % (ms); detection window 1 start
  680. intrinsicPropertiesAnalysis.window_1_end = 350; % (ms); detection window 1 end
  681. intrinsicPropertiesAnalysis.window_1_direction = 0; % (ms); detection window 1 direction (-1: negative, 0: either, 1: positive; e.g. for peak detection)
  682. intrinsicPropertiesAnalysis.window_2_start = 400; % (ms); analysis window 2 start
  683. intrinsicPropertiesAnalysis.window_2_end = 500; % (ms); analysis window 2 end
  684. intrinsicPropertiesAnalysis.window_2_direction = 0; % (ms); analysis window 2 direction (-1: negative, 0: either, 1: positive; e.g. for peak detection)
  685. %}
  686. % display options
  687. intrinsicPropertiesAnalysis.stepStart = intrinsicPropertiesAnalysis.window_start; % defined above
  688. intrinsicPropertiesAnalysis.stepEnd = intrinsicPropertiesAnalysis.window_end; % defined above
  689. intrinsicPropertiesAnalysis.stepLength = intrinsicPropertiesAnalysis.stepEnd - intrinsicPropertiesAnalysis.stepStart;
  690. intrinsicPropertiesAnalysis.displayMargin = 0.25; % relative to step length
  691. intrinsicPropertiesAnalysis.displayStart = intrinsicPropertiesAnalysis.stepStart - intrinsicPropertiesAnalysis.displayMargin * intrinsicPropertiesAnalysis.stepLength;
  692. intrinsicPropertiesAnalysis.displayEnd = intrinsicPropertiesAnalysis.stepEnd + intrinsicPropertiesAnalysis.displayMargin * intrinsicPropertiesAnalysis.stepLength;
  693. %{
  694. intrinsicPropertiesAnalysis.stepStart = intrinsicPropertiesAnalysis.window_1_start; % defined above
  695. intrinsicPropertiesAnalysis.stepEnd = intrinsicPropertiesAnalysis.window_2_end; % defined above
  696. intrinsicPropertiesAnalysis.stepLength = intrinsicPropertiesAnalysis.stepEnd - intrinsicPropertiesAnalysis.stepStart;
  697. intrinsicPropertiesAnalysis.displayMargin = 0.25; % relative to step length
  698. intrinsicPropertiesAnalysis.displayStart = intrinsicPropertiesAnalysis.stepStart - intrinsicPropertiesAnalysis.displayMargin * intrinsicPropertiesAnalysis.stepLength;
  699. intrinsicPropertiesAnalysis.displayEnd = intrinsicPropertiesAnalysis.stepEnd + intrinsicPropertiesAnalysis.displayMargin * intrinsicPropertiesAnalysis.stepLength;
  700. %}
  701. % R_in calculation
  702. intrinsicPropertiesAnalysis.iStepSize = 20; % (pA); default i_cmd step size to override where i_cmd data is unavailable
  703. intrinsicPropertiesAnalysis.iStepFirst = -200; % (pA); default i_cmd first step to override where i_cmd data is unavailable
  704. intrinsicPropertiesAnalysis.iStepLast = 2000; % (pA); default i_cmd last step to override where i_cmd data is unavailable
  705. intrinsicPropertiesAnalysis.iStepOverride = 1; % override i_step definition with values above where i_cmd data is unavailable
  706. intrinsicPropertiesAnalysis.RinAtSteadyState = 0; % no more of those idiotic practice at 46
  707. intrinsicPropertiesAnalysis.RinByLinearFit = 1; % don't like this either
  708. intrinsicPropertiesAnalysis.RinSweep = 1; %
  709. % Spike threshold
  710. %intrinsicPropertiesAnalysis.spikeThreshold = 10; % (mV); relatively strict
  711. intrinsicPropertiesAnalysis.spikeThreshold = 0; % (mV); meh
  712. %intrinsicPropertiesAnalysis.spikeThreshold = -10; % (mV); relatively loose
  713. intrinsicPropertiesAnalysis.spikeDetectionRearm = -10; % (mV); very arbitrary
  714. end
  715. function defaultSettingsCallback(src, ~)
  716. % default settings
  717. % load
  718. h = guidata(src);
  719. win1 = src.Parent;
  720. srcButton = src;
  721. set(srcButton, 'enable', 'off');
  722. % load parameters
  723. analysisParameters = h.params.actualParams;
  724. analysisParametersDefault = h.params.defaultParams;
  725. % reverse compatibility
  726. try
  727. timeColumnAvailable = analysisParameters.timeColumnAvailable;
  728. catch ME
  729. analysisParameters.timeColumn = 1;
  730. timeColumnAvailable = 1;
  731. end
  732. % options
  733. optionsWin = figure('Name', 'Import Settings', 'NumberTitle', 'off', 'MenuBar', 'none', 'Units', 'Normalized', 'Position', [0.2, 0.25, 0.45, 0.6], 'resize', 'off', 'DeleteFcn', @winClosed); % use CloseRequestFcn?
  734. oWin.t101 = uicontrol('Parent', optionsWin, 'Style', 'text', 'fontweight', 'bold', 'string', 'DAC gain', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.025, 0.925, 0.9, 0.04]);
  735. oWin.t102 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', '(Cf. Amplifier output & "Acquisition Channel Properties" in PV "Voltage Recording" window)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.125, 0.925, 0.8, 0.04]);
  736. oWin.t111 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'Voltage scaling factor', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.05, 0.88, 0.4, 0.04]);
  737. oWin.t112 = uicontrol('Parent', optionsWin, 'Style', 'edit', 'string', num2str(analysisParameters.pvbsVoltageScalingFactor), 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.25, 0.8875, 0.125, 0.04], 'callback', @updateParams);
  738. oWin.t113 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', '(mV/V)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.4, 0.88, 0.1, 0.04]);
  739. oWin.t121 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'Current scaling factor', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.55, 0.88, 0.4, 0.04]);
  740. oWin.t122 = uicontrol('Parent', optionsWin, 'Style', 'edit', 'string', num2str(analysisParameters.pvbsCurrentScalingFactor), 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.75, 0.8875, 0.125, 0.04], 'callback', @updateParams);
  741. oWin.t123 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', '(pA/V)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.9, 0.88, 0.1, 0.04]);
  742. oWin.t201 = uicontrol('Parent', optionsWin, 'Style', 'text', 'fontweight', 'bold', 'string', '.CSV import', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.025, 0.825, 0.9, 0.04]);
  743. oWin.t202 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', '(NB. Settings overridden when directly importing .csv, instead of via PV metadata .xml; _iff_ "Columns represent sweeps" is checked)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.125, 0.825, 0.85, 0.04]);
  744. oWin.t211 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'Row offset:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.05, 0.78, 0.4, 0.04]);
  745. oWin.t212 = uicontrol('Parent', optionsWin, 'Style', 'edit', 'string', num2str(analysisParameters.csvOffsetRow), 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.25, 0.7875, 0.125, 0.04], 'callback', @updateParams);
  746. oWin.t213 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', '', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.4, 0.78, 0.1, 0.04]);
  747. oWin.t221 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'Column offset:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.55, 0.78, 0.4, 0.04]);
  748. oWin.t222 = uicontrol('Parent', optionsWin, 'Style', 'edit', 'string', num2str(analysisParameters.csvOffsetColumn), 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.75, 0.7875, 0.125, 0.04], 'callback', @updateParams);
  749. oWin.t223 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', '', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.9, 0.78, 0.1, 0.04]);
  750. oWin.t231 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'Timestamp (t; ms) at column:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.05, 0.73, 0.4, 0.04]);
  751. oWin.t232 = uicontrol('Parent', optionsWin, 'Style', 'edit', 'enable', 'off', 'string', num2str(analysisParameters.timeColumn), 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.25, 0.7375, 0.125, 0.04], 'callback', @updateParams);
  752. oWin.t233 = uicontrol('Parent', optionsWin, 'Style', 'checkbox', 'enable', 'off', 'string', '(available)', 'value', logical(timeColumnAvailable), 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.4, 0.7375, 0.4, 0.04], 'callback', @updateParams);
  753. oWin.t241 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'Voltage (V; mV) at column:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.05, 0.68, 0.4, 0.04]);
  754. oWin.t242 = uicontrol('Parent', optionsWin, 'Style', 'edit', 'string', num2str(analysisParameters.pvbsVoltageColumn), 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.25, 0.6875, 0.125, 0.04], 'callback', @updateParams);
  755. oWin.t243 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', '', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.4, 0.68, 0.1, 0.04]);
  756. oWin.t251 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'Current (i; pA) at column:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.55, 0.68, 0.4, 0.04]);
  757. oWin.t252 = uicontrol('Parent', optionsWin, 'Style', 'edit', 'string', num2str(analysisParameters.pvbsCurrentColumn), 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.75, 0.6875, 0.125, 0.04], 'callback', @updateParams);
  758. oWin.t253 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', '', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.9, 0.68, 0.1, 0.04]);
  759. oWin.t261 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'Columns represent sweeps:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.55, 0.73, 0.4, 0.04]);
  760. oWin.t262 = uicontrol('Parent', optionsWin, 'Style', 'checkbox', 'string', '(for direct import only)', 'value', logical(analysisParameters.csvColumnsAsSweeps), 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.75, 0.7375, 0.2, 0.04], 'callback', @updateParams);
  761. oWin.t263 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', '', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.9, 0.73, 0.1, 0.04]);
  762. oWin.t301 = uicontrol('Parent', optionsWin, 'Style', 'text', 'fontweight', 'bold', 'string', 'Linescan analysis', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.025, 0.625, 0.9, 0.04]);
  763. oWin.t311 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'dF/F channel:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.05, 0.58, 0.4, 0.04]);
  764. oWin.t312 = uicontrol('Parent', optionsWin, 'Style', 'edit', 'string', num2str(analysisParameters.lineScanChannel), 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.25, 0.5875, 0.125, 0.04], 'callback', @updateParams);
  765. oWin.t313 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', '', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.4, 0.58, 0.1, 0.04]);
  766. oWin.t321 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'Baseline start:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.05, 0.53, 0.4, 0.04]);
  767. oWin.t322 = uicontrol('Parent', optionsWin, 'Style', 'edit', 'string', num2str(analysisParameters.lineScanBaseline(1)), 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.25, 0.5375, 0.125, 0.04], 'callback', @updateParams);
  768. oWin.t323 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', '(ms)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.4, 0.53, 0.1, 0.04]);
  769. oWin.t331 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'Baseline end:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.55, 0.53, 0.4, 0.04]);
  770. oWin.t332 = uicontrol('Parent', optionsWin, 'Style', 'edit', 'string', num2str(analysisParameters.lineScanBaseline(2)), 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.75, 0.5375, 0.125, 0.04], 'callback', @updateParams);
  771. oWin.t333 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', '(ms)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.9, 0.53, 0.1, 0.04]);
  772. oWin.t341 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'ROI threshold:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.05, 0.48, 0.4, 0.04]);
  773. oWin.t342 = uicontrol('Parent', optionsWin, 'Style', 'edit', 'string', num2str(analysisParameters.lineScanROIThreshold), 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.25, 0.4875, 0.125, 0.04], 'callback', @updateParams);
  774. oWin.t343 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', '(sd)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.4, 0.48, 0.1, 0.04]);
  775. oWin.t351 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'Background threshold:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.55, 0.48, 0.4, 0.04]);
  776. oWin.t352 = uicontrol('Parent', optionsWin, 'Style', 'edit', 'string', num2str(analysisParameters.lineScanBackgroundThreshold), 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.75, 0.4875, 0.125, 0.04], 'callback', @updateParams);
  777. oWin.t353 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', '(sd)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.9, 0.48, 0.1, 0.04]);
  778. oWin.t361 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'ROI smoothing:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.05, 0.43, 0.4, 0.04]);
  779. oWin.t362 = uicontrol('Parent', optionsWin, 'Style', 'edit', 'string', num2str(analysisParameters.lineScanROISmoothing), 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.25, 0.4375, 0.125, 0.04], 'callback', @updateParams);
  780. oWin.t363 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', '(points)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.4, 0.43, 0.1, 0.04]);
  781. oWin.t371 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'Detect ROI during baseline:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.55, 0.43, 0.4, 0.04]);
  782. oWin.t372 = uicontrol('Parent', optionsWin, 'Style', 'checkbox', 'value', logical(analysisParameters.lineScanROIDetectDuringBaseline), 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.75, 0.4375, 0.125, 0.04], 'callback', @updateParams);
  783. oWin.t373 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', '', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.9, 0.43, 0.1, 0.04]);
  784. oWin.t401 = uicontrol('Parent', optionsWin, 'Style', 'text', 'fontweight', 'bold', 'string', 'Postprocessing', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.025, 0.375, 0.9, 0.04]);
  785. oWin.t411 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'S1 Boxcar order:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.05, 0.33, 0.4, 0.04]);
  786. oWin.t412 = uicontrol('Parent', optionsWin, 'Style', 'edit', 'string', num2str(analysisParameters.boxcarLength1), 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.25, 0.3375, 0.125, 0.04], 'callback', @updateParams);
  787. oWin.t413 = uicontrol('Parent', optionsWin, 'Style', 'checkbox', 'value', logical(analysisParameters.boxcarLength1), 'string', '', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.4, 0.33, 0.1, 0.04], 'callback', @updateParams);
  788. oWin.t421 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'S2 Boxcar order:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.55, 0.33, 0.4, 0.04]);
  789. oWin.t422 = uicontrol('Parent', optionsWin, 'Style', 'edit', 'string', num2str(analysisParameters.boxcarLength2), 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.75, 0.3375, 0.125, 0.04], 'callback', @updateParams);
  790. oWin.t423 = uicontrol('Parent', optionsWin, 'Style', 'checkbox', 'value', logical(analysisParameters.boxcarLength2), 'string', '', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.9, 0.33, 0.1, 0.04], 'callback', @updateParams);
  791. oWin.t431 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'S1 Bessel order:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.05, 0.28, 0.4, 0.04]);
  792. oWin.t432 = uicontrol('Parent', optionsWin, 'Style', 'edit', 'enable', 'off', 'string', num2str(analysisParameters.besselOrder1), 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.25, 0.2875, 0.125, 0.04], 'callback', @updateParams);
  793. oWin.t433 = uicontrol('Parent', optionsWin, 'Style', 'checkbox', 'value', logical(analysisParameters.besselFreq1), 'string', '', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.4, 0.28, 0.1, 0.04], 'callback', @updateParams);
  794. oWin.t441 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'S2 Bessel order:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.55, 0.28, 0.4, 0.04]);
  795. oWin.t442 = uicontrol('Parent', optionsWin, 'Style', 'edit', 'enable', 'off', 'string', num2str(analysisParameters.besselOrder2), 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.75, 0.2875, 0.125, 0.04], 'callback', @updateParams);
  796. oWin.t443 = uicontrol('Parent', optionsWin, 'Style', 'checkbox', 'value', logical(analysisParameters.besselFreq2), 'string', '', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.9, 0.28, 0.1, 0.04], 'callback', @updateParams);
  797. oWin.t451 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'S1 Bessel frequency:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.05, 0.23, 0.4, 0.04]);
  798. oWin.t452 = uicontrol('Parent', optionsWin, 'Style', 'edit', 'string', num2str(analysisParameters.besselFreq1), 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.25, 0.2375, 0.125, 0.04], 'callback', @updateParams);
  799. oWin.t453 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', '(kHz)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.4, 0.23, 0.1, 0.04]);
  800. oWin.t461 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'S2 Bessel frequency:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.55, 0.23, 0.4, 0.04]);
  801. oWin.t462 = uicontrol('Parent', optionsWin, 'Style', 'edit', 'string', num2str(analysisParameters.besselFreq2), 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.75, 0.2375, 0.125, 0.04], 'callback', @updateParams);
  802. oWin.t463 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', '(kHz)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.9, 0.23, 0.1, 0.04]);
  803. oWin.t501 = uicontrol('Parent', optionsWin, 'Style', 'text', 'fontweight', 'bold', 'string', 'Sweep grouping', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.025, 0.175, 0.9, 0.04]);
  804. oWin.t511 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'Group by metadata:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.05, 0.13, 0.4, 0.04]);
  805. oWin.t512 = uicontrol('Parent', optionsWin, 'Style', 'popupmenu', 'string', {'Disable', 'Automatic', 'MarkPoints', 'VoltageOutput'}, 'value', 2, 'enable', 'off', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.25, 0.1375, 0.2, 0.04], 'callback', @updateParams);
  806. oWin.t513 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', '(Automatic: MarkPoint for LineScan, VoltageOutput for TSeries)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.475, 0.13, 0.4, 0.04]);
  807. oWin.resetButton = uicontrol('Parent', optionsWin, 'Style', 'pushbutton', 'string', 'Reset to defaults', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.54, 0.05, 0.2, 0.06], 'callback', @resetParams, 'interruptible', 'off');
  808. oWin.saveButton = uicontrol('Parent', optionsWin, 'Style', 'pushbutton', 'string', 'Save', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.75, 0.05, 0.2, 0.06], 'callback', @saveParams, 'interruptible', 'off');
  809. t112 = str2num(oWin.t112.String);
  810. t122 = str2num(oWin.t122.String);
  811. t212 = str2num(oWin.t212.String);
  812. t222 = str2num(oWin.t222.String);
  813. t232 = str2num(oWin.t232.String);
  814. t233 = oWin.t233.Value;
  815. t242 = str2num(oWin.t242.String);
  816. t252 = str2num(oWin.t252.String);
  817. t262 = oWin.t262.Value;
  818. t312 = str2num(oWin.t312.String);
  819. t322 = str2num(oWin.t322.String);
  820. t332 = str2num(oWin.t332.String);
  821. t342 = str2num(oWin.t342.String);
  822. t352 = str2num(oWin.t352.String);
  823. t362 = str2num(oWin.t362.String);
  824. t372 = oWin.t372.Value;
  825. t412 = str2num(oWin.t412.String);
  826. t413 = oWin.t413.Value;
  827. t422 = str2num(oWin.t422.String);
  828. t423 = oWin.t423.Value;
  829. t432 = str2num(oWin.t432.String);
  830. t433 = oWin.t433.Value;
  831. t442 = str2num(oWin.t442.String);
  832. t443 = oWin.t443.Value;
  833. t452 = str2num(oWin.t452.String);
  834. t462 = str2num(oWin.t462.String);
  835. %t512 = oWin.t512.String{oWin.t512.Value};
  836. function winClosed(src, ~)
  837. set(srcButton, 'enable', 'on');
  838. %guidata(srcButton, h); % don't save when closed without using the save button
  839. end
  840. function updateParams(src, ~)
  841. t112 = str2num(oWin.t112.String);
  842. t122 = str2num(oWin.t122.String);
  843. t212 = str2num(oWin.t212.String);
  844. t222 = str2num(oWin.t222.String);
  845. t232 = str2num(oWin.t232.String);
  846. t233 = oWin.t233.Value;
  847. t242 = str2num(oWin.t242.String);
  848. t252 = str2num(oWin.t252.String);
  849. t262 = oWin.t262.Value;
  850. if t262
  851. % overrides now moved within loadCSV()
  852. %{
  853. t112 = 1; % default to scaling factor = 1 for V
  854. t122 = 1; % default to scaling factor = 1 for i
  855. t212 = 0; % default to no row offset
  856. t222 = 0; % default to no column offset
  857. t252 = 0; % default to reading columns as voltage
  858. oWin.t112.String = num2str(t112);
  859. oWin.t122.String = num2str(t122);
  860. oWin.t212.String = num2str(t212);
  861. oWin.t222.String = num2str(t222);
  862. oWin.t252.String = num2str(t252);
  863. %}
  864. else
  865. end
  866. t312 = str2num(oWin.t312.String);
  867. t322 = str2num(oWin.t322.String);
  868. t332 = str2num(oWin.t332.String);
  869. t342 = str2num(oWin.t342.String);
  870. t352 = str2num(oWin.t352.String);
  871. t362 = str2num(oWin.t362.String);
  872. t372 = oWin.t372.Value;
  873. t412 = str2num(oWin.t412.String);
  874. t413 = oWin.t413.Value;
  875. t422 = str2num(oWin.t422.String);
  876. t423 = oWin.t423.Value;
  877. t432 = str2num(oWin.t432.String);
  878. t433 = oWin.t433.Value;
  879. t442 = str2num(oWin.t442.String);
  880. t443 = oWin.t443.Value;
  881. t452 = str2num(oWin.t452.String);
  882. t462 = str2num(oWin.t462.String);
  883. %t512 = oWin.t512.String{oWin.t512.Value}; %%% fixlater
  884. if ~logical(t432)
  885. t433 = 0;
  886. oWin.t433.Value = t433;
  887. end
  888. if ~logical(t442)
  889. t443 = 0;
  890. oWin.t443.Value = t443;
  891. end
  892. end
  893. function resetParams(src, ~)
  894. analysisParametersIntrinsic = analysisParameters.intrinsicPropertiesAnalysis; % salvage this
  895. analysisParameters = analysisParametersDefault;
  896. analysisParameters.intrinsicPropertiesAnalysis = analysisParametersIntrinsic;
  897. oWin.t112.String = num2str(analysisParameters.pvbsVoltageScalingFactor);
  898. oWin.t122.String = num2str(analysisParameters.pvbsCurrentScalingFactor);
  899. oWin.t212.String = num2str(analysisParameters.csvOffsetRow);
  900. oWin.t222.String = num2str(analysisParameters.csvOffsetColumn);
  901. oWin.t232.String = num2str(analysisParameters.timeColumn);
  902. oWin.t233.Value = logical(analysisParameters.timeColumn);
  903. oWin.t242.String = num2str(analysisParameters.pvbsVoltageColumn);
  904. oWin.t252.String = num2str(analysisParameters.pvbsCurrentColumn);
  905. oWin.t262.Value = logical(analysisParameters.csvColumnsAsSweeps);
  906. oWin.t312.String = num2str(analysisParameters.lineScanChannel);
  907. oWin.t322.String = num2str(analysisParameters.lineScanBaseline(1));
  908. oWin.t332.String = num2str(analysisParameters.lineScanBaseline(2));
  909. oWin.t342.String = num2str(analysisParameters.lineScanROIThreshold);
  910. oWin.t352.String = num2str(analysisParameters.lineScanBackgroundThreshold);
  911. oWin.t362.String = num2str(analysisParameters.lineScanROISmoothing);
  912. oWin.t372.Value = logical(analysisParameters.lineScanROIDetectDuringBaseline);
  913. oWin.t412.String = num2str(analysisParameters.boxcarLength1);
  914. oWin.t413.Value = logical(analysisParameters.boxcarLength1);
  915. oWin.t422.String = num2str(analysisParameters.boxcarLength2);
  916. oWin.t423.Value = logical(analysisParameters.boxcarLength2);
  917. oWin.t432.String = num2str(analysisParameters.besselOrder1);
  918. oWin.t433.Value = logical(analysisParameters.besselFreq1);
  919. oWin.t442.String = num2str(analysisParameters.besselOrder2);
  920. oWin.t443.Value = logical(analysisParameters.besselFreq2);
  921. oWin.t452.String = num2str(analysisParameters.besselFreq1);
  922. oWin.t462.String = num2str(analysisParameters.besselFreq2);
  923. %oWin.t512.Value = fixlater; %%% fixlater
  924. t112 = str2num(oWin.t112.String);
  925. t122 = str2num(oWin.t122.String);
  926. t212 = str2num(oWin.t212.String);
  927. t222 = str2num(oWin.t222.String);
  928. t232 = str2num(oWin.t232.String);
  929. t233 = oWin.t233.Value;
  930. t242 = str2num(oWin.t242.String);
  931. t252 = str2num(oWin.t252.String);
  932. t262 = oWin.t262.Value;
  933. t312 = str2num(oWin.t312.String);
  934. t322 = str2num(oWin.t322.String);
  935. t332 = str2num(oWin.t332.String);
  936. t342 = str2num(oWin.t342.String);
  937. t352 = str2num(oWin.t352.String);
  938. t362 = str2num(oWin.t362.String);
  939. t372 = oWin.t372.Value;
  940. t412 = str2num(oWin.t412.String);
  941. t413 = oWin.t413.Value;
  942. t422 = str2num(oWin.t422.String);
  943. t423 = oWin.t423.Value;
  944. t432 = str2num(oWin.t432.String);
  945. t433 = oWin.t433.Value;
  946. t442 = str2num(oWin.t442.String);
  947. t443 = oWin.t443.Value;
  948. t452 = str2num(oWin.t452.String);
  949. t462 = str2num(oWin.t462.String);
  950. %t512 = oWin.t512.String{oWin.t512.Value};
  951. %guidata(win1, h);
  952. %close(optionsWin);
  953. %set(srcButton, 'enable', 'on');
  954. end
  955. function saveParams(src, ~)
  956. analysisParameters.pvbsVoltageScalingFactor = t112;
  957. analysisParameters.pvbsCurrentScalingFactor = t122;
  958. analysisParameters.csvOffsetRow = t212;
  959. analysisParameters.csvOffsetColumn = t222;
  960. if t233
  961. analysisParameters.timeColumn = t232;
  962. else
  963. analysisParameters.timeColumn = 0;
  964. end
  965. analysisParameters.pvbsVoltageColumn = t242;
  966. analysisParameters.pvbsCurrentColumn = t252;
  967. analysisParameters.csvColumnsAsSweeps = t262;
  968. if t262
  969. % overrides now moved within loadCSV()
  970. %{
  971. analysisParameters.pvbsVoltageScalingFactor = 1; % default to scaling factor = 1 for V
  972. analysisParameters.pvbsCurrentScalingFactor = 1; % default to scaling factor = 1 for i
  973. analysisParameters.csvOffsetRow = 0; % default to no row offset
  974. analysisParameters.csvOffsetColumn = 0; % default to no column offset
  975. analysisParameters.pvbsCurrentColumn = 0; % default to reading columns as voltage
  976. %}
  977. else
  978. end
  979. analysisParameters.lineScanChannel = t312;
  980. analysisParameters.lineScanBaseline(1) = t322;
  981. analysisParameters.lineScanBaseline(2) = t332;
  982. analysisParameters.lineScanROIThreshold = t342;
  983. analysisParameters.lineScanBackgroundThreshold = t352;
  984. analysisParameters.lineScanROISmoothing = t362;
  985. analysisParameters.lineScanROIDetectDuringBaseline = t372;
  986. if t413
  987. analysisParameters.boxcarLength1 = t412;
  988. else
  989. analysisParameters.boxcarLength1 = 0;
  990. end
  991. if t423
  992. analysisParameters.boxcarLength2 = t422;
  993. else
  994. analysisParameters.boxcarLength2 = 0;
  995. end
  996. analysisParameters.besselOrder1 = t432;
  997. analysisParameters.besselOrder2 = t442;
  998. if t433 % NB. this is for t452, not t432
  999. analysisParameters.besselFreq1 = t452;
  1000. else
  1001. analysisParameters.besselFreq1 = 0;
  1002. end
  1003. if t443 % NB. this is for t462, not t442
  1004. analysisParameters.besselFreq2 = t462;
  1005. else
  1006. analysisParameters.besselFreq2 = 0;
  1007. end
  1008. %analysisParameters.autoGroup = t512; %%% fixlater
  1009. h.params.actualParams = analysisParameters;
  1010. guidata(win1, h);
  1011. close(optionsWin);
  1012. set(srcButton, 'enable', 'on');
  1013. end
  1014. end
  1015. %% Save/Load Experiments
  1016. function saveMat(src, ~)
  1017. % export dataset as .mat
  1018. % start stopwatch
  1019. tic;
  1020. % default save parameters - could go into settings
  1021. defaultSaveFilePrefix = 'pvbs_';
  1022. defaultSavePath = cd;
  1023. defaultSavedVariableName = 'h';
  1024. % load
  1025. h = guidata(src);
  1026. if isempty(h.ui.cellListDisplay.String)
  1027. error('Error: No experiment file present');
  1028. end
  1029. % shed ui elements
  1030. hNew.exp = h.exp;
  1031. hNew.results = h.results;
  1032. hNew.analysis = h.analysis;
  1033. hNew.params = h.params;
  1034. % ... except
  1035. hNew.ui.cellList = h.ui.cellList;
  1036. % overwrite, just to keep the variable name
  1037. h = hNew;
  1038. % set save path and file name
  1039. todayYY = num2str(year(datetime));
  1040. todayYY = todayYY(end-1:end);
  1041. todayMM = sprintf('%02.0f', month(datetime));
  1042. todayDD = sprintf('%02.0f', day(datetime));
  1043. todayhh = sprintf('%02.0f', hour(datetime));
  1044. todaymm = sprintf('%02.0f', minute(datetime));
  1045. todayss = sprintf('%02.0f', second(datetime));
  1046. saveNameDate = [todayYY, todayMM, todayDD ,'_', todayhh, todaymm, todayss];
  1047. %saveNameDate = [todayYY, todayMM, todayDD ,'_', todayhh, todaymm];
  1048. saveNameCell = h.exp.fileName{1}(1:end-4);
  1049. saveNameCell = [defaultSaveFilePrefix, saveNameCell];
  1050. if length(h.exp.fileName) > 1 % more than 1 experiments in dataset
  1051. expCount = length(h.exp.fileName);
  1052. expCount = num2str(expCount);
  1053. saveNameCellSuffix = ['_N', expCount];
  1054. saveNameCell = [saveNameCell, saveNameCellSuffix];
  1055. end
  1056. saveName = [saveNameCell, '_', saveNameDate, '.mat'];
  1057. savePath = [defaultSavePath, '\']; % appending backslash for proper formatting
  1058. % prompt, since it could take some time
  1059. fprintf('Saving dataset... ');
  1060. % save
  1061. warning('off', 'all');
  1062. [actualName, actualPath, isSaved] = uisaveX(defaultSavedVariableName, [savePath, saveName]);
  1063. warning('on', 'all');
  1064. % print results
  1065. if isSaved
  1066. elapsedTime = toc;
  1067. fprintf('\nSaved as: %s%s\n (elapsed time: %.2f s)\n\n', actualPath, actualName, elapsedTime);
  1068. else
  1069. elapsedTime = toc;
  1070. fprintf('canceled.\n\n');
  1071. end
  1072. end
  1073. function saveGUI(src, ~)
  1074. % save everything as .mat - will create a large file because the figure itself is saved
  1075. % start stopwatch
  1076. tic;
  1077. % default save parameters - could go into settings
  1078. defaultSaveFilePrefix = 'pvbs_debug_';
  1079. defaultSavePath = cd;
  1080. defaultSavedVariableName = 'h';
  1081. % load
  1082. h = guidata(src);
  1083. if isempty(h.ui.cellListDisplay.String)
  1084. error('Error: No experiment file present');
  1085. end
  1086. % set save path and file name
  1087. todayYY = num2str(year(datetime));
  1088. todayYY = todayYY(end-1:end);
  1089. todayMM = sprintf('%02.0f', month(datetime));
  1090. todayDD = sprintf('%02.0f', day(datetime));
  1091. todayhh = sprintf('%02.0f', hour(datetime));
  1092. todaymm = sprintf('%02.0f', minute(datetime));
  1093. todayss = sprintf('%02.0f', second(datetime));
  1094. saveNameDate = [todayYY, todayMM, todayDD ,'_', todayhh, todaymm, todayss];
  1095. %saveNameDate = [todayYY, todayMM, todayDD ,'_', todayhh, todaymm];
  1096. saveNameCell = h.exp.fileName{1}(1:end-4);
  1097. saveNameCell = [defaultSaveFilePrefix, saveNameCell];
  1098. if length(h.exp.fileName) > 1 % more than 1 experiments in dataset
  1099. expCount = length(h.exp.fileName);
  1100. expCount = num2str(expCount);
  1101. saveNameCellSuffix = ['_N', expCount];
  1102. saveNameCell = [saveNameCell, saveNameCellSuffix];
  1103. end
  1104. saveName = [saveNameCell, '_', saveNameDate, '.mat'];
  1105. savePath = [defaultSavePath, '\']; % appending backslash for proper formatting
  1106. % prompt, since it could take some time
  1107. fprintf('Saving GUI (debug mode)... ');
  1108. % save
  1109. warning('off', 'all');
  1110. [actualName, actualPath, isSaved] = uisaveX(defaultSavedVariableName, [savePath, saveName]);
  1111. warning('on', 'all');
  1112. % print results
  1113. if isSaved
  1114. elapsedTime = toc;
  1115. fprintf('\nSaved as: %s%s\n (elapsed time: %.2f s)\n\n', actualPath, actualName, elapsedTime);
  1116. else
  1117. elapsedTime = toc;
  1118. fprintf('canceled.\n\n');
  1119. end
  1120. end
  1121. function newMat(src, ~)
  1122. % clear data in GUI
  1123. % load
  1124. h = guidata(src);
  1125. % clear...
  1126. % data structure
  1127. exp.experimentCount = 0;
  1128. exp.metadata = {}; % cell for tSeries metadata files
  1129. % below are for easier access without having to dig into metadata
  1130. exp.fileName = {}; % file name
  1131. exp.filePath = {}; % file path
  1132. exp.sweeps = {}; % total sweep count for each tSeries
  1133. % actual data
  1134. data.VRec = {}; % VRec (.csv)
  1135. data.VRecOriginal = {}; % VRec (.csv), to preserve original in case of postprocessing - again real lack of foresight
  1136. data.VRecMetadata = {}; % metadata for each VRec (.xml)
  1137. data.VOut = {}; % VOut (.xml) - may have to omit due to PV insanity in formatting these
  1138. data.VOutName = {}; % VRec experiment type (e.g. "single stim") - VOut name will work most of the time
  1139. %data.lineScanMetadata = {}; % metadata for each LScn (.xml) - obsolete, linescans don't have separate metadata per cycle
  1140. data.lineScan = {}; % LScn (.tiff)
  1141. data.lineScanDFF = {}; % LScn dF/F
  1142. data.lineScanDFFOriginal = {}; % LScn dF/F, to preserve original in case of postprocessing - again real lack of foresight
  1143. data.lineScanF = {}; % LScn F
  1144. data.lineScanFChannel = {}; % LScn channel used for F, dF/F
  1145. data.lineScanROI = {}; % LScn ROI
  1146. data.lineScanBaseline = {}; % LScn baseline period (time)
  1147. data.lineScanCSV = {}; % LScn profile (.csv)
  1148. data.postprocessing = {}; % postprocessing info (e.g. downsampling)
  1149. data.artifactRemoval = {}; % artifact removal info
  1150. data.markPointsIdx = {}; % indices for MkPts
  1151. data.markPointsMetadata = {}; % MkPts metadata (.xml)
  1152. data.intrinsicProperties = {}; % intrinsic properties, analyzed from file below
  1153. data.intrinsicPropertiesVRec = {}; % intrinsic properties VRec (.csv)
  1154. data.intrinsicPropertiesVRecMetadata = {}; % metadata for intrinsic properties VRec (.xml)
  1155. data.intrinsicPropertiesFileName = {}; % file path and name for intrinsic properties
  1156. data.zStack = {}; % z-stack
  1157. data.zStackFileName = {}; % file path and name for z-stack
  1158. data.singleScan = {}; % single-scan image
  1159. data.singleScanFileName = {}; % file path and name for single-scan
  1160. data.sweepIdx = {}; % sweep indices
  1161. data.sweepStr = {}; % sweep strings for display
  1162. data.groupIdx = {}; % sweep grouping indices
  1163. data.groupStr = {}; % sweep grouping indices in string format for display
  1164. data.notes = {}; % notes
  1165. exp.data = data; % meta-struct for VRec data
  1166. % analysis results
  1167. results = {};
  1168. % more analysis results - another unplanned mess "resulting" in more of really stupid naming and structuring
  1169. analysis = struct();
  1170. % gui elements
  1171. %%% fixlater
  1172. % save
  1173. guidata(src, h);
  1174. end
  1175. function loadMat(src, ~)
  1176. % import dataset from previously exported .mat and appeend to current dataset
  1177. % start stopwatch
  1178. tic;
  1179. % load
  1180. h = guidata(src);
  1181. win = src.Parent;
  1182. % import cell data from a previously saved .mat file
  1183. fprintf('Loading... ');
  1184. [fName, fPath] = uigetfile({'*.mat', 'PVBS dataset'});
  1185. if ~isempty(fName)
  1186. fprintf('(%s%s) ', fPath, fName);
  1187. end
  1188. % check if a file was loaded
  1189. if fName ~= 0
  1190. dataset = load([fPath, fName]);
  1191. hNew = dataset.h; % "h" will be the name of the top level struct
  1192. experimentCountAdditional = hNew.exp.experimentCount;
  1193. h.exp.experimentCount = h.exp.experimentCount + hNew.exp.experimentCount;
  1194. for i = 1:experimentCountAdditional
  1195. % h.exp
  1196. h.exp.metadata{end + 1} = hNew.exp.metadata{i};
  1197. h.exp.fileName{end + 1} = hNew.exp.fileName{i};
  1198. h.exp.filePath{end + 1} = hNew.exp.filePath{i};
  1199. h.exp.sweeps{end + 1} = hNew.exp.sweeps{i};
  1200. % h.exp.data
  1201. try
  1202. h.exp.data.fileType{end + 1} = hNew.exp.data.fileType{i};
  1203. catch ME
  1204. fileTypeNew = '';
  1205. h.exp.data.fileType{end + 1} = fileTypeNew;
  1206. end
  1207. h.exp.data.VRec{end + 1} = hNew.exp.data.VRec{i};
  1208. h.exp.data.VRecOriginal{end + 1} = hNew.exp.data.VRecOriginal{i};
  1209. h.exp.data.VRecMetadata{end + 1} = hNew.exp.data.VRecMetadata{i};
  1210. h.exp.data.VOut{end + 1} = hNew.exp.data.VOut{i};
  1211. h.exp.data.VOutName{end + 1} = hNew.exp.data.VOutName{i};
  1212. h.exp.data.lineScan{end + 1} = hNew.exp.data.lineScan{i};
  1213. h.exp.data.lineScanDFF{end + 1} = hNew.exp.data.lineScanDFF{i};
  1214. h.exp.data.lineScanDFFOriginal{end + 1} = hNew.exp.data.lineScanDFFOriginal{i};
  1215. h.exp.data.lineScanF{end + 1} = hNew.exp.data.lineScanF{i};
  1216. h.exp.data.lineScanFChannel{end + 1} = hNew.exp.data.lineScanFChannel{i};
  1217. h.exp.data.lineScanROI{end + 1} = hNew.exp.data.lineScanROI{i};
  1218. h.exp.data.lineScanBaseline{end + 1} = hNew.exp.data.lineScanBaseline{i};
  1219. h.exp.data.lineScanCSV{end + 1} = hNew.exp.data.lineScanCSV{i};
  1220. try
  1221. h.exp.data.postprocessing{end + 1} = hNew.exp.data.postprocessing{i};
  1222. catch ME
  1223. postprocessingNew = [h.params.actualParams.boxcarLength1, h.params.actualParams.besselFreq1, h.params.actualParams.besselOrder1];
  1224. postprocessingNew = [postprocessingNew; [h.params.actualParams.boxcarLength2, h.params.actualParams.besselFreq2, h.params.actualParams.besselOrder2]];
  1225. h.exp.data.postprocessing{end + 1} = postprocessingNew;
  1226. end
  1227. try
  1228. h.exp.data.artifactRemoval{end + 1} = hNew.exp.data.artifactRemoval{i};
  1229. catch ME
  1230. artifactRemovalNew = [];
  1231. h.exp.data.artifactRemoval{end + 1} = artifactRemovalNew;
  1232. end
  1233. h.exp.data.markPointsIdx{end + 1} = hNew.exp.data.markPointsIdx{i};
  1234. h.exp.data.markPointsMetadata{end + 1} = hNew.exp.data.markPointsMetadata{i};
  1235. h.exp.data.intrinsicProperties{end + 1} = hNew.exp.data.intrinsicProperties{i};
  1236. h.exp.data.intrinsicPropertiesVRec{end + 1} = hNew.exp.data.intrinsicPropertiesVRec{i};
  1237. h.exp.data.intrinsicPropertiesVRecMetadata{end + 1} = hNew.exp.data.intrinsicPropertiesVRecMetadata{i};
  1238. h.exp.data.intrinsicPropertiesFileName{end + 1} = hNew.exp.data.intrinsicPropertiesFileName{i};
  1239. h.exp.data.zStack{end + 1} = hNew.exp.data.zStack{i};
  1240. h.exp.data.zStackFileName{end + 1} = hNew.exp.data.zStackFileName{i};
  1241. h.exp.data.singleScan{end + 1} = hNew.exp.data.singleScan{i};
  1242. h.exp.data.singleScanFileName{end + 1} = hNew.exp.data.singleScanFileName{i};
  1243. h.exp.data.sweepIdx{end + 1} = hNew.exp.data.sweepIdx{i};
  1244. h.exp.data.sweepStr{end + 1} = hNew.exp.data.sweepStr{i};
  1245. h.exp.data.groupIdx{end + 1} = hNew.exp.data.groupIdx{i};
  1246. h.exp.data.groupStr{end + 1} = hNew.exp.data.groupStr{i};
  1247. try
  1248. h.exp.data.notes{end + 1} = hNew.exp.data.notes{i};
  1249. catch ME
  1250. notesNew = {};
  1251. h.exp.data.notes{end + 1} = notesNew;
  1252. end
  1253. % h.results
  1254. h.results{end + 1} = hNew.results{i};
  1255. % h.analysis %%% fixlater and also see below
  1256. h.params = hNew.params; % leave as is %%% no
  1257. % h.ui - leave as is, except...
  1258. h.ui.cellList{end + 1} = hNew.ui.cellList{i};
  1259. end
  1260. h.ui.cellListDisplay.String = h.ui.cellList; % not to be confused here
  1261. %%% fixlater
  1262. if isempty(fieldnames(h.analysis))
  1263. h.analysis = hNew.analysis;
  1264. end
  1265. h = cellListClick2(h, 1); % select 1st entry by default - unfortunate, but has to select something to update trace display
  1266. %{
  1267. h.exp = hNew.exp;
  1268. h.results = hNew.results;
  1269. h.analysis = hNew.analysis;
  1270. h.params = hNew.params;
  1271. h.ui.cellList = hNew.ui.cellList;
  1272. h.ui.cellListDisplay.String = h.ui.cellList;
  1273. h.ui.cellListDisplay.Value = 1;
  1274. h = cellListClick2(h, 1); % select 1st entry by default
  1275. %}
  1276. else
  1277. fprintf('\ncanceled.\n\n');
  1278. return
  1279. end
  1280. % ugh...
  1281. try % ... to display results
  1282. resultsTempGrp = h.results{1}.VRec.groupResults;
  1283. resultsTemp2Grp = h.results{1}.dff.groupResults;
  1284. % plot 1: by default, display Vm, win 1, peak, by group, for current experiment
  1285. targetPlot = h.ui.analysisPlot1; % plot 1
  1286. winToPlot = 1; % analysis window 1
  1287. peakDirToPlot = h.params.actualParams.peakDirection1;
  1288. switch peakDirToPlot % converting to column indices for old code
  1289. case -1 % negative
  1290. peakDirToPlot = 1;
  1291. case 0 % absolute
  1292. peakDirToPlot = 2;
  1293. case 1 % positive
  1294. peakDirToPlot = 3;
  1295. otherwise
  1296. peakDirToPlot = 1;
  1297. end
  1298. dataX = 1:length(resultsTempGrp.groups); % group number - will plot by groups
  1299. dataY = resultsTempGrp.peak; % grouped results, peak
  1300. dataY = dataY(winToPlot, :); % analysis window 1
  1301. dataYNew = nan(length(dataY), 1); % initialize
  1302. for i = 1:length(dataY)
  1303. dataYi = dataY{i}; % current sweep/group
  1304. if isempty(dataYi)
  1305. dataYi = NaN;
  1306. else
  1307. dataYi = dataYi(peakDirToPlot);
  1308. end
  1309. dataYNew(i) = dataYi; % update
  1310. end
  1311. dataY = dataYNew; % update
  1312. axes(targetPlot);
  1313. hold on;
  1314. color = [0, 0, 0];
  1315. targetPlot = displayResults(targetPlot, dataX, dataY, color);
  1316. set(gca, 'xlim', [0, length(dataX) + 1]); % padding for appearance
  1317. hold off;
  1318. xlabel('Group #');
  1319. ylabel('PSP (mV)');
  1320. %xticks(0:5:10000);
  1321. %%{
  1322. if nanmax(dataY) > 40
  1323. ylim([0, 40.5]);
  1324. %yticks(-1000:10:1000);
  1325. elseif nanmax(dataY) > 10
  1326. ylim([0, nanmax(dataY) + 0.5]);
  1327. %yticks(-1000:5:1000);
  1328. else
  1329. ylim([0, 10.5]);
  1330. %yticks(-1000:2:1000);
  1331. end
  1332. %}
  1333. set(gca, 'xminortick', 'on', 'yminortick', 'on');
  1334. h.ui.analysisPlot1 = targetPlot;
  1335. params.resultsPlot1YRange = targetPlot.YLim;
  1336. h.ui.analysisPlot1Menu1.Value = 2; % voltage
  1337. h.ui.analysisPlot1Menu2.Value = 2; % window 1
  1338. %h.ui.analysisPlot1Menu3.Value = 1; % results - will update later
  1339. h.ui.analysisPlot1Menu4.Value = 3; % by group
  1340. traceDisplay = h.ui.traceDisplay;
  1341. axes(traceDisplay);
  1342. % plot 2: by default, display dF/F, win 2, peak, by group, for current experiment
  1343. try
  1344. targetPlot = h.ui.analysisPlot2; % plot 2
  1345. winToPlot = 2; % analysis window 2
  1346. peakDirToPlot = h.params.actualParams.peakDirection2;
  1347. switch peakDirToPlot % converting to column indices for old code
  1348. case -1 % negative
  1349. peakDirToPlot = 1;
  1350. case 0 % absolute
  1351. peakDirToPlot = 2;
  1352. case 1 % positive
  1353. peakDirToPlot = 3;
  1354. otherwise
  1355. peakDirToPlot = 1;
  1356. end
  1357. dataX = 1:length(resultsTemp2Grp.groups); % group number - will plot by groups
  1358. dataY = resultsTemp2Grp.peak; % grouped results, peak
  1359. dataY = dataY(winToPlot, :); % analysis window 2
  1360. dataYNew = nan(length(dataY), 1); % initialize
  1361. %%%
  1362. %%%%%%%
  1363. % data grouping not fucking working properly - why???
  1364. %%%%%%% the fuck happened here? was it fixed? (2022-05-03)
  1365. for i = 1:length(dataY)
  1366. dataYi = dataY{i}; % current sweep/group
  1367. if isempty(dataYi)
  1368. dataYi = NaN;
  1369. else
  1370. dataYi = dataYi(peakDirToPlot);
  1371. end
  1372. dataYNew(i) = dataYi; % update
  1373. end
  1374. dataY = dataYNew; % update
  1375. axes(targetPlot);
  1376. hold on;
  1377. color = [0, 0.5, 0];
  1378. targetPlot = displayResults(targetPlot, dataX, dataY, color);
  1379. set(gca, 'xlim', [0, length(dataX) + 1]); % padding for appearance
  1380. hold off;
  1381. xlabel('Group #');
  1382. ylabel('dF/F');
  1383. %xticks(0:5:10000);
  1384. %{
  1385. if max(dataY) > 4
  1386. ylim([-0.5, max(dataY) + 0.5]);
  1387. yticks(-10:1:100);
  1388. else
  1389. ylim([-0.5, 4.5]);
  1390. yticks(-10:1:100);
  1391. end
  1392. %}
  1393. set(gca, 'xminortick', 'on', 'yminortick', 'on');
  1394. h.ui.analysisPlot2 = targetPlot;
  1395. params.resultsPlot2YRange = targetPlot.YLim;
  1396. h.ui.analysisPlot2Menu1.Value = 3; % fluorescence
  1397. h.ui.analysisPlot2Menu2.Value = 3; % window 2
  1398. %h.ui.analysisPlot2Menu3.Value = 1; % results - will update later
  1399. h.ui.analysisPlot2Menu4.Value = 3; % by group
  1400. catch ME
  1401. traceDisplay = h.ui.traceDisplay;
  1402. axes(traceDisplay);
  1403. end
  1404. % which results to plot
  1405. try
  1406. switch h.ui.analysisType1.Value % analysis type for window 1
  1407. case 1 % unselected
  1408. case 2 % peak/area/mean
  1409. switch h.ui.analysisPlot1Menu2.Value % plot 1, window number
  1410. case 1 % unselected
  1411. h.ui.analysisPlot1Menu3.String = h.params.analysisPlotMenuList3; % to default
  1412. h.ui.analysisPlot1Menu3.Value = 1;
  1413. case 2 % window 1
  1414. h.ui.analysisPlot1Menu3.String = h.params.analysisPlotMenuList31;
  1415. h.ui.analysisPlot1Menu3.Value = 2; % default to peak
  1416. case 3 % window 2
  1417. h.ui.analysisPlot1Menu3.String = h.params.analysisPlotMenuList3; % to default
  1418. h.ui.analysisPlot1Menu3.Value = 1;
  1419. end
  1420. case 3 % threshold detection
  1421. switch h.ui.analysisPlot1Menu2.Value % plot 1, window number
  1422. case 1 % unselected
  1423. h.ui.analysisPlot1Menu3.String = h.params.analysisPlotMenuList3; % to default
  1424. h.ui.analysisPlot1Menu3.Value = 1;
  1425. case 2 % window 1
  1426. h.ui.analysisPlot1Menu3.String = h.params.analysisPlotMenuList32;
  1427. h.ui.analysisPlot1Menu3.Value = 2; % default to event count
  1428. case 3 % window 2
  1429. h.ui.analysisPlot1Menu3.String = h.params.analysisPlotMenuList3; % to default
  1430. h.ui.analysisPlot1Menu3.Value = 1;
  1431. end
  1432. case 4 % waveform
  1433. switch h.ui.analysisPlot1Menu2.Value % plot 1, window number
  1434. case 1 % unselected
  1435. h.ui.analysisPlot1Menu3.String = h.params.analysisPlotMenuList3; % to default
  1436. h.ui.analysisPlot1Menu3.Value = 1;
  1437. case 2 % window 1
  1438. h.ui.analysisPlot1Menu3.String = h.params.analysisPlotMenuList33;
  1439. h.ui.analysisPlot1Menu3.Value = 2; % default to ap threshold
  1440. case 3 % window 2
  1441. h.ui.analysisPlot1Menu3.String = h.params.analysisPlotMenuList3; % to default
  1442. h.ui.analysisPlot1Menu3.Value = 1;
  1443. end
  1444. end
  1445. catch ME
  1446. end
  1447. try
  1448. switch h.ui.analysisType2.Value % analysis type for window 2
  1449. case 1 % unselected
  1450. case 2 % peak/area/mean
  1451. switch h.ui.analysisPlot2Menu2.Value % plot 1, window number
  1452. case 1 % unselected
  1453. h.ui.analysisPlot2Menu3.String = h.params.analysisPlotMenuList3; % to default
  1454. h.ui.analysisPlot2Menu3.Value = 1;
  1455. case 2 % window 1
  1456. h.ui.analysisPlot2Menu3.String = h.params.analysisPlotMenuList3; % to default
  1457. h.ui.analysisPlot2Menu3.Value = 1;
  1458. case 3 % window 2
  1459. h.ui.analysisPlot2Menu3.String = h.params.analysisPlotMenuList31;
  1460. h.ui.analysisPlot2Menu3.Value = 2; % default to peak
  1461. end
  1462. case 3 % threshold detection
  1463. switch h.ui.analysisPlot2Menu2.Value % plot 1, window number
  1464. case 1 % unselected
  1465. h.ui.analysisPlot2Menu3.String = h.params.analysisPlotMenuList3; % to default
  1466. h.ui.analysisPlot2Menu3.Value = 1;
  1467. case 2 % window 1
  1468. h.ui.analysisPlot2Menu3.String = h.params.analysisPlotMenuList3; % to default
  1469. h.ui.analysisPlot2Menu3.Value = 1;
  1470. case 3 % window 2
  1471. h.ui.analysisPlot2Menu3.String = h.params.analysisPlotMenuList32;
  1472. h.ui.analysisPlot2Menu3.Value = 2; % default to event count
  1473. end
  1474. case 4 % waveform
  1475. switch h.ui.analysisPlot2Menu2.Value % plot 1, window number
  1476. case 1 % unselected
  1477. h.ui.analysisPlot2Menu3.String = h.params.analysisPlotMenuList3; % to default
  1478. h.ui.analysisPlot2Menu3.Value = 1;
  1479. case 2 % window 1
  1480. h.ui.analysisPlot2Menu3.String = h.params.analysisPlotMenuList3; % to default
  1481. h.ui.analysisPlot2Menu3.Value = 1;
  1482. case 3 % window 2
  1483. h.ui.analysisPlot2Menu3.String = h.params.analysisPlotMenuList33;
  1484. h.ui.analysisPlot2Menu3.Value = 2; % default to ap threshold
  1485. end
  1486. end
  1487. catch ME
  1488. end
  1489. catch ME
  1490. end
  1491. h = traceDisplayResetCalled(h);
  1492. traceDisplay = h.ui.traceDisplay;
  1493. axes(traceDisplay);
  1494. % save
  1495. guidata(src, h);
  1496. % print results
  1497. elapsedTime = toc;
  1498. fprintf('\nImport complete. (elapsed time: %.2f s) \n\n', elapsedTime);
  1499. end
  1500. function loadMatNew(src, ~)
  1501. % import dataset from previously exported .mat and discard current dataset
  1502. % start stopwatch
  1503. tic;
  1504. % load
  1505. h = guidata(src);
  1506. win = src.Parent;
  1507. % import cell data from a previously saved .mat file
  1508. fprintf('Loading... ');
  1509. [fName, fPath] = uigetfile({'*.mat', 'PVBS dataset'});
  1510. if ~isempty(fName)
  1511. fprintf('(%s%s) ', fPath, fName);
  1512. end
  1513. % check if a file was loaded
  1514. if fName ~= 0
  1515. dataset = load([fPath, fName]);
  1516. hNew = dataset.h; % "h" will be the name of the top level struct
  1517. h.exp = hNew.exp;
  1518. h.results = hNew.results;
  1519. h.analysis = hNew.analysis;
  1520. h.params = hNew.params;
  1521. h.ui.cellList = hNew.ui.cellList;
  1522. h.ui.cellListDisplay.String = h.ui.cellList;
  1523. h.ui.cellListDisplay.Value = 1;
  1524. h = cellListClick2(h, 1); % select 1st entry by default
  1525. else
  1526. fprintf('\ncanceled.\n\n');
  1527. return
  1528. end
  1529. % ugh...
  1530. try % ... to display results
  1531. resultsTempGrp = h.results{1}.VRec.groupResults;
  1532. resultsTemp2Grp = h.results{1}.dff.groupResults;
  1533. % plot 1: by default, display Vm, win 1, peak, by group, for current experiment
  1534. targetPlot = h.ui.analysisPlot1; % plot 1
  1535. winToPlot = 1; % analysis window 1
  1536. peakDirToPlot = h.params.actualParams.peakDirection1;
  1537. switch peakDirToPlot % converting to column indices for old code
  1538. case -1 % negative
  1539. peakDirToPlot = 1;
  1540. case 0 % absolute
  1541. peakDirToPlot = 2;
  1542. case 1 % positive
  1543. peakDirToPlot = 3;
  1544. otherwise
  1545. peakDirToPlot = 1;
  1546. end
  1547. dataX = 1:length(resultsTempGrp.groups); % group number - will plot by groups
  1548. dataY = resultsTempGrp.peak; % grouped results, peak
  1549. dataY = dataY(winToPlot, :); % analysis window 1
  1550. dataYNew = nan(length(dataY), 1); % initialize
  1551. for i = 1:length(dataY)
  1552. dataYi = dataY{i}; % current sweep/group
  1553. if isempty(dataYi)
  1554. dataYi = NaN;
  1555. else
  1556. dataYi = dataYi(peakDirToPlot);
  1557. end
  1558. dataYNew(i) = dataYi; % update
  1559. end
  1560. dataY = dataYNew; % update
  1561. axes(targetPlot);
  1562. hold on;
  1563. color = [0, 0, 0];
  1564. targetPlot = displayResults(targetPlot, dataX, dataY, color);
  1565. set(gca, 'xlim', [0, length(dataX) + 1]); % padding for appearance
  1566. hold off;
  1567. xlabel('Group #');
  1568. ylabel('PSP (mV)');
  1569. %xticks(0:5:10000);
  1570. %%{
  1571. if nanmax(dataY) > 40
  1572. ylim([0, 40.5]);
  1573. %yticks(-1000:10:1000);
  1574. elseif nanmax(dataY) > 10
  1575. ylim([0, nanmax(dataY) + 0.5]);
  1576. %yticks(-1000:5:1000);
  1577. else
  1578. ylim([0, 10.5]);
  1579. %yticks(-1000:2:1000);
  1580. end
  1581. %}
  1582. set(gca, 'xminortick', 'on', 'yminortick', 'on');
  1583. h.ui.analysisPlot1 = targetPlot;
  1584. params.resultsPlot1YRange = targetPlot.YLim;
  1585. h.ui.analysisPlot1Menu1.Value = 2; % voltage
  1586. h.ui.analysisPlot1Menu2.Value = 2; % window 1
  1587. %h.ui.analysisPlot1Menu3.Value = 1; % results - will update later
  1588. h.ui.analysisPlot1Menu4.Value = 3; % by group
  1589. traceDisplay = h.ui.traceDisplay;
  1590. axes(traceDisplay);
  1591. % plot 2: by default, display dF/F, win 2, peak, by group, for current experiment
  1592. try
  1593. targetPlot = h.ui.analysisPlot2; % plot 2
  1594. winToPlot = 2; % analysis window 2
  1595. peakDirToPlot = h.params.actualParams.peakDirection2;
  1596. switch peakDirToPlot % converting to column indices for old code
  1597. case -1 % negative
  1598. peakDirToPlot = 1;
  1599. case 0 % absolute
  1600. peakDirToPlot = 2;
  1601. case 1 % positive
  1602. peakDirToPlot = 3;
  1603. otherwise
  1604. peakDirToPlot = 1;
  1605. end
  1606. dataX = 1:length(resultsTemp2Grp.groups); % group number - will plot by groups
  1607. dataY = resultsTemp2Grp.peak; % grouped results, peak
  1608. dataY = dataY(winToPlot, :); % analysis window 2
  1609. dataYNew = nan(length(dataY), 1); % initialize
  1610. %%%
  1611. %%%%%%%
  1612. % data grouping not fucking working properly - why???
  1613. %%%%%%% the fuck happened here? was it fixed? (2022-05-03)
  1614. for i = 1:length(dataY)
  1615. dataYi = dataY{i}; % current sweep/group
  1616. if isempty(dataYi)
  1617. dataYi = NaN;
  1618. else
  1619. dataYi = dataYi(peakDirToPlot);
  1620. end
  1621. dataYNew(i) = dataYi; % update
  1622. end
  1623. dataY = dataYNew; % update
  1624. axes(targetPlot);
  1625. hold on;
  1626. color = [0, 0.5, 0];
  1627. targetPlot = displayResults(targetPlot, dataX, dataY, color);
  1628. set(gca, 'xlim', [0, length(dataX) + 1]); % padding for appearance
  1629. hold off;
  1630. xlabel('Group #');
  1631. ylabel('dF/F');
  1632. %xticks(0:5:10000);
  1633. %{
  1634. if max(dataY) > 4
  1635. ylim([-0.5, max(dataY) + 0.5]);
  1636. yticks(-10:1:100);
  1637. else
  1638. ylim([-0.5, 4.5]);
  1639. yticks(-10:1:100);
  1640. end
  1641. %}
  1642. set(gca, 'xminortick', 'on', 'yminortick', 'on');
  1643. h.ui.analysisPlot2 = targetPlot;
  1644. params.resultsPlot2YRange = targetPlot.YLim;
  1645. h.ui.analysisPlot2Menu1.Value = 3; % fluorescence
  1646. h.ui.analysisPlot2Menu2.Value = 3; % window 2
  1647. %h.ui.analysisPlot2Menu3.Value = 1; % results - will update later
  1648. h.ui.analysisPlot2Menu4.Value = 3; % by group
  1649. catch ME
  1650. traceDisplay = h.ui.traceDisplay;
  1651. axes(traceDisplay);
  1652. end
  1653. % which results to plot
  1654. try
  1655. switch h.ui.analysisType1.Value % analysis type for window 1
  1656. case 1 % unselected
  1657. case 2 % peak/area/mean
  1658. switch h.ui.analysisPlot1Menu2.Value % plot 1, window number
  1659. case 1 % unselected
  1660. h.ui.analysisPlot1Menu3.String = h.params.analysisPlotMenuList3; % to default
  1661. h.ui.analysisPlot1Menu3.Value = 1;
  1662. case 2 % window 1
  1663. h.ui.analysisPlot1Menu3.String = h.params.analysisPlotMenuList31;
  1664. h.ui.analysisPlot1Menu3.Value = 2; % default to peak
  1665. case 3 % window 2
  1666. h.ui.analysisPlot1Menu3.String = h.params.analysisPlotMenuList3; % to default
  1667. h.ui.analysisPlot1Menu3.Value = 1;
  1668. end
  1669. case 3 % threshold detection
  1670. switch h.ui.analysisPlot1Menu2.Value % plot 1, window number
  1671. case 1 % unselected
  1672. h.ui.analysisPlot1Menu3.String = h.params.analysisPlotMenuList3; % to default
  1673. h.ui.analysisPlot1Menu3.Value = 1;
  1674. case 2 % window 1
  1675. h.ui.analysisPlot1Menu3.String = h.params.analysisPlotMenuList32;
  1676. h.ui.analysisPlot1Menu3.Value = 2; % default to event count
  1677. case 3 % window 2
  1678. h.ui.analysisPlot1Menu3.String = h.params.analysisPlotMenuList3; % to default
  1679. h.ui.analysisPlot1Menu3.Value = 1;
  1680. end
  1681. case 4 % waveform
  1682. switch h.ui.analysisPlot1Menu2.Value % plot 1, window number
  1683. case 1 % unselected
  1684. h.ui.analysisPlot1Menu3.String = h.params.analysisPlotMenuList3; % to default
  1685. h.ui.analysisPlot1Menu3.Value = 1;
  1686. case 2 % window 1
  1687. h.ui.analysisPlot1Menu3.String = h.params.analysisPlotMenuList33;
  1688. h.ui.analysisPlot1Menu3.Value = 2; % default to ap threshold
  1689. case 3 % window 2
  1690. h.ui.analysisPlot1Menu3.String = h.params.analysisPlotMenuList3; % to default
  1691. h.ui.analysisPlot1Menu3.Value = 1;
  1692. end
  1693. end
  1694. catch ME
  1695. end
  1696. try
  1697. switch h.ui.analysisType2.Value % analysis type for window 2
  1698. case 1 % unselected
  1699. case 2 % peak/area/mean
  1700. switch h.ui.analysisPlot2Menu2.Value % plot 1, window number
  1701. case 1 % unselected
  1702. h.ui.analysisPlot2Menu3.String = h.params.analysisPlotMenuList3; % to default
  1703. h.ui.analysisPlot2Menu3.Value = 1;
  1704. case 2 % window 1
  1705. h.ui.analysisPlot2Menu3.String = h.params.analysisPlotMenuList3; % to default
  1706. h.ui.analysisPlot2Menu3.Value = 1;
  1707. case 3 % window 2
  1708. h.ui.analysisPlot2Menu3.String = h.params.analysisPlotMenuList31;
  1709. h.ui.analysisPlot2Menu3.Value = 2; % default to peak
  1710. end
  1711. case 3 % threshold detection
  1712. switch h.ui.analysisPlot2Menu2.Value % plot 1, window number
  1713. case 1 % unselected
  1714. h.ui.analysisPlot2Menu3.String = h.params.analysisPlotMenuList3; % to default
  1715. h.ui.analysisPlot2Menu3.Value = 1;
  1716. case 2 % window 1
  1717. h.ui.analysisPlot2Menu3.String = h.params.analysisPlotMenuList3; % to default
  1718. h.ui.analysisPlot2Menu3.Value = 1;
  1719. case 3 % window 2
  1720. h.ui.analysisPlot2Menu3.String = h.params.analysisPlotMenuList32;
  1721. h.ui.analysisPlot2Menu3.Value = 2; % default to event count
  1722. end
  1723. case 4 % waveform
  1724. switch h.ui.analysisPlot2Menu2.Value % plot 1, window number
  1725. case 1 % unselected
  1726. h.ui.analysisPlot2Menu3.String = h.params.analysisPlotMenuList3; % to default
  1727. h.ui.analysisPlot2Menu3.Value = 1;
  1728. case 2 % window 1
  1729. h.ui.analysisPlot2Menu3.String = h.params.analysisPlotMenuList3; % to default
  1730. h.ui.analysisPlot2Menu3.Value = 1;
  1731. case 3 % window 2
  1732. h.ui.analysisPlot2Menu3.String = h.params.analysisPlotMenuList33;
  1733. h.ui.analysisPlot2Menu3.Value = 2; % default to ap threshold
  1734. end
  1735. end
  1736. catch ME
  1737. end
  1738. catch ME
  1739. end
  1740. h = traceDisplayResetCalled(h);
  1741. traceDisplay = h.ui.traceDisplay;
  1742. axes(traceDisplay);
  1743. % save
  1744. guidata(src, h);
  1745. % print results
  1746. elapsedTime = toc;
  1747. fprintf('\nImport complete. (elapsed time: %.2f s) \n\n', elapsedTime);
  1748. end
  1749. function expFile = loadExp(src, ~)
  1750. % load Experiment XML files
  1751. % load
  1752. h = guidata(src);
  1753. experiment = h.exp;
  1754. data = experiment.data;
  1755. results = h.results;
  1756. cellList = h.ui.cellList;
  1757. cellListDisplay = h.ui.cellListDisplay;
  1758. % prompt, since this could take some time
  1759. fprintf('Loading experiment(s)...');
  1760. % select experiment metadata .xml (or directory of the same name containing it)
  1761. filesToImport = uipickfiles_pvbs('type', {'*.*', 'All files (.*)'; '*.abf', 'Axon binary file (.abf)'; '*.xml', 'VRec/LScn/tSer directory or metadata (.xml)'; '*.csv', 'VRec data (.csv)'});
  1762. tic; % start stopwatch
  1763. if iscell(filesToImport)
  1764. if isempty(filesToImport)
  1765. fprintf(' canceled.\n\n');
  1766. return
  1767. else
  1768. for i = 1:length(filesToImport)
  1769. try % sometimes files are corrupt because stupid PV crashes all the time
  1770. isCSV = 0;
  1771. isABF = 0;
  1772. [fPath, fName, fExt] = fileparts(filesToImport{i});
  1773. if isempty(fExt) % if directory is selected
  1774. fExt = '.xml';
  1775. fPath = [fPath, '\', fName, '\'];
  1776. fName = [fName, fExt];
  1777. elseif strcmp(fExt, '.xml'); % if .xml file is selected
  1778. fPath = [fPath, '\'];
  1779. fName = [fName, fExt];
  1780. elseif strcmp(fExt, '.csv'); % if .csv file is selected
  1781. fPath = [fPath, '\'];
  1782. fName = [fName, fExt];
  1783. isCSV = 1;
  1784. elseif strcmp(fExt, '.abf'); % if .abf file is selected
  1785. fPath = [fPath, '\'];
  1786. fName = [fName, fExt];
  1787. isABF = 1;
  1788. else
  1789. %error('Error: Invalid file type');
  1790. end
  1791. fprintf('\n(%d/%d) ', i, length(filesToImport));
  1792. %actualParams = setDefaultParams(src); % load parameters
  1793. %h.params.actualParams = actualParams; % save parameters
  1794. actualParams = h.params.actualParams;
  1795. if isCSV
  1796. h = loadCSV(h, fPath, fName, actualParams);
  1797. elseif isABF
  1798. h = loadABF(h, fPath, fName, actualParams);
  1799. else
  1800. h = loadExpMain(h, fPath, fName, actualParams);
  1801. end
  1802. catch ME
  1803. fprintf('- aborted');
  1804. end
  1805. end
  1806. end
  1807. elseif filesToImport == 0
  1808. fprintf(' canceled.\n\n');
  1809. return
  1810. end
  1811. % display first experiment if first time loading files, otherwise last experiment
  1812. if h.params.firstRun == 1
  1813. set(h.ui.cellListDisplay, 'value', 1);
  1814. h = displayTrace(h, 1);
  1815. h.params.firstRun = 0;
  1816. else
  1817. set(h.ui.cellListDisplay, 'value', length(cellList) + length(filesToImport));
  1818. h = displayTrace(h, length(cellList) + length(filesToImport));
  1819. %{
  1820. set(h.ui.cellListDisplay, 'value', length(cellList));
  1821. h = displayTrace(h, length(cellList));
  1822. %}
  1823. end
  1824. % highlight first sweep
  1825. %h.ui.groupListDisplay.Value = 1;
  1826. h.ui.sweepListDisplay.Value = 1;
  1827. h = highlightSweep(h, 1);
  1828. set(h.ui.groupSweepText, 'string', 'Sweep 1');
  1829. % reset trace display range
  1830. h = traceDisplayResetCalled(h);
  1831. % save
  1832. guidata(src, h);
  1833. elapsedTime = toc;
  1834. fprintf('\n Load complete. (elapsed time: %.2f s)\n\n', elapsedTime);
  1835. end
  1836. % loadExpMain - find default parameters here
  1837. function h = loadExpMain(h, fPath, fName, actualParams)
  1838. % load each experiment - VRec, LScn, or tSer (of VRec)
  1839. % because PV records data in its own units, data must be scaled appropriately
  1840. % hard-coding here, instead of digging again into insane PV metadata
  1841. % below are set for MC700B with Rf = 500 MO and usual gain settings for whole-cell recordings
  1842. pvbsVoltageScalingFactor = actualParams.pvbsVoltageScalingFactor; % "100 mV" to mV
  1843. pvbsCurrentScalingFactor = actualParams.pvbsCurrentScalingFactor; % "0.1 nA" to pA
  1844. timeColumn = actualParams.timeColumn; % csv column for timestamp
  1845. pvbsVoltageColumn = actualParams.pvbsVoltageColumn; % csv column to apply voltage scaling (column 1 is timestamp, followed by channels)
  1846. pvbsCurrentColumn = actualParams.pvbsCurrentColumn; % csv column to apply current scaling
  1847. csvColumnsAsSweeps = actualParams.csvColumnsAsSweeps; % interpret columns as sweeps (default: 0)
  1848. csvOffsetRow = actualParams.csvOffsetRow; % row offset while reading csv with csvread() (default: 1)
  1849. csvOffsetColumn = actualParams.csvOffsetColumn; % column offset while reading csv with csvread() (default: 0)
  1850. lineScanChannel = actualParams.lineScanChannel; % primary channel for calcium imaging signal; e.g. for P4, 1: red, 2: green (primary)
  1851. lineScanBaseline = actualParams.lineScanBaseline; % (ms), baseline for F_0 in linescans, avoid starting from 0 to prevent possible contamination from shutter artifact
  1852. lineScanROIDetectDuringBaseline = actualParams.lineScanROIDetectDuringBaseline; % detect linescan ROI only during baseline window specified above (0: no, 1: yes), in order to prevent possible errors from uncaging artifact
  1853. lineScanDownsamplingFactor = actualParams.lineScanDownsamplingFactor; % downsampling factor for fluorescence signals, for the dF/F to be robust to noise
  1854. lineScanROISmoothing = actualParams.lineScanDownsamplingFactor; % will average over this many points (before and after) while detecting ROI to be robust from noise - obsolete with single ROI
  1855. lineScanROIThreshold = actualParams.lineScanROIThreshold; % (s.d.); z-score for 1st quartile
  1856. lineScanBackgroundThreshold = actualParams.lineScanBackgroundThreshold; % (s.d.); z-score for 67th percentile
  1857. offloadMarkPointsMetadata = actualParams.offloadMarkPointsMetadata; % delete markpoints metadata after retrieving point indices to save space (0: no, 1: yes)
  1858. % PV GPIO box can quite unbelievably also introduce current measurement error
  1859. % via bleedthrough across channels, which has to be corrected if present
  1860. % otherwise, there will be "phantom" DC injection present in data
  1861. % DO NOT use if recordings DO have intentional baseline DC injection at the beginning!
  1862. % DO NOT be confused with having incorrect bias current settings from amplifier!
  1863. pvbsCurrentCorrectionFlag = actualParams.pvbsCurrentCorrectionFlag; % set to 1 to correct, 0 to leave as is
  1864. pvbsCurrentCorrectionDataPoints = actualParams.pvbsCurrentCorrectionDataPoints; % this many points at the beginning will be used for baseline correction
  1865. % load
  1866. experiment = h.exp;
  1867. data = experiment.data;
  1868. results = h.results;
  1869. cellList = h.ui.cellList;
  1870. cellListDisplay = h.ui.cellListDisplay;
  1871. % prompt
  1872. fprintf(' %s%s ', fPath, fName);
  1873. % load file
  1874. sweeps = 1;
  1875. metadata = xml2struct_pvbs([fPath, fName]); % load metadata from .xml, using modified xml2struct
  1876. try
  1877. sweeps = length(metadata.PVScan.Sequence); % !!! this will need to be changed if the TSeries does not entirely consist of VRecs %%%
  1878. catch ME
  1879. sweeps = 1;
  1880. end
  1881. % fill cells
  1882. experiment.metadata{end + 1} = metadata;
  1883. experiment.fileName{end + 1} = fName; % just to make file name and path readily accessible
  1884. experiment.filePath{end + 1} = fPath;
  1885. experiment.sweeps{end + 1} = sweeps;
  1886. results{end + 1} = struct;
  1887. % check experiment type
  1888. if sweeps == 1
  1889. expTypeStr = metadata.PVScan.Sequence.Attributes.type;
  1890. else
  1891. expTypeStr = metadata.PVScan.Sequence{1}.Attributes.type;
  1892. end
  1893. expTypeTSer = 'TSeries Voltage Recording';
  1894. expTypeVRec = 'VoltageRecording';
  1895. expTypeLScn = 'Linescan'; % note cases and spaces because PV is inconsistent
  1896. if strcmp(expTypeStr, expTypeTSer)
  1897. expType = 1; % T-Series
  1898. elseif strcmp(expTypeStr, expTypeVRec)
  1899. expType = 2; % VoltageRecording
  1900. elseif strcmp(expTypeStr, expTypeLScn)
  1901. expType = 3; % LineScan
  1902. else
  1903. expType = 0; % invalid
  1904. fprintf('\nInvalid file type\n');
  1905. return
  1906. end
  1907. % fill cells within cells (... interlinked)
  1908. VOutName = {cell(sweeps, 1)};
  1909. VOut = {cell(sweeps, 1)};
  1910. VRecMetadata = {cell(sweeps, 1)};
  1911. VRec = {cell(sweeps, 1)};
  1912. VRecOriginal = {cell(sweeps, 1)};
  1913. %lineScanMetadata = {cell(sweeps, 1)};
  1914. lineScanFile = {cell(sweeps, 1)};
  1915. lineScan = {cell(sweeps, 1)};
  1916. lineScanF = {cell(sweeps, 1)};
  1917. lineScanDFF = {cell(sweeps, 1)};
  1918. lineScanDFFOriginal = {cell(sweeps, 1)};
  1919. lineScanCSVFile = {cell(sweeps, 1)};
  1920. lineScanCSV = {cell(sweeps, 1)};
  1921. lineScanFChannel = {cell(sweeps, 1)};
  1922. lineScanROI = {cell(sweeps, 1)};
  1923. postprocessing = [];
  1924. artifactRemoval = [];
  1925. markPointsMetadata = {cell(sweeps, 1)};
  1926. markPointsIdx = {cell(sweeps, 1)};
  1927. intrinsicProperties = struct(); % struct, not cell
  1928. intrinsicPropertiesVRec = {cell(1)};
  1929. intrinsicPropertiesVRecMetadata = struct();
  1930. intrinsicPropertiesFileName = [];
  1931. zStack = {cell(1)}; % only one
  1932. zStackFileName = [];
  1933. singleScan = {cell(1)}; % only one as representative, since saving all of them will be overwhelming for file size
  1934. singleScanFileName = [];
  1935. sweepIdx = 1:sweeps; % note that this is an array and not a cell
  1936. sweepStr = cell(sweeps, 1);
  1937. if sweeps == 1
  1938. sweepStr{1} = '1';
  1939. else
  1940. for i = 1:sweeps
  1941. sweepStr{i} = num2str(i);
  1942. end
  1943. end
  1944. groupIdx = {}; % groupIdx = {cell(sweeps, 1)};
  1945. groupStr = {};
  1946. notes = {};
  1947. postprocessing = [h.params.actualParams.boxcarLength1, h.params.actualParams.besselFreq1, h.params.actualParams.besselOrder1];
  1948. postprocessing = [postprocessing; [h.params.actualParams.boxcarLength2, h.params.actualParams.besselFreq2, h.params.actualParams.besselOrder2]];
  1949. if sweeps == 1 % this has to be separated because if sweep == 1, "Sequence" (in PV metadata) becomes a struct rather than a cell by xml2struct
  1950. VRecMetadata{1} = {metadata.PVScan.Sequence.VoltageRecording.Attributes.configurationFile}; % mind the curly braces on RHS
  1951. VRecFile = metadata.PVScan.Sequence.VoltageRecording.Attributes.dataFile;
  1952. VRecTemp = csvread([fPath, VRecFile], csvOffsetRow, csvOffsetColumn); % offset row by 1 ("time(ms), input 0, input 1"), and column by 0
  1953. % this bizzare step has to be taken, because Prairie
  1954. VRecTemp(:, pvbsVoltageColumn) = VRecTemp(:, pvbsVoltageColumn)*pvbsVoltageScalingFactor;
  1955. VRecTemp(:, pvbsCurrentColumn) = VRecTemp(:, pvbsCurrentColumn)*pvbsCurrentScalingFactor;
  1956. pvbsCurrentCorrectionAmount = nanmean(VRecTemp(1:pvbsCurrentCorrectionDataPoints, pvbsCurrentColumn));
  1957. VRecTemp(:, pvbsCurrentColumn) = VRecTemp(:, pvbsCurrentColumn) - pvbsCurrentCorrectionFlag * pvbsCurrentCorrectionAmount;
  1958. % - end of PV correction -
  1959. VRecOriginalTemp = VRecTemp;
  1960. try
  1961. if logical(h.params.actualParams.besselFreq1) % do bessel first before boxcar if applicable, although menu order is backwards - another stupid me doing stupid things
  1962. besselOrder = h.params.actualParams.besselOrder1;
  1963. cutoffFreq = h.params.actualParams.besselFreq1;
  1964. cutoffFreq = cutoffFreq*1000; % converting to Hz from kHz
  1965. samplingRate = VRecTemp(2, 1) - VRecTemp(1, 1); % sampling interval (ms), since first column is timestamp
  1966. samplingRate = 1000*(1/samplingRate); % converting to Hz from ms
  1967. for j = 2:size(VRecTemp, 2) % skip timestamp in column 1
  1968. VRecTempTemp = VRecTemp(:, j); % skip the timestamp in column 1
  1969. VRecTempTemp = besselLowpass(VRecTempTemp, besselOrder, cutoffFreq, samplingRate);
  1970. VRecTemp(:, j) = VRecTempTemp;
  1971. end
  1972. end
  1973. if logical(h.params.actualParams.boxcarLength1) % do boxcar after bessel, again if applicable
  1974. boxcarLength = h.params.actualParams.boxcarLength1;
  1975. dataLengthReduced = floor(size(VRecTemp, 1)/boxcarLength);
  1976. VRecReducedTemp = nan(dataLengthReduced, size(VRecTemp, 2)); % initializing
  1977. for j = 1:size(VRecTemp, 2) % NB. timestamp can be treated the same way
  1978. for k = 1:dataLengthReduced
  1979. VRecReducedTemp(k, j) = nanmean(VRecTemp(1 + (k-1)*boxcarLength : k*boxcarLength, j));
  1980. end
  1981. end
  1982. VRecTemp = VRecReducedTemp; % simply overwrite if data reduction took place
  1983. end
  1984. catch ME
  1985. end
  1986. VRec{1} = VRecTemp;
  1987. VRecOriginal{1} = VRecOriginalTemp;
  1988. try % some experiments might have been recorded with null VOut
  1989. VOutName{1} = {metadata.PVScan.Sequence.VoltageOutput.Attributes.name};
  1990. VOut{1} = {metadata.PVScan.Sequence.VoltageOutput.Attributes.filename}; % let's just read the file name and not the actual file, since that one's insane
  1991. catch ME
  1992. VOutName{1} = {};
  1993. VOut{1} = {};
  1994. end
  1995. try
  1996. lineScanFileChannelCount = metadata.PVScan.Sequence.Frame.File;
  1997. lineScanFileChannelCount = length(lineScanFileChannelCount);
  1998. if lineScanFileChannelCount == 1
  1999. lineScanFileTemp = metadata.PVScan.Sequence.Frame.File.Attributes.filename;
  2000. lineScanFile{1, 1} = lineScanFileTemp;
  2001. warning('off','all');
  2002. lineScan{1, 1} = read(Tiff([fPath, lineScanFileTemp])); % Tiff() is a built-in function
  2003. warning('on','all');
  2004. else
  2005. for j = 1:lineScanFileChannelCount
  2006. lineScanFileTemp = metadata.PVScan.Sequence.Frame.File{j}.Attributes.filename;
  2007. lineScanFile{j, 1} = lineScanFileTemp;
  2008. warning('off','all');
  2009. lineScan{j, 1} = read(Tiff([fPath, lineScanFileTemp])); % Tiff() is a built-in function
  2010. warning('on','all');
  2011. end
  2012. end
  2013. catch ME
  2014. lineScanFile{:, 1} = {};
  2015. lineScan{:, 1} = {};
  2016. end
  2017. try
  2018. lineScanCSVFile{1} = metadata.PVScan.Sequence.PVLinescanDefinition.LineScanProfiles.Attributes.DataFile; % LineScanProfile csv will include all applicable channels
  2019. lineScanCSV{1} = csvread([fPath, lineScanFile], csvOffsetRow, csvOffsetColumn); % offset row by 1 ("Ch1 time, Ch1, Ch2 time, Ch2"), and column by 0
  2020. catch ME
  2021. lineScanCSV{1} = {};
  2022. end
  2023. try
  2024. % Applicable if the loaded .xml is a linescan
  2025. % columns 1, 2, 3, 4 in the astounding PV metadata: framePeriod, linesPerFrame, pixelsPerLine, scanLinePeriod
  2026. % i.e. 1 = 2*3*4, but 2 & 3 can be inferred from data
  2027. % unit is (s)
  2028. lineScanChannelUsed = lineScanChannel;
  2029. framePeriodIdx = 1;
  2030. framePeriod = metadata.PVScan.Sequence.Frame.PVStateShard.PVStateValue{framePeriodIdx}.Attributes.key;
  2031. if strcmp(framePeriod, 'framePeriod')
  2032. framePeriod = metadata.PVScan.Sequence.Frame.PVStateShard.PVStateValue{framePeriodIdx}.Attributes.value;
  2033. framePeriod = str2num(framePeriod);
  2034. end
  2035. if size(lineScan, 1) < lineScanChannel
  2036. lineScanChannelUsed = 1;
  2037. else
  2038. lineScanChannelUsed = lineScanChannel;
  2039. end
  2040. lineScanImage = lineScan{lineScanChannelUsed, 1}; % use only the relevant channel
  2041. linesPerFrame = size(lineScanImage, 1); % this should be the same as the entry in column 2 above
  2042. lineScanInterval = framePeriod/linesPerFrame; % (s)
  2043. lineScanInterval = lineScanInterval * 1000; % (ms)
  2044. framePeriod = framePeriod * 1000; % (ms)
  2045. lineScanTimestamp = 0:lineScanInterval:(framePeriod - lineScanInterval); % this will slightly shift the quasismiultaneous linescan towards earlier in time
  2046. lineScanTimestamp = lineScanTimestamp';
  2047. [lineScanFTemp, lineScanDFFTemp, roiTemp] = lineScanImgToF(lineScanImage, lineScanTimestamp, lineScanBaseline, actualParams);
  2048. lineScanDFFOriginalTemp = lineScanDFFTemp;
  2049. try
  2050. if logical(h.params.actualParams.besselFreq2)
  2051. besselOrder = h.params.actualParams.besselOrder2;
  2052. cutoffFreq = h.params.actualParams.besselFreq2;
  2053. cutoffFreq = cutoffFreq*1000; % converting to Hz from kHz
  2054. samplingRate = lineScanDFFTemp(2, 1) - lineScanDFFTemp(1, 1); % sampling interval (ms), since first column is timestamp
  2055. samplingRate = 1000*(1/samplingRate); % converting to Hz from ms
  2056. lineScanDFFTempTemp = lineScanDFFTemp(:, 2); % skip the timestamp in column 1
  2057. lineScanDFFTempTemp = besselLowpass(lineScanDFFTempTemp, besselOrder, cutoffFreq, samplingRate);
  2058. lineScanDFFTemp(:, 2) = lineScanDFFTempTemp;
  2059. end
  2060. if logical(h.params.actualParams.boxcarLength2)
  2061. boxcarLength = h.params.actualParams.boxcarLength2;
  2062. dataLengthReduced = floor(size(lineScanDFFTemp, 1)/boxcarLength);
  2063. lineScanDFFReducedTemp = nan(dataLengthReduced, size(lineScanDFFTemp, 2)); % initializing
  2064. for j = 1:size(lineScanDFFTemp, 2) % NB. timestamp can be treated the same way
  2065. for k = 1:dataLengthReduced
  2066. lineScanDFFReducedTemp(k, j) = nanmean(lineScanDFFTemp(1 + (k-1)*boxcarLength : k*boxcarLength, j));
  2067. end
  2068. end
  2069. lineScanDFFTemp = lineScanDFFReducedTemp; % simply overwrite if data reduction took place
  2070. end
  2071. catch ME
  2072. end
  2073. lineScanF{1} = lineScanFTemp;
  2074. lineScanDFF{1} = lineScanDFFTemp;
  2075. lineScanDFFOriginal{1} = lineScanDFFOriginalTemp;
  2076. lineScanFChannel{1} = lineScanChannelUsed;
  2077. lineScanROI{1} = roiTemp;
  2078. catch ME
  2079. lineScanF{1} = [];
  2080. lineScanDFF{1} = [];
  2081. lineScanDFFOriginal{1} = [];
  2082. lineScanFChannel{1} = [];
  2083. lineScanROI{1} = [];
  2084. end
  2085. try
  2086. markPointsMetadataFile = metadata.PVScan.MarkPoints.Attributes.filename;
  2087. markPointsMetadata{1} = xml2struct_pvbs([fPath, markPointsMetadataFile]);
  2088. markPointsIdx{1} = markPointsMetadata{1}.PVMarkPointSeriesElements.PVMarkPointElement.PVGalvoPointElement.Attributes.Indices;
  2089. catch ME
  2090. markPointsMetadata{1} = struct();
  2091. end
  2092. else
  2093. for i = 1:sweeps
  2094. VRecMetadata{i} = metadata.PVScan.Sequence{i}.VoltageRecording.Attributes.configurationFile;
  2095. VRecFile = metadata.PVScan.Sequence{i}.VoltageRecording.Attributes.dataFile;
  2096. VRecTemp = csvread([fPath, VRecFile], csvOffsetRow, csvOffsetColumn); % offset row by 1 ("time(ms), input 0, input 1"), and column by 0
  2097. % this bizzare step has to be taken, because Prairie
  2098. VRecTemp(:, pvbsVoltageColumn) = VRecTemp(:, pvbsVoltageColumn)*pvbsVoltageScalingFactor;
  2099. VRecTemp(:, pvbsCurrentColumn) = VRecTemp(:, pvbsCurrentColumn)*pvbsCurrentScalingFactor;
  2100. pvbsCurrentCorrectionAmount = nanmean(VRecTemp(1:pvbsCurrentCorrectionDataPoints, pvbsCurrentColumn));
  2101. VRecTemp(:, pvbsCurrentColumn) = VRecTemp(:, pvbsCurrentColumn) - pvbsCurrentCorrectionFlag * pvbsCurrentCorrectionAmount;
  2102. % - end of PV correction -
  2103. VRecOriginalTemp = VRecTemp;
  2104. try
  2105. if logical(h.params.actualParams.besselFreq1)
  2106. besselOrder = h.params.actualParams.besselOrder1;
  2107. cutoffFreq = h.params.actualParams.besselFreq1;
  2108. cutoffFreq = cutoffFreq*1000; % converting to Hz from kHz
  2109. samplingRate = VRecTemp(2, 1) - VRecTemp(1, 1); % sampling interval (ms), since first column is timestamp
  2110. samplingRate = 1000*(1/samplingRate); % converting to Hz from ms
  2111. for j = 2:size(VRecTemp, 2) % skip timestamp in column 1
  2112. VRecTempTemp = VRecTemp(:, j); % skip the timestamp in column 1
  2113. VRecTempTemp = besselLowpass(VRecTempTemp, besselOrder, cutoffFreq, samplingRate);
  2114. VRecTemp(:, j) = VRecTempTemp;
  2115. end
  2116. end
  2117. if logical(h.params.actualParams.boxcarLength1)
  2118. boxcarLength = h.params.actualParams.boxcarLength1;
  2119. dataLengthReduced = floor(size(VRecTemp, 1)/boxcarLength);
  2120. VRecReducedTemp = nan(dataLengthReduced, size(VRecTemp, 2)); % initializing
  2121. for j = 1:size(VRecTemp, 2) % NB. timestamp can be treated the same way
  2122. for k = 1:dataLengthReduced
  2123. VRecReducedTemp(k, j) = nanmean(VRecTemp(1 + (k-1)*boxcarLength : k*boxcarLength, j));
  2124. end
  2125. end
  2126. VRecTemp = VRecReducedTemp; % simply overwrite if data reduction took place
  2127. end
  2128. catch ME
  2129. end
  2130. VRec{i} = VRecTemp;
  2131. VRecOriginal{i} = VRecOriginalTemp;
  2132. try % some experiments might have been recorded with null VOut
  2133. VOutName{i} = metadata.PVScan.Sequence{i}.VoltageOutput.Attributes.name;
  2134. VOut{i} = metadata.PVScan.Sequence{i}.VoltageOutput.Attributes.filename; % let's just read the file name and not the actual file, since that one's insane
  2135. catch ME
  2136. VOutName{i} = [];
  2137. VOut{i} = [];
  2138. end
  2139. try
  2140. lineScanFileChannelCount = metadata.PVScan.Sequence{i}.Frame.File;
  2141. lineScanFileChannelCount = length(lineScanFileChannelCount);
  2142. if lineScanFileChannelCount == 1
  2143. lineScanFileTemp = metadata.PVScan.Sequence{i}.Frame.File.Attributes.filename;
  2144. lineScanFile{1, i} = lineScanFileTemp;
  2145. warning('off','all');
  2146. lineScan{1, i} = read(Tiff([fPath, lineScanFileTemp])); % Tiff() is a built-in function
  2147. warning('on','all');
  2148. else
  2149. for j = 1:lineScanFileChannelCount
  2150. lineScanFileTemp = metadata.PVScan.Sequence{i}.Frame.File{j}.Attributes.filename;
  2151. lineScanFile{j, i} = lineScanFileTemp;
  2152. warning('off','all');
  2153. lineScan{j, i} = read(Tiff([fPath, lineScanFileTemp])); % Tiff() is a built-in function
  2154. warning('on','all');
  2155. end
  2156. end
  2157. catch ME
  2158. lineScanFile{:, i} = [];
  2159. lineScan{:, i} = [];
  2160. end
  2161. try
  2162. lineScanCSVFile{i} = metadata.PVScan.Sequence{i}.PVLinescanDefinition.LineScanProfiles.Attributes.DataFile; % LineScanProfile csv will include all applicable channels
  2163. lineScanCSV{i} = csvread([fPath, lineScanFile], csvOffsetRow, csvOffsetColumn); % offset row by 1 ("Prof 1 time, Prof 1, Prof 2 time, Prof 2"), and column by 0
  2164. catch ME
  2165. lineScanCSV{i} = [];
  2166. end
  2167. try
  2168. % Applicable if the loaded .xml is a linescan
  2169. % columns 1, 2, 3, 4 in the astounding PV metadata: framePeriod, linesPerFrame, pixelsPerLine, scanLinePeriod
  2170. % i.e. 1 = 2*3*4, but 2 & 3 can be inferred from data
  2171. % unit is (s)
  2172. framePeriodIdx = 1;
  2173. framePeriod = metadata.PVScan.Sequence{i}.Frame.PVStateShard.PVStateValue{framePeriodIdx}.Attributes.key;
  2174. if strcmp(framePeriod, 'framePeriod')
  2175. framePeriod = metadata.PVScan.Sequence{i}.Frame.PVStateShard.PVStateValue{framePeriodIdx}.Attributes.value;
  2176. framePeriod = str2num(framePeriod);
  2177. end
  2178. if size(lineScan, 1) < lineScanChannel
  2179. lineScanChannelUsed = 1;
  2180. else
  2181. lineScanChannelUsed = lineScanChannel;
  2182. end
  2183. lineScanImage = lineScan{lineScanChannelUsed, i}; % use only the relevant channel
  2184. linesPerFrame = size(lineScanImage, 1); % this should be the same as the entry in column 2 above
  2185. lineScanInterval = framePeriod/linesPerFrame; % (s)
  2186. lineScanInterval = lineScanInterval * 1000; % (ms)
  2187. framePeriod = framePeriod * 1000; % (ms)
  2188. lineScanTimestamp = 0:lineScanInterval:(framePeriod - lineScanInterval); % this will slightly shift the quasismiultaneous linescan towards earlier in time
  2189. lineScanTimestamp = lineScanTimestamp';
  2190. [lineScanFTemp, lineScanDFFTemp, roiTemp] = lineScanImgToF(lineScanImage, lineScanTimestamp, lineScanBaseline, actualParams);
  2191. lineScanDFFOriginalTemp = lineScanDFFTemp;
  2192. try
  2193. if logical(h.params.actualParams.besselFreq2)
  2194. besselOrder = h.params.actualParams.besselOrder2;
  2195. cutoffFreq = h.params.actualParams.besselFreq2;
  2196. cutoffFreq = cutoffFreq*1000; % converting to Hz from kHz
  2197. samplingRate = lineScanDFFTemp(2, 1) - lineScanDFFTemp(1, 1); % sampling interval (ms), since first column is timestamp
  2198. samplingRate = 1000*(1/samplingRate); % converting to Hz from ms
  2199. lineScanDFFTempTemp = lineScanDFFTemp(:, 2); % skip the timestamp in column 1
  2200. lineScanDFFTempTemp = besselLowpass(lineScanDFFTempTemp, besselOrder, cutoffFreq, samplingRate);
  2201. lineScanDFFTemp(:, 2) = lineScanDFFTempTemp;
  2202. end
  2203. if logical(h.params.actualParams.boxcarLength2)
  2204. boxcarLength = h.params.actualParams.boxcarLength2;
  2205. dataLengthReduced = floor(size(lineScanDFFTemp, 1)/boxcarLength);
  2206. lineScanDFFReducedTemp = nan(dataLengthReduced, size(lineScanDFFTemp, 2)); % initializing
  2207. for j = 1:size(lineScanDFFTemp, 2) % NB. timestamp can be treated the same way
  2208. for k = 1:dataLengthReduced
  2209. lineScanDFFReducedTemp(k, j) = nanmean(lineScanDFFTemp(1 + (k-1)*boxcarLength : k*boxcarLength, j));
  2210. end
  2211. end
  2212. lineScanDFFTemp = lineScanDFFReducedTemp; % simply overwrite if data reduction took place
  2213. end
  2214. catch ME
  2215. end
  2216. lineScanF{i} = lineScanFTemp;
  2217. lineScanDFF{i} = lineScanDFFTemp;
  2218. lineScanDFFOriginal{i} = lineScanDFFOriginalTemp;
  2219. lineScanFChannel{i} = lineScanChannelUsed;
  2220. lineScanROI{i} = roiTemp;
  2221. catch ME
  2222. lineScanF{i} = [];
  2223. lineScanDFF{i} = [];
  2224. lineScanDFFOriginal{i} = [];
  2225. lineScanFChannel{i} = [];
  2226. lineScanROI{i} = [];
  2227. end
  2228. try
  2229. markPointsMetadataFile = metadata.PVScan.Sequence{i}.MarkPoints.Attributes.filename;
  2230. markPointsMetadata{i} = xml2struct_pvbs([fPath, markPointsMetadataFile]);
  2231. markPointsIdx{i} = markPointsMetadata{i}.PVMarkPointSeriesElements.PVMarkPointElement.PVGalvoPointElement.Attributes.Indices;
  2232. catch ME
  2233. markPointsMetadata{i} = struct();
  2234. markPointsIdx{i} = [];
  2235. end
  2236. %groupIdx{i} = {}; %groupIdx{i} = 0; % default to this, but do implement autodetect function
  2237. %groupStr{i} = {};
  2238. end
  2239. if offloadMarkPointsMetadata
  2240. for i = 1:length(markPointsMetadata)
  2241. markPointsMetadata{i} = struct(); % to save space
  2242. end
  2243. end
  2244. end
  2245. % if ROI detection fails for linescans, inherit ROI from the previous sweep
  2246. %{
  2247. try
  2248. if isempty(lineScanROI{1}) % if the first sweep is missing a ROI
  2249. firstSweepWithROI = find(~cellfun(@isempty, lineScanROI), 1);
  2250. lineScanROI{1} = lineScanROI{firstSweepWithROI};
  2251. % recalculate dF/F with inherited ROI
  2252. roiTemp = lineScanROI{1};
  2253. lineScanImage = lineScan{lineScanChannelUsed, 1}; % use only the relevant channel
  2254. [lineScanFTemp, lineScanDFFTemp] = lineScanImgToFManualROI(lineScanImage, lineScanTimestamp, lineScanBaseline, actualParams, roiTemp);
  2255. lineScanF{1} = lineScanFTemp;
  2256. lineScanDFF{1} = lineScanDFFTemp;
  2257. lineScanFChannel{1} = lineScanChannelUsed;
  2258. end
  2259. if length(lineScanROI) > 1
  2260. for i = 2:length(lineScanROI)
  2261. if isempty(lineScanROI{i})
  2262. lineScanROI{i} = lineScanROI{i - 1};
  2263. % recalculate dF/F with inherited ROI
  2264. roiTemp = lineScanROI{i};
  2265. lineScanImage = lineScan{lineScanChannelUsed, i}; % use only the relevant channel
  2266. [lineScanFTemp, lineScanDFFTemp] = lineScanImgToFManualROI(lineScanImage, lineScanTimestamp, lineScanBaseline, actualParams, roiTemp);
  2267. lineScanF{i} = lineScanFTemp;
  2268. lineScanDFF{i} = lineScanDFFTemp;
  2269. lineScanFChannel{i} = lineScanChannelUsed;
  2270. end
  2271. end
  2272. end
  2273. catch ME
  2274. end
  2275. %}
  2276. % ... or not; set ROI to the entire length of the line(scan)
  2277. try
  2278. lineLength = size(lineScanImage, 2);
  2279. if isempty(lineScanROI{1}) % if the first sweep is missing a ROI
  2280. firstSweepWithROI = find(~cellfun(@isempty, lineScanROI), 1);
  2281. %lineScanROI{1} = lineScanROI{firstSweepWithROI};
  2282. lineScanROI{1} = [1, lineLength];
  2283. % recalculate dF/F with inherited ROI
  2284. roiTemp = lineScanROI{1};
  2285. lineScanImage = lineScan{lineScanChannelUsed, 1}; % use only the relevant channel
  2286. [lineScanFTemp, lineScanDFFTemp] = lineScanImgToFManualROI(lineScanImage, lineScanTimestamp, lineScanBaseline, actualParams, roiTemp);
  2287. lineScanF{1} = lineScanFTemp;
  2288. lineScanDFF{1} = lineScanDFFTemp;
  2289. lineScanFChannel{1} = lineScanChannelUsed;
  2290. end
  2291. if length(lineScanROI) > 1
  2292. for i = 2:length(lineScanROI)
  2293. if isempty(lineScanROI{i})
  2294. %lineScanROI{i} = lineScanROI{i - 1};
  2295. lineScanROI{i} = [1, lineLength];
  2296. % recalculate dF/F with inherited ROI
  2297. roiTemp = lineScanROI{i};
  2298. lineScanImage = lineScan{lineScanChannelUsed, i}; % use only the relevant channel
  2299. [lineScanFTemp, lineScanDFFTemp] = lineScanImgToFManualROI(lineScanImage, lineScanTimestamp, lineScanBaseline, actualParams, roiTemp);
  2300. lineScanF{i} = lineScanFTemp;
  2301. lineScanDFF{i} = lineScanDFFTemp;
  2302. lineScanFChannel{i} = lineScanChannelUsed;
  2303. end
  2304. end
  2305. end
  2306. catch ME
  2307. end
  2308. % load one representative branch image for linescans %%% shockingly, PV LScn metadata doesn't have reference image information
  2309. %{
  2310. try
  2311. singleScanDisplay = h.ui.singleScanDisplay;
  2312. [singleScan, singleScanDisplay] = loadSingleScan2(singleScanDisplay, ssPath, ssName);
  2313. h.ui.singleScanDisplay = singleScanDisplay;
  2314. catch ME
  2315. end
  2316. %}
  2317. % group sweeps automatically
  2318. groupIdx2 = 1;
  2319. if sweeps == 1
  2320. %{
  2321. groupIdx{1} = 1;
  2322. groupStr{1} = '1';
  2323. %}
  2324. groupIdx{1} = 1;
  2325. groupStr{1} = '1';
  2326. else
  2327. switch expType
  2328. case 1 % TSer
  2329. if ~iscell(VOutName)
  2330. VOutName = {VOutName};
  2331. end
  2332. if length(VOutName) > 1
  2333. for i = 2:length(VOutName)
  2334. for j = 1:max(groupIdx2)
  2335. searchIdx = find(groupIdx2 == j, 1);
  2336. if strcmp(VOutName{i}, VOutName{searchIdx})
  2337. groupIdx2(i) = groupIdx2(searchIdx);
  2338. break
  2339. else
  2340. groupIdx2(i) = groupIdx2(searchIdx) + 1;
  2341. searchIdx = searchIdx + 1;
  2342. end
  2343. end
  2344. end
  2345. end
  2346. for i = 1:max(groupIdx2)
  2347. groupIdxNew = find(groupIdx2 == i);
  2348. groupIdx{end + 1} = groupIdxNew;
  2349. groupStrNew = num2str(groupIdxNew(1));
  2350. if length(groupIdxNew) > 1
  2351. for i = 2:length(groupIdxNew);
  2352. groupStrNew = [groupStrNew, ',', num2str(groupIdxNew(i))];
  2353. end
  2354. end
  2355. groupStr{end + 1} = groupStrNew;
  2356. end
  2357. case 2 % VRec
  2358. case 3 % LScn
  2359. try % group according to markpoints indices for uncaging experiments
  2360. %%{
  2361. firstSwpGrp = [];
  2362. for i = 1:length(markPointsIdx)
  2363. %firstSwpGrp(end + 1) = ~iscell(markPointsIdx{i});
  2364. firstSwpGrp(end + 1) = isstr(markPointsIdx{i});
  2365. end
  2366. firstSwpGrp = find(firstSwpGrp);
  2367. firstSwpGrp = firstSwpGrp(1);
  2368. firstSwpGrp = max(2, firstSwpGrp);
  2369. %}
  2370. %for i = firstSwpGrp:length(markPointsIdx)
  2371. for i = 2:length(markPointsIdx)
  2372. %groupIdx2
  2373. for j = 1:max(groupIdx2)
  2374. searchIdx = find(groupIdx2 == j, 1);
  2375. try
  2376. if strcmp(markPointsIdx{i}, markPointsIdx{searchIdx})
  2377. groupIdx2(i) = groupIdx2(searchIdx);
  2378. break
  2379. else
  2380. groupIdx2(i) = groupIdx2(searchIdx) + 1;
  2381. searchIdx = searchIdx + 1;
  2382. end
  2383. catch ME
  2384. groupIdx2(i) = groupIdx2(searchIdx) + 1;
  2385. searchIdx = searchIdx + 1;
  2386. end
  2387. end
  2388. end
  2389. for i = 1:max(groupIdx2)
  2390. groupIdxNew = find(groupIdx2 == i);
  2391. groupIdx{end + 1} = groupIdxNew;
  2392. groupStrNew = num2str(groupIdxNew(1));
  2393. if length(groupIdxNew) > 1
  2394. for i = 2:length(groupIdxNew);
  2395. groupStrNew = [groupStrNew, ',', num2str(groupIdxNew(i))];
  2396. end
  2397. end
  2398. try
  2399. markPointsStr = markPointsIdx{groupIdxNew(1)}; % point indices, should be same for all elements of groupIdxNew at this point
  2400. groupStrNew = ['(# ', markPointsStr, ') ', groupStrNew]; % append point indices to be clear
  2401. groupStr{end + 1} = groupStrNew;
  2402. catch ME
  2403. groupStrNew = ['(# ', '', ') ', groupStrNew]; % append point indices to be clear
  2404. groupStr{end + 1} = groupStrNew;
  2405. end
  2406. end
  2407. catch ME
  2408. end
  2409. end
  2410. end
  2411. %%% no group means no group - another workaround amongst hundreds
  2412. if isempty(groupStr)
  2413. groupIdx = [];
  2414. end
  2415. % update experiment count and cell list
  2416. experiment.experimentCount = experiment.experimentCount + 1;
  2417. cellList{end + 1} = fName(1:end-4); % getting rid of the extension
  2418. set(cellListDisplay, 'string', cellList);
  2419. % bring up downsampling information if applied
  2420. if logical(h.params.actualParams.boxcarLength1) || logical(h.params.actualParams.besselFreq1) % either downsampling has been done on signal 1 - prioritize signal 1 over 2
  2421. h.ui.traceProcessingTarget.Value = 2; % 1st item would be selection indicator
  2422. h.ui.downsamplingButton.Value = logical(h.params.actualParams.boxcarLength1); % check the button
  2423. h.ui.lowPassFilterButton.Value = logical(h.params.actualParams.besselFreq1); % check the button
  2424. elseif logical(h.params.actualParams.boxcarLength2) || logical(h.params.actualParams.besselFreq2) % if both signals were processed, display will default to signal 1
  2425. h.ui.traceProcessingTarget.Value = 3; % 1st item would be selection indicator
  2426. h.ui.downsamplingButton.Value = logical(h.params.actualParams.boxcarLength2); % check the button
  2427. h.ui.lowPassFilterButton.Value = logical(h.params.actualParams.besselFreq2); % check the button
  2428. end
  2429. % save
  2430. data.fileType{end + 1} = 'PV';
  2431. data.VRecMetadata{end + 1} = VRecMetadata;
  2432. data.VRec{end + 1} = VRec;
  2433. data.VRecOriginal{end + 1} = VRecOriginal;
  2434. data.VOutName{end + 1} = VOutName;
  2435. data.VOut{end + 1} = VOut;
  2436. data.lineScan{end + 1} = lineScan;
  2437. data.lineScanF{end + 1} = lineScanF;
  2438. data.lineScanDFF{end + 1} = lineScanDFF;
  2439. data.lineScanDFFOriginal{end + 1} = lineScanDFFOriginal;
  2440. data.lineScanCSV{end + 1} = lineScanCSV;
  2441. data.lineScanFChannel{end + 1} = lineScanFChannel;
  2442. data.lineScanROI{end + 1} = lineScanROI;
  2443. data.lineScanBaseline{end + 1} = lineScanBaseline;
  2444. data.postprocessing{end + 1} = postprocessing;
  2445. data.artifactRemoval{end + 1} = artifactRemoval;
  2446. data.markPointsMetadata{end + 1} = markPointsMetadata;
  2447. data.markPointsIdx{end + 1} = markPointsIdx;
  2448. data.intrinsicProperties{end + 1} = intrinsicProperties;
  2449. data.intrinsicPropertiesVRec{end + 1} = intrinsicPropertiesVRec;
  2450. data.intrinsicPropertiesVRecMetadata{end + 1} = intrinsicPropertiesVRecMetadata;
  2451. data.intrinsicPropertiesFileName{end + 1} = intrinsicPropertiesFileName;
  2452. data.zStack{end + 1} = zStack;
  2453. data.zStackFileName{end + 1} = zStackFileName;
  2454. data.singleScan{end + 1} = singleScan;
  2455. data.singleScanFileName{end + 1} = singleScanFileName;
  2456. data.sweepIdx{end + 1} = sweepIdx;
  2457. data.sweepStr{end + 1} = sweepStr;
  2458. data.groupIdx{end + 1} = groupIdx;
  2459. data.groupStr{end + 1} = groupStr;
  2460. data.notes{end + 1} = notes;
  2461. experiment.data = data;
  2462. h.exp = experiment;
  2463. h.results = results;
  2464. h.ui.cellList = cellList;
  2465. h.ui.cellListDisplay = cellListDisplay;
  2466. end % end of loadExpMain()
  2467. function h = loadCSV(h, fPath, fName, actualParams)
  2468. % modified loadExpMain() for VRec (.csv)
  2469. % currently treating all .csv as V, not F %%% fixlater ?
  2470. % because PV records data in its own units, data must be scaled appropriately
  2471. % hard-coding here, instead of digging again into insane PV metadata
  2472. % below are set for MC700B with Rf = 500 MO and usual gain settings for whole-cell recordings
  2473. pvbsVoltageScalingFactor = actualParams.pvbsVoltageScalingFactor; % "100 mV" to mV
  2474. pvbsCurrentScalingFactor = actualParams.pvbsCurrentScalingFactor; % "0.1 nA" to pA
  2475. timeColumn = actualParams.timeColumn; % csv column for timestamp
  2476. pvbsVoltageColumn = actualParams.pvbsVoltageColumn; % csv column to apply voltage scaling (column 1 is timestamp, followed by channels)
  2477. pvbsCurrentColumn = actualParams.pvbsCurrentColumn; % csv column to apply current scaling
  2478. csvOffsetRow = actualParams.csvOffsetRow; % row offset while reading csv with csvread() (default: 1)
  2479. csvOffsetColumn = actualParams.csvOffsetColumn; % column offset while reading csv with csvread() (default: 0)
  2480. csvColumnsAsSweeps = actualParams.csvColumnsAsSweeps; % interpret columns as sweeps (default: 0)
  2481. lineScanChannel = actualParams.lineScanChannel; % primary channel for calcium imaging signal; e.g. for P4, 1: red, 2: green (primary)
  2482. lineScanBaseline = actualParams.lineScanBaseline; % (ms), baseline for F_0 in linescans, avoid starting from 0 to prevent possible contamination from shutter artifact
  2483. lineScanROIDetectDuringBaseline = actualParams.lineScanROIDetectDuringBaseline; % detect linescan ROI only during baseline window specified above (0: no, 1: yes), in order to prevent possible errors from uncaging artifact
  2484. lineScanDownsamplingFactor = actualParams.lineScanDownsamplingFactor; % downsampling factor for fluorescence signals, for the dF/F to be robust to noise
  2485. lineScanROISmoothing = actualParams.lineScanDownsamplingFactor; % will average over this many points (before and after) while detecting ROI to be robust from noise - obsolete with single ROI
  2486. lineScanROIThreshold = actualParams.lineScanROIThreshold; % (s.d.); z-score for 1st quartile
  2487. lineScanBackgroundThreshold = actualParams.lineScanBackgroundThreshold; % (s.d.); z-score for 67th percentile
  2488. offloadMarkPointsMetadata = actualParams.offloadMarkPointsMetadata; % delete markpoints metadata after retrieving point indices to save space (0: no, 1: yes)
  2489. % PV GPIO box can quite unbelievably also introduce current measurement error
  2490. % via bleedthrough across channels, which has to be corrected if present
  2491. % otherwise, there will be "phantom" DC injection present in data
  2492. % DO NOT use if recordings DO have intentional baseline DC injection at the beginning!
  2493. % DO NOT be confused with having incorrect bias current settings from amplifier!
  2494. pvbsCurrentCorrectionFlag = actualParams.pvbsCurrentCorrectionFlag; % set to 1 to correct, 0 to leave as is
  2495. pvbsCurrentCorrectionDataPoints = actualParams.pvbsCurrentCorrectionDataPoints; % this many points at the beginning will be used for baseline correction
  2496. % load
  2497. experiment = h.exp;
  2498. data = experiment.data;
  2499. results = h.results;
  2500. cellList = h.ui.cellList;
  2501. cellListDisplay = h.ui.cellListDisplay;
  2502. % prompt
  2503. fprintf(' %s%s ', fPath, fName);
  2504. % load file
  2505. %%% fixlater: csvColumnsAsSweeps assumes "correct" values, i.e. not scaled - this will create confusion when reading .csv saved from PV
  2506. VRecFile = [fPath, fName];
  2507. VRecTemp = csvread([fPath, fName], csvOffsetRow, csvOffsetColumn); % offset row by 1 ("time(ms), input 0, input 1"), and column by 0
  2508. if csvColumnsAsSweeps
  2509. %%% look here!
  2510. % force scaling factor = 1
  2511. pvbsVoltageScalingFactor = 1;
  2512. pvbsCurrentScalingFactor = 1;
  2513. % force reading data as voltage
  2514. pvbsCurrentColumn = 0;
  2515. % force no column/row offset
  2516. csvOffsetRow = 0;
  2517. csvOffsetColumn = 0;
  2518. if timeColumn % timestamp column is present
  2519. sweeps = size(VRecTemp, 2); % each column represents a sweep
  2520. nonTimeColumn = 1:sweeps; % do this first
  2521. nonTimeColumn = nonTimeColumn(nonTimeColumn ~= timeColumn);
  2522. sweeps = sweeps - 1; % since one column is for timestamp and not an actual sweep
  2523. else
  2524. sweeps = size(VRecTemp, 2); % each column represents a sweep
  2525. nonTimeColumn = 1:sweeps;
  2526. nonTimeColumn = nonTimeColumn(nonTimeColumn ~= timeColumn);
  2527. end
  2528. % pv bleedthrough correction
  2529. if pvbsVoltageColumn ~= 0
  2530. if pvbsCurrentColumn == 0 % just adding for possible future use of the next else block
  2531. VRecTemp(:, nonTimeColumn) = VRecTemp(:, nonTimeColumn)*pvbsVoltageScalingFactor;
  2532. else % if both are nonzero, default to interpret as voltage
  2533. VRecTemp(:, nonTimeColumn) = VRecTemp(:, nonTimeColumn)*pvbsVoltageScalingFactor;
  2534. end
  2535. elseif pvbsCurrentColumn == 0 % if both are 0, again default to interpret as voltage; this could be used later to interpret as F instead %%% fixlater
  2536. VRecTemp(:, nonTimeColumn) = VRecTemp(:, nonTimeColumn)*pvbsVoltageScalingFactor;
  2537. else % now interpret as current
  2538. VRecTemp(:, nonTimeColumn) = VRecTemp(:, nonTimeColumn)*pvbsCurrentScalingFactor;
  2539. pvbsCurrentCorrectionAmount = nanmean(VRecTemp(1:pvbsCurrentCorrectionDataPoints, pvbsCurrentColumn));
  2540. VRecTemp(:, pvbsCurrentColumn) = VRecTemp(:, pvbsCurrentColumn) - pvbsCurrentCorrectionFlag * pvbsCurrentCorrectionAmount;
  2541. end
  2542. else
  2543. sweeps = 1; % gap-free
  2544. % pv bleedthrough correction
  2545. VRecTemp(:, pvbsVoltageColumn) = VRecTemp(:, pvbsVoltageColumn)*pvbsVoltageScalingFactor;
  2546. VRecTemp(:, pvbsCurrentColumn) = VRecTemp(:, pvbsCurrentColumn)*pvbsCurrentScalingFactor;
  2547. pvbsCurrentCorrectionAmount = nanmean(VRecTemp(1:pvbsCurrentCorrectionDataPoints, pvbsCurrentColumn));
  2548. VRecTemp(:, pvbsCurrentColumn) = VRecTemp(:, pvbsCurrentColumn) - pvbsCurrentCorrectionFlag * pvbsCurrentCorrectionAmount;
  2549. end
  2550. % fill cells
  2551. experiment.metadata{end + 1} = [];
  2552. experiment.fileName{end + 1} = fName; % just to make file name and path readily accessible
  2553. experiment.filePath{end + 1} = fPath;
  2554. experiment.sweeps{end + 1} = sweeps;
  2555. results{end + 1} = struct;
  2556. % fill cells within cells (... interlinked)
  2557. VOutName = {cell(sweeps, 1)};
  2558. VOut = {cell(sweeps, 1)};
  2559. VRecMetadata = {cell(sweeps, 1)};
  2560. VRec = {cell(sweeps, 1)};
  2561. VRecOriginal = {cell(sweeps, 1)};
  2562. %lineScanMetadata = {cell(sweeps, 1)};
  2563. lineScanFile = {cell(sweeps, 1)};
  2564. lineScan = {cell(sweeps, 1)};
  2565. lineScanF = {cell(sweeps, 1)};
  2566. lineScanDFF = {cell(sweeps, 1)};
  2567. lineScanDFFOriginal = {cell(sweeps, 1)};
  2568. lineScanCSVFile = {cell(sweeps, 1)};
  2569. lineScanCSV = {cell(sweeps, 1)};
  2570. lineScanFChannel = {cell(sweeps, 1)};
  2571. lineScanROI = {cell(sweeps, 1)};
  2572. postprocessing = [];
  2573. artifactRemoval = [];
  2574. markPointsMetadata = {cell(sweeps, 1)};
  2575. markPointsIdx = {cell(sweeps, 1)};
  2576. intrinsicProperties = struct(); % struct, not cell
  2577. intrinsicPropertiesVRec = {cell(1)};
  2578. intrinsicPropertiesVRecMetadata = struct();
  2579. intrinsicPropertiesFileName = [];
  2580. zStack = {cell(1)}; % only one
  2581. zStackFileName = [];
  2582. singleScan = {cell(1)}; % only one as representative, since saving all of them will be overwhelming for file size %%% what was this?
  2583. singleScanFileName = [];
  2584. sweepIdx = 1:sweeps;
  2585. sweepStr = cell(sweeps, 1);
  2586. for i = 1:sweeps
  2587. VRecMetadata{i} = [];
  2588. sweepStr{i} = num2str(i);
  2589. VOutName{i} = [];
  2590. VOut{i} = []; % let's just read the file name and not the actual file, since that one's insane
  2591. end
  2592. groupIdx = {}; % groupIdx = {cell(sweeps, 1)};
  2593. groupStr = {};
  2594. if sweeps == 1 % just for convenience if there's only one sweep
  2595. groupIdx{end + 1} = 1;
  2596. groupStr{end + 1} = '1';
  2597. end
  2598. notes = {};
  2599. postprocessing = [h.params.actualParams.boxcarLength1, h.params.actualParams.besselFreq1, h.params.actualParams.besselOrder1];
  2600. postprocessing = [postprocessing; [h.params.actualParams.boxcarLength2, h.params.actualParams.besselFreq2, h.params.actualParams.besselOrder2]];
  2601. % fill sweeps
  2602. if csvColumnsAsSweeps
  2603. for i = 1:sweeps
  2604. VRec{i} = [VRecTemp(:, timeColumn), VRecTemp(:, nonTimeColumn(i))];
  2605. end
  2606. else
  2607. VRec{1} = VRecTemp;
  2608. end
  2609. VRecOriginal = VRec;
  2610. % postprocessing - if applicable
  2611. % this block now moved up in different parts to accommodate multiple-sweep .csv
  2612. %{
  2613. % load VRec
  2614. VRecMetadata{1} = [];
  2615. VRecFile = [fPath, fName];
  2616. VRecTemp = csvread([fPath, fName], csvOffsetRow, csvOffsetColumn); % offset row by 1 ("time(ms), input 0, input 1"), and column by 0
  2617. % this bizzare step has to be taken, because Prairie
  2618. VRecTemp(:, pvbsVoltageColumn) = VRecTemp(:, pvbsVoltageColumn)*pvbsVoltageScalingFactor;
  2619. VRecTemp(:, pvbsCurrentColumn) = VRecTemp(:, pvbsCurrentColumn)*pvbsCurrentScalingFactor;
  2620. pvbsCurrentCorrectionAmount = nanmean(VRecTemp(1:pvbsCurrentCorrectionDataPoints, pvbsCurrentColumn));
  2621. VRecTemp(:, pvbsCurrentColumn) = VRecTemp(:, pvbsCurrentColumn) - pvbsCurrentCorrectionFlag * pvbsCurrentCorrectionAmount;
  2622. % - end of PV correction -
  2623. VRec = VRecTemp;
  2624. VRecOriginal = VRecTemp;
  2625. VOutName = [];
  2626. VOut = []; % let's just read the file name and not the actual file, since that one's insane
  2627. %}
  2628. % update experiment count and cell list
  2629. experiment.experimentCount = experiment.experimentCount + 1;
  2630. cellList{end + 1} = fName(1:end-4); % getting rid of the extension
  2631. set(cellListDisplay, 'string', cellList);
  2632. % save
  2633. data.fileType{end + 1} = 'CSV';
  2634. data.VRecMetadata{end + 1} = VRecMetadata;
  2635. data.VRec{end + 1} = VRec;
  2636. data.VRecOriginal{end + 1} = VRecOriginal;
  2637. data.VOutName{end + 1} = VOutName;
  2638. data.VOut{end + 1} = VOut;
  2639. data.lineScan{end + 1} = lineScan;
  2640. data.lineScanF{end + 1} = lineScanF;
  2641. data.lineScanDFF{end + 1} = lineScanDFF;
  2642. data.lineScanDFFOriginal{end + 1} = lineScanDFFOriginal;
  2643. data.lineScanCSV{end + 1} = lineScanCSV;
  2644. data.lineScanFChannel{end + 1} = lineScanFChannel;
  2645. data.lineScanROI{end + 1} = lineScanROI;
  2646. data.lineScanBaseline{end + 1} = lineScanBaseline;
  2647. data.postprocessing{end + 1} = postprocessing;
  2648. data.artifactRemoval{end + 1} = artifactRemoval;
  2649. data.markPointsMetadata{end + 1} = markPointsMetadata;
  2650. data.markPointsIdx{end + 1} = markPointsIdx;
  2651. data.intrinsicProperties{end + 1} = intrinsicProperties;
  2652. data.intrinsicPropertiesVRec{end + 1} = intrinsicPropertiesVRec;
  2653. data.intrinsicPropertiesVRecMetadata{end + 1} = intrinsicPropertiesVRecMetadata;
  2654. data.intrinsicPropertiesFileName{end + 1} = intrinsicPropertiesFileName;
  2655. data.zStack{end + 1} = zStack;
  2656. data.zStackFileName{end + 1} = zStackFileName;
  2657. data.singleScan{end + 1} = singleScan;
  2658. data.singleScanFileName{end + 1} = singleScanFileName;
  2659. data.sweepIdx{end + 1} = sweepIdx;
  2660. data.sweepStr{end + 1} = sweepStr;
  2661. data.groupIdx{end + 1} = groupIdx;
  2662. data.groupStr{end + 1} = groupStr;
  2663. data.notes{end + 1} = notes;
  2664. experiment.data = data;
  2665. h.exp = experiment;
  2666. h.results = results;
  2667. h.ui.cellList = cellList;
  2668. h.ui.cellListDisplay = cellListDisplay;
  2669. end
  2670. function h = loadABF(h, fPath, fName, actualParams)
  2671. % modified loadExpMain() for .ABF
  2672. % what an irony writing this after returning to pClamp...
  2673. % because PV records data in its own units, data must be scaled appropriately
  2674. % hard-coding here, instead of digging again into insane PV metadata
  2675. % below are set for MC700B with Rf = 500 MO and usual gain settings for whole-cell recordings
  2676. pvbsVoltageScalingFactor = actualParams.pvbsVoltageScalingFactor; % "100 mV" to mV
  2677. pvbsCurrentScalingFactor = actualParams.pvbsCurrentScalingFactor; % "0.1 nA" to pA
  2678. timeColumn = actualParams.timeColumn; % csv column for timestamp
  2679. pvbsVoltageColumn = actualParams.pvbsVoltageColumn; % csv column to apply voltage scaling (column 1 is timestamp, followed by channels)
  2680. pvbsCurrentColumn = actualParams.pvbsCurrentColumn; % csv column to apply current scaling
  2681. csvOffsetRow = actualParams.csvOffsetRow; % row offset while reading csv with csvread() (default: 1)
  2682. csvOffsetColumn = actualParams.csvOffsetColumn; % column offset while reading csv with csvread() (default: 0)
  2683. csvColumnsAsSweeps = actualParams.csvColumnsAsSweeps; % interpret columns as sweeps (default: 0)
  2684. lineScanChannel = actualParams.lineScanChannel; % primary channel for calcium imaging signal; e.g. for P4, 1: red, 2: green (primary)
  2685. lineScanBaseline = actualParams.lineScanBaseline; % (ms), baseline for F_0 in linescans, avoid starting from 0 to prevent possible contamination from shutter artifact
  2686. lineScanROIDetectDuringBaseline = actualParams.lineScanROIDetectDuringBaseline; % detect linescan ROI only during baseline window specified above (0: no, 1: yes), in order to prevent possible errors from uncaging artifact
  2687. lineScanDownsamplingFactor = actualParams.lineScanDownsamplingFactor; % downsampling factor for fluorescence signals, for the dF/F to be robust to noise
  2688. lineScanROISmoothing = actualParams.lineScanDownsamplingFactor; % will average over this many points (before and after) while detecting ROI to be robust from noise - obsolete with single ROI
  2689. lineScanROIThreshold = actualParams.lineScanROIThreshold; % (s.d.); z-score for 1st quartile
  2690. lineScanBackgroundThreshold = actualParams.lineScanBackgroundThreshold; % (s.d.); z-score for 67th percentile
  2691. offloadMarkPointsMetadata = actualParams.offloadMarkPointsMetadata; % delete markpoints metadata after retrieving point indices to save space (0: no, 1: yes)
  2692. % PV GPIO box can quite unbelievably also introduce current measurement error
  2693. % via bleedthrough across channels, which has to be corrected if present
  2694. % otherwise, there will be "phantom" DC injection present in data
  2695. % DO NOT use if recordings DO have intentional baseline DC injection at the beginning!
  2696. % DO NOT be confused with having incorrect bias current settings from amplifier!
  2697. pvbsCurrentCorrectionFlag = actualParams.pvbsCurrentCorrectionFlag; % set to 1 to correct, 0 to leave as is
  2698. pvbsCurrentCorrectionDataPoints = actualParams.pvbsCurrentCorrectionDataPoints; % this many points at the beginning will be used for baseline correction
  2699. % load
  2700. experiment = h.exp;
  2701. data = experiment.data;
  2702. results = h.results;
  2703. cellList = h.ui.cellList;
  2704. cellListDisplay = h.ui.cellListDisplay;
  2705. % prompt
  2706. fprintf(' %s%s ', fPath, fName);
  2707. % load file
  2708. %%% fixlater: csvColumnsAsSweeps assumes "correct" values, i.e. not scaled - this will create confusion when reading .csv saved from PV
  2709. VRecFile = [fPath, fName];
  2710. %VRecTemp = csvread([fPath, fName], csvOffsetRow, csvOffsetColumn); % offset row by 1 ("time(ms), input 0, input 1"), and column by 0
  2711. [abfTemp, abfSamplingInterval, abfMetadata] = abfload_pvbs(VRecFile); % abfMetadata is not very informative, can disregard
  2712. abfSamplingInterval = abfSamplingInterval/1000; % converting from us to ms
  2713. %%{
  2714. try
  2715. % load parameters
  2716. %h = guidata(win1);
  2717. params = h.params;
  2718. analysisParameters = h.params.actualParams;
  2719. analysisParametersDefault = h.params.defaultParams;
  2720. abfUnits = abfMetadata.recChUnits;
  2721. abfSignals = length(abfUnits);
  2722. %{
  2723. if abfSignals > 2
  2724. warningString = sprintf(' Warning: more than 2 signals present - displaying first two only\n');
  2725. fprintf(warningString);
  2726. elseif abfSignals == 2 % dual recordings
  2727. else % single recordings
  2728. end
  2729. %}
  2730. for i = 1:abfSignals %%% fixlater - che puzza, this is being overwritten for every experiment loaded
  2731. try % ditto; but should be irrelevant because this feature was missing
  2732. if i == 1
  2733. if strcmp(abfUnits(i), 'pA')
  2734. signal1Type = 1; % current, voltage, fluorescence
  2735. elseif strcmp(abfUnits(i), 'nA') % in case someone has a very bad taste
  2736. signal1Type = 1; % current, voltage, fluorescence
  2737. elseif strcmp(abfUnits(i), 'mV')
  2738. signal1Type = 2; % current, voltage, fluorescence
  2739. elseif strcmp(abfUnits(i), 'uV') % maybe for field recordings this might be the case, but really just here because of OCD %%% but they would be written as actual micro instead of "u"?
  2740. signal1Type = 2; % current, voltage, fluorescence
  2741. else % don't know what to do, so leave it alone for now %%% fixlater
  2742. signal1Type = 2; % current, voltage, fluorescence - defaulting to voltage, vestige from 46
  2743. end
  2744. signal1Channel = 2; % for .abf timestamp will not be present initially upon loading with abfload(), but will be appended at the end of this function
  2745. h.params.actualParams.signal1Channel = signal1Channel;
  2746. h.params.actualParams.signal1Type = signal1Type;
  2747. h.params.defaultParams.signal1Channel = signal1Channel;
  2748. h.params.defaultParams.signal1Type = signal1Type;
  2749. signal2Type = signal1Type; % this is really only for aesthetics, for axis label
  2750. signal2Channel = 0; % to suppress signal 2 display in a very crude stupid way %%% fixlater %%% cazzo
  2751. h.params.actualParams.signal2Channel = signal2Channel;
  2752. h.params.actualParams.signal2Type = signal2Type;
  2753. h.params.defaultParams.signal2Channel = signal2Channel;
  2754. h.params.defaultParams.signal2Type = signal2Type;
  2755. else
  2756. if strcmp(abfUnits(i), 'pA')
  2757. signal2Type = 1; % current, voltage, fluorescence
  2758. elseif strcmp(abfUnits(i), 'nA') % in case someone has a very bad taste
  2759. signal2Type = 1; % current, voltage, fluorescence
  2760. elseif strcmp(abfUnits(i), 'mV')
  2761. signal2Type = 2; % current, voltage, fluorescence
  2762. elseif strcmp(abfUnits(i), 'uV') % maybe for field recordings this might be the case, but really just here because of OCD %%% but they would be written as actual micro instead of "u"?
  2763. signal2Type = 2; % current, voltage, fluorescence
  2764. else % don't know what to do, so leave it alone for now %%% fixlater
  2765. signal2Type = signal1Type; % match to signal 1 in case of dual recordings (will backfire in some cases, e.g. when recording i_cmd with V_m)
  2766. end
  2767. signal2Channel = 2; % for .abf timestamp will not be present initially upon loading with abfload(), but will be appended at the end of this function
  2768. h.params.actualParams.signal2Channel = signal2Channel;
  2769. h.params.actualParams.signal2Type = signal2Type;
  2770. h.params.defaultParams.signal2Channel = signal2Channel;
  2771. h.params.defaultParams.signal2Type = signal2Type;
  2772. end
  2773. catch ME
  2774. end
  2775. end
  2776. catch ME
  2777. end
  2778. %}
  2779. csvColumnsAsSweeps = 0; % override this for .abf; NB. see start of function for definition intended for the original function loadCSV()
  2780. if csvColumnsAsSweeps
  2781. %%% look here!
  2782. % force scaling factor = 1
  2783. pvbsVoltageScalingFactor = 1;
  2784. pvbsCurrentScalingFactor = 1;
  2785. % force reading data as voltage
  2786. pvbsCurrentColumn = 0;
  2787. % force no column/row offset
  2788. csvOffsetRow = 0;
  2789. csvOffsetColumn = 0;
  2790. timeColumn = 0; % override this for .abf; NB. see start of function for definition intended for the original function loadCSV()
  2791. %{
  2792. if timeColumn % timestamp column is present
  2793. sweeps = size(VRecTemp, 2); % each column represents a sweep
  2794. nonTimeColumn = 1:sweeps; % do this first
  2795. nonTimeColumn = nonTimeColumn(nonTimeColumn ~= timeColumn);
  2796. sweeps = sweeps - 1; % since one column is for timestamp and not an actual sweep
  2797. else
  2798. sweeps = size(VRecTemp, 2); % each column represents a sweep
  2799. nonTimeColumn = 1:sweeps;
  2800. nonTimeColumn = nonTimeColumn(nonTimeColumn ~= timeColumn);
  2801. end
  2802. %}
  2803. sweeps = size(abfTemp, 3); % could also be fetched from metadata: sweeps = abfMetadata.lActualEpisodes;
  2804. nonTimeColumn = 1:sweeps;
  2805. nonTimeColumn = nonTimeColumn(nonTimeColumn ~= timeColumn);
  2806. % pv bleedthrough correction
  2807. %{
  2808. if pvbsVoltageColumn ~= 0
  2809. if pvbsCurrentColumn == 0 % just adding for possible future use of the next else block
  2810. VRecTemp(:, nonTimeColumn) = VRecTemp(:, nonTimeColumn)*pvbsVoltageScalingFactor;
  2811. else % if both are nonzero, default to interpret as voltage
  2812. VRecTemp(:, nonTimeColumn) = VRecTemp(:, nonTimeColumn)*pvbsVoltageScalingFactor;
  2813. end
  2814. elseif pvbsCurrentColumn == 0 % if both are 0, again default to interpret as voltage; this could be used later to interpret as F instead %%% fixlater
  2815. VRecTemp(:, nonTimeColumn) = VRecTemp(:, nonTimeColumn)*pvbsVoltageScalingFactor;
  2816. else % now interpret as current
  2817. VRecTemp(:, nonTimeColumn) = VRecTemp(:, nonTimeColumn)*pvbsCurrentScalingFactor;
  2818. pvbsCurrentCorrectionAmount = nanmean(VRecTemp(1:pvbsCurrentCorrectionDataPoints, pvbsCurrentColumn));
  2819. VRecTemp(:, pvbsCurrentColumn) = VRecTemp(:, pvbsCurrentColumn) - pvbsCurrentCorrectionFlag * pvbsCurrentCorrectionAmount;
  2820. end
  2821. %}
  2822. else
  2823. %sweeps = 1; % gap-free
  2824. sweeps = size(abfTemp, 3); % could also be fetched from metadata: sweeps = abfMetadata.lActualEpisodes;
  2825. % pv bleedthrough correction
  2826. %{
  2827. VRecTemp(:, pvbsVoltageColumn) = VRecTemp(:, pvbsVoltageColumn)*pvbsVoltageScalingFactor;
  2828. VRecTemp(:, pvbsCurrentColumn) = VRecTemp(:, pvbsCurrentColumn)*pvbsCurrentScalingFactor;
  2829. pvbsCurrentCorrectionAmount = nanmean(VRecTemp(1:pvbsCurrentCorrectionDataPoints, pvbsCurrentColumn));
  2830. VRecTemp(:, pvbsCurrentColumn) = VRecTemp(:, pvbsCurrentColumn) - pvbsCurrentCorrectionFlag * pvbsCurrentCorrectionAmount;
  2831. %}
  2832. end
  2833. % fill cells
  2834. experiment.metadata{end + 1} = [];
  2835. experiment.fileName{end + 1} = fName; % just to make file name and path readily accessible
  2836. experiment.filePath{end + 1} = fPath;
  2837. experiment.sweeps{end + 1} = sweeps;
  2838. results{end + 1} = struct;
  2839. % fill cells within cells (... interlinked)
  2840. VOutName = {cell(sweeps, 1)};
  2841. VOut = {cell(sweeps, 1)};
  2842. VRecMetadata = {cell(sweeps, 1)};
  2843. VRec = {cell(sweeps, 1)};
  2844. VRecOriginal = {cell(sweeps, 1)};
  2845. %lineScanMetadata = {cell(sweeps, 1)};
  2846. lineScanFile = {cell(sweeps, 1)};
  2847. lineScan = {cell(sweeps, 1)};
  2848. lineScanF = {cell(sweeps, 1)};
  2849. lineScanDFF = {cell(sweeps, 1)};
  2850. lineScanDFFOriginal = {cell(sweeps, 1)};
  2851. lineScanCSVFile = {cell(sweeps, 1)};
  2852. lineScanCSV = {cell(sweeps, 1)};
  2853. lineScanFChannel = {cell(sweeps, 1)};
  2854. lineScanROI = {cell(sweeps, 1)};
  2855. postprocessing = [];
  2856. artifactRemoval = [];
  2857. markPointsMetadata = {cell(sweeps, 1)};
  2858. markPointsIdx = {cell(sweeps, 1)};
  2859. intrinsicProperties = struct(); % struct, not cell
  2860. intrinsicPropertiesVRec = {cell(1)};
  2861. intrinsicPropertiesVRecMetadata = struct();
  2862. intrinsicPropertiesFileName = [];
  2863. zStack = {cell(1)}; % only one
  2864. zStackFileName = [];
  2865. singleScan = {cell(1)}; % only one as representative, since saving all of them will be overwhelming for file size %%% what was this?
  2866. singleScanFileName = [];
  2867. sweepIdx = 1:sweeps;
  2868. sweepStr = cell(sweeps, 1);
  2869. for i = 1:sweeps
  2870. VRecMetadata{i} = [];
  2871. sweepStr{i} = num2str(i);
  2872. VOutName{i} = [];
  2873. VOut{i} = []; % let's just read the file name and not the actual file, since that one's insane
  2874. end
  2875. groupIdx = {}; % groupIdx = {cell(sweeps, 1)};
  2876. groupStr = {};
  2877. if sweeps == 1 % just for convenience if there's only one sweep
  2878. groupIdx{end + 1} = 1;
  2879. groupStr{end + 1} = '1';
  2880. end
  2881. notes = {};
  2882. postprocessing = [h.params.actualParams.boxcarLength1, h.params.actualParams.besselFreq1, h.params.actualParams.besselOrder1];
  2883. postprocessing = [postprocessing; [h.params.actualParams.boxcarLength2, h.params.actualParams.besselFreq2, h.params.actualParams.besselOrder2]];
  2884. % fill sweeps
  2885. %{
  2886. if csvColumnsAsSweeps
  2887. for i = 1:sweeps
  2888. VRec{i} = [VRecTemp(:, timeColumn), VRecTemp(:, nonTimeColumn(i))];
  2889. end
  2890. else
  2891. VRec{1} = VRecTemp;
  2892. end
  2893. %}
  2894. % makeshift code for abf support %%% fixlater
  2895. abfCh1Column = pvbsVoltageColumn - 1;
  2896. abfCh2Column = pvbsCurrentColumn - 1;
  2897. %VRec1 = abfTemp(:, abfCh1Column, :);
  2898. %VRec2 = abfTemp(:, abfCh2Column, :);
  2899. %VRec = abfTemp(:, abfCh1Column, :);
  2900. if abfSignals > 2
  2901. warningString = sprintf(' Warning: more than 2 signals present - displaying first two only\n');
  2902. fprintf(warningString);
  2903. VRec1 = abfTemp(:, abfCh1Column, :);
  2904. VRec2 = abfTemp(:, abfCh2Column, :);
  2905. VRec = [VRec1, VRec2];
  2906. h.params.actualParams.signal1Channel = abfCh1Column + 1; % +1 is necessary... stupid coding as usual by me, will surely regret this later
  2907. h.params.actualParams.signal2Channel = abfCh2Column + 1;
  2908. h.params.defaultParams.signal1Channel = abfCh1Column + 1;
  2909. h.params.defaultParams.signal2Channel = abfCh2Column + 1;
  2910. elseif abfSignals == 2 % dual recordings
  2911. VRec1 = abfTemp(:, abfCh1Column, :);
  2912. VRec2 = abfTemp(:, abfCh2Column, :);
  2913. VRec = [VRec1, VRec2];
  2914. h.params.actualParams.signal1Channel = abfCh1Column + 1;
  2915. h.params.actualParams.signal2Channel = abfCh2Column + 1;
  2916. h.params.defaultParams.signal1Channel = abfCh1Column + 1;
  2917. h.params.defaultParams.signal2Channel = abfCh2Column + 1;
  2918. else % single recordings
  2919. VRec = abfTemp(:, abfCh1Column, :);
  2920. end
  2921. timeStampColumn = 0 : abfSamplingInterval : abfSamplingInterval*(size(abfTemp, 1) - 1);
  2922. timeStampColumn = timeStampColumn';
  2923. VRecTempTemp = {};
  2924. for i = 1:size(VRec, 3) % unfortunate redundancy but better than not taking advantage of abfload()
  2925. VRecTemp = VRec(:,:,i);
  2926. VRecTemp = [timeStampColumn, VRecTemp];
  2927. VRecTempTemp{end + 1} = VRecTemp;
  2928. end
  2929. VRec = VRecTempTemp;
  2930. VRecOriginal = VRec;
  2931. % postprocessing - if applicable
  2932. % this block now moved up in different parts to accommodate multiple-sweep .csv
  2933. %{
  2934. % load VRec
  2935. VRecMetadata{1} = [];
  2936. VRecFile = [fPath, fName];
  2937. VRecTemp = csvread([fPath, fName], csvOffsetRow, csvOffsetColumn); % offset row by 1 ("time(ms), input 0, input 1"), and column by 0
  2938. % this bizzare step has to be taken, because Prairie
  2939. VRecTemp(:, pvbsVoltageColumn) = VRecTemp(:, pvbsVoltageColumn)*pvbsVoltageScalingFactor;
  2940. VRecTemp(:, pvbsCurrentColumn) = VRecTemp(:, pvbsCurrentColumn)*pvbsCurrentScalingFactor;
  2941. pvbsCurrentCorrectionAmount = nanmean(VRecTemp(1:pvbsCurrentCorrectionDataPoints, pvbsCurrentColumn));
  2942. VRecTemp(:, pvbsCurrentColumn) = VRecTemp(:, pvbsCurrentColumn) - pvbsCurrentCorrectionFlag * pvbsCurrentCorrectionAmount;
  2943. % - end of PV correction -
  2944. VRec = VRecTemp;
  2945. VRecOriginal = VRecTemp;
  2946. VOutName = [];
  2947. VOut = []; % let's just read the file name and not the actual file, since that one's insane
  2948. %}
  2949. % update experiment count and cell list
  2950. experiment.experimentCount = experiment.experimentCount + 1;
  2951. cellList{end + 1} = fName(1:end-4); % getting rid of the extension
  2952. set(cellListDisplay, 'string', cellList);
  2953. % save
  2954. data.fileType{end + 1} = 'ABF';
  2955. data.VRecMetadata{end + 1} = VRecMetadata;
  2956. data.VRec{end + 1} = VRec;
  2957. data.VRecOriginal{end + 1} = VRecOriginal;
  2958. data.VOutName{end + 1} = VOutName;
  2959. data.VOut{end + 1} = VOut;
  2960. data.lineScan{end + 1} = lineScan;
  2961. data.lineScanF{end + 1} = lineScanF;
  2962. data.lineScanDFF{end + 1} = lineScanDFF;
  2963. data.lineScanDFFOriginal{end + 1} = lineScanDFFOriginal;
  2964. data.lineScanCSV{end + 1} = lineScanCSV;
  2965. data.lineScanFChannel{end + 1} = lineScanFChannel;
  2966. data.lineScanROI{end + 1} = lineScanROI;
  2967. data.lineScanBaseline{end + 1} = lineScanBaseline;
  2968. data.postprocessing{end + 1} = postprocessing;
  2969. data.artifactRemoval{end + 1} = artifactRemoval;
  2970. data.markPointsMetadata{end + 1} = markPointsMetadata;
  2971. data.markPointsIdx{end + 1} = markPointsIdx;
  2972. data.intrinsicProperties{end + 1} = intrinsicProperties;
  2973. data.intrinsicPropertiesVRec{end + 1} = intrinsicPropertiesVRec;
  2974. data.intrinsicPropertiesVRecMetadata{end + 1} = intrinsicPropertiesVRecMetadata;
  2975. data.intrinsicPropertiesFileName{end + 1} = intrinsicPropertiesFileName;
  2976. data.zStack{end + 1} = zStack;
  2977. data.zStackFileName{end + 1} = zStackFileName;
  2978. data.singleScan{end + 1} = singleScan;
  2979. data.singleScanFileName{end + 1} = singleScanFileName;
  2980. data.sweepIdx{end + 1} = sweepIdx;
  2981. data.sweepStr{end + 1} = sweepStr;
  2982. data.groupIdx{end + 1} = groupIdx;
  2983. data.groupStr{end + 1} = groupStr;
  2984. data.notes{end + 1} = notes;
  2985. experiment.data = data;
  2986. h.exp = experiment;
  2987. h.results = results;
  2988. h.ui.cellList = cellList;
  2989. h.ui.cellListDisplay = cellListDisplay;
  2990. end
  2991. %% Trace Display
  2992. function h = displayTrace(h, itemSelected)
  2993. % load
  2994. params = h.params;
  2995. VRec = h.exp.data.VRec;
  2996. traceDisplay = h.ui.traceDisplay;
  2997. axes(traceDisplay); % absolutely necessary - bring focus to main display, since other functions might have brought it to another axes
  2998. % clear display
  2999. trace = {}; % clear current plot
  3000. analysisWindowHandle = {}; % clear current analysis window display
  3001. axes(traceDisplay);
  3002. yyaxis left; cla;
  3003. yyaxis right; cla;
  3004. yyaxis left;
  3005. % clear sweep list items
  3006. sweepListDisplay = h.ui.sweepListDisplay;
  3007. sweepList = {};
  3008. groupListDisplay = h.ui.groupListDisplay;
  3009. % axis range information
  3010. traceDisplayYRange = h.ui.traceDisplayYRange; % y range; to be shared across experiments
  3011. traceDisplayY2Range = h.ui.traceDisplayY2Range; % y range; to be shared across experiments
  3012. traceDisplayXRange = h.ui.traceDisplayXRange; % x range; to be shared across experiments
  3013. % break if invalid - for when called before loading experiments
  3014. if isempty(VRec)
  3015. return
  3016. end
  3017. % experiment to display
  3018. try % try-catch for reverse compatibility
  3019. timeColumnAvailable = h.params.actualParams.timeColumnAvailable;
  3020. catch ME
  3021. timeColumn = 1;
  3022. timeColumnAvailable = 1;
  3023. h.params.actualParams.timeColumn = timeColumn;
  3024. h.params.actualParams.timeColumnAvailable = timeColumnAvailable;
  3025. end
  3026. try % ditto
  3027. signal1Type = h.params.actualParams.signal1Type; % current, voltage, fluorescence
  3028. signal2Type = h.params.actualParams.signal2Type; % current, voltage, fluorescence
  3029. signal1Channel = h.params.actualParams.signal1Channel; % corresponding to data column, but mind timestamp availability
  3030. signal2Channel = h.params.actualParams.signal2Channel; % corresponding to data column, but mind timestamp availability
  3031. catch ME
  3032. signal1Type = 2; % current, voltage, fluorescence - defaulting to voltage
  3033. signal2Type = 3; % current, voltage, fluorescence - defaulting to fluorescence
  3034. try % additional layer of safety
  3035. signal1Channel = h.params.actualParams.pvbsVoltageColumn; % defaulting to voltage
  3036. signal2Channel = h.params.actualParams.lineScanChannel; % defaulting to fluorescence
  3037. catch ME
  3038. signal1Channel = 2;
  3039. signal2Channel = 2;
  3040. h.params.actualParams.signal1Channel = signal1Channel;
  3041. h.params.actualParams.signal2Channel = signal2Channel;
  3042. h.params.defaultParams.signal1Channel = signal1Channel;
  3043. h.params.defaultParams.signal2Channel = signal2Channel;
  3044. end
  3045. end
  3046. columnTimeStamp = h.params.actualParams.timeColumn;
  3047. %columnToDisplay = h.params.actualParams.pvbsVoltageColumn; %%% fixlater
  3048. itemToDisplay = itemSelected(1); % display only the first one if multiple items are selected - obsolete
  3049. VRecToDisplay = VRec{itemToDisplay};
  3050. if iscell(VRecToDisplay)
  3051. sweepCount = length(VRecToDisplay);
  3052. if sweepCount == 1
  3053. VRecToDisplay = VRecToDisplay{1};
  3054. end
  3055. else
  3056. sweepCount = 1;
  3057. end
  3058. sweepIdx = h.exp.data.sweepIdx{itemSelected};
  3059. sweepStr = h.exp.data.sweepStr{itemSelected};
  3060. groupIdx = h.exp.data.groupIdx{itemSelected};
  3061. groupStr = h.exp.data.groupStr{itemSelected};
  3062. % do display
  3063. axes(traceDisplay);
  3064. %xlabel('t (ms)', 'color', 'k');
  3065. try % use try-catch here
  3066. workingAxis = 1;
  3067. if signal1Type == 3 % i, V, F
  3068. displayTraceF(workingAxis);
  3069. elseif signal1Type == 1
  3070. displayTraceV(workingAxis); % can't think of a better name; also separate axis labeling from this function
  3071. else % default to V in case signal1Type is incorrectly set due to whatever miracle
  3072. displayTraceV(workingAxis); % can't think of a better name; also separate axis labeling from this function
  3073. end
  3074. catch ME
  3075. errorString = sprintf(' \nWarning: invalid display parameters (Axis #%s) - check signal channels\n', num2str(workingAxis));
  3076. %error(errorString);
  3077. fprintf(errorString); % not exactly an error
  3078. yyaxis left; % return to left axis as a failsafe
  3079. %return
  3080. end
  3081. try % use try-catch here
  3082. workingAxis = 2;
  3083. if signal2Type == 3 % i, V, F
  3084. displayTraceF(workingAxis);
  3085. elseif signal2Type == 1
  3086. displayTraceV(workingAxis); % can't think of a better name; also separate axis labeling from this function
  3087. else % default to V in case signal1Type is incorrectly set due to whatever miracle
  3088. displayTraceV

pvbs.m at commit 92d713d, under GPL-3.0 · at the source

Overview

Authors: Jaeyoung Yoon1,2, Ricardo Silva1,3, Scellig Stone4,5, Hart Lidov6,7, Emily Osterweil2,8, Brielle R. Ferguson1,9
ORCID iDs: Ricardo Silva
  1. F. M. Kirby Neurobiology Center, Boston Children's Hospital, Boston, MA, United States
  2. Department of Neurology, Harvard Medical School, Boston, MA, United States
  3. Department of Neurobiology, Harvard Medical School, Boston, MA, United States
  4. Department of Neurosurgery, Boston Children's Hospital, Boston, MA, United States
  5. Department of Neurosurgery, Harvard Medical School, Boston, MA, United States
  6. Department of Pathology, Boston Children's Hospital, Boston, MA, United States
  7. Department of Pathology, Harvard Medical School, Boston, MA, United States
  8. Zander & Wyss Translational Neuroscience Center, Boston Children's Hospital, Boston, MA, United States
  9. Department of Genetics, Harvard Medical School, Boston, MA, United States
Institutions: Boston Children's Hospital (United States); Harvard University (United States)
Journal: Frontiers in synaptic neuroscience, volume 18, article 1843277
Dates: received 30 March 2026; accepted 12 May 2026; published online 26 June 2026
Type: Research article · Language: English
License: CC BY
Identifiers: DOI 10.3389/fnsyn.2026.1843277 · PMID 42433477 · PMCID PMC13352477 · OpenAlex W7166034385
Open access: gold, a free copy (OpenAlex)
Status: code verified
Categories: intracellular / patch clamp (modality), human (organism), epilepsy (population), cellular / molecular (subfield)
Methods: Statistics, Single-unit activity, calcium imaging
Keywords: cortical stimulation, electrical stimulation, epilepsy, excitation-inhibition balance, fast-spiking interneuron, human brain slice, parvalbumin interneuron, patch clamp electrophysiology
Topic: Neurological disorders and treatments (Neurology, Medicine), according to OpenAlex
Funding: NICHD NIH HHS (P50 HD105351); NIMH NIH HHS (R00 MH128892)
Citations: not cited yet (Europe PMC); 54 references in the paper

Abstract

Electrical brain stimulation has been used to treat epilepsy with therapeutic success, but without complete understanding of its cellular mechanisms of seizure suppression. Using acute human brain slices obtained from pharmaco-resistant epilepsy patients, we delivered high-frequency, high-intensity extracellular electrical stimulation while recording from neocortical layer 2/3 pyramidal neurons (PNs), fast-spiking interneurons (FSINs), and non-fast-spiking interneurons (nFSINs). Electrical stimulation led to an increasingly selective activation of FSINs at higher stimulation frequencies, which consistently fired with high fidelity throughout prolonged stimulation periods while both PNs and nFSINs were suppressed rapidly. In addition, stimulation caused a long-term rebalancing of synaptic weights through selective and differential depression of synaptic inputs, resulting in an approximately twofold increase in the normalized excitatory-to-inhibitory postsynaptic conductance at FSINs while not affecting PNs, thereby providing support for FSIN activation toward increased inhibitory tone and network stabilization. These stimulation-induced effects were accompanied by only minimal changes in neuronal intrinsic excitability.

Reproduced under the paper's license (CC BY), from the paper cited above.

Repository

Its files are read in the Code ↔ Paper reader above, with 2 matches between paragraphs and lines of code.

flosfor/pvbs

License: GPL-3.0
State: the link answers, verified on 27 September 2026
Evidence: files inventoried
Commit: 92d713d76616ca3bf67aecaef1222b72f9f5ce01, 30 May 2025
Languages: MATLAB (1)
Size: 9 files, 1 script
Software Heritage: not archived
Found in: the text, “Data analysis and statistics”
Holds: README, license file
Not found: CITATION.cff, environment file, tests, continuous integration, documentation
Availability: 1 check, the latest on 27 September 2026: the link answers
  • 27 September 2026: the link answers
3 files

Tracing map

Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.

What the map holds:

  • 1 repository of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
  • 1 script, each with its path and the digest of its content;
  • 2 matches between paragraphs of the paper and lines of the code (method lexical-v1);
  • neither the text of the paper nor the code itself.

Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.

Data

No dataset and no data link were found in the paper.

Data availability statement

The original contributions presented in the study are included in the article/Supplementary material, further inquiries can be directed to the corresponding authors.

Reproduced under the paper's license (CC BY), from the paper cited above.

Versions

The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.

Version 1, 27 September 2026: the first record

Recorded: type, language, journal, volume, pages, dates, 6 authors, 8 keywords, 2 funders, 54 references.

Cite

This paper

Yoon, J., Silva, R., Stone, S., Lidov, H., Osterweil, E., & Ferguson, B. R. (2026). High-frequency, high-intensity electrical stimulation selectively activates human fast-spiking interneurons. Frontiers in synaptic neuroscience, 18, 1843277. https://doi.org/10.3389/fnsyn.2026.1843277

BibTeX

@article{yoon2026high,
author = {Yoon, Jaeyoung and Silva, Ricardo and Stone, Scellig and Lidov, Hart and Osterweil, Emily and Ferguson, Brielle R.},
title = {{High-frequency, high-intensity electrical stimulation selectively activates human fast-spiking interneurons}},
journal = {Frontiers in synaptic neuroscience},
year = {2026},
month = jun,
volume = {18},
pages = {1843277},
publisher = {Frontiers Media SA},
issn = {1663-3563},
doi = {10.3389/fnsyn.2026.1843277},
url = {https://doi.org/10.3389/fnsyn.2026.1843277},
pmid = {42433477},
pmcid = {PMC13352477}
}

RIS

TY - JOUR
AU - Yoon, Jaeyoung
AU - Silva, Ricardo
AU - Stone, Scellig
AU - Lidov, Hart
AU - Osterweil, Emily
AU - Ferguson, Brielle R.
TI - High-frequency, high-intensity electrical stimulation selectively activates human fast-spiking interneurons
T2 - Frontiers in synaptic neuroscience
J2 - Front Synaptic Neurosci
PY - 2026
DA - 2026/06/26
VL - 18
SP - 1843277
SN - 1663-3563
PB - Frontiers Media SA
DO - 10.3389/fnsyn.2026.1843277
UR - https://doi.org/10.3389/fnsyn.2026.1843277
LA - en
ER -

CSL-JSON

{
"id": "10.3389/fnsyn.2026.1843277",
"type": "article-journal",
"title": "High-frequency, high-intensity electrical stimulation selectively activates human fast-spiking interneurons",
"container-title": "Frontiers in synaptic neuroscience",
"author": [
{
"family": "Yoon",
"given": "Jaeyoung"
},
{
"family": "Silva",
"given": "Ricardo"
},
{
"family": "Stone",
"given": "Scellig"
},
{
"family": "Lidov",
"given": "Hart"
},
{
"family": "Osterweil",
"given": "Emily"
},
{
"family": "Ferguson",
"given": "Brielle R."
}
],
"container-title-short": "Front Synaptic Neurosci",
"volume": "18",
"page": "1843277",
"DOI": "10.3389/fnsyn.2026.1843277",
"PMID": "42433477",
"PMCID": "PMC13352477",
"ISSN": "1663-3563",
"publisher": "Frontiers Media SA",
"URL": "https://doi.org/10.3389/fnsyn.2026.1843277",
"language": "en",
"issued": {
"date-parts": [
[
2026,
6,
26
]
]
}
}

The tracing map gets a citation of its own once an author has validated it and it has a DOI.

Similar papers

The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.

[1] doi:10.1038/s42003-026-10063-9 [code]
Conserved Kir channel mechanisms governing intrinsic excitability in human and rodent parvalbumin neurons.
Journal: Communications biology
In common: intracellular / patch clamp, cellular / molecular, 7 references
[2] doi:10.1016/j.neurot.2026.e01031
Single-neuron responses to neurostimulation: Insights for epilepsy.
Journal: Neurotherapeutics : the journal of the American Society for Experimental NeuroTherapeutics
In common: epilepsy, 4 references
[3] doi:10.3389/fnins.2026.1815732
Dataset of chronic intracranial EEG of epilepsy patients via responsive neurostimulation system.
Journal: Frontiers in neuroscience
In common: epilepsy, 4 references
[4] doi:10.1038/s42003-026-10418-2 [code]
Cortical PV and VIP interneurons similarly influence SST neuron output despite distinct unitary properties.
Journal: Communications biology
In common: intracellular / patch clamp, cellular / molecular, 4 references
[5] doi:10.3389/fncom.2026.1862383 [code]
Microstructural spine alterations increase neuronal excitability in focal cortical dysplasia Type I.
Journal: Frontiers in computational neuroscience
In common: epilepsy, 3 references
[6] doi:10.1016/j.ebiom.2026.106362 [code]
Neuron-derived neurotrophic factor-positive interneurons: a cellular target for anti-seizure therapies.
Journal: EBioMedicine
In common: epilepsy, 3 references
[7] doi:10.1093/braincomms/fcag323 [code]
Induced epileptic seizures in larval zebrafish reveal a synaptic modulation associated with the post-ictal state.
Journal: Brain communications
In common: epilepsy, cellular / molecular, 2 references
[8] doi:10.1038/s41467-026-72935-2 [code]
Spindle neurons in human cortex possess distinctive firing properties and transcriptomic signatures.
Journal: Nature communications
In common: Statistics and Machine Learning Toolbox, intracellular / patch clamp, cellular / molecular, 1 reference
[9] doi:10.1016/j.celrep.2026.117388 [code]
An unsuspected physiological role for mGluRIII glutamate receptors in hippocampal area CA1.
Journal: Cell reports
In common: intracellular / patch clamp, cellular / molecular, 2 references
[10] doi:10.1162/imag.a.1279 [code]
Multimodal laminar characterization of visual areas along the cortical hierarchy.
Journal: Imaging neuroscience (Cambridge, Mass.)
In common: 3 references

Contribute

The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.

Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.

Request its removal

To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).

Discussion, reproductions, activity

Discussion: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.

Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.

Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.