High-frequency, high-intensity electrical stimulation selectively activates human fast-spiking interneurons.
The 2 matches
- [1] § Methods › Slice electrophysiology ↔ pvbs.m, lines 111–180 · score 0.75 · AP half width, AP amplitude, AP threshold, rising, detection, peak
- [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
- %% PVBS: Prairie View Browsing Solution
- % (https://github.com/flosfor/pvbs)
- %
- % Copyright (C) 2022-2024, Jaeyoung Yoon.
- %
- % The use or modification of this software (PVBS) is consented only
- % under agreement to cite the developer and/or the original source code
- % (https://github.com/flosfor/pvbs) within the body of the published
- % work or presentation, wherein PVBS was used.
- %
- %
- % -------------------------- <!> Important <!> ---------------------------
- %
- % - Required Matlab Toolboxes:
- % 1) Statistics & Machine Learning
- % 2) Signal Processing
- %
- % - Import Settings:
- % Make sure the import settings are correctly defined to match YOUR data
- % before importing experiments, as they can be easily different across
- % setups; e.g. DAC gain, input channels, etc. To access import settings,
- % use the button on the GUI, or see function setDefaultParams() in the
- % code for default parameters.
- %
- % ------------------------------------------------------------------------
- %
- % - Supported experiment types:
- % 1) *.CSV (any data)
- % 2) *.ABF (from pClamp)
- % 3) *.XML (from Prairie View (PV))
- % 3-1) VoltageRecording
- % 3-2) LineScan (synchronized with VoltageRecording and/or MarkPoints)
- % 3-3) T-Series (of VoltageRecording type experiments)
- %
- % ------------------------------------------------------------------------
- %
- % - Import settings can be found and modified with the options button;
- % by default, PVBS assumes the following:
- % - timestamp present at column 1
- % - following columns represent sweeps (for i or V)
- % - ... or acquisition channels (for F)
- %
- % If metadata is available (from .abf, or .xml in the case of PV
- % experiments), PVBS will attempt to read correct signal definitions
- % from metadata.
- %
- % PVBS assumes that values are in units of: ms, mV, pA. This also
- % applies to display, even when metadata is available (see below).
- %
- % ------------------------------------------------------------------------
- %
- % - NB.
- %
- % Default settings (including display) were intended for i-clamp
- % experiments and positive peak direction (e.g. EPSP), but PVBS is
- % compatible with both i-clamp or V-clamp, or peaks in any direction.
- % PVBS attempts to read correct signal definition from metadata, but
- % in some cases, axis labels can be displayed incorrectly especially
- % when the signal definitions (type or channel) are inconsistent across
- % experiments loaded in the same instance of PVBS. Nevertheless, the
- % numerical values of data will still be correct even in such cases.
- %
- % To avoid confusion, it is recommended that a single instance of PVBS
- % is used for a set of experiments with consistent signal (axis)
- % definitions. For experiments with different signal definitions
- % (e.g. i-clamp and V-clamp), simply launch another instance of PVBS
- % to load them separately.
- %
- % ------------------------------------------------------------------------
- %
- %
- % ------------------------------------------------------------------------
- %% ------------------------------------------------------------------------
- function pvbs()
- % main window
- % version
- pvbsTitle = 'PVBS (Prairie View Browsing Solution)';
- pvbsLastMod = '2025.05.30';
- pvbsStage = '(c)';
- theGreatCorona = 2020; % best year ever
- pvbsVer = [num2str(str2num(pvbsLastMod(1:4)) - theGreatCorona), pvbsLastMod(5:end)]; % why not
- fpVer = '5.5'; % not the version of this code, but PV itself
- matlabVer = '2023a'; % with Statistics & Machine Learning Toolbox (v. 12.0) and Signal Processing Toolbox (v. 8.5)
- github = '(https://github.com/flosfor/pvbs)';
- copyright = 'Copyright (C) 2022-2024, ';
- yjy = 'Jaeyoung Yoon';
- % open and initialize
- fprintf('\n%s v.%s%s\n%s\n%s%s.\n\n\n', pvbsTitle, pvbsVer, pvbsStage, github, copyright, yjy);
- 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]);
- win.WindowState = 'maximized';
- h = struct();
- %%{
- 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');
- function aboutPVBS(src, ~)
- aboutButton = src;
- set(aboutButton, 'enable', 'off');
- aboutWin = figure('Name', 'About PVBS', 'NumberTitle', 'off', 'MenuBar', 'none', 'Units', 'Normalized', 'Position', [0.4, 0.4, 0.25, 0.25], 'resize', 'off', 'CloseRequestFcn', @closeAboutWin);
- 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]);
- 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]);
- 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');
- try
- set(h.ui.saveGUIButton, 'enable', 'on');
- catch ME
- end
- function closeAboutWin(src, ~)
- set(aboutButton, 'enable', 'on');
- delete(aboutWin);
- end
- end
- %}
- % load default parameters
- guidata(win, h);
- %params.defaultParams = struct();
- defaultParams = setDefaultParams(win); % default parameter set
- params.actualParams = defaultParams; % actual parameters to be used; initializing with defaults
- params.defaultParams = defaultParams; % store separately for access (e.g. to revert to defaults)
- % default parameters that can be hard-coded without much concern
- %params.defaultParams = struct(); % moved up
- params.analysisBaseline = [27, 44]; % baseline window; NB. choose ~ 16.67 ms to average out 60 Hz noise
- params.analysisWindow1 = [52, 202]; % analysis window 1
- params.analysisWindow2 = [60, 210]; % analysis window 2
- %params.analysisTargetList = {'(Target)', 'All Groups', 'Selected Groups', 'All Sweeps', 'Selected Sweeps'};
- %{
- params.analysisOptionList11 = {'(Dir.)', '+/-', '+', '-'};
- params.analysisOptionList12 = {'(Kin.)', '20-80', '10-90', 'Custom...'};
- params.analysisOptionList21 = {'(Dir.)', '+/-', '+', '-'};
- params.analysisOptionList22 = {'(Kin.)', '20-80', '10-90', 'Custom...'};
- %}
- %params.analysisPlotMenuList0 = {'(Experiment)', 'Current Experiment', 'All Experiments'};
- params.analysisPlotMenuList1 = {'(Signal)', 'S1', 'S2'};
- params.analysisPlotMenuList2 = {'(Window)', 'W1', 'W2'};
- params.analysisPlotMenuList3 = {'(Results)', '(Select Window # for options)'};
- params.analysisPlotMenuList31 = {'(Results)', 'Peak', 'Area', 'Mean', 'Time of Peak', 'Rise (time)', 'Decay (time)', 'Rise (slope)', 'Decay (slope)'};
- params.analysisPlotMenuList32 = {'(Results)', 'No. of Events', 'Event Peak Value', 'Event Amplitude', 'Event Time of Peak', 'Event Baseline'};
- params.analysisPlotMenuList33 = {'(Results)', 'AP Threshold', 'AP Amplitude', 'AP Time of Peak', 'AP Half-width', 'Max Depol', 'Max Repol', 'RMP'};
- params.analysisPlotMenuList4 = {'(Plot by...)', 'Swps.', 'Grps.'};
- params.analysisTypeList1 = {'(Type)', 'Peak / Area / Mean', 'Threshold Detection', 'Waveform'};
- params.analysisTypeList2 = {'(Type)', 'Peak / Area / Mean', 'Threshold Detection', 'Waveform'};
- params.analysisPresetList = {'(Select)', 'Uncaging w/ LineScan'};
- params.analysisBaselineColor = [0.4, 0.5, 0.6]; % baseline window color
- params.analysisWindow1Color = [0, 0.75, 0.75]; % analysis window 1 color
- params.analysisWindow2Color = [0, 0.6, 0.6]; % analysis window 2 color
- %params.intrinsicPropertiesAnalysis = struct(); % default analysis parameters for intrinsic membrane properties %%% moved under params.actualParams
- params.xRange = []; % x axis range for main trace display; leave this empty
- params.xRangeZoom = 2; % x range zooming factor
- params.xRangeMove = 0.166666667; % x range moving factor
- params.yRangeDefault = [-140, 20]; % y axis range for main trace display, for V
- params.yRange = params.yRangeDefault;
- params.yRangeZoom = 2; % y range zooming factor, for V
- params.yRangeMove = 0.083333334; % y range moving factor, for V
- params.y2RangeDefault = [-1, 4]; % y axis range for main trace display, for F
- params.y2Range = params.y2RangeDefault;
- params.y2RangeZoom = 2; % y range zooming factor, for F
- params.y2RangeMove = 0.083333334; % y range moving factor, for F
- params.y3RangeDefault = [-500, 400]; % y axis range for main trace display, for i
- params.y3Range = params.y3RangeDefault;
- params.y3RangeZoom = 2; % y range zooming factor, for i
- params.y3RangeMove = 0.083333334; % y range moving factor, for i
- params.traceColorInactive = [0.75, 0.75, 0.75]; % color for inactive traces
- params.traceColorActive = [1, 0, 0]; % color for active (selected) traces
- params.trace2ColorInactive = [0.9, 0.95, 0.9]; % secondary color for inactive traces
- params.trace2ColorActive = [0.6, 0.8, 0.6]; % secondary color for active (selected) traces
- params.selectionInterval = 1; % default sweep selection interval
- params.groupSelectionInterval = 1; % misleading name; previously default selection interval for grouping, now group every this number of sweeps
- params.groupSweepIdx = 0; % index of sweep to display within group
- %params.peakDirection = 0; % direction for peak detection (-1: negative, 0: absolute, 1: positive) - obsolete
- params.traceProcessingTargetList = {'Voltage / Current', 'Fluorescence'}; % obsolete, using params.analysisPlotMenuList1 instead
- %params.exportTarget = 1; % which signal to export - default to 1 - obsolete
- params.resultsPlot1YRange = []; % will be updated upon analysis
- params.resultsPlot2YRange = []; % will be updated upon analysis
- params.lastSweepDeleted = 0; % flag to indicate if last sweep had been deleted; for correct indexing
- params.firstRun = 1; % flag for first run
- % data structure
- exp.experimentCount = 0;
- exp.metadata = {}; % cell for tSeries metadata files
- % below are for easier access without having to dig into metadata
- exp.fileName = {}; % file name
- exp.filePath = {}; % file path
- exp.sweeps = {}; % total sweep count for each tSeries
- % actual data
- data.fileType = {}; % cell for file type identifier (PV? CSV? ABF?)
- data.VRec = {}; % VRec (.csv)
- data.VRecOriginal = {}; % VRec (.csv), to preserve original in case of postprocessing - again real lack of foresight
- data.VRecMetadata = {}; % metadata for each VRec (.xml)
- data.VOut = {}; % VOut (.xml) - may have to omit due to PV insanity in formatting these
- data.VOutName = {}; % VRec experiment type (e.g. "single stim") - VOut name will work most of the time
- %data.lineScanMetadata = {}; % metadata for each LScn (.xml) - obsolete, linescans don't have separate metadata per cycle
- data.lineScan = {}; % LScn (.tiff)
- data.lineScanDFF = {}; % LScn dF/F
- data.lineScanDFFOriginal = {}; % LScn dF/F, to preserve original in case of postprocessing - again real lack of foresight
- data.lineScanF = {}; % LScn F
- data.lineScanFChannel = {}; % LScn channel used for F, dF/F
- data.lineScanROI = {}; % LScn ROI
- data.lineScanBaseline = {}; % LScn baseline period (time)
- data.lineScanCSV = {}; % LScn profile (.csv)
- data.postprocessing = {}; % postprocessing info (e.g. downsampling)
- data.artifactRemoval = {}; % artifact removal info
- data.markPointsIdx = {}; % indices for MkPts
- data.markPointsMetadata = {}; % MkPts metadata (.xml)
- data.intrinsicProperties = {}; % intrinsic properties, analyzed from file below
- data.intrinsicPropertiesVRec = {}; % intrinsic properties VRec (.csv)
- data.intrinsicPropertiesVRecMetadata = {}; % metadata for intrinsic properties VRec (.xml)
- data.intrinsicPropertiesFileName = {}; % file path and name for intrinsic properties
- data.zStack = {}; % z-stack
- data.zStackFileName = {}; % file path and name for z-stack
- data.singleScan = {}; % single-scan image
- data.singleScanFileName = {}; % file path and name for single-scan
- data.sweepIdx = {}; % sweep indices
- data.sweepStr = {}; % sweep strings for display
- data.groupIdx = {}; % sweep grouping indices
- data.groupStr = {}; % sweep grouping indices in string format for display
- data.notes = {}; % notes
- exp.data = data; % meta-struct for VRec data
- % analysis results
- results = {};
- % more analysis results - another unplanned mess "resulting" in more of really stupid naming and structuring
- analysis = struct();
- % UI elements
- % experiment list
- ui.experimentTitle = uicontrol('Style', 'text', 'string', 'Experiments', 'fontweight', 'bold', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.015, 0.955, 0.09, 0.02]);
- 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');
- 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');
- 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');
- 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');
- 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');
- 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
- 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
- ui.cellList = {}; % experiment list items - in hindsight, this was very poorly named
- ui.cellListUp = uicontrol('Style', 'pushbutton', 'String', '^', 'Units', 'normalized', 'Position', [0.015, 0.51, 0.02, 0.03], 'Callback', @cellListUp, 'interruptible', 'off');
- ui.cellListDown = uicontrol('Style', 'pushbutton', 'String', 'v', 'Units', 'normalized', 'Position', [0.0345, 0.51, 0.02, 0.03], 'Callback', @cellListDown, 'interruptible', 'off');
- ui.cellListMerge = uicontrol('Style', 'pushbutton', 'String', 'Merge', 'Units', 'normalized', 'Position', [0.0555, 0.51, 0.025, 0.03], 'Callback', @cellListMerge, 'interruptible', 'off');
- ui.cellListDuplicate = uicontrol('Style', 'pushbutton', 'String', 'Duplicate', 'Units', 'normalized', 'Position', [0.08, 0.51, 0.035, 0.03], 'Callback', @cellListDuplicate, 'interruptible', 'off');
- ui.cellListDel = uicontrol('Style', 'pushbutton', 'String', 'X', 'Units', 'normalized', 'Position', [0.1155, 0.51, 0.02, 0.03], 'Callback', @cellListDel, 'interruptible', 'off');
- % main trace display window
- ui.traceDisplayTitle = uicontrol('Style', 'text', 'string', 'Traces', 'fontweight', 'bold', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.15, 0.955, 0.04, 0.02]);
- ui.traceDisplay = axes('Units', 'Normalized', 'Position', [0.19, 0.42, 0.57, 0.53], 'xminortick', 'on', 'yminortick', 'on', 'box', 'on');
- 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');
- ui.traceDisplayXZoomIn = uicontrol('Style', 'pushbutton', 'String', '+', 'fontweight', 'bold', 'Units', 'normalized', 'Position', [0.5245, 0.361, 0.015, 0.03], 'Callback', @traceDisplayXZoomIn, 'interruptible', 'off');
- ui.traceDisplayXZoomOut = uicontrol('Style', 'pushbutton', 'String', '-', 'fontweight', 'bold', 'Units', 'normalized', 'Position', [0.4115, 0.361, 0.015, 0.03], 'Callback', @traceDisplayXZoomOut, 'interruptible', 'off');
- ui.traceDisplayXMoveRight = uicontrol('Style', 'pushbutton', 'String', '>', 'fontweight', 'bold', 'Units', 'normalized', 'Position', [0.695, 0.361, 0.015, 0.03], 'Callback', @traceDisplayXMoveRight, 'interruptible', 'off');
- ui.traceDisplayXMoveLeft = uicontrol('Style', 'pushbutton', 'String', '<', 'fontweight', 'bold', 'Units', 'normalized', 'Position', [0.241, 0.361, 0.015, 0.03], 'Callback', @traceDisplayXMoveLeft, 'interruptible', 'off');
- ui.traceDisplayXMoveToStart = uicontrol('Style', 'pushbutton', 'String', '<<', 'fontweight', 'bold', 'Units', 'normalized', 'Position', [0.212, 0.361, 0.015, 0.03], 'Callback', @traceDisplayXMoveToStart, 'interruptible', 'off');
- ui.traceDisplayXMoveToEnd = uicontrol('Style', 'pushbutton', 'String', '>>', 'fontweight', 'bold', 'Units', 'normalized', 'Position', [0.724, 0.361, 0.015, 0.03], 'Callback', @traceDisplayXMoveToEnd, 'interruptible', 'off');
- ui.traceDisplayYZoomIn = uicontrol('Style', 'pushbutton', 'String', '+', 'fontweight', 'bold', 'Units', 'normalized', 'Position', [0.15, 0.76, 0.015, 0.03], 'Callback', @traceDisplayYZoomIn, 'interruptible', 'off');
- ui.traceDisplayYZoomOut = uicontrol('Style', 'pushbutton', 'String', '-', 'fontweight', 'bold', 'Units', 'normalized', 'Position', [0.15, 0.58, 0.015, 0.03], 'Callback', @traceDisplayYZoomOut, 'interruptible', 'off');
- ui.traceDisplayYMoveUp = uicontrol('Style', 'pushbutton', 'String', '^', 'fontweight', 'bold', 'Units', 'normalized', 'Position', [0.15, 0.89, 0.015, 0.03], 'Callback', @traceDisplayYMoveUp, 'interruptible', 'off');
- ui.traceDisplayYMoveDown = uicontrol('Style', 'pushbutton', 'String', 'v', 'fontweight', 'bold', 'Units', 'normalized', 'Position', [0.15, 0.45, 0.015, 0.03], 'Callback', @traceDisplayYMoveDown, 'interruptible', 'off');
- 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');
- 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');
- 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');
- 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');
- ui.traceDisplayReset = uicontrol('Style', 'pushbutton', 'String', 'O', 'fontweight', 'bold', 'Units', 'normalized', 'Position', [0.15, 0.361, 0.015, 0.03], 'Callback', @traceDisplayReset, 'interruptible', 'off');
- 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');
- ui.traceDisplayYRange = params.yRange; % set to default Y range
- ui.traceDisplayY2Range = params.y2Range; % set to default Y range
- ui.traceDisplayXRange = params.xRange; % set to default X range
- ui.trace = {}; % traces, saved for sweep indexing
- ui.trace2 = {}; % traces (2), saved for sweep indexing
- % sweep and group list
- ui.sweepListTitle = uicontrol('Style', 'text', 'string', 'Sweeps ', 'fontweight', 'bold', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.815, 0.955, 0.045, 0.02]);
- 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');
- ui.sweepList = {}; % sweep list items
- ui.groupListTitle = uicontrol('Style', 'text', 'string', 'Groups ', 'fontweight', 'bold', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.86, 0.955, 0.09, 0.02]);
- 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');
- ui.groupList = {}; % group list items
- %ui.sweepSelectGroupText = uicontrol('Style', 'text', 'string', '(Sweeps)', 'fontweight', 'bold', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.936, 0.93, 0.045, 0.02]);
- ui.sweepSelectText = uicontrol('Style', 'text', 'string', 'Select Swps: ', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.936, 0.93, 0.09, 0.02]);
- ui.sweepSelectMod = uicontrol('Style', 'pushbutton', 'string', 'Interval:', 'Units', 'normalized', 'Position', [0.936, 0.9, 0.032, 0.03], 'Callback', @sweepSelectMod, 'interruptible', 'off');
- 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');
- ui.sweepSelectOdd = uicontrol('Style', 'pushbutton', 'string', 'Odd', 'Units', 'normalized', 'Position', [0.936, 0.87, 0.0165, 0.03], 'Callback', @sweepSelectOdd, 'interruptible', 'off');
- ui.sweepSelectEven = uicontrol('Style', 'pushbutton', 'string', 'Evn', 'Units', 'normalized', 'Position', [0.952, 0.87, 0.0165, 0.03], 'Callback', @sweepSelectEven, 'interruptible', 'off');
- ui.sweepSelectInvert = uicontrol('Style', 'pushbutton', 'string', 'Inv', 'Units', 'normalized', 'Position', [0.968, 0.87, 0.0165, 0.03], 'Callback', @sweepSelectInvert, 'interruptible', 'off');
- ui.sweepGroupText = uicontrol('Style', 'text', 'string', 'Grp. by: ', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.936, 0.71, 0.045, 0.02]);
- ui.groupSelected = uicontrol('Style', 'pushbutton', 'String', 'Sel.', 'Units', 'normalized', 'Position', [0.96, 0.71, 0.024, 0.03], 'Callback', @groupSelected, 'interruptible', 'off');
- ui.groupSelectedMod = uicontrol('Style', 'pushbutton', 'string', 'Swps', 'Units', 'normalized', 'Position', [0.96, 0.68, 0.024, 0.03], 'Callback', @groupSelectedMod, 'interruptible', 'off');
- 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');
- %{
- ui.groupAuto1 = uicontrol('Style', 'pushbutton', 'String', 'VOut', 'Units', 'normalized', 'Position', [0.936, 0.65, 0.024, 0.03], 'Callback', @groupAutoVOut, 'interruptible', 'off');
- ui.groupAuto2 = uicontrol('Style', 'pushbutton', 'String', 'MkPts', 'Units', 'normalized', 'Position', [0.96, 0.65, 0.024, 0.03], 'Callback', @groupAutoMkPts, 'interruptible', 'off');
- %}
- ui.sweepProcessText = uicontrol('Style', 'text', 'string', 'Selected Swps: ', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.936, 0.84, 0.09, 0.02]);
- ui.sweepSegment = uicontrol('Style', 'pushbutton', 'String', 'Segm.', 'Units', 'normalized', 'Position', [0.936, 0.81, 0.024, 0.03], 'Callback', @sweepsSegmentation, 'interruptible', 'off');
- ui.sweepTrucante = uicontrol('Style', 'pushbutton', 'String', 'Trunc.', 'Units', 'normalized', 'Position', [0.96, 0.81, 0.024, 0.03], 'Callback', @sweepsTruncate, 'interruptible', 'off');
- ui.sweepAverage = uicontrol('Style', 'pushbutton', 'String', 'Avg.', 'Units', 'normalized', 'Position', [0.936, 0.78, 0.024, 0.03], 'Callback', @sweepsAverage, 'interruptible', 'off');
- %ui.sweepArithmetic = uicontrol('Style', 'pushbutton', 'String', '+ / -', 'Units', 'normalized', 'Position', [0.96, 0.78, 0.024, 0.03], 'Callback', @sweepsArithmetic, 'interruptible', 'off');
- ui.sweepAdd = uicontrol('Style', 'pushbutton', 'String', '+', 'Units', 'normalized', 'Position', [0.96, 0.78, 0.012, 0.03], 'Callback', @sweepsAdd, 'interruptible', 'off');
- ui.sweepSubtract = uicontrol('Style', 'pushbutton', 'String', '-', 'Units', 'normalized', 'Position', [0.972, 0.78, 0.012, 0.03], 'Callback', @sweepsSubtract, 'interruptible', 'off');
- ui.sweepConcatenate = uicontrol('Style', 'pushbutton', 'String', 'Concat.', 'Units', 'normalized', 'Position', [0.936, 0.75, 0.024, 0.03], 'Callback', @sweepsConcatenate, 'interruptible', 'off');
- ui.sweepDel = uicontrol('Style', 'pushbutton', 'String', 'X', 'Units', 'normalized', 'Position', [0.96, 0.75, 0.024, 0.03], 'Callback', @sweepsDelete, 'interruptible', 'off');
- %ui.groupText = uicontrol('Style', 'text', 'String', '(Groups)', 'fontweight', 'bold', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.936, 0.68, 0.03, 0.02], 'interruptible', 'off');
- ui.groupText = uicontrol('Style', 'text', 'String', 'Selected Grps:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.936, 0.65, 0.09, 0.02], 'interruptible', 'off');
- ui.groupListUp = uicontrol('Style', 'pushbutton', 'String', '^', 'Units', 'normalized', 'Position', [0.936, 0.62, 0.0165, 0.03], 'Callback', @groupListUp, 'interruptible', 'off');
- ui.groupListDown = uicontrol('Style', 'pushbutton', 'String', 'v', 'Units', 'normalized', 'Position', [0.936, 0.59, 0.0165, 0.03], 'Callback', @groupListDown, 'interruptible', 'off');
- ui.groupListInvert = uicontrol('Style', 'pushbutton', 'String', 'Inv', 'Units', 'normalized', 'Position', [0.968, 0.62, 0.0165, 0.03], 'Callback', @groupListInvert, 'interruptible', 'off');
- ui.groupListReverse = uicontrol('Style', 'pushbutton', 'String', 'Rev', 'Units', 'normalized', 'Position', [0.952, 0.62, 0.0165, 0.03], 'Callback', @groupListReverse, 'interruptible', 'off');
- ui.groupListMerge = uicontrol('Style', 'pushbutton', 'String', 'Mrg', 'Units', 'normalized', 'Position', [0.952, 0.59, 0.0165, 0.03], 'Callback', @groupListMerge, 'interruptible', 'off');
- ui.groupListDel = uicontrol('Style', 'pushbutton', 'String', 'X', 'Units', 'normalized', 'Position', [0.968, 0.59, 0.0165, 0.03], 'Callback', @groupListDel, 'interruptible', 'off');
- ui.groupSweepText = uicontrol('Style', 'text', 'string', 'Sweep #', 'horizontalalignment', 'center', 'Units', 'normalized', 'Position', [0.871, 0.592, 0.05, 0.02]);
- ui.groupSweepPrev = uicontrol('Style', 'pushbutton', 'String', '<', 'Units', 'normalized', 'Position', [0.86, 0.59, 0.015, 0.03], 'Callback', @groupSweepPrev, 'interruptible', 'off');
- ui.groupSweepNext = uicontrol('Style', 'pushbutton', 'String', '>', 'Units', 'normalized', 'Position', [0.917, 0.59, 0.015, 0.03], 'Callback', @groupSweepNext, 'interruptible', 'off');
- % analysis window
- ui.analysisTitle = uicontrol('Style', 'text', 'string', 'Analysis', 'fontweight', 'bold', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.815, 0.56, 0.09, 0.02]);
- ui.analysisBaselineText = uicontrol('Style', 'text', 'string', 'Bsln: ', 'foregroundcolor', params.analysisBaselineColor, 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.816, 0.532, 0.045, 0.02]);
- ui.analysisBaselineText2 = uicontrol('Style', 'text', 'string', '-', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.856, 0.532, 0.02, 0.02]);
- ui.analysisBaselineText3 = uicontrol('Style', 'text', 'string', '(ms)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.88, 0.532, 0.045, 0.02]);
- 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');
- 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');
- 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');
- ui.analysisWindow1Text = uicontrol('Style', 'text', 'string', 'Win 1: ', 'foregroundcolor', params.analysisWindow1Color, 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.816, 0.502, 0.045, 0.02]);
- ui.analysisWindow1Text2 = uicontrol('Style', 'text', 'string', '-', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.856, 0.502, 0.02, 0.02]);
- ui.analysisWindow1Text3 = uicontrol('Style', 'text', 'string', '(ms)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.88, 0.502, 0.045, 0.02]);
- 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');
- 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');
- ui.analysisWindow2Text = uicontrol('Style', 'text', 'string', 'Win 2: ', 'foregroundcolor', params.analysisWindow2Color, 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.816, 0.472, 0.045, 0.02]);
- ui.analysisWindow2Text2 = uicontrol('Style', 'text', 'string', '-', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.856, 0.472, 0.02, 0.02]);
- ui.analysisWindow2Text3 = uicontrol('Style', 'text', 'string', '(ms)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.88, 0.472, 0.045, 0.02]);
- 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');
- 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');
- ui.analysisWindowHandle = cell(1, 6); % handle for displaying analysis windows - somehow it is overly complicated to make this work
- % analysis parameters
- 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');
- 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
- %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');
- 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');
- 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');
- 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]);
- 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');
- 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');
- % analysis results
- ui.analysisResultsTitle = uicontrol('Style', 'text', 'string', 'Results', 'fontweight', 'bold', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.815, 0.39, 0.09, 0.02]);
- ui.analysisPlot1 = axes('Units', 'Normalized', 'Position', [0.835, 0.255, 0.135, 0.13], 'xminortick', 'on', 'yminortick', 'on');
- ui.analysisPlot2 = axes('Units', 'Normalized', 'Position', [0.835, 0.05, 0.135, 0.13], 'xminortick', 'on', 'yminortick', 'on');
- 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');
- 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');
- 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');
- 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');
- 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');
- 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');
- 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');
- 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');
- ui.analysisPlot1MoveUp = uicontrol('Style', 'pushbutton', 'String', '^', 'Units', 'normalized', 'Position', [0.972, 0.36, 0.0125, 0.024], 'Callback', @resultsPlot1YMoveUp, 'interruptible', 'off');
- ui.analysisPlot1MoveDown = uicontrol('Style', 'pushbutton', 'String', 'v', 'Units', 'normalized', 'Position', [0.972, 0.255, 0.0125, 0.024], 'Callback', @resultsPlot1YMoveDown, 'interruptible', 'off');
- ui.analysisPlot1ZoomIn = uicontrol('Style', 'pushbutton', 'String', '+', 'Units', 'normalized', 'Position', [0.972, 0.335, 0.0125, 0.024], 'Callback', @resultsPlot1YZoomIn, 'interruptible', 'off');
- ui.analysisPlot1ZoomOut = uicontrol('Style', 'pushbutton', 'String', '-', 'Units', 'normalized', 'Position', [0.972, 0.28, 0.0125, 0.024], 'Callback', @resultsPlot1YZoomOut, 'interruptible', 'off');
- ui.analysisPlot1ZoomReset = uicontrol('Style', 'pushbutton', 'String', 'O', 'Units', 'normalized', 'Position', [0.972, 0.3075, 0.0125, 0.024], 'Callback', @resultsPlot1YReset, 'interruptible', 'off');
- ui.analysisPlot2MoveUp = uicontrol('Style', 'pushbutton', 'String', '^', 'Units', 'normalized', 'Position', [0.972, 0.155, 0.0125, 0.024], 'Callback', @resultsPlot2YMoveUp, 'interruptible', 'off');
- ui.analysisPlot2MoveDown = uicontrol('Style', 'pushbutton', 'String', 'v', 'Units', 'normalized', 'Position', [0.972, 0.05, 0.0125, 0.024], 'Callback', @resultsPlot2YMoveDown, 'interruptible', 'off');
- ui.analysisPlot2ZoomIn = uicontrol('Style', 'pushbutton', 'String', '+', 'Units', 'normalized', 'Position', [0.972, 0.13, 0.0125, 0.024], 'Callback', @resultsPlot2YZoomIn, 'interruptible', 'off');
- ui.analysisPlot2ZoomOut = uicontrol('Style', 'pushbutton', 'String', '-', 'Units', 'normalized', 'Position', [0.972, 0.075, 0.0125, 0.024], 'Callback', @resultsPlot2YZoomOut, 'interruptible', 'off');
- ui.analysisPlot2ZoomReset = uicontrol('Style', 'pushbutton', 'String', 'O', 'Units', 'normalized', 'Position', [0.972, 0.1025, 0.0125, 0.024], 'Callback', @resultsPlot2YReset, 'interruptible', 'off');
- % cell info
- ui.cellInfoTitle = uicontrol('Style', 'text', 'string', 'Cell Info', 'fontweight', 'bold', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.015, 0.48, 0.09, 0.02]);
- 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');
- 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');
- 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');
- 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');
- % notes
- ui.notesTitle = uicontrol('Style', 'text', 'string', 'Notes', 'fontweight', 'bold', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.015, 0.39, 0.09, 0.02]);
- 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);
- % trace processing
- ui.traceProcessingTitle = uicontrol('Style', 'text', 'string', 'Postprocessing', 'fontweight', 'bold', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.015, 0.30, 0.09, 0.02]);
- ui.traceProcessingTargetText = uicontrol('Style', 'text', 'string', 'Target Signal: ', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.02, 0.274, 0.09, 0.02]);
- 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');
- 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');
- 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');
- ui.downsamplingText = uicontrol('Style', 'text', 'string', 'x', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.096, 0.242, 0.02, 0.02]);
- 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');
- 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');
- ui.lowPassFilterText = uicontrol('Style', 'text', 'string', '(kHz)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.096, 0.212, 0.02, 0.02]);
- 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');
- 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');
- ui.stimArtifactText = uicontrol('Style', 'text', 'string', '(ms)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.096, 0.182, 0.03, 0.02]);
- ui.stimArtifactText2 = uicontrol('Style', 'text', 'string', 'from', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.025, 0.152, 0.02, 0.02]);
- 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');
- ui.stimArtifactText3 = uicontrol('Style', 'text', 'string', '(ms)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.056, 0.152, 0.02, 0.02]);
- ui.stimArtifactText4 = uicontrol('Style', 'text', 'string', 'x', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.073, 0.152, 0.01, 0.02]);
- 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');
- ui.stimArtifactText5 = uicontrol('Style', 'text', 'string', 'at', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.096, 0.152, 0.03, 0.02]);
- 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');
- ui.stimArtifactText6 = uicontrol('Style', 'text', 'string', '(Hz)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.121, 0.152, 0.02, 0.02]);
- % export
- ui.exportDisplayTitle = uicontrol('Style', 'text', 'string', 'Export', 'fontweight', 'bold', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.015, 0.12, 0.09, 0.02]);
- ui.exportTargetText = uicontrol('Style', 'text', 'string', 'Source (Plot / Axis): ', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.02, 0.09, 0.09, 0.02]);
- %ui.exportTarget = uicontrol('Style', 'popupmenu', 'string', params.analysisPlotMenuList1, 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.042, 0.09, 0.093, 0.025]);
- 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');
- 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');
- 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');
- 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');
- 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');
- 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');
- % intrinsic properties
- ui.intrinsicTitle = uicontrol('Style', 'text', 'string', 'Intrinsic Membrane Properties: ', 'fontweight', 'bold', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.15, 0.3, 0.12, 0.02]);
- 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');
- ui.intrinsicUseCurrentFile = uicontrol('Style', 'pushbutton', 'String', 'Use ^', 'Units', 'normalized', 'Position', [0.3525, 0.3, 0.02, 0.024], 'Callback', @intrinsicUseCurrent, 'interruptible', 'off');
- ui.intrinsicReanalyze = uicontrol('Style', 'pushbutton', 'String', 'Re-analyze', 'Units', 'normalized', 'Position', [0.3725, 0.3, 0.04, 0.024], 'Callback', @intrinsicReanalyze, 'interruptible', 'off');
- ui.intrinsicDel = uicontrol('Style', 'pushbutton', 'String', 'X', 'Units', 'normalized', 'Position', [0.412, 0.3, 0.012, 0.024], 'Callback', @intrinsicDel, 'interruptible', 'off');
- ui.intrinsicPlot1 = axes('Units', 'Normalized', 'Position', [0.19, 0.05, 0.11, 0.23], 'xminortick', 'on', 'yminortick', 'on', 'box', 'on');
- ui.intrinsicPlot2 = axes('Units', 'Normalized', 'Position', [0.325, 0.19, 0.1, 0.09], 'xminortick', 'on', 'yminortick', 'on');
- ui.intrinsicPlot3 = axes('Units', 'Normalized', 'Position', [0.325, 0.05, 0.1, 0.09], 'xminortick', 'on', 'yminortick', 'on');
- ui.intrinsicPlot1Enlarge = uicontrol('Style', 'pushbutton', 'String', '+', 'Units', 'normalized', 'Position', [0.288, 0.254, 0.012, 0.024], 'Callback', @intrinsicPlot1Enlarge, 'interruptible', 'off');
- ui.intrinsicPlot2Enlarge = uicontrol('Style', 'pushbutton', 'String', '+', 'Units', 'normalized', 'Position', [0.413, 0.254, 0.012, 0.024], 'Callback', @intrinsicPlot2Enlarge, 'interruptible', 'off');
- ui.intrinsicPlot3Enlarge = uicontrol('Style', 'pushbutton', 'String', '+', 'Units', 'normalized', 'Position', [0.413, 0.114, 0.012, 0.024], 'Callback', @intrinsicPlot3Enlarge, 'interruptible', 'off');
- ui.intrinsicRMP = uicontrol('Style', 'text', 'string', '', 'backgroundcolor', 'w', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.2425, 0.235, 0.055, 0.02]);
- ui.intrinsicRin = uicontrol('Style', 'text', 'string', '', 'backgroundcolor', 'w', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.2425, 0.215, 0.055, 0.02]);
- ui.intrinsicSag = uicontrol('Style', 'text', 'string', '', 'backgroundcolor', 'w', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.2425, 0.195, 0.055, 0.02]);
- % z-stack and single-scan images
- ui.zStackTitle = uicontrol('Style', 'text', 'string', 'Z-Stack: ', 'fontweight', 'bold', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.445, 0.3, 0.08, 0.02]);
- 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');
- ui.zStackDel = uicontrol('Style', 'pushbutton', 'String', 'X', 'Units', 'normalized', 'Position', [0.562, 0.3, 0.012, 0.024], 'Callback', @zStackDel, 'interruptible', 'off');
- ui.zStackEnlarge = uicontrol('Style', 'pushbutton', 'String', '+', 'Units', 'normalized', 'Position', [0.562, 0.2725, 0.012, 0.024], 'Callback', @zStackEnlarge, 'interruptible', 'off');
- 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]);
- ui.singleScanTitle = uicontrol('Style', 'text', 'string', 'Single-Scan: ', 'fontweight', 'bold', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.58, 0.3, 0.08, 0.02]);
- 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');
- ui.singleScanDel = uicontrol('Style', 'pushbutton', 'String', 'X', 'Units', 'normalized', 'Position', [0.697, 0.3, 0.012, 0.024], 'Callback', @singleScanDel, 'interruptible', 'off');
- ui.singleScanEnlarge = uicontrol('Style', 'pushbutton', 'String', '+', 'Units', 'normalized', 'Position', [0.697, 0.2725, 0.012, 0.024], 'Callback', @singleScanEnlarge, 'interruptible', 'off');
- 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]);
- % linescan
- ui.lineScanDisplayTitle = uicontrol('Style', 'text', 'string', 'Linescans: ', 'fontweight', 'bold', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.72, 0.3, 0.08, 0.02]);
- 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');
- ui.lineScan1Title = uicontrol('Style', 'text', 'string', 'Ch. 1', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.72, 0.27, 0.04, 0.02]);
- ui.lineScan2Title = uicontrol('Style', 'text', 'string', 'Ch. 2', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.761, 0.27, 0.04, 0.02]);
- 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]);
- 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]);
- % initialize display areas
- %{
- set(ui.traceDisplay, 'xtick', [], 'ytick', [], 'xlabel', [], 'ylabel', []);
- set(ui.analysisPlot1, 'xtick', [], 'ytick', [], 'xlabel', [], 'ylabel', []);
- set(ui.analysisPlot2, 'xtick', [], 'ytick', [], 'xlabel', [], 'ylabel', []);
- set(get(ui.traceDisplay, 'xlabel'), 'string', 't (ms)');
- set(get(ui.traceDisplay, 'ylabel'), 'string', 'V_m (mV)');
- %}
- axes(ui.intrinsicPlot1);
- xlabel('t (ms)');
- ylabel('V_m (mV)');
- xticks(''); yticks('');
- axes(ui.intrinsicPlot2);
- xlabel('i (pA)');
- ylabel('dV (mV)');
- xticks(''); yticks('');
- axes(ui.intrinsicPlot3);
- xlabel('i (pA)');
- ylabel('f (Hz)');
- xticks(''); yticks('');
- axes(ui.analysisPlot1);
- %xlabel('Sweep #');
- %xticks(''); %yticks('');
- axes(ui.analysisPlot2);
- %xlabel('Sweep #');
- %xticks(''); %yticks('');
- axes(ui.traceDisplay); % move focus to main display panel
- set(gca, 'layer', 'top');
- xlabel('t (ms)');
- %{
- yyaxis left; ylabel('V_m (mV)', 'color', 'k'); ylim(params.yRange); set(gca, 'ycolor', 'k', 'yminortick', 'on');
- yyaxis right; ylabel('dF/F', 'color', 'g'); ylim(params.y2Range); set(gca, 'ycolor', [0, 0.5, 0], 'yminortick', 'on');
- %}
- xlabel(' ', 'color', 'k'); xlim([-1, 0]);
- yyaxis left; ylabel(' ', 'color', 'k'); ylim([-10000, 10000]); set(gca, 'ycolor', 'k');
- yyaxis right; ylabel(' ', 'color', 'g'); ylim([-10000, 10000]); set(gca, 'ycolor', [0, 0.5, 0]);
- yyaxis left; % move focus back to left y axis to be safe
- % save
- h.exp = exp;
- h.results = results;
- h.analysis = analysis;
- h.params = params;
- h.ui = ui;
- guidata(win, h);
- % load default parameters - moved up
- %defaultParams = setDefaultParams(win); % this has to be done after guidata(win, h)
- %h.params.defaultParams = defaultParams;
- end
- %% Default Parameters
- function defaultParams = setDefaultParams(win);
- % load
- h = guidata(win);
- % gain settings
- % below are set for MC700B with Rf = 500 MO and usual gain settings for whole-cell recordings, in combination with PV
- % reminder: these are dependent on both acquisition hardware and software settings; make sure they are correct!
- pvbsVoltageScalingFactor = 100; % (mV/V); % 100 for P-IV (MIT MIBR 46-6178) and Rigs 1 & 2 (46-6190)
- pvbsCurrentScalingFactor = 2000; % (pA/V); % 2000 for P-IV (MIT MIBR 46-6178), or 10000 for Rigs 1 & 2 (46-6190) - 2022-07-19 JY
- % PV software conventions
- % below are set for single channel recording of V and i (in that order)
- % multiple-channel support pending %%% fixlater
- timeColumn = 1; % column 1: timestamp
- timeColumnAvailable = 1; % flag for timestamp availability
- pvbsVoltageColumn = 2; % column 2: voltage
- pvbsCurrentColumn = 3; % column 3: current
- csvOffsetRow = 1; % row 1: title
- csvOffsetColumn = 0; % no column offset
- 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)
- % voltage/current data
- analysisColumn = pvbsVoltageColumn; % column for analysis; NB. column 1 will usually be timestamp in the current code
- peakDirection1 = 0; % window 1 default peak direction (-1, 0, 1 : negative, absolute, positive)
- peakDirection2 = 0; % window 2 default peak direction (-1, 0, 1 : negative, absolute, positive)
- useMedian = 1; % use median instead of mean for baseline, "mean" (in peak analysis), etc., to be robust from noise
- riseDecay = [20, 80]; % low/high point for kinetics analysis (e.g. [20, 80] for 20-80 %)
- % fluorescence data
- lineScanChannel = 2; % primary channel for calcium imaging signal; e.g. for P4, 1: red, 2: green (primary)
- lineScanBaseline = [23, 40]; % (ms), baseline for F_0 in linescans, avoid starting from 0 to prevent possible contamination from shutter artifact
- lineScanROIDetectDuringBaseline = 1; % detect linescan ROI only during baseline window specified above (0: no, 1: yes), in order to prevent possible errors from uncaging artifact
- lineScanDownsamplingFactor = 1; % downsampling factor for fluorescence signals, for the dF/F to be robust to noise
- % NB. for best performance in ROI detection, use minimal (or zero) smoothing,
- % high threshold for ROI, and low (in terms of absolute value) threshold for background;
- % +/- 1 pixel, top 2% (roi), bottom 50% (background) seems best (2022-02-03)
- 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
- %lineScanROIThreshold = 2.32635; % (s.d.); z-score for 1st percentile
- lineScanROIThreshold = 2.05375; % (s.d.); z-score for 2nd percentile
- %lineScanROIThreshold = 1.64485; % (s.d.); z-score for 5th percentile
- %lineScanROIThreshold = 1.28125; % (s.d.); z-score for 10th percentile
- %lineScanROIThreshold = 0.67449; % (s.d.); z-score for 1st quartile
- %lineScanROIThreshold = 0.43991; % (s.d.); z-score for 33rd percentile
- lineScanBackgroundThreshold = -0; % (s.d.); z-score for 2nd quartile
- %lineScanBackgroundThreshold = -0.43991; % (s.d.); z-score for 67th percentile
- %lineScanBackgroundThreshold = -0.67449; % (s.d.); z-score for 3rd quartile
- %lineScanBackgroundThreshold = -1.28125; % (s.d.); z-score for 90th percentile
- %lineScanBackgroundThreshold = -2.05375; % (s.d.); z-score for 98th percentile
- lineScanColorMapRange = 0.8; % saturate displayed intensity for signals above this percentage of maximum
- offloadMarkPointsMetadata = 0; % delete markpoints metadata after retrieving point indices to save space (0: no, 1: yes)
- % signals to display
- signal1Type = 2; % current, voltage, fluorescence
- signal2Type = 3; % current, voltage, fluorescence
- signal1Channel = pvbsVoltageColumn; % corresponding to data column, but mind timestamp availability
- signal2Channel = lineScanChannel; % corresponding to data column, but mind timestamp availability
- % PV hardware error correction
- % Prairie (now Bruker) GPIO box (DAC) can quite unbelievably have bleedthrough across channels,
- % which has to be corrected if present; otherwise, it could lead to introducing
- % "phantom" DC offset error in data...
- % - DO NOT use if recordings DO have intentional baseline DC injection at the beginning!
- % - DO NOT confuse this with having an incorrect bias setting on the amplifier!
- % (e.g. RV2 for MC700B, or i_G for BVC700A)
- pvbsCurrentCorrectionFlag = 0; % set to 1 to correct, 0 to leave as is
- pvbsCurrentCorrectionDataPoints = 50; % this many points at the beginning will be used for baseline correction
- % data downsampling
- boxcarLength1 = 0; % boxcar length for Ch. 1 (e.g. V); 0 to disable by default
- %boxcarLength2 = 4; % boxcar length for Ch. 2 (e.g. dF/F); 0 to disable by default
- boxcarLength2 = 0; % boxcar length for Ch. 2 (e.g. dF/F); 0 to disable by default
- besselFreq1 = 0; % (kHz); Bessel filter cutoff frequency for Ch. 1; 0 to disable by default
- %besselFreq2 = 1; % (kHz); Bessel filter cutoff frequency for Ch. 2; 0 to disable by default
- besselFreq2 = 0; % (kHz); Bessel filter cutoff frequency for Ch. 2; 0 to disable by default
- besselOrder1 = 4; % reverse Bessel polynomial order for Ch. 1
- besselOrder2 = 4; % reverse Bessel polynomial order for Ch. 2
- % artifact removal
- artifactLength = 2; % (ms)
- artifactStart = 50; % (ms)
- artifactCount = 1;
- artifactFreq = 10; % (Hz)
- % sweep segmentation
- % for convenience with single spines - none of which should be necessary were PV not gap-free all the time
- segmentationLength = 200; % segment length (ms)
- segmentationOffset = 150; % segmentation initial offset (ms)
- % below was for convenience with 3 groups of spines
- %{
- segmentationLength = 400; % segment length (ms)
- segmentationOffset = 350; % segmentation initial offset (ms)
- %}
- segmentationTruncate = 1; % truncate remainder (0: no, 1: yes)
- segmentationCount = 0; % keep only this many segments and discard the rest (0 to disable)
- % analysis - intrinsic properties (to be reverse compatible with ancient code)
- % data format
- intrinsicPropertiesAnalysis = struct();
- intrinsicPropertiesAnalysisInput = [pvbsVoltageScalingFactor, pvbsCurrentScalingFactor, pvbsCurrentCorrectionFlag];
- intrinsicPropertiesAnalysis = setDefaultParamsIntrinsic(intrinsicPropertiesAnalysis, intrinsicPropertiesAnalysisInput);
- % event detection and waveform analysis
- eventAnalysis = struct();
- eventAnalysis.detectionThreshold = 0; % event detection threshold (e.g. 0 mV; do not confuse with AP threshold definition (e.g. 20 V/s))
- eventAnalysis.detectionRearm = -10; % event detection re-arm point (e.g. -10 mV)
- 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
- eventAnalysis.apThresholdDvdt = 20; % definition of AP threshold (e.g. 20 V/s)
- eventAnalysis.apThresholdInterpolate = 1; % interpolate data points to obtain AP threshold (0: no, 1: yes)
- 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)
- eventAnalysis.restingStateDuration = 100; % (ms); e.g. for RMP calculation
- % uncaging analysis - moved from auto analysis macro (messed up old code)
- uncagingAnalysis = struct();
- uncagingAnalysis.winV = 1; % analysis window for V (NB. do not confuse with signal channel)
- uncagingAnalysis.winF = 2; % analysis window for dF/F (NB. do not confuse with signal channel)
- uncagingAnalysis.pspMax = 35; % max PSP (mV) for threshold detection
- uncagingAnalysis.uncUnitSizeDefault = 1; % default assumption for unit size (in number of spines), only used when markpoints metadata is not available
- % sweep grouping
- autoGroup = 'Automatic'; % somewhat arbitrary but whatever - currently set to MarkPoints for LineScan and VoltageOutput for TSeries, see loadExpMain()
- % default directory
- dirSaveDefault = cd;
- dirLoadDefault = cd;
- % save
- defaultParams.pvbsVoltageScalingFactor = pvbsVoltageScalingFactor;
- defaultParams.pvbsCurrentScalingFactor = pvbsCurrentScalingFactor;
- defaultParams.timeColumn = timeColumn;
- defaultParams.timeColumnAvailable = timeColumnAvailable;
- defaultParams.pvbsVoltageColumn = pvbsVoltageColumn;
- defaultParams.pvbsCurrentColumn = pvbsCurrentColumn;
- defaultParams.csvOffsetRow = csvOffsetRow;
- defaultParams.csvOffsetColumn = csvOffsetColumn;
- defaultParams.csvColumnsAsSweeps = csvColumnsAsSweeps;
- defaultParams.signal1Type = signal1Type;
- defaultParams.signal2Type = signal2Type;
- defaultParams.signal1Channel = signal1Channel;
- defaultParams.signal2Channel = signal2Channel;
- defaultParams.analysisColumn = analysisColumn;
- defaultParams.peakDirection1 = peakDirection1;
- defaultParams.peakDirection2 = peakDirection2;
- defaultParams.useMedian = useMedian;
- defaultParams.riseDecay = riseDecay;
- defaultParams.autoGroup = autoGroup;
- defaultParams.lineScanChannel = lineScanChannel;
- defaultParams.lineScanBaseline = lineScanBaseline;
- defaultParams.lineScanROIDetectDuringBaseline = lineScanROIDetectDuringBaseline;
- defaultParams.lineScanDownsamplingFactor = lineScanDownsamplingFactor;
- defaultParams.lineScanROISmoothing = lineScanROISmoothing;
- defaultParams.lineScanROIThreshold = lineScanROIThreshold;
- defaultParams.lineScanBackgroundThreshold = lineScanBackgroundThreshold;
- defaultParams.lineScanColorMapRange = lineScanColorMapRange;
- defaultParams.offloadMarkPointsMetadata = offloadMarkPointsMetadata;
- defaultParams.pvbsCurrentCorrectionFlag = pvbsCurrentCorrectionFlag;
- defaultParams.pvbsCurrentCorrectionDataPoints = pvbsCurrentCorrectionDataPoints;
- defaultParams.boxcarLength1 = boxcarLength1;
- defaultParams.boxcarLength2 = boxcarLength2;
- defaultParams.besselFreq1 = besselFreq1;
- defaultParams.besselFreq2 = besselFreq2;
- defaultParams.besselOrder1 = besselOrder1;
- defaultParams.besselOrder2 = besselOrder2;
- defaultParams.artifactLength = artifactLength;
- defaultParams.artifactStart = artifactStart;
- defaultParams.artifactCount = artifactCount;
- defaultParams.artifactFreq = artifactFreq;
- defaultParams.segmentationLength = segmentationLength;
- defaultParams.segmentationOffset = segmentationOffset;
- defaultParams.segmentationTruncate = segmentationTruncate;
- defaultParams.segmentationCount = segmentationCount;
- defaultParams.intrinsicPropertiesAnalysis = intrinsicPropertiesAnalysis;
- defaultParams.eventAnalysis = eventAnalysis;
- defaultParams.uncagingAnalysis = uncagingAnalysis;
- %h.params.actualParams = actualParams;
- guidata(win, h);
- end
- function intrinsicPropertiesAnalysis = setDefaultParamsIntrinsic(intrinsicPropertiesAnalysis, intrinsicPropertiesAnalysisInput)
- % separated for access from elsewhere
- % relics
- pvbsVoltageScalingFactor = intrinsicPropertiesAnalysisInput(1);
- pvbsCurrentScalingFactor = intrinsicPropertiesAnalysisInput(2);
- pvbsCurrentCorrectionFlag = intrinsicPropertiesAnalysisInput(3);
- % actual stuff
- intrinsicPropertiesAnalysis.v_rec_gain = pvbsVoltageScalingFactor; % gain for V, defined above
- intrinsicPropertiesAnalysis.i_cmd_gain = pvbsCurrentScalingFactor; % gain for i, defined above
- intrinsicPropertiesAnalysis.voltage_signal_channel = 1; % V_m channel, from PV (NB. defined differently above as .csv comlumn index)
- intrinsicPropertiesAnalysis.data_length_unit = 100; % (ms); truncate data to a nice multiple of this (e.g. 17919 ms -> 17900 ms)
- intrinsicPropertiesAnalysis.data_voltage_samplingrate = 20; % (kHz); sampling rate (e.g. 20 kHz = 20 points/ms)
- intrinsicPropertiesAnalysis.data_voltage_interval = 1/intrinsicPropertiesAnalysis.data_voltage_samplingrate; % (ms); data point interval (e.g. 20 kHz = 20 points/ms)
- intrinsicPropertiesAnalysis.i_bsln_correction = pvbsCurrentCorrectionFlag; % GPIO error correction, defined above
- intrinsicPropertiesAnalysis.i_bsln_correction_window = 10; % GPIO error correction window (ms) (NB. defined differently above as datapoints)
- % long protocol
- %%{
- % segmentation (episodic transformation)
- intrinsicPropertiesAnalysis.data_segmentation_cutoff_first = 0; % (ms); discard this length of data at the beginning
- intrinsicPropertiesAnalysis.data_segment_length = 1000; % Sweep duration (ms), synonymous with inter-sweep interval because of absolutely stupid gap-free PV
- % detection window; for more than 2 windows, manually set them as n*3 arrays (start, end, direction) and pass them onto functions
- intrinsicPropertiesAnalysis.window_baseline_start = 0; % (ms); baseline start - this is not for main analysis window, but for intrinsic properties!
- intrinsicPropertiesAnalysis.window_baseline_end = 100; % (ms); baseline end
- intrinsicPropertiesAnalysis.window_n = 1; % number of detection windows (1 or 2)
- intrinsicPropertiesAnalysis.window_start = 100; % (ms); detection window start
- intrinsicPropertiesAnalysis.window_end = 600; % (ms); detection window end
- intrinsicPropertiesAnalysis.window_direction = 0; % (ms); detection window 1 direction (-1: negative, 0: either, 1: positive; e.g. for peak detection)
- %{
- intrinsicPropertiesAnalysis.window_n = 2; % number of detection windows (1 or 2)
- intrinsicPropertiesAnalysis.window_1_start = 100; % (ms); detection window 1 start
- intrinsicPropertiesAnalysis.window_1_end = 200; % (ms); detection window 1 end
- intrinsicPropertiesAnalysis.window_1_direction = 0; % (ms); detection window 1 direction (-1: negative, 0: either, 1: positive; e.g. for peak detection)
- intrinsicPropertiesAnalysis.window_2_start = 500; % (ms); analysis window 2 start
- intrinsicPropertiesAnalysis.window_2_end = 600; % (ms); analysis window 2 end
- intrinsicPropertiesAnalysis.window_2_direction = 0; % (ms); analysis window 2 direction (-1: negative, 0: either, 1: positive; e.g. for peak detection)
- %}
- % short protocol
- %{
- % segmentation (episodic transformation)
- intrinsicPropertiesAnalysis.data_segmentation_cutoff_first = 0; % (ms); discard this length of data at the beginning
- intrinsicPropertiesAnalysis.data_segment_length = 1000; % Sweep duration (ms), synonymous with inter-sweep interval because of absolutely stupid gap-free PV
- % detection window; for more than 2 windows, manually set them as n*3 arrays (start, end, direction) and pass them onto functions
- intrinsicPropertiesAnalysis.window_baseline_start = 0; % (ms); baseline start - this is not for main analysis window, but for intrinsic properties!
- intrinsicPropertiesAnalysis.window_baseline_end = 250; % (ms); baseline end
- intrinsicPropertiesAnalysis.window_n = 2; % number of detection windows (1 or 2)
- intrinsicPropertiesAnalysis.window_1_start = 250; % (ms); detection window 1 start
- intrinsicPropertiesAnalysis.window_1_end = 350; % (ms); detection window 1 end
- intrinsicPropertiesAnalysis.window_1_direction = 0; % (ms); detection window 1 direction (-1: negative, 0: either, 1: positive; e.g. for peak detection)
- intrinsicPropertiesAnalysis.window_2_start = 400; % (ms); analysis window 2 start
- intrinsicPropertiesAnalysis.window_2_end = 500; % (ms); analysis window 2 end
- intrinsicPropertiesAnalysis.window_2_direction = 0; % (ms); analysis window 2 direction (-1: negative, 0: either, 1: positive; e.g. for peak detection)
- %}
- % display options
- intrinsicPropertiesAnalysis.stepStart = intrinsicPropertiesAnalysis.window_start; % defined above
- intrinsicPropertiesAnalysis.stepEnd = intrinsicPropertiesAnalysis.window_end; % defined above
- intrinsicPropertiesAnalysis.stepLength = intrinsicPropertiesAnalysis.stepEnd - intrinsicPropertiesAnalysis.stepStart;
- intrinsicPropertiesAnalysis.displayMargin = 0.25; % relative to step length
- intrinsicPropertiesAnalysis.displayStart = intrinsicPropertiesAnalysis.stepStart - intrinsicPropertiesAnalysis.displayMargin * intrinsicPropertiesAnalysis.stepLength;
- intrinsicPropertiesAnalysis.displayEnd = intrinsicPropertiesAnalysis.stepEnd + intrinsicPropertiesAnalysis.displayMargin * intrinsicPropertiesAnalysis.stepLength;
- %{
- intrinsicPropertiesAnalysis.stepStart = intrinsicPropertiesAnalysis.window_1_start; % defined above
- intrinsicPropertiesAnalysis.stepEnd = intrinsicPropertiesAnalysis.window_2_end; % defined above
- intrinsicPropertiesAnalysis.stepLength = intrinsicPropertiesAnalysis.stepEnd - intrinsicPropertiesAnalysis.stepStart;
- intrinsicPropertiesAnalysis.displayMargin = 0.25; % relative to step length
- intrinsicPropertiesAnalysis.displayStart = intrinsicPropertiesAnalysis.stepStart - intrinsicPropertiesAnalysis.displayMargin * intrinsicPropertiesAnalysis.stepLength;
- intrinsicPropertiesAnalysis.displayEnd = intrinsicPropertiesAnalysis.stepEnd + intrinsicPropertiesAnalysis.displayMargin * intrinsicPropertiesAnalysis.stepLength;
- %}
- % R_in calculation
- intrinsicPropertiesAnalysis.iStepSize = 20; % (pA); default i_cmd step size to override where i_cmd data is unavailable
- intrinsicPropertiesAnalysis.iStepFirst = -200; % (pA); default i_cmd first step to override where i_cmd data is unavailable
- intrinsicPropertiesAnalysis.iStepLast = 2000; % (pA); default i_cmd last step to override where i_cmd data is unavailable
- intrinsicPropertiesAnalysis.iStepOverride = 1; % override i_step definition with values above where i_cmd data is unavailable
- intrinsicPropertiesAnalysis.RinAtSteadyState = 0; % no more of those idiotic practice at 46
- intrinsicPropertiesAnalysis.RinByLinearFit = 1; % don't like this either
- intrinsicPropertiesAnalysis.RinSweep = 1; %
- % Spike threshold
- %intrinsicPropertiesAnalysis.spikeThreshold = 10; % (mV); relatively strict
- intrinsicPropertiesAnalysis.spikeThreshold = 0; % (mV); meh
- %intrinsicPropertiesAnalysis.spikeThreshold = -10; % (mV); relatively loose
- intrinsicPropertiesAnalysis.spikeDetectionRearm = -10; % (mV); very arbitrary
- end
- function defaultSettingsCallback(src, ~)
- % default settings
- % load
- h = guidata(src);
- win1 = src.Parent;
- srcButton = src;
- set(srcButton, 'enable', 'off');
- % load parameters
- analysisParameters = h.params.actualParams;
- analysisParametersDefault = h.params.defaultParams;
- % reverse compatibility
- try
- timeColumnAvailable = analysisParameters.timeColumnAvailable;
- catch ME
- analysisParameters.timeColumn = 1;
- timeColumnAvailable = 1;
- end
- % options
- 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?
- 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]);
- 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]);
- oWin.t111 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'Voltage scaling factor', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.05, 0.88, 0.4, 0.04]);
- 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);
- oWin.t113 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', '(mV/V)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.4, 0.88, 0.1, 0.04]);
- oWin.t121 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'Current scaling factor', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.55, 0.88, 0.4, 0.04]);
- 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);
- oWin.t123 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', '(pA/V)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.9, 0.88, 0.1, 0.04]);
- 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]);
- 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]);
- oWin.t211 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'Row offset:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.05, 0.78, 0.4, 0.04]);
- 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);
- oWin.t213 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', '', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.4, 0.78, 0.1, 0.04]);
- oWin.t221 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'Column offset:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.55, 0.78, 0.4, 0.04]);
- 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);
- oWin.t223 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', '', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.9, 0.78, 0.1, 0.04]);
- 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]);
- 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);
- 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);
- 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]);
- 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);
- oWin.t243 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', '', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.4, 0.68, 0.1, 0.04]);
- 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]);
- 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);
- oWin.t253 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', '', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.9, 0.68, 0.1, 0.04]);
- oWin.t261 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'Columns represent sweeps:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.55, 0.73, 0.4, 0.04]);
- 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);
- oWin.t263 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', '', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.9, 0.73, 0.1, 0.04]);
- 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]);
- oWin.t311 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'dF/F channel:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.05, 0.58, 0.4, 0.04]);
- 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);
- oWin.t313 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', '', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.4, 0.58, 0.1, 0.04]);
- oWin.t321 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'Baseline start:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.05, 0.53, 0.4, 0.04]);
- 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);
- oWin.t323 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', '(ms)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.4, 0.53, 0.1, 0.04]);
- oWin.t331 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'Baseline end:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.55, 0.53, 0.4, 0.04]);
- 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);
- oWin.t333 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', '(ms)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.9, 0.53, 0.1, 0.04]);
- oWin.t341 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'ROI threshold:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.05, 0.48, 0.4, 0.04]);
- 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);
- oWin.t343 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', '(sd)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.4, 0.48, 0.1, 0.04]);
- oWin.t351 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'Background threshold:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.55, 0.48, 0.4, 0.04]);
- 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);
- oWin.t353 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', '(sd)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.9, 0.48, 0.1, 0.04]);
- oWin.t361 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'ROI smoothing:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.05, 0.43, 0.4, 0.04]);
- 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);
- oWin.t363 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', '(points)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.4, 0.43, 0.1, 0.04]);
- 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]);
- 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);
- oWin.t373 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', '', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.9, 0.43, 0.1, 0.04]);
- oWin.t401 = uicontrol('Parent', optionsWin, 'Style', 'text', 'fontweight', 'bold', 'string', 'Postprocessing', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.025, 0.375, 0.9, 0.04]);
- oWin.t411 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'S1 Boxcar order:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.05, 0.33, 0.4, 0.04]);
- 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);
- 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);
- oWin.t421 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'S2 Boxcar order:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.55, 0.33, 0.4, 0.04]);
- 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);
- 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);
- oWin.t431 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'S1 Bessel order:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.05, 0.28, 0.4, 0.04]);
- 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);
- 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);
- oWin.t441 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'S2 Bessel order:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.55, 0.28, 0.4, 0.04]);
- 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);
- 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);
- oWin.t451 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'S1 Bessel frequency:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.05, 0.23, 0.4, 0.04]);
- 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);
- oWin.t453 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', '(kHz)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.4, 0.23, 0.1, 0.04]);
- oWin.t461 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'S2 Bessel frequency:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.55, 0.23, 0.4, 0.04]);
- 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);
- oWin.t463 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', '(kHz)', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.9, 0.23, 0.1, 0.04]);
- 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]);
- oWin.t511 = uicontrol('Parent', optionsWin, 'Style', 'text', 'string', 'Group by metadata:', 'horizontalalignment', 'left', 'Units', 'normalized', 'Position', [0.05, 0.13, 0.4, 0.04]);
- 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);
- 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]);
- 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');
- 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');
- t112 = str2num(oWin.t112.String);
- t122 = str2num(oWin.t122.String);
- t212 = str2num(oWin.t212.String);
- t222 = str2num(oWin.t222.String);
- t232 = str2num(oWin.t232.String);
- t233 = oWin.t233.Value;
- t242 = str2num(oWin.t242.String);
- t252 = str2num(oWin.t252.String);
- t262 = oWin.t262.Value;
- t312 = str2num(oWin.t312.String);
- t322 = str2num(oWin.t322.String);
- t332 = str2num(oWin.t332.String);
- t342 = str2num(oWin.t342.String);
- t352 = str2num(oWin.t352.String);
- t362 = str2num(oWin.t362.String);
- t372 = oWin.t372.Value;
- t412 = str2num(oWin.t412.String);
- t413 = oWin.t413.Value;
- t422 = str2num(oWin.t422.String);
- t423 = oWin.t423.Value;
- t432 = str2num(oWin.t432.String);
- t433 = oWin.t433.Value;
- t442 = str2num(oWin.t442.String);
- t443 = oWin.t443.Value;
- t452 = str2num(oWin.t452.String);
- t462 = str2num(oWin.t462.String);
- %t512 = oWin.t512.String{oWin.t512.Value};
- function winClosed(src, ~)
- set(srcButton, 'enable', 'on');
- %guidata(srcButton, h); % don't save when closed without using the save button
- end
- function updateParams(src, ~)
- t112 = str2num(oWin.t112.String);
- t122 = str2num(oWin.t122.String);
- t212 = str2num(oWin.t212.String);
- t222 = str2num(oWin.t222.String);
- t232 = str2num(oWin.t232.String);
- t233 = oWin.t233.Value;
- t242 = str2num(oWin.t242.String);
- t252 = str2num(oWin.t252.String);
- t262 = oWin.t262.Value;
- if t262
- % overrides now moved within loadCSV()
- %{
- t112 = 1; % default to scaling factor = 1 for V
- t122 = 1; % default to scaling factor = 1 for i
- t212 = 0; % default to no row offset
- t222 = 0; % default to no column offset
- t252 = 0; % default to reading columns as voltage
- oWin.t112.String = num2str(t112);
- oWin.t122.String = num2str(t122);
- oWin.t212.String = num2str(t212);
- oWin.t222.String = num2str(t222);
- oWin.t252.String = num2str(t252);
- %}
- else
- end
- t312 = str2num(oWin.t312.String);
- t322 = str2num(oWin.t322.String);
- t332 = str2num(oWin.t332.String);
- t342 = str2num(oWin.t342.String);
- t352 = str2num(oWin.t352.String);
- t362 = str2num(oWin.t362.String);
- t372 = oWin.t372.Value;
- t412 = str2num(oWin.t412.String);
- t413 = oWin.t413.Value;
- t422 = str2num(oWin.t422.String);
- t423 = oWin.t423.Value;
- t432 = str2num(oWin.t432.String);
- t433 = oWin.t433.Value;
- t442 = str2num(oWin.t442.String);
- t443 = oWin.t443.Value;
- t452 = str2num(oWin.t452.String);
- t462 = str2num(oWin.t462.String);
- %t512 = oWin.t512.String{oWin.t512.Value}; %%% fixlater
- if ~logical(t432)
- t433 = 0;
- oWin.t433.Value = t433;
- end
- if ~logical(t442)
- t443 = 0;
- oWin.t443.Value = t443;
- end
- end
- function resetParams(src, ~)
- analysisParametersIntrinsic = analysisParameters.intrinsicPropertiesAnalysis; % salvage this
- analysisParameters = analysisParametersDefault;
- analysisParameters.intrinsicPropertiesAnalysis = analysisParametersIntrinsic;
- oWin.t112.String = num2str(analysisParameters.pvbsVoltageScalingFactor);
- oWin.t122.String = num2str(analysisParameters.pvbsCurrentScalingFactor);
- oWin.t212.String = num2str(analysisParameters.csvOffsetRow);
- oWin.t222.String = num2str(analysisParameters.csvOffsetColumn);
- oWin.t232.String = num2str(analysisParameters.timeColumn);
- oWin.t233.Value = logical(analysisParameters.timeColumn);
- oWin.t242.String = num2str(analysisParameters.pvbsVoltageColumn);
- oWin.t252.String = num2str(analysisParameters.pvbsCurrentColumn);
- oWin.t262.Value = logical(analysisParameters.csvColumnsAsSweeps);
- oWin.t312.String = num2str(analysisParameters.lineScanChannel);
- oWin.t322.String = num2str(analysisParameters.lineScanBaseline(1));
- oWin.t332.String = num2str(analysisParameters.lineScanBaseline(2));
- oWin.t342.String = num2str(analysisParameters.lineScanROIThreshold);
- oWin.t352.String = num2str(analysisParameters.lineScanBackgroundThreshold);
- oWin.t362.String = num2str(analysisParameters.lineScanROISmoothing);
- oWin.t372.Value = logical(analysisParameters.lineScanROIDetectDuringBaseline);
- oWin.t412.String = num2str(analysisParameters.boxcarLength1);
- oWin.t413.Value = logical(analysisParameters.boxcarLength1);
- oWin.t422.String = num2str(analysisParameters.boxcarLength2);
- oWin.t423.Value = logical(analysisParameters.boxcarLength2);
- oWin.t432.String = num2str(analysisParameters.besselOrder1);
- oWin.t433.Value = logical(analysisParameters.besselFreq1);
- oWin.t442.String = num2str(analysisParameters.besselOrder2);
- oWin.t443.Value = logical(analysisParameters.besselFreq2);
- oWin.t452.String = num2str(analysisParameters.besselFreq1);
- oWin.t462.String = num2str(analysisParameters.besselFreq2);
- %oWin.t512.Value = fixlater; %%% fixlater
- t112 = str2num(oWin.t112.String);
- t122 = str2num(oWin.t122.String);
- t212 = str2num(oWin.t212.String);
- t222 = str2num(oWin.t222.String);
- t232 = str2num(oWin.t232.String);
- t233 = oWin.t233.Value;
- t242 = str2num(oWin.t242.String);
- t252 = str2num(oWin.t252.String);
- t262 = oWin.t262.Value;
- t312 = str2num(oWin.t312.String);
- t322 = str2num(oWin.t322.String);
- t332 = str2num(oWin.t332.String);
- t342 = str2num(oWin.t342.String);
- t352 = str2num(oWin.t352.String);
- t362 = str2num(oWin.t362.String);
- t372 = oWin.t372.Value;
- t412 = str2num(oWin.t412.String);
- t413 = oWin.t413.Value;
- t422 = str2num(oWin.t422.String);
- t423 = oWin.t423.Value;
- t432 = str2num(oWin.t432.String);
- t433 = oWin.t433.Value;
- t442 = str2num(oWin.t442.String);
- t443 = oWin.t443.Value;
- t452 = str2num(oWin.t452.String);
- t462 = str2num(oWin.t462.String);
- %t512 = oWin.t512.String{oWin.t512.Value};
- %guidata(win1, h);
- %close(optionsWin);
- %set(srcButton, 'enable', 'on');
- end
- function saveParams(src, ~)
- analysisParameters.pvbsVoltageScalingFactor = t112;
- analysisParameters.pvbsCurrentScalingFactor = t122;
- analysisParameters.csvOffsetRow = t212;
- analysisParameters.csvOffsetColumn = t222;
- if t233
- analysisParameters.timeColumn = t232;
- else
- analysisParameters.timeColumn = 0;
- end
- analysisParameters.pvbsVoltageColumn = t242;
- analysisParameters.pvbsCurrentColumn = t252;
- analysisParameters.csvColumnsAsSweeps = t262;
- if t262
- % overrides now moved within loadCSV()
- %{
- analysisParameters.pvbsVoltageScalingFactor = 1; % default to scaling factor = 1 for V
- analysisParameters.pvbsCurrentScalingFactor = 1; % default to scaling factor = 1 for i
- analysisParameters.csvOffsetRow = 0; % default to no row offset
- analysisParameters.csvOffsetColumn = 0; % default to no column offset
- analysisParameters.pvbsCurrentColumn = 0; % default to reading columns as voltage
- %}
- else
- end
- analysisParameters.lineScanChannel = t312;
- analysisParameters.lineScanBaseline(1) = t322;
- analysisParameters.lineScanBaseline(2) = t332;
- analysisParameters.lineScanROIThreshold = t342;
- analysisParameters.lineScanBackgroundThreshold = t352;
- analysisParameters.lineScanROISmoothing = t362;
- analysisParameters.lineScanROIDetectDuringBaseline = t372;
- if t413
- analysisParameters.boxcarLength1 = t412;
- else
- analysisParameters.boxcarLength1 = 0;
- end
- if t423
- analysisParameters.boxcarLength2 = t422;
- else
- analysisParameters.boxcarLength2 = 0;
- end
- analysisParameters.besselOrder1 = t432;
- analysisParameters.besselOrder2 = t442;
- if t433 % NB. this is for t452, not t432
- analysisParameters.besselFreq1 = t452;
- else
- analysisParameters.besselFreq1 = 0;
- end
- if t443 % NB. this is for t462, not t442
- analysisParameters.besselFreq2 = t462;
- else
- analysisParameters.besselFreq2 = 0;
- end
- %analysisParameters.autoGroup = t512; %%% fixlater
- h.params.actualParams = analysisParameters;
- guidata(win1, h);
- close(optionsWin);
- set(srcButton, 'enable', 'on');
- end
- end
- %% Save/Load Experiments
- function saveMat(src, ~)
- % export dataset as .mat
- % start stopwatch
- tic;
- % default save parameters - could go into settings
- defaultSaveFilePrefix = 'pvbs_';
- defaultSavePath = cd;
- defaultSavedVariableName = 'h';
- % load
- h = guidata(src);
- if isempty(h.ui.cellListDisplay.String)
- error('Error: No experiment file present');
- end
- % shed ui elements
- hNew.exp = h.exp;
- hNew.results = h.results;
- hNew.analysis = h.analysis;
- hNew.params = h.params;
- % ... except
- hNew.ui.cellList = h.ui.cellList;
- % overwrite, just to keep the variable name
- h = hNew;
- % set save path and file name
- todayYY = num2str(year(datetime));
- todayYY = todayYY(end-1:end);
- todayMM = sprintf('%02.0f', month(datetime));
- todayDD = sprintf('%02.0f', day(datetime));
- todayhh = sprintf('%02.0f', hour(datetime));
- todaymm = sprintf('%02.0f', minute(datetime));
- todayss = sprintf('%02.0f', second(datetime));
- saveNameDate = [todayYY, todayMM, todayDD ,'_', todayhh, todaymm, todayss];
- %saveNameDate = [todayYY, todayMM, todayDD ,'_', todayhh, todaymm];
- saveNameCell = h.exp.fileName{1}(1:end-4);
- saveNameCell = [defaultSaveFilePrefix, saveNameCell];
- if length(h.exp.fileName) > 1 % more than 1 experiments in dataset
- expCount = length(h.exp.fileName);
- expCount = num2str(expCount);
- saveNameCellSuffix = ['_N', expCount];
- saveNameCell = [saveNameCell, saveNameCellSuffix];
- end
- saveName = [saveNameCell, '_', saveNameDate, '.mat'];
- savePath = [defaultSavePath, '\']; % appending backslash for proper formatting
- % prompt, since it could take some time
- fprintf('Saving dataset... ');
- % save
- warning('off', 'all');
- [actualName, actualPath, isSaved] = uisaveX(defaultSavedVariableName, [savePath, saveName]);
- warning('on', 'all');
- % print results
- if isSaved
- elapsedTime = toc;
- fprintf('\nSaved as: %s%s\n (elapsed time: %.2f s)\n\n', actualPath, actualName, elapsedTime);
- else
- elapsedTime = toc;
- fprintf('canceled.\n\n');
- end
- end
- function saveGUI(src, ~)
- % save everything as .mat - will create a large file because the figure itself is saved
- % start stopwatch
- tic;
- % default save parameters - could go into settings
- defaultSaveFilePrefix = 'pvbs_debug_';
- defaultSavePath = cd;
- defaultSavedVariableName = 'h';
- % load
- h = guidata(src);
- if isempty(h.ui.cellListDisplay.String)
- error('Error: No experiment file present');
- end
- % set save path and file name
- todayYY = num2str(year(datetime));
- todayYY = todayYY(end-1:end);
- todayMM = sprintf('%02.0f', month(datetime));
- todayDD = sprintf('%02.0f', day(datetime));
- todayhh = sprintf('%02.0f', hour(datetime));
- todaymm = sprintf('%02.0f', minute(datetime));
- todayss = sprintf('%02.0f', second(datetime));
- saveNameDate = [todayYY, todayMM, todayDD ,'_', todayhh, todaymm, todayss];
- %saveNameDate = [todayYY, todayMM, todayDD ,'_', todayhh, todaymm];
- saveNameCell = h.exp.fileName{1}(1:end-4);
- saveNameCell = [defaultSaveFilePrefix, saveNameCell];
- if length(h.exp.fileName) > 1 % more than 1 experiments in dataset
- expCount = length(h.exp.fileName);
- expCount = num2str(expCount);
- saveNameCellSuffix = ['_N', expCount];
- saveNameCell = [saveNameCell, saveNameCellSuffix];
- end
- saveName = [saveNameCell, '_', saveNameDate, '.mat'];
- savePath = [defaultSavePath, '\']; % appending backslash for proper formatting
- % prompt, since it could take some time
- fprintf('Saving GUI (debug mode)... ');
- % save
- warning('off', 'all');
- [actualName, actualPath, isSaved] = uisaveX(defaultSavedVariableName, [savePath, saveName]);
- warning('on', 'all');
- % print results
- if isSaved
- elapsedTime = toc;
- fprintf('\nSaved as: %s%s\n (elapsed time: %.2f s)\n\n', actualPath, actualName, elapsedTime);
- else
- elapsedTime = toc;
- fprintf('canceled.\n\n');
- end
- end
- function newMat(src, ~)
- % clear data in GUI
- % load
- h = guidata(src);
- % clear...
- % data structure
- exp.experimentCount = 0;
- exp.metadata = {}; % cell for tSeries metadata files
- % below are for easier access without having to dig into metadata
- exp.fileName = {}; % file name
- exp.filePath = {}; % file path
- exp.sweeps = {}; % total sweep count for each tSeries
- % actual data
- data.VRec = {}; % VRec (.csv)
- data.VRecOriginal = {}; % VRec (.csv), to preserve original in case of postprocessing - again real lack of foresight
- data.VRecMetadata = {}; % metadata for each VRec (.xml)
- data.VOut = {}; % VOut (.xml) - may have to omit due to PV insanity in formatting these
- data.VOutName = {}; % VRec experiment type (e.g. "single stim") - VOut name will work most of the time
- %data.lineScanMetadata = {}; % metadata for each LScn (.xml) - obsolete, linescans don't have separate metadata per cycle
- data.lineScan = {}; % LScn (.tiff)
- data.lineScanDFF = {}; % LScn dF/F
- data.lineScanDFFOriginal = {}; % LScn dF/F, to preserve original in case of postprocessing - again real lack of foresight
- data.lineScanF = {}; % LScn F
- data.lineScanFChannel = {}; % LScn channel used for F, dF/F
- data.lineScanROI = {}; % LScn ROI
- data.lineScanBaseline = {}; % LScn baseline period (time)
- data.lineScanCSV = {}; % LScn profile (.csv)
- data.postprocessing = {}; % postprocessing info (e.g. downsampling)
- data.artifactRemoval = {}; % artifact removal info
- data.markPointsIdx = {}; % indices for MkPts
- data.markPointsMetadata = {}; % MkPts metadata (.xml)
- data.intrinsicProperties = {}; % intrinsic properties, analyzed from file below
- data.intrinsicPropertiesVRec = {}; % intrinsic properties VRec (.csv)
- data.intrinsicPropertiesVRecMetadata = {}; % metadata for intrinsic properties VRec (.xml)
- data.intrinsicPropertiesFileName = {}; % file path and name for intrinsic properties
- data.zStack = {}; % z-stack
- data.zStackFileName = {}; % file path and name for z-stack
- data.singleScan = {}; % single-scan image
- data.singleScanFileName = {}; % file path and name for single-scan
- data.sweepIdx = {}; % sweep indices
- data.sweepStr = {}; % sweep strings for display
- data.groupIdx = {}; % sweep grouping indices
- data.groupStr = {}; % sweep grouping indices in string format for display
- data.notes = {}; % notes
- exp.data = data; % meta-struct for VRec data
- % analysis results
- results = {};
- % more analysis results - another unplanned mess "resulting" in more of really stupid naming and structuring
- analysis = struct();
- % gui elements
- %%% fixlater
- % save
- guidata(src, h);
- end
- function loadMat(src, ~)
- % import dataset from previously exported .mat and appeend to current dataset
- % start stopwatch
- tic;
- % load
- h = guidata(src);
- win = src.Parent;
- % import cell data from a previously saved .mat file
- fprintf('Loading... ');
- [fName, fPath] = uigetfile({'*.mat', 'PVBS dataset'});
- if ~isempty(fName)
- fprintf('(%s%s) ', fPath, fName);
- end
- % check if a file was loaded
- if fName ~= 0
- dataset = load([fPath, fName]);
- hNew = dataset.h; % "h" will be the name of the top level struct
- experimentCountAdditional = hNew.exp.experimentCount;
- h.exp.experimentCount = h.exp.experimentCount + hNew.exp.experimentCount;
- for i = 1:experimentCountAdditional
- % h.exp
- h.exp.metadata{end + 1} = hNew.exp.metadata{i};
- h.exp.fileName{end + 1} = hNew.exp.fileName{i};
- h.exp.filePath{end + 1} = hNew.exp.filePath{i};
- h.exp.sweeps{end + 1} = hNew.exp.sweeps{i};
- % h.exp.data
- try
- h.exp.data.fileType{end + 1} = hNew.exp.data.fileType{i};
- catch ME
- fileTypeNew = '';
- h.exp.data.fileType{end + 1} = fileTypeNew;
- end
- h.exp.data.VRec{end + 1} = hNew.exp.data.VRec{i};
- h.exp.data.VRecOriginal{end + 1} = hNew.exp.data.VRecOriginal{i};
- h.exp.data.VRecMetadata{end + 1} = hNew.exp.data.VRecMetadata{i};
- h.exp.data.VOut{end + 1} = hNew.exp.data.VOut{i};
- h.exp.data.VOutName{end + 1} = hNew.exp.data.VOutName{i};
- h.exp.data.lineScan{end + 1} = hNew.exp.data.lineScan{i};
- h.exp.data.lineScanDFF{end + 1} = hNew.exp.data.lineScanDFF{i};
- h.exp.data.lineScanDFFOriginal{end + 1} = hNew.exp.data.lineScanDFFOriginal{i};
- h.exp.data.lineScanF{end + 1} = hNew.exp.data.lineScanF{i};
- h.exp.data.lineScanFChannel{end + 1} = hNew.exp.data.lineScanFChannel{i};
- h.exp.data.lineScanROI{end + 1} = hNew.exp.data.lineScanROI{i};
- h.exp.data.lineScanBaseline{end + 1} = hNew.exp.data.lineScanBaseline{i};
- h.exp.data.lineScanCSV{end + 1} = hNew.exp.data.lineScanCSV{i};
- try
- h.exp.data.postprocessing{end + 1} = hNew.exp.data.postprocessing{i};
- catch ME
- postprocessingNew = [h.params.actualParams.boxcarLength1, h.params.actualParams.besselFreq1, h.params.actualParams.besselOrder1];
- postprocessingNew = [postprocessingNew; [h.params.actualParams.boxcarLength2, h.params.actualParams.besselFreq2, h.params.actualParams.besselOrder2]];
- h.exp.data.postprocessing{end + 1} = postprocessingNew;
- end
- try
- h.exp.data.artifactRemoval{end + 1} = hNew.exp.data.artifactRemoval{i};
- catch ME
- artifactRemovalNew = [];
- h.exp.data.artifactRemoval{end + 1} = artifactRemovalNew;
- end
- h.exp.data.markPointsIdx{end + 1} = hNew.exp.data.markPointsIdx{i};
- h.exp.data.markPointsMetadata{end + 1} = hNew.exp.data.markPointsMetadata{i};
- h.exp.data.intrinsicProperties{end + 1} = hNew.exp.data.intrinsicProperties{i};
- h.exp.data.intrinsicPropertiesVRec{end + 1} = hNew.exp.data.intrinsicPropertiesVRec{i};
- h.exp.data.intrinsicPropertiesVRecMetadata{end + 1} = hNew.exp.data.intrinsicPropertiesVRecMetadata{i};
- h.exp.data.intrinsicPropertiesFileName{end + 1} = hNew.exp.data.intrinsicPropertiesFileName{i};
- h.exp.data.zStack{end + 1} = hNew.exp.data.zStack{i};
- h.exp.data.zStackFileName{end + 1} = hNew.exp.data.zStackFileName{i};
- h.exp.data.singleScan{end + 1} = hNew.exp.data.singleScan{i};
- h.exp.data.singleScanFileName{end + 1} = hNew.exp.data.singleScanFileName{i};
- h.exp.data.sweepIdx{end + 1} = hNew.exp.data.sweepIdx{i};
- h.exp.data.sweepStr{end + 1} = hNew.exp.data.sweepStr{i};
- h.exp.data.groupIdx{end + 1} = hNew.exp.data.groupIdx{i};
- h.exp.data.groupStr{end + 1} = hNew.exp.data.groupStr{i};
- try
- h.exp.data.notes{end + 1} = hNew.exp.data.notes{i};
- catch ME
- notesNew = {};
- h.exp.data.notes{end + 1} = notesNew;
- end
- % h.results
- h.results{end + 1} = hNew.results{i};
- % h.analysis %%% fixlater and also see below
- h.params = hNew.params; % leave as is %%% no
- % h.ui - leave as is, except...
- h.ui.cellList{end + 1} = hNew.ui.cellList{i};
- end
- h.ui.cellListDisplay.String = h.ui.cellList; % not to be confused here
- %%% fixlater
- if isempty(fieldnames(h.analysis))
- h.analysis = hNew.analysis;
- end
- h = cellListClick2(h, 1); % select 1st entry by default - unfortunate, but has to select something to update trace display
- %{
- h.exp = hNew.exp;
- h.results = hNew.results;
- h.analysis = hNew.analysis;
- h.params = hNew.params;
- h.ui.cellList = hNew.ui.cellList;
- h.ui.cellListDisplay.String = h.ui.cellList;
- h.ui.cellListDisplay.Value = 1;
- h = cellListClick2(h, 1); % select 1st entry by default
- %}
- else
- fprintf('\ncanceled.\n\n');
- return
- end
- % ugh...
- try % ... to display results
- resultsTempGrp = h.results{1}.VRec.groupResults;
- resultsTemp2Grp = h.results{1}.dff.groupResults;
- % plot 1: by default, display Vm, win 1, peak, by group, for current experiment
- targetPlot = h.ui.analysisPlot1; % plot 1
- winToPlot = 1; % analysis window 1
- peakDirToPlot = h.params.actualParams.peakDirection1;
- switch peakDirToPlot % converting to column indices for old code
- case -1 % negative
- peakDirToPlot = 1;
- case 0 % absolute
- peakDirToPlot = 2;
- case 1 % positive
- peakDirToPlot = 3;
- otherwise
- peakDirToPlot = 1;
- end
- dataX = 1:length(resultsTempGrp.groups); % group number - will plot by groups
- dataY = resultsTempGrp.peak; % grouped results, peak
- dataY = dataY(winToPlot, :); % analysis window 1
- dataYNew = nan(length(dataY), 1); % initialize
- for i = 1:length(dataY)
- dataYi = dataY{i}; % current sweep/group
- if isempty(dataYi)
- dataYi = NaN;
- else
- dataYi = dataYi(peakDirToPlot);
- end
- dataYNew(i) = dataYi; % update
- end
- dataY = dataYNew; % update
- axes(targetPlot);
- hold on;
- color = [0, 0, 0];
- targetPlot = displayResults(targetPlot, dataX, dataY, color);
- set(gca, 'xlim', [0, length(dataX) + 1]); % padding for appearance
- hold off;
- xlabel('Group #');
- ylabel('PSP (mV)');
- %xticks(0:5:10000);
- %%{
- if nanmax(dataY) > 40
- ylim([0, 40.5]);
- %yticks(-1000:10:1000);
- elseif nanmax(dataY) > 10
- ylim([0, nanmax(dataY) + 0.5]);
- %yticks(-1000:5:1000);
- else
- ylim([0, 10.5]);
- %yticks(-1000:2:1000);
- end
- %}
- set(gca, 'xminortick', 'on', 'yminortick', 'on');
- h.ui.analysisPlot1 = targetPlot;
- params.resultsPlot1YRange = targetPlot.YLim;
- h.ui.analysisPlot1Menu1.Value = 2; % voltage
- h.ui.analysisPlot1Menu2.Value = 2; % window 1
- %h.ui.analysisPlot1Menu3.Value = 1; % results - will update later
- h.ui.analysisPlot1Menu4.Value = 3; % by group
- traceDisplay = h.ui.traceDisplay;
- axes(traceDisplay);
- % plot 2: by default, display dF/F, win 2, peak, by group, for current experiment
- try
- targetPlot = h.ui.analysisPlot2; % plot 2
- winToPlot = 2; % analysis window 2
- peakDirToPlot = h.params.actualParams.peakDirection2;
- switch peakDirToPlot % converting to column indices for old code
- case -1 % negative
- peakDirToPlot = 1;
- case 0 % absolute
- peakDirToPlot = 2;
- case 1 % positive
- peakDirToPlot = 3;
- otherwise
- peakDirToPlot = 1;
- end
- dataX = 1:length(resultsTemp2Grp.groups); % group number - will plot by groups
- dataY = resultsTemp2Grp.peak; % grouped results, peak
- dataY = dataY(winToPlot, :); % analysis window 2
- dataYNew = nan(length(dataY), 1); % initialize
- %%%
- %%%%%%%
- % data grouping not fucking working properly - why???
- %%%%%%% the fuck happened here? was it fixed? (2022-05-03)
- for i = 1:length(dataY)
- dataYi = dataY{i}; % current sweep/group
- if isempty(dataYi)
- dataYi = NaN;
- else
- dataYi = dataYi(peakDirToPlot);
- end
- dataYNew(i) = dataYi; % update
- end
- dataY = dataYNew; % update
- axes(targetPlot);
- hold on;
- color = [0, 0.5, 0];
- targetPlot = displayResults(targetPlot, dataX, dataY, color);
- set(gca, 'xlim', [0, length(dataX) + 1]); % padding for appearance
- hold off;
- xlabel('Group #');
- ylabel('dF/F');
- %xticks(0:5:10000);
- %{
- if max(dataY) > 4
- ylim([-0.5, max(dataY) + 0.5]);
- yticks(-10:1:100);
- else
- ylim([-0.5, 4.5]);
- yticks(-10:1:100);
- end
- %}
- set(gca, 'xminortick', 'on', 'yminortick', 'on');
- h.ui.analysisPlot2 = targetPlot;
- params.resultsPlot2YRange = targetPlot.YLim;
- h.ui.analysisPlot2Menu1.Value = 3; % fluorescence
- h.ui.analysisPlot2Menu2.Value = 3; % window 2
- %h.ui.analysisPlot2Menu3.Value = 1; % results - will update later
- h.ui.analysisPlot2Menu4.Value = 3; % by group
- catch ME
- traceDisplay = h.ui.traceDisplay;
- axes(traceDisplay);
- end
- % which results to plot
- try
- switch h.ui.analysisType1.Value % analysis type for window 1
- case 1 % unselected
- case 2 % peak/area/mean
- switch h.ui.analysisPlot1Menu2.Value % plot 1, window number
- case 1 % unselected
- h.ui.analysisPlot1Menu3.String = h.params.analysisPlotMenuList3; % to default
- h.ui.analysisPlot1Menu3.Value = 1;
- case 2 % window 1
- h.ui.analysisPlot1Menu3.String = h.params.analysisPlotMenuList31;
- h.ui.analysisPlot1Menu3.Value = 2; % default to peak
- case 3 % window 2
- h.ui.analysisPlot1Menu3.String = h.params.analysisPlotMenuList3; % to default
- h.ui.analysisPlot1Menu3.Value = 1;
- end
- case 3 % threshold detection
- switch h.ui.analysisPlot1Menu2.Value % plot 1, window number
- case 1 % unselected
- h.ui.analysisPlot1Menu3.String = h.params.analysisPlotMenuList3; % to default
- h.ui.analysisPlot1Menu3.Value = 1;
- case 2 % window 1
- h.ui.analysisPlot1Menu3.String = h.params.analysisPlotMenuList32;
- h.ui.analysisPlot1Menu3.Value = 2; % default to event count
- case 3 % window 2
- h.ui.analysisPlot1Menu3.String = h.params.analysisPlotMenuList3; % to default
- h.ui.analysisPlot1Menu3.Value = 1;
- end
- case 4 % waveform
- switch h.ui.analysisPlot1Menu2.Value % plot 1, window number
- case 1 % unselected
- h.ui.analysisPlot1Menu3.String = h.params.analysisPlotMenuList3; % to default
- h.ui.analysisPlot1Menu3.Value = 1;
- case 2 % window 1
- h.ui.analysisPlot1Menu3.String = h.params.analysisPlotMenuList33;
- h.ui.analysisPlot1Menu3.Value = 2; % default to ap threshold
- case 3 % window 2
- h.ui.analysisPlot1Menu3.String = h.params.analysisPlotMenuList3; % to default
- h.ui.analysisPlot1Menu3.Value = 1;
- end
- end
- catch ME
- end
- try
- switch h.ui.analysisType2.Value % analysis type for window 2
- case 1 % unselected
- case 2 % peak/area/mean
- switch h.ui.analysisPlot2Menu2.Value % plot 1, window number
- case 1 % unselected
- h.ui.analysisPlot2Menu3.String = h.params.analysisPlotMenuList3; % to default
- h.ui.analysisPlot2Menu3.Value = 1;
- case 2 % window 1
- h.ui.analysisPlot2Menu3.String = h.params.analysisPlotMenuList3; % to default
- h.ui.analysisPlot2Menu3.Value = 1;
- case 3 % window 2
- h.ui.analysisPlot2Menu3.String = h.params.analysisPlotMenuList31;
- h.ui.analysisPlot2Menu3.Value = 2; % default to peak
- end
- case 3 % threshold detection
- switch h.ui.analysisPlot2Menu2.Value % plot 1, window number
- case 1 % unselected
- h.ui.analysisPlot2Menu3.String = h.params.analysisPlotMenuList3; % to default
- h.ui.analysisPlot2Menu3.Value = 1;
- case 2 % window 1
- h.ui.analysisPlot2Menu3.String = h.params.analysisPlotMenuList3; % to default
- h.ui.analysisPlot2Menu3.Value = 1;
- case 3 % window 2
- h.ui.analysisPlot2Menu3.String = h.params.analysisPlotMenuList32;
- h.ui.analysisPlot2Menu3.Value = 2; % default to event count
- end
- case 4 % waveform
- switch h.ui.analysisPlot2Menu2.Value % plot 1, window number
- case 1 % unselected
- h.ui.analysisPlot2Menu3.String = h.params.analysisPlotMenuList3; % to default
- h.ui.analysisPlot2Menu3.Value = 1;
- case 2 % window 1
- h.ui.analysisPlot2Menu3.String = h.params.analysisPlotMenuList3; % to default
- h.ui.analysisPlot2Menu3.Value = 1;
- case 3 % window 2
- h.ui.analysisPlot2Menu3.String = h.params.analysisPlotMenuList33;
- h.ui.analysisPlot2Menu3.Value = 2; % default to ap threshold
- end
- end
- catch ME
- end
- catch ME
- end
- h = traceDisplayResetCalled(h);
- traceDisplay = h.ui.traceDisplay;
- axes(traceDisplay);
- % save
- guidata(src, h);
- % print results
- elapsedTime = toc;
- fprintf('\nImport complete. (elapsed time: %.2f s) \n\n', elapsedTime);
- end
- function loadMatNew(src, ~)
- % import dataset from previously exported .mat and discard current dataset
- % start stopwatch
- tic;
- % load
- h = guidata(src);
- win = src.Parent;
- % import cell data from a previously saved .mat file
- fprintf('Loading... ');
- [fName, fPath] = uigetfile({'*.mat', 'PVBS dataset'});
- if ~isempty(fName)
- fprintf('(%s%s) ', fPath, fName);
- end
- % check if a file was loaded
- if fName ~= 0
- dataset = load([fPath, fName]);
- hNew = dataset.h; % "h" will be the name of the top level struct
- h.exp = hNew.exp;
- h.results = hNew.results;
- h.analysis = hNew.analysis;
- h.params = hNew.params;
- h.ui.cellList = hNew.ui.cellList;
- h.ui.cellListDisplay.String = h.ui.cellList;
- h.ui.cellListDisplay.Value = 1;
- h = cellListClick2(h, 1); % select 1st entry by default
- else
- fprintf('\ncanceled.\n\n');
- return
- end
- % ugh...
- try % ... to display results
- resultsTempGrp = h.results{1}.VRec.groupResults;
- resultsTemp2Grp = h.results{1}.dff.groupResults;
- % plot 1: by default, display Vm, win 1, peak, by group, for current experiment
- targetPlot = h.ui.analysisPlot1; % plot 1
- winToPlot = 1; % analysis window 1
- peakDirToPlot = h.params.actualParams.peakDirection1;
- switch peakDirToPlot % converting to column indices for old code
- case -1 % negative
- peakDirToPlot = 1;
- case 0 % absolute
- peakDirToPlot = 2;
- case 1 % positive
- peakDirToPlot = 3;
- otherwise
- peakDirToPlot = 1;
- end
- dataX = 1:length(resultsTempGrp.groups); % group number - will plot by groups
- dataY = resultsTempGrp.peak; % grouped results, peak
- dataY = dataY(winToPlot, :); % analysis window 1
- dataYNew = nan(length(dataY), 1); % initialize
- for i = 1:length(dataY)
- dataYi = dataY{i}; % current sweep/group
- if isempty(dataYi)
- dataYi = NaN;
- else
- dataYi = dataYi(peakDirToPlot);
- end
- dataYNew(i) = dataYi; % update
- end
- dataY = dataYNew; % update
- axes(targetPlot);
- hold on;
- color = [0, 0, 0];
- targetPlot = displayResults(targetPlot, dataX, dataY, color);
- set(gca, 'xlim', [0, length(dataX) + 1]); % padding for appearance
- hold off;
- xlabel('Group #');
- ylabel('PSP (mV)');
- %xticks(0:5:10000);
- %%{
- if nanmax(dataY) > 40
- ylim([0, 40.5]);
- %yticks(-1000:10:1000);
- elseif nanmax(dataY) > 10
- ylim([0, nanmax(dataY) + 0.5]);
- %yticks(-1000:5:1000);
- else
- ylim([0, 10.5]);
- %yticks(-1000:2:1000);
- end
- %}
- set(gca, 'xminortick', 'on', 'yminortick', 'on');
- h.ui.analysisPlot1 = targetPlot;
- params.resultsPlot1YRange = targetPlot.YLim;
- h.ui.analysisPlot1Menu1.Value = 2; % voltage
- h.ui.analysisPlot1Menu2.Value = 2; % window 1
- %h.ui.analysisPlot1Menu3.Value = 1; % results - will update later
- h.ui.analysisPlot1Menu4.Value = 3; % by group
- traceDisplay = h.ui.traceDisplay;
- axes(traceDisplay);
- % plot 2: by default, display dF/F, win 2, peak, by group, for current experiment
- try
- targetPlot = h.ui.analysisPlot2; % plot 2
- winToPlot = 2; % analysis window 2
- peakDirToPlot = h.params.actualParams.peakDirection2;
- switch peakDirToPlot % converting to column indices for old code
- case -1 % negative
- peakDirToPlot = 1;
- case 0 % absolute
- peakDirToPlot = 2;
- case 1 % positive
- peakDirToPlot = 3;
- otherwise
- peakDirToPlot = 1;
- end
- dataX = 1:length(resultsTemp2Grp.groups); % group number - will plot by groups
- dataY = resultsTemp2Grp.peak; % grouped results, peak
- dataY = dataY(winToPlot, :); % analysis window 2
- dataYNew = nan(length(dataY), 1); % initialize
- %%%
- %%%%%%%
- % data grouping not fucking working properly - why???
- %%%%%%% the fuck happened here? was it fixed? (2022-05-03)
- for i = 1:length(dataY)
- dataYi = dataY{i}; % current sweep/group
- if isempty(dataYi)
- dataYi = NaN;
- else
- dataYi = dataYi(peakDirToPlot);
- end
- dataYNew(i) = dataYi; % update
- end
- dataY = dataYNew; % update
- axes(targetPlot);
- hold on;
- color = [0, 0.5, 0];
- targetPlot = displayResults(targetPlot, dataX, dataY, color);
- set(gca, 'xlim', [0, length(dataX) + 1]); % padding for appearance
- hold off;
- xlabel('Group #');
- ylabel('dF/F');
- %xticks(0:5:10000);
- %{
- if max(dataY) > 4
- ylim([-0.5, max(dataY) + 0.5]);
- yticks(-10:1:100);
- else
- ylim([-0.5, 4.5]);
- yticks(-10:1:100);
- end
- %}
- set(gca, 'xminortick', 'on', 'yminortick', 'on');
- h.ui.analysisPlot2 = targetPlot;
- params.resultsPlot2YRange = targetPlot.YLim;
- h.ui.analysisPlot2Menu1.Value = 3; % fluorescence
- h.ui.analysisPlot2Menu2.Value = 3; % window 2
- %h.ui.analysisPlot2Menu3.Value = 1; % results - will update later
- h.ui.analysisPlot2Menu4.Value = 3; % by group
- catch ME
- traceDisplay = h.ui.traceDisplay;
- axes(traceDisplay);
- end
- % which results to plot
- try
- switch h.ui.analysisType1.Value % analysis type for window 1
- case 1 % unselected
- case 2 % peak/area/mean
- switch h.ui.analysisPlot1Menu2.Value % plot 1, window number
- case 1 % unselected
- h.ui.analysisPlot1Menu3.String = h.params.analysisPlotMenuList3; % to default
- h.ui.analysisPlot1Menu3.Value = 1;
- case 2 % window 1
- h.ui.analysisPlot1Menu3.String = h.params.analysisPlotMenuList31;
- h.ui.analysisPlot1Menu3.Value = 2; % default to peak
- case 3 % window 2
- h.ui.analysisPlot1Menu3.String = h.params.analysisPlotMenuList3; % to default
- h.ui.analysisPlot1Menu3.Value = 1;
- end
- case 3 % threshold detection
- switch h.ui.analysisPlot1Menu2.Value % plot 1, window number
- case 1 % unselected
- h.ui.analysisPlot1Menu3.String = h.params.analysisPlotMenuList3; % to default
- h.ui.analysisPlot1Menu3.Value = 1;
- case 2 % window 1
- h.ui.analysisPlot1Menu3.String = h.params.analysisPlotMenuList32;
- h.ui.analysisPlot1Menu3.Value = 2; % default to event count
- case 3 % window 2
- h.ui.analysisPlot1Menu3.String = h.params.analysisPlotMenuList3; % to default
- h.ui.analysisPlot1Menu3.Value = 1;
- end
- case 4 % waveform
- switch h.ui.analysisPlot1Menu2.Value % plot 1, window number
- case 1 % unselected
- h.ui.analysisPlot1Menu3.String = h.params.analysisPlotMenuList3; % to default
- h.ui.analysisPlot1Menu3.Value = 1;
- case 2 % window 1
- h.ui.analysisPlot1Menu3.String = h.params.analysisPlotMenuList33;
- h.ui.analysisPlot1Menu3.Value = 2; % default to ap threshold
- case 3 % window 2
- h.ui.analysisPlot1Menu3.String = h.params.analysisPlotMenuList3; % to default
- h.ui.analysisPlot1Menu3.Value = 1;
- end
- end
- catch ME
- end
- try
- switch h.ui.analysisType2.Value % analysis type for window 2
- case 1 % unselected
- case 2 % peak/area/mean
- switch h.ui.analysisPlot2Menu2.Value % plot 1, window number
- case 1 % unselected
- h.ui.analysisPlot2Menu3.String = h.params.analysisPlotMenuList3; % to default
- h.ui.analysisPlot2Menu3.Value = 1;
- case 2 % window 1
- h.ui.analysisPlot2Menu3.String = h.params.analysisPlotMenuList3; % to default
- h.ui.analysisPlot2Menu3.Value = 1;
- case 3 % window 2
- h.ui.analysisPlot2Menu3.String = h.params.analysisPlotMenuList31;
- h.ui.analysisPlot2Menu3.Value = 2; % default to peak
- end
- case 3 % threshold detection
- switch h.ui.analysisPlot2Menu2.Value % plot 1, window number
- case 1 % unselected
- h.ui.analysisPlot2Menu3.String = h.params.analysisPlotMenuList3; % to default
- h.ui.analysisPlot2Menu3.Value = 1;
- case 2 % window 1
- h.ui.analysisPlot2Menu3.String = h.params.analysisPlotMenuList3; % to default
- h.ui.analysisPlot2Menu3.Value = 1;
- case 3 % window 2
- h.ui.analysisPlot2Menu3.String = h.params.analysisPlotMenuList32;
- h.ui.analysisPlot2Menu3.Value = 2; % default to event count
- end
- case 4 % waveform
- switch h.ui.analysisPlot2Menu2.Value % plot 1, window number
- case 1 % unselected
- h.ui.analysisPlot2Menu3.String = h.params.analysisPlotMenuList3; % to default
- h.ui.analysisPlot2Menu3.Value = 1;
- case 2 % window 1
- h.ui.analysisPlot2Menu3.String = h.params.analysisPlotMenuList3; % to default
- h.ui.analysisPlot2Menu3.Value = 1;
- case 3 % window 2
- h.ui.analysisPlot2Menu3.String = h.params.analysisPlotMenuList33;
- h.ui.analysisPlot2Menu3.Value = 2; % default to ap threshold
- end
- end
- catch ME
- end
- catch ME
- end
- h = traceDisplayResetCalled(h);
- traceDisplay = h.ui.traceDisplay;
- axes(traceDisplay);
- % save
- guidata(src, h);
- % print results
- elapsedTime = toc;
- fprintf('\nImport complete. (elapsed time: %.2f s) \n\n', elapsedTime);
- end
- function expFile = loadExp(src, ~)
- % load Experiment XML files
- % load
- h = guidata(src);
- experiment = h.exp;
- data = experiment.data;
- results = h.results;
- cellList = h.ui.cellList;
- cellListDisplay = h.ui.cellListDisplay;
- % prompt, since this could take some time
- fprintf('Loading experiment(s)...');
- % select experiment metadata .xml (or directory of the same name containing it)
- filesToImport = uipickfiles_pvbs('type', {'*.*', 'All files (.*)'; '*.abf', 'Axon binary file (.abf)'; '*.xml', 'VRec/LScn/tSer directory or metadata (.xml)'; '*.csv', 'VRec data (.csv)'});
- tic; % start stopwatch
- if iscell(filesToImport)
- if isempty(filesToImport)
- fprintf(' canceled.\n\n');
- return
- else
- for i = 1:length(filesToImport)
- try % sometimes files are corrupt because stupid PV crashes all the time
- isCSV = 0;
- isABF = 0;
- [fPath, fName, fExt] = fileparts(filesToImport{i});
- if isempty(fExt) % if directory is selected
- fExt = '.xml';
- fPath = [fPath, '\', fName, '\'];
- fName = [fName, fExt];
- elseif strcmp(fExt, '.xml'); % if .xml file is selected
- fPath = [fPath, '\'];
- fName = [fName, fExt];
- elseif strcmp(fExt, '.csv'); % if .csv file is selected
- fPath = [fPath, '\'];
- fName = [fName, fExt];
- isCSV = 1;
- elseif strcmp(fExt, '.abf'); % if .abf file is selected
- fPath = [fPath, '\'];
- fName = [fName, fExt];
- isABF = 1;
- else
- %error('Error: Invalid file type');
- end
- fprintf('\n(%d/%d) ', i, length(filesToImport));
- %actualParams = setDefaultParams(src); % load parameters
- %h.params.actualParams = actualParams; % save parameters
- actualParams = h.params.actualParams;
- if isCSV
- h = loadCSV(h, fPath, fName, actualParams);
- elseif isABF
- h = loadABF(h, fPath, fName, actualParams);
- else
- h = loadExpMain(h, fPath, fName, actualParams);
- end
- catch ME
- fprintf('- aborted');
- end
- end
- end
- elseif filesToImport == 0
- fprintf(' canceled.\n\n');
- return
- end
- % display first experiment if first time loading files, otherwise last experiment
- if h.params.firstRun == 1
- set(h.ui.cellListDisplay, 'value', 1);
- h = displayTrace(h, 1);
- h.params.firstRun = 0;
- else
- set(h.ui.cellListDisplay, 'value', length(cellList) + length(filesToImport));
- h = displayTrace(h, length(cellList) + length(filesToImport));
- %{
- set(h.ui.cellListDisplay, 'value', length(cellList));
- h = displayTrace(h, length(cellList));
- %}
- end
- % highlight first sweep
- %h.ui.groupListDisplay.Value = 1;
- h.ui.sweepListDisplay.Value = 1;
- h = highlightSweep(h, 1);
- set(h.ui.groupSweepText, 'string', 'Sweep 1');
- % reset trace display range
- h = traceDisplayResetCalled(h);
- % save
- guidata(src, h);
- elapsedTime = toc;
- fprintf('\n Load complete. (elapsed time: %.2f s)\n\n', elapsedTime);
- end
- % loadExpMain - find default parameters here
- function h = loadExpMain(h, fPath, fName, actualParams)
- % load each experiment - VRec, LScn, or tSer (of VRec)
- % because PV records data in its own units, data must be scaled appropriately
- % hard-coding here, instead of digging again into insane PV metadata
- % below are set for MC700B with Rf = 500 MO and usual gain settings for whole-cell recordings
- pvbsVoltageScalingFactor = actualParams.pvbsVoltageScalingFactor; % "100 mV" to mV
- pvbsCurrentScalingFactor = actualParams.pvbsCurrentScalingFactor; % "0.1 nA" to pA
- timeColumn = actualParams.timeColumn; % csv column for timestamp
- pvbsVoltageColumn = actualParams.pvbsVoltageColumn; % csv column to apply voltage scaling (column 1 is timestamp, followed by channels)
- pvbsCurrentColumn = actualParams.pvbsCurrentColumn; % csv column to apply current scaling
- csvColumnsAsSweeps = actualParams.csvColumnsAsSweeps; % interpret columns as sweeps (default: 0)
- csvOffsetRow = actualParams.csvOffsetRow; % row offset while reading csv with csvread() (default: 1)
- csvOffsetColumn = actualParams.csvOffsetColumn; % column offset while reading csv with csvread() (default: 0)
- lineScanChannel = actualParams.lineScanChannel; % primary channel for calcium imaging signal; e.g. for P4, 1: red, 2: green (primary)
- lineScanBaseline = actualParams.lineScanBaseline; % (ms), baseline for F_0 in linescans, avoid starting from 0 to prevent possible contamination from shutter artifact
- 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
- lineScanDownsamplingFactor = actualParams.lineScanDownsamplingFactor; % downsampling factor for fluorescence signals, for the dF/F to be robust to noise
- lineScanROISmoothing = actualParams.lineScanDownsamplingFactor; % will average over this many points (before and after) while detecting ROI to be robust from noise - obsolete with single ROI
- lineScanROIThreshold = actualParams.lineScanROIThreshold; % (s.d.); z-score for 1st quartile
- lineScanBackgroundThreshold = actualParams.lineScanBackgroundThreshold; % (s.d.); z-score for 67th percentile
- offloadMarkPointsMetadata = actualParams.offloadMarkPointsMetadata; % delete markpoints metadata after retrieving point indices to save space (0: no, 1: yes)
- % PV GPIO box can quite unbelievably also introduce current measurement error
- % via bleedthrough across channels, which has to be corrected if present
- % otherwise, there will be "phantom" DC injection present in data
- % DO NOT use if recordings DO have intentional baseline DC injection at the beginning!
- % DO NOT be confused with having incorrect bias current settings from amplifier!
- pvbsCurrentCorrectionFlag = actualParams.pvbsCurrentCorrectionFlag; % set to 1 to correct, 0 to leave as is
- pvbsCurrentCorrectionDataPoints = actualParams.pvbsCurrentCorrectionDataPoints; % this many points at the beginning will be used for baseline correction
- % load
- experiment = h.exp;
- data = experiment.data;
- results = h.results;
- cellList = h.ui.cellList;
- cellListDisplay = h.ui.cellListDisplay;
- % prompt
- fprintf(' %s%s ', fPath, fName);
- % load file
- sweeps = 1;
- metadata = xml2struct_pvbs([fPath, fName]); % load metadata from .xml, using modified xml2struct
- try
- sweeps = length(metadata.PVScan.Sequence); % !!! this will need to be changed if the TSeries does not entirely consist of VRecs %%%
- catch ME
- sweeps = 1;
- end
- % fill cells
- experiment.metadata{end + 1} = metadata;
- experiment.fileName{end + 1} = fName; % just to make file name and path readily accessible
- experiment.filePath{end + 1} = fPath;
- experiment.sweeps{end + 1} = sweeps;
- results{end + 1} = struct;
- % check experiment type
- if sweeps == 1
- expTypeStr = metadata.PVScan.Sequence.Attributes.type;
- else
- expTypeStr = metadata.PVScan.Sequence{1}.Attributes.type;
- end
- expTypeTSer = 'TSeries Voltage Recording';
- expTypeVRec = 'VoltageRecording';
- expTypeLScn = 'Linescan'; % note cases and spaces because PV is inconsistent
- if strcmp(expTypeStr, expTypeTSer)
- expType = 1; % T-Series
- elseif strcmp(expTypeStr, expTypeVRec)
- expType = 2; % VoltageRecording
- elseif strcmp(expTypeStr, expTypeLScn)
- expType = 3; % LineScan
- else
- expType = 0; % invalid
- fprintf('\nInvalid file type\n');
- return
- end
- % fill cells within cells (... interlinked)
- VOutName = {cell(sweeps, 1)};
- VOut = {cell(sweeps, 1)};
- VRecMetadata = {cell(sweeps, 1)};
- VRec = {cell(sweeps, 1)};
- VRecOriginal = {cell(sweeps, 1)};
- %lineScanMetadata = {cell(sweeps, 1)};
- lineScanFile = {cell(sweeps, 1)};
- lineScan = {cell(sweeps, 1)};
- lineScanF = {cell(sweeps, 1)};
- lineScanDFF = {cell(sweeps, 1)};
- lineScanDFFOriginal = {cell(sweeps, 1)};
- lineScanCSVFile = {cell(sweeps, 1)};
- lineScanCSV = {cell(sweeps, 1)};
- lineScanFChannel = {cell(sweeps, 1)};
- lineScanROI = {cell(sweeps, 1)};
- postprocessing = [];
- artifactRemoval = [];
- markPointsMetadata = {cell(sweeps, 1)};
- markPointsIdx = {cell(sweeps, 1)};
- intrinsicProperties = struct(); % struct, not cell
- intrinsicPropertiesVRec = {cell(1)};
- intrinsicPropertiesVRecMetadata = struct();
- intrinsicPropertiesFileName = [];
- zStack = {cell(1)}; % only one
- zStackFileName = [];
- singleScan = {cell(1)}; % only one as representative, since saving all of them will be overwhelming for file size
- singleScanFileName = [];
- sweepIdx = 1:sweeps; % note that this is an array and not a cell
- sweepStr = cell(sweeps, 1);
- if sweeps == 1
- sweepStr{1} = '1';
- else
- for i = 1:sweeps
- sweepStr{i} = num2str(i);
- end
- end
- groupIdx = {}; % groupIdx = {cell(sweeps, 1)};
- groupStr = {};
- notes = {};
- postprocessing = [h.params.actualParams.boxcarLength1, h.params.actualParams.besselFreq1, h.params.actualParams.besselOrder1];
- postprocessing = [postprocessing; [h.params.actualParams.boxcarLength2, h.params.actualParams.besselFreq2, h.params.actualParams.besselOrder2]];
- 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
- VRecMetadata{1} = {metadata.PVScan.Sequence.VoltageRecording.Attributes.configurationFile}; % mind the curly braces on RHS
- VRecFile = metadata.PVScan.Sequence.VoltageRecording.Attributes.dataFile;
- VRecTemp = csvread([fPath, VRecFile], csvOffsetRow, csvOffsetColumn); % offset row by 1 ("time(ms), input 0, input 1"), and column by 0
- % this bizzare step has to be taken, because Prairie
- VRecTemp(:, pvbsVoltageColumn) = VRecTemp(:, pvbsVoltageColumn)*pvbsVoltageScalingFactor;
- VRecTemp(:, pvbsCurrentColumn) = VRecTemp(:, pvbsCurrentColumn)*pvbsCurrentScalingFactor;
- pvbsCurrentCorrectionAmount = nanmean(VRecTemp(1:pvbsCurrentCorrectionDataPoints, pvbsCurrentColumn));
- VRecTemp(:, pvbsCurrentColumn) = VRecTemp(:, pvbsCurrentColumn) - pvbsCurrentCorrectionFlag * pvbsCurrentCorrectionAmount;
- % - end of PV correction -
- VRecOriginalTemp = VRecTemp;
- try
- if logical(h.params.actualParams.besselFreq1) % do bessel first before boxcar if applicable, although menu order is backwards - another stupid me doing stupid things
- besselOrder = h.params.actualParams.besselOrder1;
- cutoffFreq = h.params.actualParams.besselFreq1;
- cutoffFreq = cutoffFreq*1000; % converting to Hz from kHz
- samplingRate = VRecTemp(2, 1) - VRecTemp(1, 1); % sampling interval (ms), since first column is timestamp
- samplingRate = 1000*(1/samplingRate); % converting to Hz from ms
- for j = 2:size(VRecTemp, 2) % skip timestamp in column 1
- VRecTempTemp = VRecTemp(:, j); % skip the timestamp in column 1
- VRecTempTemp = besselLowpass(VRecTempTemp, besselOrder, cutoffFreq, samplingRate);
- VRecTemp(:, j) = VRecTempTemp;
- end
- end
- if logical(h.params.actualParams.boxcarLength1) % do boxcar after bessel, again if applicable
- boxcarLength = h.params.actualParams.boxcarLength1;
- dataLengthReduced = floor(size(VRecTemp, 1)/boxcarLength);
- VRecReducedTemp = nan(dataLengthReduced, size(VRecTemp, 2)); % initializing
- for j = 1:size(VRecTemp, 2) % NB. timestamp can be treated the same way
- for k = 1:dataLengthReduced
- VRecReducedTemp(k, j) = nanmean(VRecTemp(1 + (k-1)*boxcarLength : k*boxcarLength, j));
- end
- end
- VRecTemp = VRecReducedTemp; % simply overwrite if data reduction took place
- end
- catch ME
- end
- VRec{1} = VRecTemp;
- VRecOriginal{1} = VRecOriginalTemp;
- try % some experiments might have been recorded with null VOut
- VOutName{1} = {metadata.PVScan.Sequence.VoltageOutput.Attributes.name};
- 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
- catch ME
- VOutName{1} = {};
- VOut{1} = {};
- end
- try
- lineScanFileChannelCount = metadata.PVScan.Sequence.Frame.File;
- lineScanFileChannelCount = length(lineScanFileChannelCount);
- if lineScanFileChannelCount == 1
- lineScanFileTemp = metadata.PVScan.Sequence.Frame.File.Attributes.filename;
- lineScanFile{1, 1} = lineScanFileTemp;
- warning('off','all');
- lineScan{1, 1} = read(Tiff([fPath, lineScanFileTemp])); % Tiff() is a built-in function
- warning('on','all');
- else
- for j = 1:lineScanFileChannelCount
- lineScanFileTemp = metadata.PVScan.Sequence.Frame.File{j}.Attributes.filename;
- lineScanFile{j, 1} = lineScanFileTemp;
- warning('off','all');
- lineScan{j, 1} = read(Tiff([fPath, lineScanFileTemp])); % Tiff() is a built-in function
- warning('on','all');
- end
- end
- catch ME
- lineScanFile{:, 1} = {};
- lineScan{:, 1} = {};
- end
- try
- lineScanCSVFile{1} = metadata.PVScan.Sequence.PVLinescanDefinition.LineScanProfiles.Attributes.DataFile; % LineScanProfile csv will include all applicable channels
- lineScanCSV{1} = csvread([fPath, lineScanFile], csvOffsetRow, csvOffsetColumn); % offset row by 1 ("Ch1 time, Ch1, Ch2 time, Ch2"), and column by 0
- catch ME
- lineScanCSV{1} = {};
- end
- try
- % Applicable if the loaded .xml is a linescan
- % columns 1, 2, 3, 4 in the astounding PV metadata: framePeriod, linesPerFrame, pixelsPerLine, scanLinePeriod
- % i.e. 1 = 2*3*4, but 2 & 3 can be inferred from data
- % unit is (s)
- lineScanChannelUsed = lineScanChannel;
- framePeriodIdx = 1;
- framePeriod = metadata.PVScan.Sequence.Frame.PVStateShard.PVStateValue{framePeriodIdx}.Attributes.key;
- if strcmp(framePeriod, 'framePeriod')
- framePeriod = metadata.PVScan.Sequence.Frame.PVStateShard.PVStateValue{framePeriodIdx}.Attributes.value;
- framePeriod = str2num(framePeriod);
- end
- if size(lineScan, 1) < lineScanChannel
- lineScanChannelUsed = 1;
- else
- lineScanChannelUsed = lineScanChannel;
- end
- lineScanImage = lineScan{lineScanChannelUsed, 1}; % use only the relevant channel
- linesPerFrame = size(lineScanImage, 1); % this should be the same as the entry in column 2 above
- lineScanInterval = framePeriod/linesPerFrame; % (s)
- lineScanInterval = lineScanInterval * 1000; % (ms)
- framePeriod = framePeriod * 1000; % (ms)
- lineScanTimestamp = 0:lineScanInterval:(framePeriod - lineScanInterval); % this will slightly shift the quasismiultaneous linescan towards earlier in time
- lineScanTimestamp = lineScanTimestamp';
- [lineScanFTemp, lineScanDFFTemp, roiTemp] = lineScanImgToF(lineScanImage, lineScanTimestamp, lineScanBaseline, actualParams);
- lineScanDFFOriginalTemp = lineScanDFFTemp;
- try
- if logical(h.params.actualParams.besselFreq2)
- besselOrder = h.params.actualParams.besselOrder2;
- cutoffFreq = h.params.actualParams.besselFreq2;
- cutoffFreq = cutoffFreq*1000; % converting to Hz from kHz
- samplingRate = lineScanDFFTemp(2, 1) - lineScanDFFTemp(1, 1); % sampling interval (ms), since first column is timestamp
- samplingRate = 1000*(1/samplingRate); % converting to Hz from ms
- lineScanDFFTempTemp = lineScanDFFTemp(:, 2); % skip the timestamp in column 1
- lineScanDFFTempTemp = besselLowpass(lineScanDFFTempTemp, besselOrder, cutoffFreq, samplingRate);
- lineScanDFFTemp(:, 2) = lineScanDFFTempTemp;
- end
- if logical(h.params.actualParams.boxcarLength2)
- boxcarLength = h.params.actualParams.boxcarLength2;
- dataLengthReduced = floor(size(lineScanDFFTemp, 1)/boxcarLength);
- lineScanDFFReducedTemp = nan(dataLengthReduced, size(lineScanDFFTemp, 2)); % initializing
- for j = 1:size(lineScanDFFTemp, 2) % NB. timestamp can be treated the same way
- for k = 1:dataLengthReduced
- lineScanDFFReducedTemp(k, j) = nanmean(lineScanDFFTemp(1 + (k-1)*boxcarLength : k*boxcarLength, j));
- end
- end
- lineScanDFFTemp = lineScanDFFReducedTemp; % simply overwrite if data reduction took place
- end
- catch ME
- end
- lineScanF{1} = lineScanFTemp;
- lineScanDFF{1} = lineScanDFFTemp;
- lineScanDFFOriginal{1} = lineScanDFFOriginalTemp;
- lineScanFChannel{1} = lineScanChannelUsed;
- lineScanROI{1} = roiTemp;
- catch ME
- lineScanF{1} = [];
- lineScanDFF{1} = [];
- lineScanDFFOriginal{1} = [];
- lineScanFChannel{1} = [];
- lineScanROI{1} = [];
- end
- try
- markPointsMetadataFile = metadata.PVScan.MarkPoints.Attributes.filename;
- markPointsMetadata{1} = xml2struct_pvbs([fPath, markPointsMetadataFile]);
- markPointsIdx{1} = markPointsMetadata{1}.PVMarkPointSeriesElements.PVMarkPointElement.PVGalvoPointElement.Attributes.Indices;
- catch ME
- markPointsMetadata{1} = struct();
- end
- else
- for i = 1:sweeps
- VRecMetadata{i} = metadata.PVScan.Sequence{i}.VoltageRecording.Attributes.configurationFile;
- VRecFile = metadata.PVScan.Sequence{i}.VoltageRecording.Attributes.dataFile;
- VRecTemp = csvread([fPath, VRecFile], csvOffsetRow, csvOffsetColumn); % offset row by 1 ("time(ms), input 0, input 1"), and column by 0
- % this bizzare step has to be taken, because Prairie
- VRecTemp(:, pvbsVoltageColumn) = VRecTemp(:, pvbsVoltageColumn)*pvbsVoltageScalingFactor;
- VRecTemp(:, pvbsCurrentColumn) = VRecTemp(:, pvbsCurrentColumn)*pvbsCurrentScalingFactor;
- pvbsCurrentCorrectionAmount = nanmean(VRecTemp(1:pvbsCurrentCorrectionDataPoints, pvbsCurrentColumn));
- VRecTemp(:, pvbsCurrentColumn) = VRecTemp(:, pvbsCurrentColumn) - pvbsCurrentCorrectionFlag * pvbsCurrentCorrectionAmount;
- % - end of PV correction -
- VRecOriginalTemp = VRecTemp;
- try
- if logical(h.params.actualParams.besselFreq1)
- besselOrder = h.params.actualParams.besselOrder1;
- cutoffFreq = h.params.actualParams.besselFreq1;
- cutoffFreq = cutoffFreq*1000; % converting to Hz from kHz
- samplingRate = VRecTemp(2, 1) - VRecTemp(1, 1); % sampling interval (ms), since first column is timestamp
- samplingRate = 1000*(1/samplingRate); % converting to Hz from ms
- for j = 2:size(VRecTemp, 2) % skip timestamp in column 1
- VRecTempTemp = VRecTemp(:, j); % skip the timestamp in column 1
- VRecTempTemp = besselLowpass(VRecTempTemp, besselOrder, cutoffFreq, samplingRate);
- VRecTemp(:, j) = VRecTempTemp;
- end
- end
- if logical(h.params.actualParams.boxcarLength1)
- boxcarLength = h.params.actualParams.boxcarLength1;
- dataLengthReduced = floor(size(VRecTemp, 1)/boxcarLength);
- VRecReducedTemp = nan(dataLengthReduced, size(VRecTemp, 2)); % initializing
- for j = 1:size(VRecTemp, 2) % NB. timestamp can be treated the same way
- for k = 1:dataLengthReduced
- VRecReducedTemp(k, j) = nanmean(VRecTemp(1 + (k-1)*boxcarLength : k*boxcarLength, j));
- end
- end
- VRecTemp = VRecReducedTemp; % simply overwrite if data reduction took place
- end
- catch ME
- end
- VRec{i} = VRecTemp;
- VRecOriginal{i} = VRecOriginalTemp;
- try % some experiments might have been recorded with null VOut
- VOutName{i} = metadata.PVScan.Sequence{i}.VoltageOutput.Attributes.name;
- 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
- catch ME
- VOutName{i} = [];
- VOut{i} = [];
- end
- try
- lineScanFileChannelCount = metadata.PVScan.Sequence{i}.Frame.File;
- lineScanFileChannelCount = length(lineScanFileChannelCount);
- if lineScanFileChannelCount == 1
- lineScanFileTemp = metadata.PVScan.Sequence{i}.Frame.File.Attributes.filename;
- lineScanFile{1, i} = lineScanFileTemp;
- warning('off','all');
- lineScan{1, i} = read(Tiff([fPath, lineScanFileTemp])); % Tiff() is a built-in function
- warning('on','all');
- else
- for j = 1:lineScanFileChannelCount
- lineScanFileTemp = metadata.PVScan.Sequence{i}.Frame.File{j}.Attributes.filename;
- lineScanFile{j, i} = lineScanFileTemp;
- warning('off','all');
- lineScan{j, i} = read(Tiff([fPath, lineScanFileTemp])); % Tiff() is a built-in function
- warning('on','all');
- end
- end
- catch ME
- lineScanFile{:, i} = [];
- lineScan{:, i} = [];
- end
- try
- lineScanCSVFile{i} = metadata.PVScan.Sequence{i}.PVLinescanDefinition.LineScanProfiles.Attributes.DataFile; % LineScanProfile csv will include all applicable channels
- 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
- catch ME
- lineScanCSV{i} = [];
- end
- try
- % Applicable if the loaded .xml is a linescan
- % columns 1, 2, 3, 4 in the astounding PV metadata: framePeriod, linesPerFrame, pixelsPerLine, scanLinePeriod
- % i.e. 1 = 2*3*4, but 2 & 3 can be inferred from data
- % unit is (s)
- framePeriodIdx = 1;
- framePeriod = metadata.PVScan.Sequence{i}.Frame.PVStateShard.PVStateValue{framePeriodIdx}.Attributes.key;
- if strcmp(framePeriod, 'framePeriod')
- framePeriod = metadata.PVScan.Sequence{i}.Frame.PVStateShard.PVStateValue{framePeriodIdx}.Attributes.value;
- framePeriod = str2num(framePeriod);
- end
- if size(lineScan, 1) < lineScanChannel
- lineScanChannelUsed = 1;
- else
- lineScanChannelUsed = lineScanChannel;
- end
- lineScanImage = lineScan{lineScanChannelUsed, i}; % use only the relevant channel
- linesPerFrame = size(lineScanImage, 1); % this should be the same as the entry in column 2 above
- lineScanInterval = framePeriod/linesPerFrame; % (s)
- lineScanInterval = lineScanInterval * 1000; % (ms)
- framePeriod = framePeriod * 1000; % (ms)
- lineScanTimestamp = 0:lineScanInterval:(framePeriod - lineScanInterval); % this will slightly shift the quasismiultaneous linescan towards earlier in time
- lineScanTimestamp = lineScanTimestamp';
- [lineScanFTemp, lineScanDFFTemp, roiTemp] = lineScanImgToF(lineScanImage, lineScanTimestamp, lineScanBaseline, actualParams);
- lineScanDFFOriginalTemp = lineScanDFFTemp;
- try
- if logical(h.params.actualParams.besselFreq2)
- besselOrder = h.params.actualParams.besselOrder2;
- cutoffFreq = h.params.actualParams.besselFreq2;
- cutoffFreq = cutoffFreq*1000; % converting to Hz from kHz
- samplingRate = lineScanDFFTemp(2, 1) - lineScanDFFTemp(1, 1); % sampling interval (ms), since first column is timestamp
- samplingRate = 1000*(1/samplingRate); % converting to Hz from ms
- lineScanDFFTempTemp = lineScanDFFTemp(:, 2); % skip the timestamp in column 1
- lineScanDFFTempTemp = besselLowpass(lineScanDFFTempTemp, besselOrder, cutoffFreq, samplingRate);
- lineScanDFFTemp(:, 2) = lineScanDFFTempTemp;
- end
- if logical(h.params.actualParams.boxcarLength2)
- boxcarLength = h.params.actualParams.boxcarLength2;
- dataLengthReduced = floor(size(lineScanDFFTemp, 1)/boxcarLength);
- lineScanDFFReducedTemp = nan(dataLengthReduced, size(lineScanDFFTemp, 2)); % initializing
- for j = 1:size(lineScanDFFTemp, 2) % NB. timestamp can be treated the same way
- for k = 1:dataLengthReduced
- lineScanDFFReducedTemp(k, j) = nanmean(lineScanDFFTemp(1 + (k-1)*boxcarLength : k*boxcarLength, j));
- end
- end
- lineScanDFFTemp = lineScanDFFReducedTemp; % simply overwrite if data reduction took place
- end
- catch ME
- end
- lineScanF{i} = lineScanFTemp;
- lineScanDFF{i} = lineScanDFFTemp;
- lineScanDFFOriginal{i} = lineScanDFFOriginalTemp;
- lineScanFChannel{i} = lineScanChannelUsed;
- lineScanROI{i} = roiTemp;
- catch ME
- lineScanF{i} = [];
- lineScanDFF{i} = [];
- lineScanDFFOriginal{i} = [];
- lineScanFChannel{i} = [];
- lineScanROI{i} = [];
- end
- try
- markPointsMetadataFile = metadata.PVScan.Sequence{i}.MarkPoints.Attributes.filename;
- markPointsMetadata{i} = xml2struct_pvbs([fPath, markPointsMetadataFile]);
- markPointsIdx{i} = markPointsMetadata{i}.PVMarkPointSeriesElements.PVMarkPointElement.PVGalvoPointElement.Attributes.Indices;
- catch ME
- markPointsMetadata{i} = struct();
- markPointsIdx{i} = [];
- end
- %groupIdx{i} = {}; %groupIdx{i} = 0; % default to this, but do implement autodetect function
- %groupStr{i} = {};
- end
- if offloadMarkPointsMetadata
- for i = 1:length(markPointsMetadata)
- markPointsMetadata{i} = struct(); % to save space
- end
- end
- end
- % if ROI detection fails for linescans, inherit ROI from the previous sweep
- %{
- try
- if isempty(lineScanROI{1}) % if the first sweep is missing a ROI
- firstSweepWithROI = find(~cellfun(@isempty, lineScanROI), 1);
- lineScanROI{1} = lineScanROI{firstSweepWithROI};
- % recalculate dF/F with inherited ROI
- roiTemp = lineScanROI{1};
- lineScanImage = lineScan{lineScanChannelUsed, 1}; % use only the relevant channel
- [lineScanFTemp, lineScanDFFTemp] = lineScanImgToFManualROI(lineScanImage, lineScanTimestamp, lineScanBaseline, actualParams, roiTemp);
- lineScanF{1} = lineScanFTemp;
- lineScanDFF{1} = lineScanDFFTemp;
- lineScanFChannel{1} = lineScanChannelUsed;
- end
- if length(lineScanROI) > 1
- for i = 2:length(lineScanROI)
- if isempty(lineScanROI{i})
- lineScanROI{i} = lineScanROI{i - 1};
- % recalculate dF/F with inherited ROI
- roiTemp = lineScanROI{i};
- lineScanImage = lineScan{lineScanChannelUsed, i}; % use only the relevant channel
- [lineScanFTemp, lineScanDFFTemp] = lineScanImgToFManualROI(lineScanImage, lineScanTimestamp, lineScanBaseline, actualParams, roiTemp);
- lineScanF{i} = lineScanFTemp;
- lineScanDFF{i} = lineScanDFFTemp;
- lineScanFChannel{i} = lineScanChannelUsed;
- end
- end
- end
- catch ME
- end
- %}
- % ... or not; set ROI to the entire length of the line(scan)
- try
- lineLength = size(lineScanImage, 2);
- if isempty(lineScanROI{1}) % if the first sweep is missing a ROI
- firstSweepWithROI = find(~cellfun(@isempty, lineScanROI), 1);
- %lineScanROI{1} = lineScanROI{firstSweepWithROI};
- lineScanROI{1} = [1, lineLength];
- % recalculate dF/F with inherited ROI
- roiTemp = lineScanROI{1};
- lineScanImage = lineScan{lineScanChannelUsed, 1}; % use only the relevant channel
- [lineScanFTemp, lineScanDFFTemp] = lineScanImgToFManualROI(lineScanImage, lineScanTimestamp, lineScanBaseline, actualParams, roiTemp);
- lineScanF{1} = lineScanFTemp;
- lineScanDFF{1} = lineScanDFFTemp;
- lineScanFChannel{1} = lineScanChannelUsed;
- end
- if length(lineScanROI) > 1
- for i = 2:length(lineScanROI)
- if isempty(lineScanROI{i})
- %lineScanROI{i} = lineScanROI{i - 1};
- lineScanROI{i} = [1, lineLength];
- % recalculate dF/F with inherited ROI
- roiTemp = lineScanROI{i};
- lineScanImage = lineScan{lineScanChannelUsed, i}; % use only the relevant channel
- [lineScanFTemp, lineScanDFFTemp] = lineScanImgToFManualROI(lineScanImage, lineScanTimestamp, lineScanBaseline, actualParams, roiTemp);
- lineScanF{i} = lineScanFTemp;
- lineScanDFF{i} = lineScanDFFTemp;
- lineScanFChannel{i} = lineScanChannelUsed;
- end
- end
- end
- catch ME
- end
- % load one representative branch image for linescans %%% shockingly, PV LScn metadata doesn't have reference image information
- %{
- try
- singleScanDisplay = h.ui.singleScanDisplay;
- [singleScan, singleScanDisplay] = loadSingleScan2(singleScanDisplay, ssPath, ssName);
- h.ui.singleScanDisplay = singleScanDisplay;
- catch ME
- end
- %}
- % group sweeps automatically
- groupIdx2 = 1;
- if sweeps == 1
- %{
- groupIdx{1} = 1;
- groupStr{1} = '1';
- %}
- groupIdx{1} = 1;
- groupStr{1} = '1';
- else
- switch expType
- case 1 % TSer
- if ~iscell(VOutName)
- VOutName = {VOutName};
- end
- if length(VOutName) > 1
- for i = 2:length(VOutName)
- for j = 1:max(groupIdx2)
- searchIdx = find(groupIdx2 == j, 1);
- if strcmp(VOutName{i}, VOutName{searchIdx})
- groupIdx2(i) = groupIdx2(searchIdx);
- break
- else
- groupIdx2(i) = groupIdx2(searchIdx) + 1;
- searchIdx = searchIdx + 1;
- end
- end
- end
- end
- for i = 1:max(groupIdx2)
- groupIdxNew = find(groupIdx2 == i);
- groupIdx{end + 1} = groupIdxNew;
- groupStrNew = num2str(groupIdxNew(1));
- if length(groupIdxNew) > 1
- for i = 2:length(groupIdxNew);
- groupStrNew = [groupStrNew, ',', num2str(groupIdxNew(i))];
- end
- end
- groupStr{end + 1} = groupStrNew;
- end
- case 2 % VRec
- case 3 % LScn
- try % group according to markpoints indices for uncaging experiments
- %%{
- firstSwpGrp = [];
- for i = 1:length(markPointsIdx)
- %firstSwpGrp(end + 1) = ~iscell(markPointsIdx{i});
- firstSwpGrp(end + 1) = isstr(markPointsIdx{i});
- end
- firstSwpGrp = find(firstSwpGrp);
- firstSwpGrp = firstSwpGrp(1);
- firstSwpGrp = max(2, firstSwpGrp);
- %}
- %for i = firstSwpGrp:length(markPointsIdx)
- for i = 2:length(markPointsIdx)
- %groupIdx2
- for j = 1:max(groupIdx2)
- searchIdx = find(groupIdx2 == j, 1);
- try
- if strcmp(markPointsIdx{i}, markPointsIdx{searchIdx})
- groupIdx2(i) = groupIdx2(searchIdx);
- break
- else
- groupIdx2(i) = groupIdx2(searchIdx) + 1;
- searchIdx = searchIdx + 1;
- end
- catch ME
- groupIdx2(i) = groupIdx2(searchIdx) + 1;
- searchIdx = searchIdx + 1;
- end
- end
- end
- for i = 1:max(groupIdx2)
- groupIdxNew = find(groupIdx2 == i);
- groupIdx{end + 1} = groupIdxNew;
- groupStrNew = num2str(groupIdxNew(1));
- if length(groupIdxNew) > 1
- for i = 2:length(groupIdxNew);
- groupStrNew = [groupStrNew, ',', num2str(groupIdxNew(i))];
- end
- end
- try
- markPointsStr = markPointsIdx{groupIdxNew(1)}; % point indices, should be same for all elements of groupIdxNew at this point
- groupStrNew = ['(# ', markPointsStr, ') ', groupStrNew]; % append point indices to be clear
- groupStr{end + 1} = groupStrNew;
- catch ME
- groupStrNew = ['(# ', '', ') ', groupStrNew]; % append point indices to be clear
- groupStr{end + 1} = groupStrNew;
- end
- end
- catch ME
- end
- end
- end
- %%% no group means no group - another workaround amongst hundreds
- if isempty(groupStr)
- groupIdx = [];
- end
- % update experiment count and cell list
- experiment.experimentCount = experiment.experimentCount + 1;
- cellList{end + 1} = fName(1:end-4); % getting rid of the extension
- set(cellListDisplay, 'string', cellList);
- % bring up downsampling information if applied
- if logical(h.params.actualParams.boxcarLength1) || logical(h.params.actualParams.besselFreq1) % either downsampling has been done on signal 1 - prioritize signal 1 over 2
- h.ui.traceProcessingTarget.Value = 2; % 1st item would be selection indicator
- h.ui.downsamplingButton.Value = logical(h.params.actualParams.boxcarLength1); % check the button
- h.ui.lowPassFilterButton.Value = logical(h.params.actualParams.besselFreq1); % check the button
- elseif logical(h.params.actualParams.boxcarLength2) || logical(h.params.actualParams.besselFreq2) % if both signals were processed, display will default to signal 1
- h.ui.traceProcessingTarget.Value = 3; % 1st item would be selection indicator
- h.ui.downsamplingButton.Value = logical(h.params.actualParams.boxcarLength2); % check the button
- h.ui.lowPassFilterButton.Value = logical(h.params.actualParams.besselFreq2); % check the button
- end
- % save
- data.fileType{end + 1} = 'PV';
- data.VRecMetadata{end + 1} = VRecMetadata;
- data.VRec{end + 1} = VRec;
- data.VRecOriginal{end + 1} = VRecOriginal;
- data.VOutName{end + 1} = VOutName;
- data.VOut{end + 1} = VOut;
- data.lineScan{end + 1} = lineScan;
- data.lineScanF{end + 1} = lineScanF;
- data.lineScanDFF{end + 1} = lineScanDFF;
- data.lineScanDFFOriginal{end + 1} = lineScanDFFOriginal;
- data.lineScanCSV{end + 1} = lineScanCSV;
- data.lineScanFChannel{end + 1} = lineScanFChannel;
- data.lineScanROI{end + 1} = lineScanROI;
- data.lineScanBaseline{end + 1} = lineScanBaseline;
- data.postprocessing{end + 1} = postprocessing;
- data.artifactRemoval{end + 1} = artifactRemoval;
- data.markPointsMetadata{end + 1} = markPointsMetadata;
- data.markPointsIdx{end + 1} = markPointsIdx;
- data.intrinsicProperties{end + 1} = intrinsicProperties;
- data.intrinsicPropertiesVRec{end + 1} = intrinsicPropertiesVRec;
- data.intrinsicPropertiesVRecMetadata{end + 1} = intrinsicPropertiesVRecMetadata;
- data.intrinsicPropertiesFileName{end + 1} = intrinsicPropertiesFileName;
- data.zStack{end + 1} = zStack;
- data.zStackFileName{end + 1} = zStackFileName;
- data.singleScan{end + 1} = singleScan;
- data.singleScanFileName{end + 1} = singleScanFileName;
- data.sweepIdx{end + 1} = sweepIdx;
- data.sweepStr{end + 1} = sweepStr;
- data.groupIdx{end + 1} = groupIdx;
- data.groupStr{end + 1} = groupStr;
- data.notes{end + 1} = notes;
- experiment.data = data;
- h.exp = experiment;
- h.results = results;
- h.ui.cellList = cellList;
- h.ui.cellListDisplay = cellListDisplay;
- end % end of loadExpMain()
- function h = loadCSV(h, fPath, fName, actualParams)
- % modified loadExpMain() for VRec (.csv)
- % currently treating all .csv as V, not F %%% fixlater ?
- % because PV records data in its own units, data must be scaled appropriately
- % hard-coding here, instead of digging again into insane PV metadata
- % below are set for MC700B with Rf = 500 MO and usual gain settings for whole-cell recordings
- pvbsVoltageScalingFactor = actualParams.pvbsVoltageScalingFactor; % "100 mV" to mV
- pvbsCurrentScalingFactor = actualParams.pvbsCurrentScalingFactor; % "0.1 nA" to pA
- timeColumn = actualParams.timeColumn; % csv column for timestamp
- pvbsVoltageColumn = actualParams.pvbsVoltageColumn; % csv column to apply voltage scaling (column 1 is timestamp, followed by channels)
- pvbsCurrentColumn = actualParams.pvbsCurrentColumn; % csv column to apply current scaling
- csvOffsetRow = actualParams.csvOffsetRow; % row offset while reading csv with csvread() (default: 1)
- csvOffsetColumn = actualParams.csvOffsetColumn; % column offset while reading csv with csvread() (default: 0)
- csvColumnsAsSweeps = actualParams.csvColumnsAsSweeps; % interpret columns as sweeps (default: 0)
- lineScanChannel = actualParams.lineScanChannel; % primary channel for calcium imaging signal; e.g. for P4, 1: red, 2: green (primary)
- lineScanBaseline = actualParams.lineScanBaseline; % (ms), baseline for F_0 in linescans, avoid starting from 0 to prevent possible contamination from shutter artifact
- 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
- lineScanDownsamplingFactor = actualParams.lineScanDownsamplingFactor; % downsampling factor for fluorescence signals, for the dF/F to be robust to noise
- lineScanROISmoothing = actualParams.lineScanDownsamplingFactor; % will average over this many points (before and after) while detecting ROI to be robust from noise - obsolete with single ROI
- lineScanROIThreshold = actualParams.lineScanROIThreshold; % (s.d.); z-score for 1st quartile
- lineScanBackgroundThreshold = actualParams.lineScanBackgroundThreshold; % (s.d.); z-score for 67th percentile
- offloadMarkPointsMetadata = actualParams.offloadMarkPointsMetadata; % delete markpoints metadata after retrieving point indices to save space (0: no, 1: yes)
- % PV GPIO box can quite unbelievably also introduce current measurement error
- % via bleedthrough across channels, which has to be corrected if present
- % otherwise, there will be "phantom" DC injection present in data
- % DO NOT use if recordings DO have intentional baseline DC injection at the beginning!
- % DO NOT be confused with having incorrect bias current settings from amplifier!
- pvbsCurrentCorrectionFlag = actualParams.pvbsCurrentCorrectionFlag; % set to 1 to correct, 0 to leave as is
- pvbsCurrentCorrectionDataPoints = actualParams.pvbsCurrentCorrectionDataPoints; % this many points at the beginning will be used for baseline correction
- % load
- experiment = h.exp;
- data = experiment.data;
- results = h.results;
- cellList = h.ui.cellList;
- cellListDisplay = h.ui.cellListDisplay;
- % prompt
- fprintf(' %s%s ', fPath, fName);
- % load file
- %%% fixlater: csvColumnsAsSweeps assumes "correct" values, i.e. not scaled - this will create confusion when reading .csv saved from PV
- VRecFile = [fPath, fName];
- VRecTemp = csvread([fPath, fName], csvOffsetRow, csvOffsetColumn); % offset row by 1 ("time(ms), input 0, input 1"), and column by 0
- if csvColumnsAsSweeps
- %%% look here!
- % force scaling factor = 1
- pvbsVoltageScalingFactor = 1;
- pvbsCurrentScalingFactor = 1;
- % force reading data as voltage
- pvbsCurrentColumn = 0;
- % force no column/row offset
- csvOffsetRow = 0;
- csvOffsetColumn = 0;
- if timeColumn % timestamp column is present
- sweeps = size(VRecTemp, 2); % each column represents a sweep
- nonTimeColumn = 1:sweeps; % do this first
- nonTimeColumn = nonTimeColumn(nonTimeColumn ~= timeColumn);
- sweeps = sweeps - 1; % since one column is for timestamp and not an actual sweep
- else
- sweeps = size(VRecTemp, 2); % each column represents a sweep
- nonTimeColumn = 1:sweeps;
- nonTimeColumn = nonTimeColumn(nonTimeColumn ~= timeColumn);
- end
- % pv bleedthrough correction
- if pvbsVoltageColumn ~= 0
- if pvbsCurrentColumn == 0 % just adding for possible future use of the next else block
- VRecTemp(:, nonTimeColumn) = VRecTemp(:, nonTimeColumn)*pvbsVoltageScalingFactor;
- else % if both are nonzero, default to interpret as voltage
- VRecTemp(:, nonTimeColumn) = VRecTemp(:, nonTimeColumn)*pvbsVoltageScalingFactor;
- end
- elseif pvbsCurrentColumn == 0 % if both are 0, again default to interpret as voltage; this could be used later to interpret as F instead %%% fixlater
- VRecTemp(:, nonTimeColumn) = VRecTemp(:, nonTimeColumn)*pvbsVoltageScalingFactor;
- else % now interpret as current
- VRecTemp(:, nonTimeColumn) = VRecTemp(:, nonTimeColumn)*pvbsCurrentScalingFactor;
- pvbsCurrentCorrectionAmount = nanmean(VRecTemp(1:pvbsCurrentCorrectionDataPoints, pvbsCurrentColumn));
- VRecTemp(:, pvbsCurrentColumn) = VRecTemp(:, pvbsCurrentColumn) - pvbsCurrentCorrectionFlag * pvbsCurrentCorrectionAmount;
- end
- else
- sweeps = 1; % gap-free
- % pv bleedthrough correction
- VRecTemp(:, pvbsVoltageColumn) = VRecTemp(:, pvbsVoltageColumn)*pvbsVoltageScalingFactor;
- VRecTemp(:, pvbsCurrentColumn) = VRecTemp(:, pvbsCurrentColumn)*pvbsCurrentScalingFactor;
- pvbsCurrentCorrectionAmount = nanmean(VRecTemp(1:pvbsCurrentCorrectionDataPoints, pvbsCurrentColumn));
- VRecTemp(:, pvbsCurrentColumn) = VRecTemp(:, pvbsCurrentColumn) - pvbsCurrentCorrectionFlag * pvbsCurrentCorrectionAmount;
- end
- % fill cells
- experiment.metadata{end + 1} = [];
- experiment.fileName{end + 1} = fName; % just to make file name and path readily accessible
- experiment.filePath{end + 1} = fPath;
- experiment.sweeps{end + 1} = sweeps;
- results{end + 1} = struct;
- % fill cells within cells (... interlinked)
- VOutName = {cell(sweeps, 1)};
- VOut = {cell(sweeps, 1)};
- VRecMetadata = {cell(sweeps, 1)};
- VRec = {cell(sweeps, 1)};
- VRecOriginal = {cell(sweeps, 1)};
- %lineScanMetadata = {cell(sweeps, 1)};
- lineScanFile = {cell(sweeps, 1)};
- lineScan = {cell(sweeps, 1)};
- lineScanF = {cell(sweeps, 1)};
- lineScanDFF = {cell(sweeps, 1)};
- lineScanDFFOriginal = {cell(sweeps, 1)};
- lineScanCSVFile = {cell(sweeps, 1)};
- lineScanCSV = {cell(sweeps, 1)};
- lineScanFChannel = {cell(sweeps, 1)};
- lineScanROI = {cell(sweeps, 1)};
- postprocessing = [];
- artifactRemoval = [];
- markPointsMetadata = {cell(sweeps, 1)};
- markPointsIdx = {cell(sweeps, 1)};
- intrinsicProperties = struct(); % struct, not cell
- intrinsicPropertiesVRec = {cell(1)};
- intrinsicPropertiesVRecMetadata = struct();
- intrinsicPropertiesFileName = [];
- zStack = {cell(1)}; % only one
- zStackFileName = [];
- singleScan = {cell(1)}; % only one as representative, since saving all of them will be overwhelming for file size %%% what was this?
- singleScanFileName = [];
- sweepIdx = 1:sweeps;
- sweepStr = cell(sweeps, 1);
- for i = 1:sweeps
- VRecMetadata{i} = [];
- sweepStr{i} = num2str(i);
- VOutName{i} = [];
- VOut{i} = []; % let's just read the file name and not the actual file, since that one's insane
- end
- groupIdx = {}; % groupIdx = {cell(sweeps, 1)};
- groupStr = {};
- if sweeps == 1 % just for convenience if there's only one sweep
- groupIdx{end + 1} = 1;
- groupStr{end + 1} = '1';
- end
- notes = {};
- postprocessing = [h.params.actualParams.boxcarLength1, h.params.actualParams.besselFreq1, h.params.actualParams.besselOrder1];
- postprocessing = [postprocessing; [h.params.actualParams.boxcarLength2, h.params.actualParams.besselFreq2, h.params.actualParams.besselOrder2]];
- % fill sweeps
- if csvColumnsAsSweeps
- for i = 1:sweeps
- VRec{i} = [VRecTemp(:, timeColumn), VRecTemp(:, nonTimeColumn(i))];
- end
- else
- VRec{1} = VRecTemp;
- end
- VRecOriginal = VRec;
- % postprocessing - if applicable
- % this block now moved up in different parts to accommodate multiple-sweep .csv
- %{
- % load VRec
- VRecMetadata{1} = [];
- VRecFile = [fPath, fName];
- VRecTemp = csvread([fPath, fName], csvOffsetRow, csvOffsetColumn); % offset row by 1 ("time(ms), input 0, input 1"), and column by 0
- % this bizzare step has to be taken, because Prairie
- VRecTemp(:, pvbsVoltageColumn) = VRecTemp(:, pvbsVoltageColumn)*pvbsVoltageScalingFactor;
- VRecTemp(:, pvbsCurrentColumn) = VRecTemp(:, pvbsCurrentColumn)*pvbsCurrentScalingFactor;
- pvbsCurrentCorrectionAmount = nanmean(VRecTemp(1:pvbsCurrentCorrectionDataPoints, pvbsCurrentColumn));
- VRecTemp(:, pvbsCurrentColumn) = VRecTemp(:, pvbsCurrentColumn) - pvbsCurrentCorrectionFlag * pvbsCurrentCorrectionAmount;
- % - end of PV correction -
- VRec = VRecTemp;
- VRecOriginal = VRecTemp;
- VOutName = [];
- VOut = []; % let's just read the file name and not the actual file, since that one's insane
- %}
- % update experiment count and cell list
- experiment.experimentCount = experiment.experimentCount + 1;
- cellList{end + 1} = fName(1:end-4); % getting rid of the extension
- set(cellListDisplay, 'string', cellList);
- % save
- data.fileType{end + 1} = 'CSV';
- data.VRecMetadata{end + 1} = VRecMetadata;
- data.VRec{end + 1} = VRec;
- data.VRecOriginal{end + 1} = VRecOriginal;
- data.VOutName{end + 1} = VOutName;
- data.VOut{end + 1} = VOut;
- data.lineScan{end + 1} = lineScan;
- data.lineScanF{end + 1} = lineScanF;
- data.lineScanDFF{end + 1} = lineScanDFF;
- data.lineScanDFFOriginal{end + 1} = lineScanDFFOriginal;
- data.lineScanCSV{end + 1} = lineScanCSV;
- data.lineScanFChannel{end + 1} = lineScanFChannel;
- data.lineScanROI{end + 1} = lineScanROI;
- data.lineScanBaseline{end + 1} = lineScanBaseline;
- data.postprocessing{end + 1} = postprocessing;
- data.artifactRemoval{end + 1} = artifactRemoval;
- data.markPointsMetadata{end + 1} = markPointsMetadata;
- data.markPointsIdx{end + 1} = markPointsIdx;
- data.intrinsicProperties{end + 1} = intrinsicProperties;
- data.intrinsicPropertiesVRec{end + 1} = intrinsicPropertiesVRec;
- data.intrinsicPropertiesVRecMetadata{end + 1} = intrinsicPropertiesVRecMetadata;
- data.intrinsicPropertiesFileName{end + 1} = intrinsicPropertiesFileName;
- data.zStack{end + 1} = zStack;
- data.zStackFileName{end + 1} = zStackFileName;
- data.singleScan{end + 1} = singleScan;
- data.singleScanFileName{end + 1} = singleScanFileName;
- data.sweepIdx{end + 1} = sweepIdx;
- data.sweepStr{end + 1} = sweepStr;
- data.groupIdx{end + 1} = groupIdx;
- data.groupStr{end + 1} = groupStr;
- data.notes{end + 1} = notes;
- experiment.data = data;
- h.exp = experiment;
- h.results = results;
- h.ui.cellList = cellList;
- h.ui.cellListDisplay = cellListDisplay;
- end
- function h = loadABF(h, fPath, fName, actualParams)
- % modified loadExpMain() for .ABF
- % what an irony writing this after returning to pClamp...
- % because PV records data in its own units, data must be scaled appropriately
- % hard-coding here, instead of digging again into insane PV metadata
- % below are set for MC700B with Rf = 500 MO and usual gain settings for whole-cell recordings
- pvbsVoltageScalingFactor = actualParams.pvbsVoltageScalingFactor; % "100 mV" to mV
- pvbsCurrentScalingFactor = actualParams.pvbsCurrentScalingFactor; % "0.1 nA" to pA
- timeColumn = actualParams.timeColumn; % csv column for timestamp
- pvbsVoltageColumn = actualParams.pvbsVoltageColumn; % csv column to apply voltage scaling (column 1 is timestamp, followed by channels)
- pvbsCurrentColumn = actualParams.pvbsCurrentColumn; % csv column to apply current scaling
- csvOffsetRow = actualParams.csvOffsetRow; % row offset while reading csv with csvread() (default: 1)
- csvOffsetColumn = actualParams.csvOffsetColumn; % column offset while reading csv with csvread() (default: 0)
- csvColumnsAsSweeps = actualParams.csvColumnsAsSweeps; % interpret columns as sweeps (default: 0)
- lineScanChannel = actualParams.lineScanChannel; % primary channel for calcium imaging signal; e.g. for P4, 1: red, 2: green (primary)
- lineScanBaseline = actualParams.lineScanBaseline; % (ms), baseline for F_0 in linescans, avoid starting from 0 to prevent possible contamination from shutter artifact
- 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
- lineScanDownsamplingFactor = actualParams.lineScanDownsamplingFactor; % downsampling factor for fluorescence signals, for the dF/F to be robust to noise
- lineScanROISmoothing = actualParams.lineScanDownsamplingFactor; % will average over this many points (before and after) while detecting ROI to be robust from noise - obsolete with single ROI
- lineScanROIThreshold = actualParams.lineScanROIThreshold; % (s.d.); z-score for 1st quartile
- lineScanBackgroundThreshold = actualParams.lineScanBackgroundThreshold; % (s.d.); z-score for 67th percentile
- offloadMarkPointsMetadata = actualParams.offloadMarkPointsMetadata; % delete markpoints metadata after retrieving point indices to save space (0: no, 1: yes)
- % PV GPIO box can quite unbelievably also introduce current measurement error
- % via bleedthrough across channels, which has to be corrected if present
- % otherwise, there will be "phantom" DC injection present in data
- % DO NOT use if recordings DO have intentional baseline DC injection at the beginning!
- % DO NOT be confused with having incorrect bias current settings from amplifier!
- pvbsCurrentCorrectionFlag = actualParams.pvbsCurrentCorrectionFlag; % set to 1 to correct, 0 to leave as is
- pvbsCurrentCorrectionDataPoints = actualParams.pvbsCurrentCorrectionDataPoints; % this many points at the beginning will be used for baseline correction
- % load
- experiment = h.exp;
- data = experiment.data;
- results = h.results;
- cellList = h.ui.cellList;
- cellListDisplay = h.ui.cellListDisplay;
- % prompt
- fprintf(' %s%s ', fPath, fName);
- % load file
- %%% fixlater: csvColumnsAsSweeps assumes "correct" values, i.e. not scaled - this will create confusion when reading .csv saved from PV
- VRecFile = [fPath, fName];
- %VRecTemp = csvread([fPath, fName], csvOffsetRow, csvOffsetColumn); % offset row by 1 ("time(ms), input 0, input 1"), and column by 0
- [abfTemp, abfSamplingInterval, abfMetadata] = abfload_pvbs(VRecFile); % abfMetadata is not very informative, can disregard
- abfSamplingInterval = abfSamplingInterval/1000; % converting from us to ms
- %%{
- try
- % load parameters
- %h = guidata(win1);
- params = h.params;
- analysisParameters = h.params.actualParams;
- analysisParametersDefault = h.params.defaultParams;
- abfUnits = abfMetadata.recChUnits;
- abfSignals = length(abfUnits);
- %{
- if abfSignals > 2
- warningString = sprintf(' Warning: more than 2 signals present - displaying first two only\n');
- fprintf(warningString);
- elseif abfSignals == 2 % dual recordings
- else % single recordings
- end
- %}
- for i = 1:abfSignals %%% fixlater - che puzza, this is being overwritten for every experiment loaded
- try % ditto; but should be irrelevant because this feature was missing
- if i == 1
- if strcmp(abfUnits(i), 'pA')
- signal1Type = 1; % current, voltage, fluorescence
- elseif strcmp(abfUnits(i), 'nA') % in case someone has a very bad taste
- signal1Type = 1; % current, voltage, fluorescence
- elseif strcmp(abfUnits(i), 'mV')
- signal1Type = 2; % current, voltage, fluorescence
- 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"?
- signal1Type = 2; % current, voltage, fluorescence
- else % don't know what to do, so leave it alone for now %%% fixlater
- signal1Type = 2; % current, voltage, fluorescence - defaulting to voltage, vestige from 46
- end
- signal1Channel = 2; % for .abf timestamp will not be present initially upon loading with abfload(), but will be appended at the end of this function
- h.params.actualParams.signal1Channel = signal1Channel;
- h.params.actualParams.signal1Type = signal1Type;
- h.params.defaultParams.signal1Channel = signal1Channel;
- h.params.defaultParams.signal1Type = signal1Type;
- signal2Type = signal1Type; % this is really only for aesthetics, for axis label
- signal2Channel = 0; % to suppress signal 2 display in a very crude stupid way %%% fixlater %%% cazzo
- h.params.actualParams.signal2Channel = signal2Channel;
- h.params.actualParams.signal2Type = signal2Type;
- h.params.defaultParams.signal2Channel = signal2Channel;
- h.params.defaultParams.signal2Type = signal2Type;
- else
- if strcmp(abfUnits(i), 'pA')
- signal2Type = 1; % current, voltage, fluorescence
- elseif strcmp(abfUnits(i), 'nA') % in case someone has a very bad taste
- signal2Type = 1; % current, voltage, fluorescence
- elseif strcmp(abfUnits(i), 'mV')
- signal2Type = 2; % current, voltage, fluorescence
- 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"?
- signal2Type = 2; % current, voltage, fluorescence
- else % don't know what to do, so leave it alone for now %%% fixlater
- 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)
- end
- signal2Channel = 2; % for .abf timestamp will not be present initially upon loading with abfload(), but will be appended at the end of this function
- h.params.actualParams.signal2Channel = signal2Channel;
- h.params.actualParams.signal2Type = signal2Type;
- h.params.defaultParams.signal2Channel = signal2Channel;
- h.params.defaultParams.signal2Type = signal2Type;
- end
- catch ME
- end
- end
- catch ME
- end
- %}
- csvColumnsAsSweeps = 0; % override this for .abf; NB. see start of function for definition intended for the original function loadCSV()
- if csvColumnsAsSweeps
- %%% look here!
- % force scaling factor = 1
- pvbsVoltageScalingFactor = 1;
- pvbsCurrentScalingFactor = 1;
- % force reading data as voltage
- pvbsCurrentColumn = 0;
- % force no column/row offset
- csvOffsetRow = 0;
- csvOffsetColumn = 0;
- timeColumn = 0; % override this for .abf; NB. see start of function for definition intended for the original function loadCSV()
- %{
- if timeColumn % timestamp column is present
- sweeps = size(VRecTemp, 2); % each column represents a sweep
- nonTimeColumn = 1:sweeps; % do this first
- nonTimeColumn = nonTimeColumn(nonTimeColumn ~= timeColumn);
- sweeps = sweeps - 1; % since one column is for timestamp and not an actual sweep
- else
- sweeps = size(VRecTemp, 2); % each column represents a sweep
- nonTimeColumn = 1:sweeps;
- nonTimeColumn = nonTimeColumn(nonTimeColumn ~= timeColumn);
- end
- %}
- sweeps = size(abfTemp, 3); % could also be fetched from metadata: sweeps = abfMetadata.lActualEpisodes;
- nonTimeColumn = 1:sweeps;
- nonTimeColumn = nonTimeColumn(nonTimeColumn ~= timeColumn);
- % pv bleedthrough correction
- %{
- if pvbsVoltageColumn ~= 0
- if pvbsCurrentColumn == 0 % just adding for possible future use of the next else block
- VRecTemp(:, nonTimeColumn) = VRecTemp(:, nonTimeColumn)*pvbsVoltageScalingFactor;
- else % if both are nonzero, default to interpret as voltage
- VRecTemp(:, nonTimeColumn) = VRecTemp(:, nonTimeColumn)*pvbsVoltageScalingFactor;
- end
- elseif pvbsCurrentColumn == 0 % if both are 0, again default to interpret as voltage; this could be used later to interpret as F instead %%% fixlater
- VRecTemp(:, nonTimeColumn) = VRecTemp(:, nonTimeColumn)*pvbsVoltageScalingFactor;
- else % now interpret as current
- VRecTemp(:, nonTimeColumn) = VRecTemp(:, nonTimeColumn)*pvbsCurrentScalingFactor;
- pvbsCurrentCorrectionAmount = nanmean(VRecTemp(1:pvbsCurrentCorrectionDataPoints, pvbsCurrentColumn));
- VRecTemp(:, pvbsCurrentColumn) = VRecTemp(:, pvbsCurrentColumn) - pvbsCurrentCorrectionFlag * pvbsCurrentCorrectionAmount;
- end
- %}
- else
- %sweeps = 1; % gap-free
- sweeps = size(abfTemp, 3); % could also be fetched from metadata: sweeps = abfMetadata.lActualEpisodes;
- % pv bleedthrough correction
- %{
- VRecTemp(:, pvbsVoltageColumn) = VRecTemp(:, pvbsVoltageColumn)*pvbsVoltageScalingFactor;
- VRecTemp(:, pvbsCurrentColumn) = VRecTemp(:, pvbsCurrentColumn)*pvbsCurrentScalingFactor;
- pvbsCurrentCorrectionAmount = nanmean(VRecTemp(1:pvbsCurrentCorrectionDataPoints, pvbsCurrentColumn));
- VRecTemp(:, pvbsCurrentColumn) = VRecTemp(:, pvbsCurrentColumn) - pvbsCurrentCorrectionFlag * pvbsCurrentCorrectionAmount;
- %}
- end
- % fill cells
- experiment.metadata{end + 1} = [];
- experiment.fileName{end + 1} = fName; % just to make file name and path readily accessible
- experiment.filePath{end + 1} = fPath;
- experiment.sweeps{end + 1} = sweeps;
- results{end + 1} = struct;
- % fill cells within cells (... interlinked)
- VOutName = {cell(sweeps, 1)};
- VOut = {cell(sweeps, 1)};
- VRecMetadata = {cell(sweeps, 1)};
- VRec = {cell(sweeps, 1)};
- VRecOriginal = {cell(sweeps, 1)};
- %lineScanMetadata = {cell(sweeps, 1)};
- lineScanFile = {cell(sweeps, 1)};
- lineScan = {cell(sweeps, 1)};
- lineScanF = {cell(sweeps, 1)};
- lineScanDFF = {cell(sweeps, 1)};
- lineScanDFFOriginal = {cell(sweeps, 1)};
- lineScanCSVFile = {cell(sweeps, 1)};
- lineScanCSV = {cell(sweeps, 1)};
- lineScanFChannel = {cell(sweeps, 1)};
- lineScanROI = {cell(sweeps, 1)};
- postprocessing = [];
- artifactRemoval = [];
- markPointsMetadata = {cell(sweeps, 1)};
- markPointsIdx = {cell(sweeps, 1)};
- intrinsicProperties = struct(); % struct, not cell
- intrinsicPropertiesVRec = {cell(1)};
- intrinsicPropertiesVRecMetadata = struct();
- intrinsicPropertiesFileName = [];
- zStack = {cell(1)}; % only one
- zStackFileName = [];
- singleScan = {cell(1)}; % only one as representative, since saving all of them will be overwhelming for file size %%% what was this?
- singleScanFileName = [];
- sweepIdx = 1:sweeps;
- sweepStr = cell(sweeps, 1);
- for i = 1:sweeps
- VRecMetadata{i} = [];
- sweepStr{i} = num2str(i);
- VOutName{i} = [];
- VOut{i} = []; % let's just read the file name and not the actual file, since that one's insane
- end
- groupIdx = {}; % groupIdx = {cell(sweeps, 1)};
- groupStr = {};
- if sweeps == 1 % just for convenience if there's only one sweep
- groupIdx{end + 1} = 1;
- groupStr{end + 1} = '1';
- end
- notes = {};
- postprocessing = [h.params.actualParams.boxcarLength1, h.params.actualParams.besselFreq1, h.params.actualParams.besselOrder1];
- postprocessing = [postprocessing; [h.params.actualParams.boxcarLength2, h.params.actualParams.besselFreq2, h.params.actualParams.besselOrder2]];
- % fill sweeps
- %{
- if csvColumnsAsSweeps
- for i = 1:sweeps
- VRec{i} = [VRecTemp(:, timeColumn), VRecTemp(:, nonTimeColumn(i))];
- end
- else
- VRec{1} = VRecTemp;
- end
- %}
- % makeshift code for abf support %%% fixlater
- abfCh1Column = pvbsVoltageColumn - 1;
- abfCh2Column = pvbsCurrentColumn - 1;
- %VRec1 = abfTemp(:, abfCh1Column, :);
- %VRec2 = abfTemp(:, abfCh2Column, :);
- %VRec = abfTemp(:, abfCh1Column, :);
- if abfSignals > 2
- warningString = sprintf(' Warning: more than 2 signals present - displaying first two only\n');
- fprintf(warningString);
- VRec1 = abfTemp(:, abfCh1Column, :);
- VRec2 = abfTemp(:, abfCh2Column, :);
- VRec = [VRec1, VRec2];
- h.params.actualParams.signal1Channel = abfCh1Column + 1; % +1 is necessary... stupid coding as usual by me, will surely regret this later
- h.params.actualParams.signal2Channel = abfCh2Column + 1;
- h.params.defaultParams.signal1Channel = abfCh1Column + 1;
- h.params.defaultParams.signal2Channel = abfCh2Column + 1;
- elseif abfSignals == 2 % dual recordings
- VRec1 = abfTemp(:, abfCh1Column, :);
- VRec2 = abfTemp(:, abfCh2Column, :);
- VRec = [VRec1, VRec2];
- h.params.actualParams.signal1Channel = abfCh1Column + 1;
- h.params.actualParams.signal2Channel = abfCh2Column + 1;
- h.params.defaultParams.signal1Channel = abfCh1Column + 1;
- h.params.defaultParams.signal2Channel = abfCh2Column + 1;
- else % single recordings
- VRec = abfTemp(:, abfCh1Column, :);
- end
- timeStampColumn = 0 : abfSamplingInterval : abfSamplingInterval*(size(abfTemp, 1) - 1);
- timeStampColumn = timeStampColumn';
- VRecTempTemp = {};
- for i = 1:size(VRec, 3) % unfortunate redundancy but better than not taking advantage of abfload()
- VRecTemp = VRec(:,:,i);
- VRecTemp = [timeStampColumn, VRecTemp];
- VRecTempTemp{end + 1} = VRecTemp;
- end
- VRec = VRecTempTemp;
- VRecOriginal = VRec;
- % postprocessing - if applicable
- % this block now moved up in different parts to accommodate multiple-sweep .csv
- %{
- % load VRec
- VRecMetadata{1} = [];
- VRecFile = [fPath, fName];
- VRecTemp = csvread([fPath, fName], csvOffsetRow, csvOffsetColumn); % offset row by 1 ("time(ms), input 0, input 1"), and column by 0
- % this bizzare step has to be taken, because Prairie
- VRecTemp(:, pvbsVoltageColumn) = VRecTemp(:, pvbsVoltageColumn)*pvbsVoltageScalingFactor;
- VRecTemp(:, pvbsCurrentColumn) = VRecTemp(:, pvbsCurrentColumn)*pvbsCurrentScalingFactor;
- pvbsCurrentCorrectionAmount = nanmean(VRecTemp(1:pvbsCurrentCorrectionDataPoints, pvbsCurrentColumn));
- VRecTemp(:, pvbsCurrentColumn) = VRecTemp(:, pvbsCurrentColumn) - pvbsCurrentCorrectionFlag * pvbsCurrentCorrectionAmount;
- % - end of PV correction -
- VRec = VRecTemp;
- VRecOriginal = VRecTemp;
- VOutName = [];
- VOut = []; % let's just read the file name and not the actual file, since that one's insane
- %}
- % update experiment count and cell list
- experiment.experimentCount = experiment.experimentCount + 1;
- cellList{end + 1} = fName(1:end-4); % getting rid of the extension
- set(cellListDisplay, 'string', cellList);
- % save
- data.fileType{end + 1} = 'ABF';
- data.VRecMetadata{end + 1} = VRecMetadata;
- data.VRec{end + 1} = VRec;
- data.VRecOriginal{end + 1} = VRecOriginal;
- data.VOutName{end + 1} = VOutName;
- data.VOut{end + 1} = VOut;
- data.lineScan{end + 1} = lineScan;
- data.lineScanF{end + 1} = lineScanF;
- data.lineScanDFF{end + 1} = lineScanDFF;
- data.lineScanDFFOriginal{end + 1} = lineScanDFFOriginal;
- data.lineScanCSV{end + 1} = lineScanCSV;
- data.lineScanFChannel{end + 1} = lineScanFChannel;
- data.lineScanROI{end + 1} = lineScanROI;
- data.lineScanBaseline{end + 1} = lineScanBaseline;
- data.postprocessing{end + 1} = postprocessing;
- data.artifactRemoval{end + 1} = artifactRemoval;
- data.markPointsMetadata{end + 1} = markPointsMetadata;
- data.markPointsIdx{end + 1} = markPointsIdx;
- data.intrinsicProperties{end + 1} = intrinsicProperties;
- data.intrinsicPropertiesVRec{end + 1} = intrinsicPropertiesVRec;
- data.intrinsicPropertiesVRecMetadata{end + 1} = intrinsicPropertiesVRecMetadata;
- data.intrinsicPropertiesFileName{end + 1} = intrinsicPropertiesFileName;
- data.zStack{end + 1} = zStack;
- data.zStackFileName{end + 1} = zStackFileName;
- data.singleScan{end + 1} = singleScan;
- data.singleScanFileName{end + 1} = singleScanFileName;
- data.sweepIdx{end + 1} = sweepIdx;
- data.sweepStr{end + 1} = sweepStr;
- data.groupIdx{end + 1} = groupIdx;
- data.groupStr{end + 1} = groupStr;
- data.notes{end + 1} = notes;
- experiment.data = data;
- h.exp = experiment;
- h.results = results;
- h.ui.cellList = cellList;
- h.ui.cellListDisplay = cellListDisplay;
- end
- %% Trace Display
- function h = displayTrace(h, itemSelected)
- % load
- params = h.params;
- VRec = h.exp.data.VRec;
- traceDisplay = h.ui.traceDisplay;
- axes(traceDisplay); % absolutely necessary - bring focus to main display, since other functions might have brought it to another axes
- % clear display
- trace = {}; % clear current plot
- analysisWindowHandle = {}; % clear current analysis window display
- axes(traceDisplay);
- yyaxis left; cla;
- yyaxis right; cla;
- yyaxis left;
- % clear sweep list items
- sweepListDisplay = h.ui.sweepListDisplay;
- sweepList = {};
- groupListDisplay = h.ui.groupListDisplay;
- % axis range information
- traceDisplayYRange = h.ui.traceDisplayYRange; % y range; to be shared across experiments
- traceDisplayY2Range = h.ui.traceDisplayY2Range; % y range; to be shared across experiments
- traceDisplayXRange = h.ui.traceDisplayXRange; % x range; to be shared across experiments
- % break if invalid - for when called before loading experiments
- if isempty(VRec)
- return
- end
- % experiment to display
- try % try-catch for reverse compatibility
- timeColumnAvailable = h.params.actualParams.timeColumnAvailable;
- catch ME
- timeColumn = 1;
- timeColumnAvailable = 1;
- h.params.actualParams.timeColumn = timeColumn;
- h.params.actualParams.timeColumnAvailable = timeColumnAvailable;
- end
- try % ditto
- signal1Type = h.params.actualParams.signal1Type; % current, voltage, fluorescence
- signal2Type = h.params.actualParams.signal2Type; % current, voltage, fluorescence
- signal1Channel = h.params.actualParams.signal1Channel; % corresponding to data column, but mind timestamp availability
- signal2Channel = h.params.actualParams.signal2Channel; % corresponding to data column, but mind timestamp availability
- catch ME
- signal1Type = 2; % current, voltage, fluorescence - defaulting to voltage
- signal2Type = 3; % current, voltage, fluorescence - defaulting to fluorescence
- try % additional layer of safety
- signal1Channel = h.params.actualParams.pvbsVoltageColumn; % defaulting to voltage
- signal2Channel = h.params.actualParams.lineScanChannel; % defaulting to fluorescence
- catch ME
- signal1Channel = 2;
- signal2Channel = 2;
- h.params.actualParams.signal1Channel = signal1Channel;
- h.params.actualParams.signal2Channel = signal2Channel;
- h.params.defaultParams.signal1Channel = signal1Channel;
- h.params.defaultParams.signal2Channel = signal2Channel;
- end
- end
- columnTimeStamp = h.params.actualParams.timeColumn;
- %columnToDisplay = h.params.actualParams.pvbsVoltageColumn; %%% fixlater
- itemToDisplay = itemSelected(1); % display only the first one if multiple items are selected - obsolete
- VRecToDisplay = VRec{itemToDisplay};
- if iscell(VRecToDisplay)
- sweepCount = length(VRecToDisplay);
- if sweepCount == 1
- VRecToDisplay = VRecToDisplay{1};
- end
- else
- sweepCount = 1;
- end
- sweepIdx = h.exp.data.sweepIdx{itemSelected};
- sweepStr = h.exp.data.sweepStr{itemSelected};
- groupIdx = h.exp.data.groupIdx{itemSelected};
- groupStr = h.exp.data.groupStr{itemSelected};
- % do display
- axes(traceDisplay);
- %xlabel('t (ms)', 'color', 'k');
- try % use try-catch here
- workingAxis = 1;
- if signal1Type == 3 % i, V, F
- displayTraceF(workingAxis);
- elseif signal1Type == 1
- displayTraceV(workingAxis); % can't think of a better name; also separate axis labeling from this function
- else % default to V in case signal1Type is incorrectly set due to whatever miracle
- displayTraceV(workingAxis); % can't think of a better name; also separate axis labeling from this function
- end
- catch ME
- errorString = sprintf(' \nWarning: invalid display parameters (Axis #%s) - check signal channels\n', num2str(workingAxis));
- %error(errorString);
- fprintf(errorString); % not exactly an error
- yyaxis left; % return to left axis as a failsafe
- %return
- end
- try % use try-catch here
- workingAxis = 2;
- if signal2Type == 3 % i, V, F
- displayTraceF(workingAxis);
- elseif signal2Type == 1
- displayTraceV(workingAxis); % can't think of a better name; also separate axis labeling from this function
- else % default to V in case signal1Type is incorrectly set due to whatever miracle
- displayTraceV
pvbs.m at commit 92d713d, under GPL-3.0 · at the source
Overview
- F. M. Kirby Neurobiology Center, Boston Children's Hospital, Boston, MA, United States
- Department of Neurology, Harvard Medical School, Boston, MA, United States
- Department of Neurobiology, Harvard Medical School, Boston, MA, United States
- Department of Neurosurgery, Boston Children's Hospital, Boston, MA, United States
- Department of Neurosurgery, Harvard Medical School, Boston, MA, United States
- Department of Pathology, Boston Children's Hospital, Boston, MA, United States
- Department of Pathology, Harvard Medical School, Boston, MA, United States
- Zander & Wyss Translational Neuroscience Center, Boston Children's Hospital, Boston, MA, United States
- Department of Genetics, Harvard Medical School, Boston, MA, United States
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/
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
92d713d76616ca3bf67aecaef1222b72f9f5ce01, 30 May 2025Availability: 1 check, the latest on 27 September 2026: the link answers
- 27 September 2026: the link answers
3 files
- pvbs.m — MATLAB, 3,320 lines, 2 matches
- LICENSE — License, 674 lines
- readme.txt — Text, 52 lines
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/
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://
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/
url = {https://
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/
VL - 18
SP - 1843277
SN - 1663-3563
PB - Frontiers Media SA
DO - 10.3389/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.3389/
"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":
"volume": "18",
"page": "1843277",
"DOI": "10.3389/
"PMID": "42433477",
"PMCID": "PMC13352477",
"ISSN": "1663-3563",
"publisher": "Frontiers Media SA",
"URL": "https://
"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 biologyIn 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 NeuroTherapeuticsIn 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 neuroscienceIn 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 biologyIn 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 neuroscienceIn 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: EBioMedicineIn 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 communicationsIn 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 communicationsIn 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 reportsIn 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.
Claim this paper
Correct its record
Say what each link of this record is, remove the ones that are not the paper's, add the ones that are missing. The correction becomes a new version of the record, in its Versions section.
Validate its tracing map
You validate the map as this page shows it: 1 repository of the authors' code, each at its verified commit and with its license, 1 script, and 2 matches between paragraphs and code (see the Code and Map sections). It then receives a DOI on Zenodo, with you (your ORCID iD) and OSCR as its creators; the code itself is not deposited.
The map's fingerprint: sha256:4f60977785ffa2bd…
Add the badge to its README
The badge links the code to this page. Copy one of these into the README of the paper's code: only you decide where it goes, and nothing is changed for you.
Markdown
[, paste the snippet at the top, then “Commit changes…” and, to review it first, “Create a new branch and start a pull request”. You open the pull request; OSCR asks for no permission.
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.
