From 9b538eee69c87a160a01cd22f96d7b4111702db6 Mon Sep 17 00:00:00 2001 From: "Nina Valerie Wiedemann (ninwie)" Date: Fri, 13 Dec 2019 15:49:08 +0100 Subject: [PATCH 1/9] added button for physio batch --- api-matlab/rtQC_display.m | 17 +++++ api-matlab/rtQC_display_setup.m | 22 +++++-- api-matlab/wrapper_physiobatch.m | 110 +++++++++++++++++++++++++++++++ 3 files changed, 145 insertions(+), 4 deletions(-) create mode 100644 api-matlab/wrapper_physiobatch.m diff --git a/api-matlab/rtQC_display.m b/api-matlab/rtQC_display.m index a85544e..f0d8150 100644 --- a/api-matlab/rtQC_display.m +++ b/api-matlab/rtQC_display.m @@ -59,6 +59,7 @@ function rtQC_display() % Setup all UIcontrols and GUI components rtQC_display_setup; + % Set callbacks gui_data.tgroup.SelectionChangedFcn = @tabChangedCallback; gui_data.pb_help.Callback = @linkToGithub; @@ -91,6 +92,7 @@ function rtQC_display() gui_data.pb_startRT.Callback = @startRT; gui_data.pb_stopRT.Callback = @stopRT; gui_data.popup_setDim.Callback = @setDim; +gui_data.popup_setVendor.Callback = @setVendor; gui_data.sld_slice.Callback = @changeSlice; gui_data.popup_setImg.Callback = @setImg; gui_data.edit_structural_pre.Callback = @editStructural; @@ -113,6 +115,7 @@ function rtQC_display() gui_data.QCtgroup.SelectionChangedFcn = @QCtabChangedCallback; gui_data.pb_open_qc_post.Callback = @generateReport; +gui_data.pb_get_physio_batch.Callback = @physioBatch; set(findall(fig, '-property', 'Interruptible'), 'Interruptible', 'on') @@ -1099,6 +1102,9 @@ function drawTHEPLOT(fig) % guidata(fig, gui_data); end +function setVendor(hObject,eventdata) + +end function setDim(hObject,eventdata) @@ -1456,6 +1462,17 @@ function generateReport(hObject,eventdata) end +function physioBatch(hObject,eventdata) + fig = ancestor(hObject,'figure'); + gui_data = guidata(fig); + + vendor = gui_data.popup_setVendor.String(gui_data.popup_setVendor.Value); + disp("Vendor:"); + disp(vendor); + wrapper_physiobatch('BIDS', 16, 1.45, 408, 0, 1, 'C:\Users\nwiedemann\Downloads\physio_out'); + % wrapper_physiobatch(data_vendor, nr_slices, TR, nr_scans, nr_dummies, onset_slice, out_dir); +end + function showFDoutliers(hObject,eventdata) fig = ancestor(hObject,'figure'); gui_data = guidata(fig); diff --git a/api-matlab/rtQC_display_setup.m b/api-matlab/rtQC_display_setup.m index 184bfe7..a390231 100644 --- a/api-matlab/rtQC_display_setup.m +++ b/api-matlab/rtQC_display_setup.m @@ -964,7 +964,7 @@ 'Style', 'push',... 'String', 'Show FD outliers', ... 'Units', 'Normalized',... - 'Position', [0.8 0.7 0.18 0.3],... + 'Position', [0.8 0.795 0.18 0.225],... 'CallBack', @showFDoutliers, ... 'UserData', 0,... 'fontsize', gui_data.button_font_size); @@ -972,7 +972,7 @@ 'Style', 'push',... 'String', 'Run Offline QC', ... 'Units', 'Normalized',... - 'Position', [0.8 0.38 0.18 0.3],... + 'Position', [0.8 0.55 0.18 0.225],... 'CallBack', @runOfflineQC, ... 'UserData', 0,... 'fontsize', gui_data.button_font_size); @@ -980,11 +980,25 @@ 'Style', 'push',... 'String', 'Generate report', ... 'Units', 'Normalized',... - 'Position', [0.8 0.06 0.18 0.3],... + 'Position', [0.8 0.06 0.18 0.225],... 'CallBack', @generateReport, ... 'UserData', 0,... 'fontsize', gui_data.button_font_size); - +gui_data.pb_get_physio_batch = uicontrol('Parent', gui_data.panel_rtsummary,... + 'Style', 'push',... + 'String', 'Get physio batch', ... + 'Units', 'Normalized',... + 'Position', [0.8 0.305 0.18 0.225],... + 'CallBack', @physioBatch, ... + 'UserData', 0,... + 'fontsize', gui_data.button_font_size); +gui_data.popup_setVendor = uicontrol('Parent', gui_data.panel_volumes,... + 'Style', 'popup',... + 'String', {'BIDS','Philips','Biopac_Txt','GE','Siemens','Siemens_HCP','Siemens_Tics'},... + 'Units', 'Normalized',... + 'Position', [0.73 0.305 0.05 0.225],... + 'Value', 1,... + 'Callback', @setVendor); % Offline summary panel UIcontrols gui_data.QCtgroup = uitabgroup('Parent', gui_data.panel_qcsummaryL,... diff --git a/api-matlab/wrapper_physiobatch.m b/api-matlab/wrapper_physiobatch.m new file mode 100644 index 0000000..c37b6d8 --- /dev/null +++ b/api-matlab/wrapper_physiobatch.m @@ -0,0 +1,110 @@ +function matlabbatch = wrapper_physiobatch(data_vendor, nr_slices, TR, nr_scans, nr_dummies, onset_slice, out_dir) + spm_jobman('initcfg'); + global defaults + defaults.stats.maxmem = 2^30; + matlabbatch = {}; + + % defaul path for spm inputs: + default_path = 'C:\Users\nwiedemann\Downloads\tapas\tapas\misc\example\PhysIO'; + + matlabbatch{1}.spm.tools.physio.save_dir = {out_dir}; + matlabbatch{1}.spm.tools.physio.log_files.vendor = data_vendor; + + % EXAMPLES IN C:\Users\nwiedemann\Downloads\tapas\tapas\misc\example\PhysIO + + % different vendor options require different file input + if strcmp(data_vendor, 'BIDS') + [tsv_filename, ~] = spm_select(1,'.*.tsv.*','Specify tsv/tsv.gz file with ECG data',{}, default_path); + % tsv_filename = input(['For BIDS, you only need to specify the tsv/tsv.gz file containing 3 columns without header.' ... + % 'There must be a json with the same file name in the same folder containing metainformation'], 's'); + matlabbatch{1}.spm.tools.physio.log_files.cardiac = {tsv_filename}; + matlabbatch{1}.spm.tools.physio.log_files.respiration = {''}; + matlabbatch{1}.spm.tools.physio.log_files.scan_timing = {''}; + elseif strcmp(data_vendor, 'Philips') + [scanphyslog, ~] = spm_select(1,'.*.log','Specify SCANPHYSLOG.log file',{}, default_path); + % scanphyslog = input('Specify file path to SCANPHYSLOG.log file', 's'); + matlabbatch{1}.spm.tools.physio.log_files.cardiac = {scanphyslog}; + matlabbatch{1}.spm.tools.physio.log_files.respiration = {scanphyslog}; + matlabbatch{1}.spm.tools.physio.log_files.scan_timing = {scanphyslog}; % or empty? + elseif strcmp(data_vendor, 'Biopac_Txt') + [scanphyslog, ~] = spm_select(1,'.*.txt','Specify biopac data export txt file',{}, default_path); + % scanphyslog = input('Specify file path to the biopac data export txt file', 's'); + matlabbatch{1}.spm.tools.physio.log_files.cardiac = {scanphyslog}; + matlabbatch{1}.spm.tools.physio.log_files.respiration = {scanphyslog}; + matlabbatch{1}.spm.tools.physio.log_files.scan_timing = {scanphyslog}; + elseif strcmp(data_vendor, 'GE') + [cardiac, ~] = spm_select(1,'any','Specify cardiac file (starting with ECGData_)',{}, default_path); + % cardiac = input('Specify file path to the cardiac file (in template starting with ECGData_)', 's'); + [respiration, ~] = spm_select(1,'any','Specify respiration file (starting with RespData_)',{}, default_path); + % respiration = input('Specify file path to the respiration file (in template starting with RespData_)', 's'); + matlabbatch{1}.spm.tools.physio.log_files.cardiac = {cardiac}; + matlabbatch{1}.spm.tools.physio.log_files.respiration = {respiration}; + matlabbatch{1}.spm.tools.physio.log_files.scan_timing = {''}; + elseif strcmp(data_vendor, 'Siemens_HCP') + [physiolog, ~] = spm_select(1,'any','Specify physio data file (sth like tfMRI_MOTOR_LR_Physio_log.txt)',{}, default_path); + % physiolog = input('Specify file path to the tfMRI_MOTOR_LR_Physio_log.txt file', 's'); + matlabbatch{1}.spm.tools.physio.log_files.cardiac = {physiolog}; + matlabbatch{1}.spm.tools.physio.log_files.respiration = {physiolog}; + matlabbatch{1}.spm.tools.physio.log_files.scan_timing = {''}; + elseif strcmp(data_vendor, 'Siemens') + [physiolog, ~] = spm_select(1,'.*.ecg','Specify physio data file (siemens_PAV.ecg)',{}, default_path); + % physiolog = input('Specify file path to the siemens_PAV.ecg file', 's'); + matlabbatch{1}.spm.tools.physio.log_files.cardiac = {physiolog}; + matlabbatch{1}.spm.tools.physio.log_files.respiration = {''}; + matlabbatch{1}.spm.tools.physio.log_files.scan_timing = {''}; + elseif strcmp(data_vendor, 'Siemens_Tics') + [cardiac, ~] = spm_select(1,'.*.log','Specify cardiac file (..._PULS.log)',{}, default_path); + % cardiac = input('Specify file path to the cardiac file (in template ending with _PULS.log)', 's'); + [respiration, ~] = spm_select(1,'.*.log','Specify respiration file (..._RESP.log)',{}, default_path); + % respiration = input('Specify file path to the respiration file (in template ending with _RESP.log)', 's'); + [timing, ~] = spm_select(1,'.*.log','Specify scan timing file (..._Info.log)',{}, default_path); + % timing = input('Specify file path to the scan timing file (in template ending with _Info.log)', 's'); + matlabbatch{1}.spm.tools.physio.log_files.cardiac = {cardiac}; + matlabbatch{1}.spm.tools.physio.log_files.respiration = {respiration}; + matlabbatch{1}.spm.tools.physio.log_files.scan_timing = {timing}; + else + ME = MException('error:wronginput', 'Wrong vendor specified. Please specify one of BIDS, Philips, Biopac_Txt, GE, Siemens, Siemens_HCP, Siemens_Tics'); + throw(ME); + end + + % scan parameters + matlabbatch{1}.spm.tools.physio.log_files.sampling_interval = []; + matlabbatch{1}.spm.tools.physio.log_files.relative_start_acquisition = 0; + matlabbatch{1}.spm.tools.physio.log_files.align_scan = 'last'; % sometimes first, sometimes last + matlabbatch{1}.spm.tools.physio.scan_timing.sqpar.Nslices = nr_slices; + matlabbatch{1}.spm.tools.physio.scan_timing.sqpar.NslicesPerBeat = []; + matlabbatch{1}.spm.tools.physio.scan_timing.sqpar.TR = TR; + matlabbatch{1}.spm.tools.physio.scan_timing.sqpar.Ndummies = nr_dummies; + matlabbatch{1}.spm.tools.physio.scan_timing.sqpar.Nscans = nr_scans; + matlabbatch{1}.spm.tools.physio.scan_timing.sqpar.onset_slice = onset_slice; + matlabbatch{1}.spm.tools.physio.scan_timing.sqpar.time_slice_to_slice = []; + + % template + matlabbatch{1}.spm.tools.physio.scan_timing.sqpar.Nprep = []; + matlabbatch{1}.spm.tools.physio.scan_timing.sync.nominal = struct([]); + matlabbatch{1}.spm.tools.physio.preproc.cardiac.modality = 'ECG'; + matlabbatch{1}.spm.tools.physio.preproc.cardiac.initial_cpulse_select.auto_matched.min = 0.4; + matlabbatch{1}.spm.tools.physio.preproc.cardiac.initial_cpulse_select.auto_matched.file = 'initial_cpulse_kRpeakfile.mat'; + matlabbatch{1}.spm.tools.physio.preproc.cardiac.posthoc_cpulse_select.off = struct([]); + matlabbatch{1}.spm.tools.physio.model.output_multiple_regressors = 'multiple_regressors.txt'; + matlabbatch{1}.spm.tools.physio.model.output_physio = 'physio.mat'; + matlabbatch{1}.spm.tools.physio.model.orthogonalise = 'none'; + matlabbatch{1}.spm.tools.physio.model.censor_unreliable_recording_intervals = false; + matlabbatch{1}.spm.tools.physio.model.retroicor.yes.order.c = 3; + matlabbatch{1}.spm.tools.physio.model.retroicor.yes.order.r = 4; + matlabbatch{1}.spm.tools.physio.model.retroicor.yes.order.cr = 1; + matlabbatch{1}.spm.tools.physio.model.rvt.no = struct([]); + matlabbatch{1}.spm.tools.physio.model.hrv.no = struct([]); + matlabbatch{1}.spm.tools.physio.model.noise_rois.no = struct([]); + matlabbatch{1}.spm.tools.physio.model.movement.no = struct([]); + matlabbatch{1}.spm.tools.physio.model.other.no = struct([]); + matlabbatch{1}.spm.tools.physio.verbose.level = 2; + matlabbatch{1}.spm.tools.physio.verbose.fig_output_file = ''; + matlabbatch{1}.spm.tools.physio.verbose.use_tabs = false; + +% % alternatively: just save batch +% save(out_dir, 'matlabbatch'); +% disp("Saved matlabbatch."); + + spm_jobman('run',matlabbatch); +end \ No newline at end of file From 56a102dd1666ca341d673dc3d28e5f403eae9f3d Mon Sep 17 00:00:00 2001 From: "Nina Valerie Wiedemann (ninwie)" Date: Wed, 18 Dec 2019 12:31:56 +0100 Subject: [PATCH 2/9] added vendor field, read in params --- api-matlab/rtQC_display.m | 13 +++++++++++-- api-matlab/rtQC_display_setup.m | 14 +++++++++++--- api-matlab/wrapper_physiobatch.m | 15 +++++++++------ 3 files changed, 31 insertions(+), 11 deletions(-) diff --git a/api-matlab/rtQC_display.m b/api-matlab/rtQC_display.m index f0d8150..7d5c924 100644 --- a/api-matlab/rtQC_display.m +++ b/api-matlab/rtQC_display.m @@ -495,6 +495,8 @@ function runPreProc(hObject,eventdata) gui_data.functional0_fn = [gui_data.functional4D_fn ',1']; % Preprocess structural and f0 images [d, f, e] = fileparts(gui_data.structural_fn); +disp(d); +disp(f); if exist([d filesep 'rc1' f e], 'file') % 1) If preprocessing has already been done, assign variables gui_data.preProc_status = 1; @@ -1469,8 +1471,15 @@ function physioBatch(hObject,eventdata) vendor = gui_data.popup_setVendor.String(gui_data.popup_setVendor.Value); disp("Vendor:"); disp(vendor); - wrapper_physiobatch('BIDS', 16, 1.45, 408, 0, 1, 'C:\Users\nwiedemann\Downloads\physio_out'); - % wrapper_physiobatch(data_vendor, nr_slices, TR, nr_scans, nr_dummies, onset_slice, out_dir); + + %% read nr slices and nr scans from nifti header: + % hdr = spm_vol('C:\Users\nwiedemann\Downloads\rtQC_sample_data\rtQC_sample_data\sub-opennft\fanon-0007.nii') + % nr_scans = length(hdr) + % nr_slices = hdr(1).dim(3) + %% + % parameter for BIDS template: 16, 1.45, 408, 0, 1, + disp([gui_data.qc_out_dir filesep 'physio_dir']); + wrapper_physiobatch(char(vendor), [gui_data.qc_out_dir filesep 'physio_dir']); end function showFDoutliers(hObject,eventdata) diff --git a/api-matlab/rtQC_display_setup.m b/api-matlab/rtQC_display_setup.m index a390231..822276c 100644 --- a/api-matlab/rtQC_display_setup.m +++ b/api-matlab/rtQC_display_setup.m @@ -988,17 +988,25 @@ 'Style', 'push',... 'String', 'Get physio batch', ... 'Units', 'Normalized',... - 'Position', [0.8 0.305 0.18 0.225],... + 'Position', [0.8 0.305 0.1 0.225],... 'CallBack', @physioBatch, ... 'UserData', 0,... 'fontsize', gui_data.button_font_size); -gui_data.popup_setVendor = uicontrol('Parent', gui_data.panel_volumes,... +gui_data.popup_setVendor = uicontrol('Parent', gui_data.panel_rtsummary,... 'Style', 'popup',... 'String', {'BIDS','Philips','Biopac_Txt','GE','Siemens','Siemens_HCP','Siemens_Tics'},... 'Units', 'Normalized',... - 'Position', [0.73 0.305 0.05 0.225],... + 'Position', [0.91 0.303 0.07 0.125],... % [0.06 0 0.22 0.1],... % 'Value', 1,... 'Callback', @setVendor); +gui_data.txt_setVendor = uicontrol('Parent', gui_data.panel_rtsummary,... + 'Style','text',... + 'String','Vendor (for physio):',... + 'Units', 'Normalized',... + 'Position',[0.91 0.44 0.07 0.09],... + 'HorizontalAlignment', 'left',... + 'fontsize', gui_data.button_font_size); + % Offline summary panel UIcontrols gui_data.QCtgroup = uitabgroup('Parent', gui_data.panel_qcsummaryL,... diff --git a/api-matlab/wrapper_physiobatch.m b/api-matlab/wrapper_physiobatch.m index c37b6d8..3f560c3 100644 --- a/api-matlab/wrapper_physiobatch.m +++ b/api-matlab/wrapper_physiobatch.m @@ -1,4 +1,4 @@ -function matlabbatch = wrapper_physiobatch(data_vendor, nr_slices, TR, nr_scans, nr_dummies, onset_slice, out_dir) +function matlabbatch = wrapper_physiobatch(data_vendor, out_dir) spm_jobman('initcfg'); global defaults defaults.stats.maxmem = 2^30; @@ -67,16 +67,19 @@ throw(ME); end + % read scan parameters + input_params = inputdlg({'Number of scans:','Number of slices:','Number of dummies:', 'TR:', 'Onset slice:'}, 'Parameters for physio'); + % scan parameters matlabbatch{1}.spm.tools.physio.log_files.sampling_interval = []; matlabbatch{1}.spm.tools.physio.log_files.relative_start_acquisition = 0; matlabbatch{1}.spm.tools.physio.log_files.align_scan = 'last'; % sometimes first, sometimes last - matlabbatch{1}.spm.tools.physio.scan_timing.sqpar.Nslices = nr_slices; + matlabbatch{1}.spm.tools.physio.scan_timing.sqpar.Nslices = str2double(input_params{2}); matlabbatch{1}.spm.tools.physio.scan_timing.sqpar.NslicesPerBeat = []; - matlabbatch{1}.spm.tools.physio.scan_timing.sqpar.TR = TR; - matlabbatch{1}.spm.tools.physio.scan_timing.sqpar.Ndummies = nr_dummies; - matlabbatch{1}.spm.tools.physio.scan_timing.sqpar.Nscans = nr_scans; - matlabbatch{1}.spm.tools.physio.scan_timing.sqpar.onset_slice = onset_slice; + matlabbatch{1}.spm.tools.physio.scan_timing.sqpar.TR = str2double(input_params{4}); + matlabbatch{1}.spm.tools.physio.scan_timing.sqpar.Ndummies = str2double(input_params{3}); + matlabbatch{1}.spm.tools.physio.scan_timing.sqpar.Nscans = str2double(input_params{1}); + matlabbatch{1}.spm.tools.physio.scan_timing.sqpar.onset_slice = str2double(input_params{5}); matlabbatch{1}.spm.tools.physio.scan_timing.sqpar.time_slice_to_slice = []; % template From d0692dffea68e983938f337a03d44061a0efadd5 Mon Sep 17 00:00:00 2001 From: "Nina Valerie Wiedemann (ninwie)" Date: Wed, 18 Dec 2019 18:24:54 +0100 Subject: [PATCH 3/9] only save, physio installation instruction --- api-matlab/rtQC_display.m | 24 ++++++++++++++++++------ api-matlab/rtQC_display_setup.m | 2 +- api-matlab/wrapper_physiobatch.m | 16 +++++++--------- 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/api-matlab/rtQC_display.m b/api-matlab/rtQC_display.m index 7d5c924..aa9f118 100644 --- a/api-matlab/rtQC_display.m +++ b/api-matlab/rtQC_display.m @@ -1465,21 +1465,33 @@ function generateReport(hObject,eventdata) end function physioBatch(hObject,eventdata) + % check if physio is installed: + pathCell = regexp(path, pathsep, 'split'); + if ispc % Windows is not case-sensitive + onPath = any(contains(pathCell, 'PhysIO')); + else + onPath = any(contains(pathCell, 'PhysIO')); + end + if ~onPath + disp("ERROR: Physio toolbox not installed or not added to path. Follow installation instructions on https://github.com/translationalneuromodeling/tapas."); + end + + % get guidata fig = ancestor(hObject,'figure'); gui_data = guidata(fig); vendor = gui_data.popup_setVendor.String(gui_data.popup_setVendor.Value); - disp("Vendor:"); - disp(vendor); - + %% read nr slices and nr scans from nifti header: % hdr = spm_vol('C:\Users\nwiedemann\Downloads\rtQC_sample_data\rtQC_sample_data\sub-opennft\fanon-0007.nii') % nr_scans = length(hdr) % nr_slices = hdr(1).dim(3) %% - % parameter for BIDS template: 16, 1.45, 408, 0, 1, - disp([gui_data.qc_out_dir filesep 'physio_dir']); - wrapper_physiobatch(char(vendor), [gui_data.qc_out_dir filesep 'physio_dir']); + % default path for spm inputs: + default_path = gui_data.data_dir; + % 'C:\Users\nwiedemann\Downloads\tapas\tapas\misc\example\PhysIO'; + + wrapper_physiobatch(char(vendor), gui_data.qc_out_dir, default_path); end function showFDoutliers(hObject,eventdata) diff --git a/api-matlab/rtQC_display_setup.m b/api-matlab/rtQC_display_setup.m index 822276c..653b1b4 100644 --- a/api-matlab/rtQC_display_setup.m +++ b/api-matlab/rtQC_display_setup.m @@ -1005,7 +1005,7 @@ 'Units', 'Normalized',... 'Position',[0.91 0.44 0.07 0.09],... 'HorizontalAlignment', 'left',... - 'fontsize', gui_data.button_font_size); + 'fontsize', gui_data.small_font_size); % Offline summary panel UIcontrols diff --git a/api-matlab/wrapper_physiobatch.m b/api-matlab/wrapper_physiobatch.m index 3f560c3..2f3d46d 100644 --- a/api-matlab/wrapper_physiobatch.m +++ b/api-matlab/wrapper_physiobatch.m @@ -1,13 +1,10 @@ -function matlabbatch = wrapper_physiobatch(data_vendor, out_dir) +function matlabbatch = wrapper_physiobatch(data_vendor, out_dir, default_path) spm_jobman('initcfg'); global defaults defaults.stats.maxmem = 2^30; matlabbatch = {}; - % defaul path for spm inputs: - default_path = 'C:\Users\nwiedemann\Downloads\tapas\tapas\misc\example\PhysIO'; - - matlabbatch{1}.spm.tools.physio.save_dir = {out_dir}; + matlabbatch{1}.spm.tools.physio.save_dir = {[out_dir filesep 'physio_dir']}; matlabbatch{1}.spm.tools.physio.log_files.vendor = data_vendor; % EXAMPLES IN C:\Users\nwiedemann\Downloads\tapas\tapas\misc\example\PhysIO @@ -105,9 +102,10 @@ matlabbatch{1}.spm.tools.physio.verbose.fig_output_file = ''; matlabbatch{1}.spm.tools.physio.verbose.use_tabs = false; -% % alternatively: just save batch -% save(out_dir, 'matlabbatch'); -% disp("Saved matlabbatch."); + % save batch + save([out_dir filesep 'physio_batch'], 'matlabbatch'); + disp("Saved matlabbatch in:"); + disp(out_dir); - spm_jobman('run',matlabbatch); + % spm_jobman('run',matlabbatch); end \ No newline at end of file From b94f10bb7b9b2b0540b11d3c06c37c64cc5d0b45 Mon Sep 17 00:00:00 2001 From: "Nina Valerie Wiedemann (ninwie)" Date: Wed, 18 Dec 2019 18:36:07 +0100 Subject: [PATCH 4/9] error message when physio not installed --- api-matlab/rtQC_display.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api-matlab/rtQC_display.m b/api-matlab/rtQC_display.m index aa9f118..94888f0 100644 --- a/api-matlab/rtQC_display.m +++ b/api-matlab/rtQC_display.m @@ -1473,7 +1473,7 @@ function physioBatch(hObject,eventdata) onPath = any(contains(pathCell, 'PhysIO')); end if ~onPath - disp("ERROR: Physio toolbox not installed or not added to path. Follow installation instructions on https://github.com/translationalneuromodeling/tapas."); + error("ERROR: Physio toolbox not installed or not added to path. Follow installation instructions on https://github.com/translationalneuromodeling/tapas."); end % get guidata From ca0beae04538b11dd58892982f5dec9b27a872b2 Mon Sep 17 00:00:00 2001 From: "Nina Valerie Wiedemann (ninwie)" Date: Thu, 9 Jan 2020 14:03:01 +0100 Subject: [PATCH 5/9] changes with respect to first comments layout in UI changed --- api-matlab/rtQC_display.m | 11 +++++------ api-matlab/rtQC_display_setup.m | 14 ++++---------- api-matlab/wrapper_physiobatch.m | 2 +- 3 files changed, 10 insertions(+), 17 deletions(-) diff --git a/api-matlab/rtQC_display.m b/api-matlab/rtQC_display.m index 94888f0..e9dac9b 100644 --- a/api-matlab/rtQC_display.m +++ b/api-matlab/rtQC_display.m @@ -1467,13 +1467,9 @@ function generateReport(hObject,eventdata) function physioBatch(hObject,eventdata) % check if physio is installed: pathCell = regexp(path, pathsep, 'split'); - if ispc % Windows is not case-sensitive - onPath = any(contains(pathCell, 'PhysIO')); - else - onPath = any(contains(pathCell, 'PhysIO')); - end + onPath = any(contains(pathCell, 'PhysIO')); if ~onPath - error("ERROR: Physio toolbox not installed or not added to path. Follow installation instructions on https://github.com/translationalneuromodeling/tapas."); + errordlg('Physio toolbox not installed or not added to path. Follow installation instructions on https://github.com/translationalneuromodeling/tapas.'); end % get guidata @@ -1481,6 +1477,9 @@ function physioBatch(hObject,eventdata) gui_data = guidata(fig); vendor = gui_data.popup_setVendor.String(gui_data.popup_setVendor.Value); + if strcmp(vendor, 'select vendor...') + errordlg('First set vendor in drop down menu to the right of the button.'); + end %% read nr slices and nr scans from nifti header: % hdr = spm_vol('C:\Users\nwiedemann\Downloads\rtQC_sample_data\rtQC_sample_data\sub-opennft\fanon-0007.nii') diff --git a/api-matlab/rtQC_display_setup.m b/api-matlab/rtQC_display_setup.m index 653b1b4..9384295 100644 --- a/api-matlab/rtQC_display_setup.m +++ b/api-matlab/rtQC_display_setup.m @@ -994,18 +994,12 @@ 'fontsize', gui_data.button_font_size); gui_data.popup_setVendor = uicontrol('Parent', gui_data.panel_rtsummary,... 'Style', 'popup',... - 'String', {'BIDS','Philips','Biopac_Txt','GE','Siemens','Siemens_HCP','Siemens_Tics'},... + 'String', {'select vendor...', 'BIDS','Philips','Biopac_Txt','GE','Siemens','Siemens_HCP','Siemens_Tics'},... 'Units', 'Normalized',... - 'Position', [0.91 0.303 0.07 0.125],... % [0.06 0 0.22 0.1],... % + 'Position', [0.91 0.305 0.07 0.225],... 'Value', 1,... - 'Callback', @setVendor); -gui_data.txt_setVendor = uicontrol('Parent', gui_data.panel_rtsummary,... - 'Style','text',... - 'String','Vendor (for physio):',... - 'Units', 'Normalized',... - 'Position',[0.91 0.44 0.07 0.09],... - 'HorizontalAlignment', 'left',... - 'fontsize', gui_data.small_font_size); + 'Callback', @setVendor,... + 'fontsize', gui_data.button_font_size); % Offline summary panel UIcontrols diff --git a/api-matlab/wrapper_physiobatch.m b/api-matlab/wrapper_physiobatch.m index 2f3d46d..cf72e42 100644 --- a/api-matlab/wrapper_physiobatch.m +++ b/api-matlab/wrapper_physiobatch.m @@ -86,7 +86,7 @@ matlabbatch{1}.spm.tools.physio.preproc.cardiac.initial_cpulse_select.auto_matched.min = 0.4; matlabbatch{1}.spm.tools.physio.preproc.cardiac.initial_cpulse_select.auto_matched.file = 'initial_cpulse_kRpeakfile.mat'; matlabbatch{1}.spm.tools.physio.preproc.cardiac.posthoc_cpulse_select.off = struct([]); - matlabbatch{1}.spm.tools.physio.model.output_multiple_regressors = 'multiple_regressors.txt'; + matlabbatch{1}.spm.tools.physio.model.output_multiple_regressors = 'retroicor_regressors.txt'; matlabbatch{1}.spm.tools.physio.model.output_physio = 'physio.mat'; matlabbatch{1}.spm.tools.physio.model.orthogonalise = 'none'; matlabbatch{1}.spm.tools.physio.model.censor_unreliable_recording_intervals = false; From 7091d6ad080b1c8e479ef21be10a46d5f0fdbcd2 Mon Sep 17 00:00:00 2001 From: "Nina Valerie Wiedemann (ninwie)" Date: Thu, 9 Jan 2020 15:02:14 +0100 Subject: [PATCH 6/9] replaced spm select box --- api-matlab/wrapper_physiobatch.m | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/api-matlab/wrapper_physiobatch.m b/api-matlab/wrapper_physiobatch.m index cf72e42..37ff6c2 100644 --- a/api-matlab/wrapper_physiobatch.m +++ b/api-matlab/wrapper_physiobatch.m @@ -11,51 +11,43 @@ % different vendor options require different file input if strcmp(data_vendor, 'BIDS') - [tsv_filename, ~] = spm_select(1,'.*.tsv.*','Specify tsv/tsv.gz file with ECG data',{}, default_path); - % tsv_filename = input(['For BIDS, you only need to specify the tsv/tsv.gz file containing 3 columns without header.' ... - % 'There must be a json with the same file name in the same folder containing metainformation'], 's'); + [tsv_filename, ~] = uigetfile('*.tsv*','Specify tsv/tsv.gz file with ECG data',default_path); matlabbatch{1}.spm.tools.physio.log_files.cardiac = {tsv_filename}; matlabbatch{1}.spm.tools.physio.log_files.respiration = {''}; matlabbatch{1}.spm.tools.physio.log_files.scan_timing = {''}; elseif strcmp(data_vendor, 'Philips') - [scanphyslog, ~] = spm_select(1,'.*.log','Specify SCANPHYSLOG.log file',{}, default_path); - % scanphyslog = input('Specify file path to SCANPHYSLOG.log file', 's'); + [scanphyslog, ~] = uigetfile('*.log','Specify SCANPHYSLOG.log file', default_path); matlabbatch{1}.spm.tools.physio.log_files.cardiac = {scanphyslog}; matlabbatch{1}.spm.tools.physio.log_files.respiration = {scanphyslog}; matlabbatch{1}.spm.tools.physio.log_files.scan_timing = {scanphyslog}; % or empty? elseif strcmp(data_vendor, 'Biopac_Txt') - [scanphyslog, ~] = spm_select(1,'.*.txt','Specify biopac data export txt file',{}, default_path); + [scanphyslog, ~] = uigetfile('*.txt','Specify biopac data export txt file', default_path); % scanphyslog = input('Specify file path to the biopac data export txt file', 's'); matlabbatch{1}.spm.tools.physio.log_files.cardiac = {scanphyslog}; matlabbatch{1}.spm.tools.physio.log_files.respiration = {scanphyslog}; matlabbatch{1}.spm.tools.physio.log_files.scan_timing = {scanphyslog}; elseif strcmp(data_vendor, 'GE') - [cardiac, ~] = spm_select(1,'any','Specify cardiac file (starting with ECGData_)',{}, default_path); + [cardiac, ~] = uigetfile('*.*','Specify cardiac file (starting with ECGData_)', default_path); % cardiac = input('Specify file path to the cardiac file (in template starting with ECGData_)', 's'); - [respiration, ~] = spm_select(1,'any','Specify respiration file (starting with RespData_)',{}, default_path); + [respiration, ~] = uigetfile('*.*','Specify respiration file (starting with RespData_)', default_path); % respiration = input('Specify file path to the respiration file (in template starting with RespData_)', 's'); matlabbatch{1}.spm.tools.physio.log_files.cardiac = {cardiac}; matlabbatch{1}.spm.tools.physio.log_files.respiration = {respiration}; matlabbatch{1}.spm.tools.physio.log_files.scan_timing = {''}; elseif strcmp(data_vendor, 'Siemens_HCP') - [physiolog, ~] = spm_select(1,'any','Specify physio data file (sth like tfMRI_MOTOR_LR_Physio_log.txt)',{}, default_path); - % physiolog = input('Specify file path to the tfMRI_MOTOR_LR_Physio_log.txt file', 's'); + [physiolog, ~] = uigetfile('*.*','Specify physio data file (sth like tfMRI_MOTOR_LR_Physio_log.txt)', default_path); matlabbatch{1}.spm.tools.physio.log_files.cardiac = {physiolog}; matlabbatch{1}.spm.tools.physio.log_files.respiration = {physiolog}; matlabbatch{1}.spm.tools.physio.log_files.scan_timing = {''}; elseif strcmp(data_vendor, 'Siemens') - [physiolog, ~] = spm_select(1,'.*.ecg','Specify physio data file (siemens_PAV.ecg)',{}, default_path); - % physiolog = input('Specify file path to the siemens_PAV.ecg file', 's'); + [physiolog, ~] = uigetfile('*.ecg','Specify physio data file (siemens_PAV.ecg)', default_path); matlabbatch{1}.spm.tools.physio.log_files.cardiac = {physiolog}; matlabbatch{1}.spm.tools.physio.log_files.respiration = {''}; matlabbatch{1}.spm.tools.physio.log_files.scan_timing = {''}; elseif strcmp(data_vendor, 'Siemens_Tics') - [cardiac, ~] = spm_select(1,'.*.log','Specify cardiac file (..._PULS.log)',{}, default_path); - % cardiac = input('Specify file path to the cardiac file (in template ending with _PULS.log)', 's'); - [respiration, ~] = spm_select(1,'.*.log','Specify respiration file (..._RESP.log)',{}, default_path); - % respiration = input('Specify file path to the respiration file (in template ending with _RESP.log)', 's'); - [timing, ~] = spm_select(1,'.*.log','Specify scan timing file (..._Info.log)',{}, default_path); - % timing = input('Specify file path to the scan timing file (in template ending with _Info.log)', 's'); + [cardiac, ~] = uigetfile('*.log','Specify cardiac file (..._PULS.log)', default_path); + [respiration, ~] = uigetfile('*.log','Specify respiration file (..._RESP.log)', default_path); + [timing, ~] = uigetfile('*.log','Specify scan timing file (..._Info.log)', default_path); matlabbatch{1}.spm.tools.physio.log_files.cardiac = {cardiac}; matlabbatch{1}.spm.tools.physio.log_files.respiration = {respiration}; matlabbatch{1}.spm.tools.physio.log_files.scan_timing = {timing}; @@ -104,8 +96,7 @@ % save batch save([out_dir filesep 'physio_batch'], 'matlabbatch'); - disp("Saved matlabbatch in:"); - disp(out_dir); + msgbox(['Saved matlabbatch in: ' out_dir], 'Success'); % spm_jobman('run',matlabbatch); end \ No newline at end of file From 86215baaa10fc89e93428e0d8fb2cbe274afa307 Mon Sep 17 00:00:00 2001 From: "Nina Valerie Wiedemann (ninwie)" Date: Fri, 24 Jan 2020 16:58:30 +0100 Subject: [PATCH 7/9] settings tab, add figures to report --- api-matlab/rtQC_display.m | 169 ++++++++++- api-matlab/rtQC_display_setup.m | 2 + api-matlab/settings_tab.m | 476 +++++++++++++++++++++++++++++++ api-matlab/wrapper_physiobatch.m | 175 +++++++----- 4 files changed, 744 insertions(+), 78 deletions(-) create mode 100644 api-matlab/settings_tab.m diff --git a/api-matlab/rtQC_display.m b/api-matlab/rtQC_display.m index e9dac9b..12e56bc 100644 --- a/api-matlab/rtQC_display.m +++ b/api-matlab/rtQC_display.m @@ -117,6 +117,34 @@ function rtQC_display() gui_data.pb_open_qc_post.Callback = @generateReport; gui_data.pb_get_physio_batch.Callback = @physioBatch; +% settings callback +gui_data.editphysio_save_dir.Callback = @editphysio_save_dir ; +gui_data.editlog_files_sampling_interval.Callback = @editlog_files_sampling_interval ; +gui_data.editlog_files_relative_start_acquisition.Callback = @editlog_files_relative_start_acquisition ; +gui_data.editlog_files_align_scan.Callback = @editlog_files_align_scan ; +gui_data.editsqpar_NslicesPerBeat.Callback = @editsqpar_NslicesPerBeat ; +gui_data.editsqpar_time_slice_to_slice.Callback = @editsqpar_time_slice_to_slice ; +gui_data.editsqpar_Nprep.Callback = @editsqpar_Nprep ; +gui_data.editsync_nominal.Callback = @editsync_nominal ; +gui_data.editauto_matched_min.Callback = @editauto_matched_min ; +gui_data.editauto_matched_file.Callback = @editauto_matched_file ; +gui_data.editposthoc_cpulse_select_off.Callback = @editposthoc_cpulse_select_off ; +gui_data.editmodel_output_multiple_regressors.Callback = @editmodel_output_multiple_regressors ; +gui_data.editmodel_output_physio.Callback = @editmodel_output_physio ; +gui_data.editmodel_orthogonalise.Callback = @editmodel_orthogonalise ; +gui_data.editmodel_censor_unreliable_recording_intervals.Callback = @editmodel_censor_unreliable_recording_intervals ; +gui_data.editorder_c.Callback = @editorder_c ; +gui_data.editorder_r.Callback = @editorder_r ; +gui_data.editorder_cr.Callback = @editorder_cr ; +gui_data.editrvt_no.Callback = @editrvt_no ; +gui_data.edithrv_no.Callback = @edithrv_no ; +gui_data.editnoise_rois_no.Callback = @editnoise_rois_no ; +gui_data.editmovement_no.Callback = @editmovement_no ; +gui_data.editother_no.Callback = @editother_no ; +gui_data.editverbose_level.Callback = @editverbose_level ; +gui_data.editverbose_fig_output_file.Callback = @editverbose_fig_output_file ; +gui_data.editverbose_use_tabs.Callback = @editverbose_use_tabs ; + set(findall(fig, '-property', 'Interruptible'), 'Interruptible', 'on') @@ -208,6 +236,119 @@ function gotoTab2(hObject,eventdata) guidata(fig,gui_data) end +%%%% start settings tab functions + +function editphysio_save_dir (hObject,eventdata) +fig = ancestor(hObject,'figure'); +gui_data = guidata(fig); +end +function editlog_files_sampling_interval (hObject,eventdata) +fig = ancestor(hObject,'figure'); +gui_data = guidata(fig); +end +function editlog_files_relative_start_acquisition (hObject,eventdata) +fig = ancestor(hObject,'figure'); +gui_data = guidata(fig); +end +function editlog_files_align_scan (hObject,eventdata) +fig = ancestor(hObject,'figure'); +gui_data = guidata(fig); +end +function editsqpar_NslicesPerBeat (hObject,eventdata) +fig = ancestor(hObject,'figure'); +gui_data = guidata(fig); +end +function editsqpar_time_slice_to_slice (hObject,eventdata) +fig = ancestor(hObject,'figure'); +gui_data = guidata(fig); +end +function editsqpar_Nprep (hObject,eventdata) +fig = ancestor(hObject,'figure'); +gui_data = guidata(fig); +end +function editsync_nominal (hObject,eventdata) +fig = ancestor(hObject,'figure'); +gui_data = guidata(fig); +end +function editauto_matched_min (hObject,eventdata) +fig = ancestor(hObject,'figure'); +gui_data = guidata(fig); +end +function editauto_matched_file (hObject,eventdata) +fig = ancestor(hObject,'figure'); +gui_data = guidata(fig); +end +function editposthoc_cpulse_select_off (hObject,eventdata) +fig = ancestor(hObject,'figure'); +gui_data = guidata(fig); +end +function editmodel_output_multiple_regressors (hObject,eventdata) +fig = ancestor(hObject,'figure'); +gui_data = guidata(fig); +end +function editmodel_output_physio (hObject,eventdata) +fig = ancestor(hObject,'figure'); +gui_data = guidata(fig); +end +function editmodel_orthogonalise (hObject,eventdata) +fig = ancestor(hObject,'figure'); +gui_data = guidata(fig); +end +function editmodel_censor_unreliable_recording_intervals (hObject,eventdata) +fig = ancestor(hObject,'figure'); +gui_data = guidata(fig); +end +function editorder_c (hObject,eventdata) +fig = ancestor(hObject,'figure'); +gui_data = guidata(fig); +end +function editorder_r (hObject,eventdata) +fig = ancestor(hObject,'figure'); +gui_data = guidata(fig); +end +function editorder_cr (hObject,eventdata) +fig = ancestor(hObject,'figure'); +gui_data = guidata(fig); +end +function editrvt_no (hObject,eventdata) +fig = ancestor(hObject,'figure'); +gui_data = guidata(fig); +end +function edithrv_no (hObject,eventdata) +fig = ancestor(hObject,'figure'); +gui_data = guidata(fig); +end +function editnoise_rois_no (hObject,eventdata) +fig = ancestor(hObject,'figure'); +gui_data = guidata(fig); +end +function editmovement_no (hObject,eventdata) +fig = ancestor(hObject,'figure'); +gui_data = guidata(fig); +end +function editother_no (hObject,eventdata) +fig = ancestor(hObject,'figure'); +gui_data = guidata(fig); +end +function editverbose_level (hObject,eventdata) +fig = ancestor(hObject,'figure'); +gui_data = guidata(fig); +end +function editverbose_fig_output_file(hObject,eventdata) +fig = ancestor(hObject,'figure'); +gui_data = guidata(fig); +txt = get(hObject, 'String'); +gui_data.editverbose_fig_output_file.String = txt; +% assignin('base', 'gui_data', gui_data) +guidata(fig,gui_data) +end +function editverbose_use_tabs (hObject,eventdata) +fig = ancestor(hObject,'figure'); +gui_data = guidata(fig); +end + +%%%%% end setting tab functions + function editFDthreshold(hObject,eventdata) fig = ancestor(hObject,'figure'); @@ -460,6 +601,7 @@ function calcAndDispMI(hObject,eventdata) return; end + msgbox('Functionality to be added: plot 2D histogram and display mutual information measure'); % slice_nr = 20; % im1 = spm_read_vols(spm_vol(gui_data.im1_dqchecks_fn)); @@ -1223,7 +1365,6 @@ function drawBrains(fig) end - % Offline tab functions function runOfflineQC(hObject,eventdata) @@ -1432,7 +1573,7 @@ function generateReport(hObject,eventdata) dt_str = [num2str(Y) num2str(MO) num2str(D) num2str(H) num2str(MI) num2str(round(S))]; t = datestr(dt); log_name = [gui_data.subject_id '_' dt_str '.html']; -fid = fopen(log_name,'a'); +fid = fopen([gui_data.qc_out_dir filesep log_name],'a'); fprintf(fid, '

Log

'); fprintf(fid, ['\n
Subject: ' gui_data.subject_id]); fprintf(fid, ['\n
Date/time: ' t]); @@ -1458,19 +1599,23 @@ function generateReport(hObject,eventdata) fprintf(fid, '\n
no picture
' ); fprintf(fid, '\n
no picture
' ); fprintf(fid, '\n
no picture
' ); +% add physio plots +phys_dir = gui_data.edit_physio_save_dir.String; +if exist([gui_data.qc_out_dir filesep phys_dir]) + fprintf(fid, '

Physio processing plots

'); + figure_file_gen = split(gui_data.edit_verbose_fig_output_file.String, '.'); + figure_file = cell2mat(join([figure_file_gen(1) '_05.' figure_file_gen(2)], '')); + img_to_plot = [phys_dir '/' figure_file]; % possible option (this works if in settings tab just allow input of directory name + % add other figures + fprintf(fid, sprintf('\n
no picture
', img_to_plot)); +end fclose(fid); url = ['file:///' gui_data.qc_out_dir filesep log_name]; -web(url, '-browser') +web(url, '-browser'); end function physioBatch(hObject,eventdata) - % check if physio is installed: - pathCell = regexp(path, pathsep, 'split'); - onPath = any(contains(pathCell, 'PhysIO')); - if ~onPath - errordlg('Physio toolbox not installed or not added to path. Follow installation instructions on https://github.com/translationalneuromodeling/tapas.'); - end % get guidata fig = ancestor(hObject,'figure'); @@ -1486,11 +1631,11 @@ function physioBatch(hObject,eventdata) % nr_scans = length(hdr) % nr_slices = hdr(1).dim(3) %% - % default path for spm inputs: + % default path for cardiac and respiratory inputs: default_path = gui_data.data_dir; - % 'C:\Users\nwiedemann\Downloads\tapas\tapas\misc\example\PhysIO'; + % default_path = 'C:\Users\nwiedemann\Downloads\tapas\tapas\misc\example\PhysIO'; - wrapper_physiobatch(char(vendor), gui_data.qc_out_dir, default_path); + wrapper_physiobatch(char(vendor), gui_data.qc_out_dir, default_path, gui_data); end function showFDoutliers(hObject,eventdata) diff --git a/api-matlab/rtQC_display_setup.m b/api-matlab/rtQC_display_setup.m index 9384295..3c188d6 100644 --- a/api-matlab/rtQC_display_setup.m +++ b/api-matlab/rtQC_display_setup.m @@ -34,6 +34,7 @@ gui_data.tab_pre = uitab('Parent', gui_data.tgroup, 'Title', 'Pre QC'); gui_data.tab_online = uitab('Parent', gui_data.tgroup, 'Title', 'Online QC'); gui_data.tab_post = uitab('Parent', gui_data.tgroup, 'Title', 'Post QC'); +gui_data.tab_settings = uitab('Parent', gui_data.tgroup, 'Title', 'Settings'); % Set variable values gui_data.current_dir = mfilename('fullpath'); @@ -1088,6 +1089,7 @@ % set(get(gui_data.panel_qcsummaryR,'Children'),'Enable','off') % set(children(strcmpi ( get (children,'Type'),'UIControl')),'enable','off') +settings_tab; % Save GUI data diff --git a/api-matlab/settings_tab.m b/api-matlab/settings_tab.m new file mode 100644 index 0000000..2dd7c0f --- /dev/null +++ b/api-matlab/settings_tab.m @@ -0,0 +1,476 @@ +%% --------------- Create UIcontrols for Settings tab -------------------- %% +% Create panels +gui_data.panel_set_general = uipanel('Parent', gui_data.tab_settings,... + 'Title','1. General parameters',... + 'Position',[.02 .8 .96 .18],... + 'fontweight', 'bold',... + 'fontsize', gui_data.standard_font_size); +gui_data.panel_set_physio = uipanel('Parent', gui_data.tab_settings,... + 'Title','2. Physio processing parameters',... + 'Position',[.02 .01 .47 .77],... + 'fontweight', 'bold',... + 'fontsize', gui_data.standard_font_size); +gui_data.panel_set_new = uipanel('Parent', gui_data.tab_settings,... + 'Title','Other parameters',... + 'Position',[.51 .01 .47 .77],... + 'fontweight', 'bold',... + 'fontsize', gui_data.standard_font_size); + + +% gui_data.verbose_level = uicontrol('Parent', gui_data.panel_set_physio,... +% 'Style','text',... +% 'String','physio.verbose.level',... +% 'Units', 'Normalized',... +% 'Position',[0.02 0.55 0.15 0.05],... +% 'HorizontalAlignment', 'left',... +% 'fontsize', gui_data.small_font_size); +% gui_data.edit_verbose_level = uicontrol('Parent', gui_data.panel_set_physio,... +% 'Style', 'edit',... +% 'String', num2str(2), ... +% 'Units', 'Normalized',... +% 'Position', [0.18 0.55 0.1 0.05],... +% 'CallBack', @editverbose_level, ... +% 'HorizontalAlignment', 'right',... +% 'fontsize', gui_data.button_font_size); + +gui_data.physio_save_dir = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','text',... +'String','physio.save_dir ',... +'Units', 'Normalized',... +'Position', [ 0.02 0.05 0.2 0.025 ], ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.edit_physio_save_dir = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','edit',... +'String','physio_out',... +'Units', 'Normalized',... +'Position', [ 0.25 0.05 0.2 0.025 ], ... +'CallBack', @editphysio_save_dir , ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.log_files_sampling_interval = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','text',... +'String','log_files.sampling_interval ',... +'Units', 'Normalized',... +'Position', [ 0.02 0.085 0.2 0.025 ], ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.edit_log_files_sampling_interval = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','edit',... +'String','[]',... +'Units', 'Normalized',... +'Position', [ 0.25 0.085 0.2 0.025 ], ... +'CallBack', @editlog_files_sampling_interval , ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.log_files_relative_start_acquisition = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','text',... +'String','log_files.relative_start_acquisition ',... +'Units', 'Normalized',... +'Position', [ 0.02 0.12000000000000001 0.2 0.025 ], ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.edit_log_files_relative_start_acquisition = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','edit',... +'String','0',... +'Units', 'Normalized',... +'Position', [ 0.25 0.12000000000000001 0.2 0.025 ], ... +'CallBack', @editlog_files_relative_start_acquisition , ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.log_files_align_scan = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','text',... +'String','log_files.align_scan ',... +'Units', 'Normalized',... +'Position', [ 0.02 0.155 0.2 0.025 ], ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.edit_log_files_align_scan = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','edit',... +'String','last',... +'Units', 'Normalized',... +'Position', [ 0.25 0.155 0.2 0.025 ], ... +'CallBack', @editlog_files_align_scan , ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.sqpar_NslicesPerBeat = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','text',... +'String','sqpar.NslicesPerBeat ',... +'Units', 'Normalized',... +'Position', [ 0.02 0.19 0.2 0.025 ], ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.edit_sqpar_NslicesPerBeat = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','edit',... +'String','[]',... +'Units', 'Normalized',... +'Position', [ 0.25 0.19 0.2 0.025 ], ... +'CallBack', @editsqpar_NslicesPerBeat , ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.sqpar_time_slice_to_slice = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','text',... +'String','sqpar.time_slice_to_slice ',... +'Units', 'Normalized',... +'Position', [ 0.02 0.22499999999999998 0.2 0.025 ], ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.edit_sqpar_time_slice_to_slice = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','edit',... +'String','[]',... +'Units', 'Normalized',... +'Position', [ 0.25 0.22499999999999998 0.2 0.025 ], ... +'CallBack', @editsqpar_time_slice_to_slice , ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.sqpar_Nprep = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','text',... +'String','sqpar.Nprep ',... +'Units', 'Normalized',... +'Position', [ 0.02 0.26 0.2 0.025 ], ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.edit_sqpar_Nprep = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','edit',... +'String','[]',... +'Units', 'Normalized',... +'Position', [ 0.25 0.26 0.2 0.025 ], ... +'CallBack', @editsqpar_Nprep , ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.sync_nominal = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','text',... +'String','sync.nominal ',... +'Units', 'Normalized',... +'Position', [ 0.02 0.295 0.2 0.025 ], ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.edit_sync_nominal = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','edit',... +'String','[]',... +'Units', 'Normalized',... +'Position', [ 0.25 0.295 0.2 0.025 ], ... +'CallBack', @editsync_nominal , ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.auto_matched_min = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','text',... +'String','auto_matched.min ',... +'Units', 'Normalized',... +'Position', [ 0.02 0.33 0.2 0.025 ], ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.edit_auto_matched_min = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','edit',... +'String','0.4',... +'Units', 'Normalized',... +'Position', [ 0.25 0.33 0.2 0.025 ], ... +'CallBack', @editauto_matched_min , ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.auto_matched_file = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','text',... +'String','auto_matched.file ',... +'Units', 'Normalized',... +'Position', [ 0.02 0.365 0.2 0.025 ], ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.edit_auto_matched_file = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','edit',... +'String','initial_cpulse_kRpeakfile.mat',... +'Units', 'Normalized',... +'Position', [ 0.25 0.365 0.2 0.025 ], ... +'CallBack', @editauto_matched_file , ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.posthoc_cpulse_select_off = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','text',... +'String','posthoc_cpulse_select.off ',... +'Units', 'Normalized',... +'Position', [ 0.02 0.39999999999999997 0.2 0.025 ], ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.edit_posthoc_cpulse_select_off = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','edit',... +'String','[]',... +'Units', 'Normalized',... +'Position', [ 0.25 0.39999999999999997 0.2 0.025 ], ... +'CallBack', @editposthoc_cpulse_select_off , ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.model_output_multiple_regressors = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','text',... +'String','model.output_multiple_regressors ',... +'Units', 'Normalized',... +'Position', [ 0.02 0.435 0.2 0.025 ], ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.edit_model_output_multiple_regressors = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','edit',... +'String','retroicor_regressors.txt',... +'Units', 'Normalized',... +'Position', [ 0.25 0.435 0.2 0.025 ], ... +'CallBack', @editmodel_output_multiple_regressors , ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.model_output_physio = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','text',... +'String','model.output_physio ',... +'Units', 'Normalized',... +'Position', [ 0.02 0.47 0.2 0.025 ], ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.edit_model_output_physio = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','edit',... +'String','physio.mat',... +'Units', 'Normalized',... +'Position', [ 0.25 0.47 0.2 0.025 ], ... +'CallBack', @editmodel_output_physio , ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.model_orthogonalise = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','text',... +'String','model.orthogonalise ',... +'Units', 'Normalized',... +'Position', [ 0.02 0.505 0.2 0.025 ], ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.edit_model_orthogonalise = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','edit',... +'String','none',... +'Units', 'Normalized',... +'Position', [ 0.25 0.505 0.2 0.025 ], ... +'CallBack', @editmodel_orthogonalise , ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.model_censor_unreliable_recording_intervals = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','text',... +'String','model.censor_unreliable_recording_intervals ',... +'Units', 'Normalized',... +'Position', [ 0.02 0.54 0.2 0.025 ], ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.edit_model_censor_unreliable_recording_intervals = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','edit',... +'String','false',... +'Units', 'Normalized',... +'Position', [ 0.25 0.54 0.2 0.025 ], ... +'CallBack', @editmodel_censor_unreliable_recording_intervals , ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.order_c = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','text',... +'String','order.c ',... +'Units', 'Normalized',... +'Position', [ 0.02 0.5750000000000001 0.2 0.025 ], ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.edit_order_c = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','edit',... +'String','3',... +'Units', 'Normalized',... +'Position', [ 0.25 0.5750000000000001 0.2 0.025 ], ... +'CallBack', @editorder_c , ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.order_r = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','text',... +'String','order.r ',... +'Units', 'Normalized',... +'Position', [ 0.02 0.6100000000000001 0.2 0.025 ], ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.edit_order_r = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','edit',... +'String','4',... +'Units', 'Normalized',... +'Position', [ 0.25 0.6100000000000001 0.2 0.025 ], ... +'CallBack', @editorder_r , ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.order_cr = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','text',... +'String','order.cr ',... +'Units', 'Normalized',... +'Position', [ 0.02 0.645 0.2 0.025 ], ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.edit_order_cr = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','edit',... +'String','1',... +'Units', 'Normalized',... +'Position', [ 0.25 0.645 0.2 0.025 ], ... +'CallBack', @editorder_cr , ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.rvt_no = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','text',... +'String','rvt.no ',... +'Units', 'Normalized',... +'Position', [ 0.02 0.68 0.2 0.025 ], ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.edit_rvt_no = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','edit',... +'String','[]',... +'Units', 'Normalized',... +'Position', [ 0.25 0.68 0.2 0.025 ], ... +'CallBack', @editrvt_no , ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.hrv_no = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','text',... +'String','hrv.no ',... +'Units', 'Normalized',... +'Position', [ 0.02 0.7150000000000001 0.2 0.025 ], ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.edit_hrv_no = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','edit',... +'String','[]',... +'Units', 'Normalized',... +'Position', [ 0.25 0.7150000000000001 0.2 0.025 ], ... +'CallBack', @edithrv_no , ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.noise_rois_no = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','text',... +'String','noise_rois.no ',... +'Units', 'Normalized',... +'Position', [ 0.02 0.75 0.2 0.025 ], ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.edit_noise_rois_no = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','edit',... +'String','[]',... +'Units', 'Normalized',... +'Position', [ 0.25 0.75 0.2 0.025 ], ... +'CallBack', @editnoise_rois_no , ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.movement_no = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','text',... +'String','movement.no ',... +'Units', 'Normalized',... +'Position', [ 0.02 0.785 0.2 0.025 ], ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.edit_movement_no = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','edit',... +'String','[]',... +'Units', 'Normalized',... +'Position', [ 0.25 0.785 0.2 0.025 ], ... +'CallBack', @editmovement_no , ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.other_no = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','text',... +'String','other.no ',... +'Units', 'Normalized',... +'Position', [ 0.02 0.8200000000000001 0.2 0.025 ], ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.edit_other_no = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','edit',... +'String','[]',... +'Units', 'Normalized',... +'Position', [ 0.25 0.8200000000000001 0.2 0.025 ], ... +'CallBack', @editother_no , ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.verbose_level = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','text',... +'String','verbose.level ',... +'Units', 'Normalized',... +'Position', [ 0.02 0.8550000000000001 0.2 0.025 ], ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.edit_verbose_level = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','edit',... +'String','2',... +'Units', 'Normalized',... +'Position', [ 0.25 0.8550000000000001 0.2 0.025 ], ... +'CallBack', @editverbose_level , ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.verbose_fig_output_file = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','text',... +'String','verbose.fig_output_file ',... +'Units', 'Normalized',... +'Position', [ 0.02 0.89 0.2 0.025 ], ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.edit_verbose_fig_output_file = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','edit',... +'String','physIO_figures.png',... +'Units', 'Normalized',... +'Position', [ 0.25 0.89 0.2 0.025 ], ... +'CallBack', @editverbose_fig_output_file , ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.verbose_use_tabs = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','text',... +'String','verbose.use_tabs ',... +'Units', 'Normalized',... +'Position', [ 0.02 0.925 0.2 0.025 ], ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); + +gui_data.edit_verbose_use_tabs = uicontrol('Parent', gui_data.panel_set_physio,... +'Style','edit',... +'String','false',... +'Units', 'Normalized',... +'Position', [ 0.25 0.925 0.2 0.025 ], ... +'CallBack', @editverbose_use_tabs , ... +'HorizontalAlignment', 'left',... +'fontsize', gui_data.small_font_size); \ No newline at end of file diff --git a/api-matlab/wrapper_physiobatch.m b/api-matlab/wrapper_physiobatch.m index 37ff6c2..66e9200 100644 --- a/api-matlab/wrapper_physiobatch.m +++ b/api-matlab/wrapper_physiobatch.m @@ -1,102 +1,145 @@ -function matlabbatch = wrapper_physiobatch(data_vendor, out_dir, default_path) +function matlabbatch = wrapper_physiobatch(data_vendor, out_dir, default_path, gui_data) spm_jobman('initcfg'); global defaults defaults.stats.maxmem = 2^30; matlabbatch = {}; - matlabbatch{1}.spm.tools.physio.save_dir = {[out_dir filesep 'physio_dir']}; matlabbatch{1}.spm.tools.physio.log_files.vendor = data_vendor; - - % EXAMPLES IN C:\Users\nwiedemann\Downloads\tapas\tapas\misc\example\PhysIO - + +% FOR TESTING: +% EXAMPLES IN C:\Users\nwiedemann\Downloads\tapas\tapas\misc\example\PhysIO +% matlabbatch{1}.spm.tools.physio.log_files.cardiac = {'C:\Users\nwiedemann\Downloads\tapas\tapas\misc\example\PhysIO\BIDS\CPULSE3T\sub-s998_task-random_run-99_physio.tsv'}; +% matlabbatch{1}.spm.tools.physio.log_files.respiration = {''}; +% matlabbatch{1}.spm.tools.physio.log_files.scan_timing = {''}; % different vendor options require different file input if strcmp(data_vendor, 'BIDS') - [tsv_filename, ~] = uigetfile('*.tsv*','Specify tsv/tsv.gz file with ECG data',default_path); - matlabbatch{1}.spm.tools.physio.log_files.cardiac = {tsv_filename}; + [tsv_filename, file_path] = uigetfile('*.tsv*','Specify tsv/tsv.gz file with ECG data',default_path); + matlabbatch{1}.spm.tools.physio.log_files.cardiac = {fullfile(file_path, tsv_filename)}; matlabbatch{1}.spm.tools.physio.log_files.respiration = {''}; matlabbatch{1}.spm.tools.physio.log_files.scan_timing = {''}; elseif strcmp(data_vendor, 'Philips') - [scanphyslog, ~] = uigetfile('*.log','Specify SCANPHYSLOG.log file', default_path); - matlabbatch{1}.spm.tools.physio.log_files.cardiac = {scanphyslog}; - matlabbatch{1}.spm.tools.physio.log_files.respiration = {scanphyslog}; - matlabbatch{1}.spm.tools.physio.log_files.scan_timing = {scanphyslog}; % or empty? + [scanphyslog, file_path] = uigetfile('*.log','Specify SCANPHYSLOG.log file', default_path); + matlabbatch{1}.spm.tools.physio.log_files.cardiac = {fullfile(file_path, scanphyslog)}; + matlabbatch{1}.spm.tools.physio.log_files.respiration = {fullfile(file_path, scanphyslog)}; + matlabbatch{1}.spm.tools.physio.log_files.scan_timing = {fullfile(file_path, scanphyslog)}; % or empty? elseif strcmp(data_vendor, 'Biopac_Txt') - [scanphyslog, ~] = uigetfile('*.txt','Specify biopac data export txt file', default_path); + [scanphyslog, file_path] = uigetfile('*.txt','Specify biopac data export txt file', default_path); % scanphyslog = input('Specify file path to the biopac data export txt file', 's'); - matlabbatch{1}.spm.tools.physio.log_files.cardiac = {scanphyslog}; - matlabbatch{1}.spm.tools.physio.log_files.respiration = {scanphyslog}; - matlabbatch{1}.spm.tools.physio.log_files.scan_timing = {scanphyslog}; + matlabbatch{1}.spm.tools.physio.log_files.cardiac = {fullfile(file_path, scanphyslog)}; + matlabbatch{1}.spm.tools.physio.log_files.respiration = {fullfile(file_path, scanphyslog)}; + matlabbatch{1}.spm.tools.physio.log_files.scan_timing = {fullfile(file_path, scanphyslog)}; elseif strcmp(data_vendor, 'GE') - [cardiac, ~] = uigetfile('*.*','Specify cardiac file (starting with ECGData_)', default_path); + [cardiac, file_path1] = uigetfile('*.*','Specify cardiac file (starting with ECGData_)', default_path); % cardiac = input('Specify file path to the cardiac file (in template starting with ECGData_)', 's'); - [respiration, ~] = uigetfile('*.*','Specify respiration file (starting with RespData_)', default_path); + [respiration, file_path2] = uigetfile('*.*','Specify respiration file (starting with RespData_)', default_path); % respiration = input('Specify file path to the respiration file (in template starting with RespData_)', 's'); - matlabbatch{1}.spm.tools.physio.log_files.cardiac = {cardiac}; - matlabbatch{1}.spm.tools.physio.log_files.respiration = {respiration}; + matlabbatch{1}.spm.tools.physio.log_files.cardiac = {fullfile(file_path1, cardiac)}; + matlabbatch{1}.spm.tools.physio.log_files.respiration = {fullfile(file_path2, respiration)}; matlabbatch{1}.spm.tools.physio.log_files.scan_timing = {''}; elseif strcmp(data_vendor, 'Siemens_HCP') - [physiolog, ~] = uigetfile('*.*','Specify physio data file (sth like tfMRI_MOTOR_LR_Physio_log.txt)', default_path); - matlabbatch{1}.spm.tools.physio.log_files.cardiac = {physiolog}; - matlabbatch{1}.spm.tools.physio.log_files.respiration = {physiolog}; + [physiolog, file_path] = uigetfile('*.*','Specify physio data file (sth like tfMRI_MOTOR_LR_Physio_log.txt)', default_path); + matlabbatch{1}.spm.tools.physio.log_files.cardiac = {fullfile(file_path, physiolog)}; + matlabbatch{1}.spm.tools.physio.log_files.respiration = {fullfile(file_path, physiolog)}; matlabbatch{1}.spm.tools.physio.log_files.scan_timing = {''}; elseif strcmp(data_vendor, 'Siemens') - [physiolog, ~] = uigetfile('*.ecg','Specify physio data file (siemens_PAV.ecg)', default_path); - matlabbatch{1}.spm.tools.physio.log_files.cardiac = {physiolog}; + [physiolog, file_path] = uigetfile('*.ecg','Specify physio data file (siemens_PAV.ecg)', default_path); + matlabbatch{1}.spm.tools.physio.log_files.cardiac = {fullfile(file_path, physiolog)}; matlabbatch{1}.spm.tools.physio.log_files.respiration = {''}; matlabbatch{1}.spm.tools.physio.log_files.scan_timing = {''}; elseif strcmp(data_vendor, 'Siemens_Tics') - [cardiac, ~] = uigetfile('*.log','Specify cardiac file (..._PULS.log)', default_path); - [respiration, ~] = uigetfile('*.log','Specify respiration file (..._RESP.log)', default_path); - [timing, ~] = uigetfile('*.log','Specify scan timing file (..._Info.log)', default_path); - matlabbatch{1}.spm.tools.physio.log_files.cardiac = {cardiac}; - matlabbatch{1}.spm.tools.physio.log_files.respiration = {respiration}; - matlabbatch{1}.spm.tools.physio.log_files.scan_timing = {timing}; + [cardiac, file_path1] = uigetfile('*.log','Specify cardiac file (..._PULS.log)', default_path); + [respiration, file_path2] = uigetfile('*.log','Specify respiration file (..._RESP.log)', default_path); + [timing, file_path3] = uigetfile('*.log','Specify scan timing file (..._Info.log)', default_path); + matlabbatch{1}.spm.tools.physio.log_files.cardiac = {fullfile(file_path1, cardiac)}; + matlabbatch{1}.spm.tools.physio.log_files.respiration = {fullfile(file_path2, respiration)}; + matlabbatch{1}.spm.tools.physio.log_files.scan_timing = {fullfile(file_path3, timing)}; else ME = MException('error:wronginput', 'Wrong vendor specified. Please specify one of BIDS, Philips, Biopac_Txt, GE, Siemens, Siemens_HCP, Siemens_Tics'); throw(ME); end % read scan parameters - input_params = inputdlg({'Number of scans:','Number of slices:','Number of dummies:', 'TR:', 'Onset slice:'}, 'Parameters for physio'); + input_params = inputdlg({'Number of scans:','Number of slices:','Number of dummies:', 'TR:', 'Onset slice:', 'ECG/PPU:'}, 'Parameters for physio', 1, {'30', '40', '0', '2', '1', 'ECG'}); - % scan parameters - matlabbatch{1}.spm.tools.physio.log_files.sampling_interval = []; - matlabbatch{1}.spm.tools.physio.log_files.relative_start_acquisition = 0; - matlabbatch{1}.spm.tools.physio.log_files.align_scan = 'last'; % sometimes first, sometimes last + % scan parameters --> input matlabbatch{1}.spm.tools.physio.scan_timing.sqpar.Nslices = str2double(input_params{2}); - matlabbatch{1}.spm.tools.physio.scan_timing.sqpar.NslicesPerBeat = []; matlabbatch{1}.spm.tools.physio.scan_timing.sqpar.TR = str2double(input_params{4}); matlabbatch{1}.spm.tools.physio.scan_timing.sqpar.Ndummies = str2double(input_params{3}); matlabbatch{1}.spm.tools.physio.scan_timing.sqpar.Nscans = str2double(input_params{1}); matlabbatch{1}.spm.tools.physio.scan_timing.sqpar.onset_slice = str2double(input_params{5}); - matlabbatch{1}.spm.tools.physio.scan_timing.sqpar.time_slice_to_slice = []; - - % template - matlabbatch{1}.spm.tools.physio.scan_timing.sqpar.Nprep = []; - matlabbatch{1}.spm.tools.physio.scan_timing.sync.nominal = struct([]); - matlabbatch{1}.spm.tools.physio.preproc.cardiac.modality = 'ECG'; - matlabbatch{1}.spm.tools.physio.preproc.cardiac.initial_cpulse_select.auto_matched.min = 0.4; - matlabbatch{1}.spm.tools.physio.preproc.cardiac.initial_cpulse_select.auto_matched.file = 'initial_cpulse_kRpeakfile.mat'; - matlabbatch{1}.spm.tools.physio.preproc.cardiac.posthoc_cpulse_select.off = struct([]); - matlabbatch{1}.spm.tools.physio.model.output_multiple_regressors = 'retroicor_regressors.txt'; - matlabbatch{1}.spm.tools.physio.model.output_physio = 'physio.mat'; - matlabbatch{1}.spm.tools.physio.model.orthogonalise = 'none'; - matlabbatch{1}.spm.tools.physio.model.censor_unreliable_recording_intervals = false; - matlabbatch{1}.spm.tools.physio.model.retroicor.yes.order.c = 3; - matlabbatch{1}.spm.tools.physio.model.retroicor.yes.order.r = 4; - matlabbatch{1}.spm.tools.physio.model.retroicor.yes.order.cr = 1; - matlabbatch{1}.spm.tools.physio.model.rvt.no = struct([]); - matlabbatch{1}.spm.tools.physio.model.hrv.no = struct([]); - matlabbatch{1}.spm.tools.physio.model.noise_rois.no = struct([]); - matlabbatch{1}.spm.tools.physio.model.movement.no = struct([]); - matlabbatch{1}.spm.tools.physio.model.other.no = struct([]); - matlabbatch{1}.spm.tools.physio.verbose.level = 2; - matlabbatch{1}.spm.tools.physio.verbose.fig_output_file = ''; - matlabbatch{1}.spm.tools.physio.verbose.use_tabs = false; + % input modality + matlabbatch{1}.spm.tools.physio.preproc.cardiac.modality = input_params{6}; - % save batch - save([out_dir filesep 'physio_batch'], 'matlabbatch'); - msgbox(['Saved matlabbatch in: ' out_dir], 'Success'); - - % spm_jobman('run',matlabbatch); -end \ No newline at end of file + % parameters from settings tab + matlabbatch{1}.spm.tools.physio.save_dir = {[out_dir filesep gui_data.edit_physio_save_dir.String]}; + matlabbatch{1}.spm.tools.physio.log_files.sampling_interval = eval(gui_data.edit_log_files_sampling_interval.String); + matlabbatch{1}.spm.tools.physio.log_files.relative_start_acquisition = str2double(gui_data.edit_log_files_relative_start_acquisition.String); + matlabbatch{1}.spm.tools.physio.log_files.align_scan = gui_data.edit_log_files_align_scan.String; + matlabbatch{1}.spm.tools.physio.scan_timing.sqpar.NslicesPerBeat = eval(gui_data.edit_sqpar_NslicesPerBeat.String); + matlabbatch{1}.spm.tools.physio.scan_timing.sqpar.time_slice_to_slice = eval(gui_data.edit_sqpar_time_slice_to_slice.String); + matlabbatch{1}.spm.tools.physio.scan_timing.sqpar.Nprep = eval(gui_data.edit_sqpar_Nprep.String); + matlabbatch{1}.spm.tools.physio.scan_timing.sync.nominal = struct(eval(gui_data.edit_sync_nominal.String)); + matlabbatch{1}.spm.tools.physio.preproc.cardiac.initial_cpulse_select.auto_matched.min = str2double(gui_data.edit_auto_matched_min.String); + matlabbatch{1}.spm.tools.physio.preproc.cardiac.initial_cpulse_select.auto_matched.file = gui_data.edit_auto_matched_file.String; + matlabbatch{1}.spm.tools.physio.preproc.cardiac.posthoc_cpulse_select.off = struct(eval(gui_data.edit_posthoc_cpulse_select_off.String)); + matlabbatch{1}.spm.tools.physio.model.output_multiple_regressors = gui_data.edit_model_output_multiple_regressors.String; + matlabbatch{1}.spm.tools.physio.model.output_physio = gui_data.edit_model_output_physio.String; + matlabbatch{1}.spm.tools.physio.model.orthogonalise = gui_data.edit_model_orthogonalise.String; + matlabbatch{1}.spm.tools.physio.model.censor_unreliable_recording_intervals = strcmpi(gui_data.edit_model_censor_unreliable_recording_intervals.String, 'true'); + matlabbatch{1}.spm.tools.physio.model.retroicor.yes.order.c = str2double(gui_data.edit_order_c.String); + matlabbatch{1}.spm.tools.physio.model.retroicor.yes.order.r = str2double(gui_data.edit_order_r.String); + matlabbatch{1}.spm.tools.physio.model.retroicor.yes.order.cr = str2double(gui_data.edit_order_cr.String); + matlabbatch{1}.spm.tools.physio.model.rvt.no = struct(eval(gui_data.edit_rvt_no.String)); + matlabbatch{1}.spm.tools.physio.model.hrv.no = struct(eval(gui_data.edit_hrv_no.String)); + matlabbatch{1}.spm.tools.physio.model.noise_rois.no = struct(eval(gui_data.edit_noise_rois_no.String)); + matlabbatch{1}.spm.tools.physio.model.movement.no = struct(eval(gui_data.edit_movement_no.String)); + matlabbatch{1}.spm.tools.physio.model.other.no = struct(eval(gui_data.edit_other_no.String)); + matlabbatch{1}.spm.tools.physio.verbose.level = str2double(gui_data.edit_verbose_level.String); + matlabbatch{1}.spm.tools.physio.verbose.fig_output_file = gui_data.edit_verbose_fig_output_file.String; + matlabbatch{1}.spm.tools.physio.verbose.use_tabs = strcmpi(gui_data.edit_verbose_use_tabs.String, 'true'); + + % check if physio is installed: + pathCell = regexp(path, pathsep, 'split'); + onPath = any(contains(pathCell, 'PhysIO')); + if onPath + spm_jobman('run',matlabbatch); + else + % save batch if physio is not installed + save([out_dir filesep 'physio_batch'], 'matlabbatch'); + % current out_dir: C:\Users\nwiedemann\Downloads\rtQC_sample_data\rtQC_sample_data\sub-hcp\rtQC_output + % msgbox(['Saved matlabbatch in: ' out_dir], 'Success'); + errordlg('Batch was saved to rtQC_output directory. \n \n Plots could not be created because the Physio toolbox is not installed or not added to path. Follow installation instructions on https://github.com/translationalneuromodeling/tapas.'); + end +end + +% matlabbatch{1}.spm.tools.physio.save_dir = {[out_dir filesep 'physio_out']}; +% +% scan parameters - defaults +% matlabbatch{1}.spm.tools.physio.log_files.sampling_interval = []; +% matlabbatch{1}.spm.tools.physio.log_files.relative_start_acquisition = 0; +% matlabbatch{1}.spm.tools.physio.log_files.align_scan = 'last'; % sometimes first, sometimes last +% matlabbatch{1}.spm.tools.physio.scan_timing.sqpar.NslicesPerBeat = []; +% matlabbatch{1}.spm.tools.physio.scan_timing.sqpar.time_slice_to_slice = []; % eval(gui_data.edit_sqpar_time_slice_to_slice.String); +% +% template +% matlabbatch{1}.spm.tools.physio.scan_timing.sqpar.Nprep = []; +% matlabbatch{1}.spm.tools.physio.scan_timing.sync.nominal = struct([]); +% matlabbatch{1}.spm.tools.physio.preproc.cardiac.initial_cpulse_select.auto_matched.min = 0.4; +% matlabbatch{1}.spm.tools.physio.preproc.cardiac.initial_cpulse_select.auto_matched.file = 'initial_cpulse_kRpeakfile.mat'; +% matlabbatch{1}.spm.tools.physio.preproc.cardiac.posthoc_cpulse_select.off = struct([]); +% matlabbatch{1}.spm.tools.physio.model.output_multiple_regressors = 'retroicor_regressors.txt'; +% matlabbatch{1}.spm.tools.physio.model.output_physio = 'physio.mat'; +% matlabbatch{1}.spm.tools.physio.model.orthogonalise = 'none'; +% matlabbatch{1}.spm.tools.physio.model.censor_unreliable_recording_intervals = false; +% matlabbatch{1}.spm.tools.physio.model.retroicor.yes.order.c = 3; +% matlabbatch{1}.spm.tools.physio.model.retroicor.yes.order.r = 4; % str2double(gui_data.edit_order_r.String); +% matlabbatch{1}.spm.tools.physio.model.retroicor.yes.order.cr = 1; +% matlabbatch{1}.spm.tools.physio.model.rvt.no = struct([]); +% matlabbatch{1}.spm.tools.physio.model.hrv.no = struct([]); +% matlabbatch{1}.spm.tools.physio.model.noise_rois.no = struct([]); +% matlabbatch{1}.spm.tools.physio.model.movement.no = struct([]); +% matlabbatch{1}.spm.tools.physio.model.other.no = struct([]); +% matlabbatch{1}.spm.tools.physio.verbose.level = 2; +% matlabbatch{1}.spm.tools.physio.verbose.fig_output_file = ''; % gui_data.edit_verbose_fig_output_file.String; +% matlabbatch{1}.spm.tools.physio.verbose.use_tabs = false; +% \ No newline at end of file From fc2cd7c020947c9cd1326c0bd397b5355c2b2dfe Mon Sep 17 00:00:00 2001 From: "Nina Valerie Wiedemann (ninwie)" Date: Mon, 3 Feb 2020 15:11:22 +0100 Subject: [PATCH 8/9] bugfix underscore missing --- api-matlab/rtQC_display.m | 55 ++++++++++++++++----------------- api-matlab/rtQC_display_setup.m | 3 +- 2 files changed, 28 insertions(+), 30 deletions(-) diff --git a/api-matlab/rtQC_display.m b/api-matlab/rtQC_display.m index 12e56bc..7851414 100644 --- a/api-matlab/rtQC_display.m +++ b/api-matlab/rtQC_display.m @@ -118,36 +118,34 @@ function rtQC_display() gui_data.pb_get_physio_batch.Callback = @physioBatch; % settings callback -gui_data.editphysio_save_dir.Callback = @editphysio_save_dir ; -gui_data.editlog_files_sampling_interval.Callback = @editlog_files_sampling_interval ; -gui_data.editlog_files_relative_start_acquisition.Callback = @editlog_files_relative_start_acquisition ; -gui_data.editlog_files_align_scan.Callback = @editlog_files_align_scan ; -gui_data.editsqpar_NslicesPerBeat.Callback = @editsqpar_NslicesPerBeat ; -gui_data.editsqpar_time_slice_to_slice.Callback = @editsqpar_time_slice_to_slice ; -gui_data.editsqpar_Nprep.Callback = @editsqpar_Nprep ; -gui_data.editsync_nominal.Callback = @editsync_nominal ; -gui_data.editauto_matched_min.Callback = @editauto_matched_min ; -gui_data.editauto_matched_file.Callback = @editauto_matched_file ; -gui_data.editposthoc_cpulse_select_off.Callback = @editposthoc_cpulse_select_off ; -gui_data.editmodel_output_multiple_regressors.Callback = @editmodel_output_multiple_regressors ; -gui_data.editmodel_output_physio.Callback = @editmodel_output_physio ; -gui_data.editmodel_orthogonalise.Callback = @editmodel_orthogonalise ; -gui_data.editmodel_censor_unreliable_recording_intervals.Callback = @editmodel_censor_unreliable_recording_intervals ; -gui_data.editorder_c.Callback = @editorder_c ; -gui_data.editorder_r.Callback = @editorder_r ; -gui_data.editorder_cr.Callback = @editorder_cr ; -gui_data.editrvt_no.Callback = @editrvt_no ; -gui_data.edithrv_no.Callback = @edithrv_no ; -gui_data.editnoise_rois_no.Callback = @editnoise_rois_no ; -gui_data.editmovement_no.Callback = @editmovement_no ; -gui_data.editother_no.Callback = @editother_no ; -gui_data.editverbose_level.Callback = @editverbose_level ; -gui_data.editverbose_fig_output_file.Callback = @editverbose_fig_output_file ; -gui_data.editverbose_use_tabs.Callback = @editverbose_use_tabs ; - +gui_data.edit_physio_save_dir.Callback = @editphysio_save_dir ; +gui_data.edit_log_files_sampling_interval.Callback = @editlog_files_sampling_interval ; +gui_data.edit_log_files_relative_start_acquisition.Callback = @editlog_files_relative_start_acquisition ; +gui_data.edit_log_files_align_scan.Callback = @editlog_files_align_scan ; +gui_data.edit_sqpar_NslicesPerBeat.Callback = @editsqpar_NslicesPerBeat ; +gui_data.edit_sqpar_time_slice_to_slice.Callback = @editsqpar_time_slice_to_slice ; +gui_data.edit_sqpar_Nprep.Callback = @editsqpar_Nprep ; +gui_data.edit_sync_nominal.Callback = @editsync_nominal ; +gui_data.edit_auto_matched_min.Callback = @editauto_matched_min ; +gui_data.edit_auto_matched_file.Callback = @editauto_matched_file ; +gui_data.edit_posthoc_cpulse_select_off.Callback = @editposthoc_cpulse_select_off ; +gui_data.edit_model_output_multiple_regressors.Callback = @editmodel_output_multiple_regressors ; +gui_data.edit_model_output_physio.Callback = @editmodel_output_physio ; +gui_data.edit_model_orthogonalise.Callback = @editmodel_orthogonalise ; +gui_data.edit_model_censor_unreliable_recording_intervals.Callback = @editmodel_censor_unreliable_recording_intervals ; +gui_data.edit_order_c.Callback = @editorder_c; +gui_data.edit_order_r.Callback = @editorder_r ; +gui_data.edit_order_cr.Callback = @editorder_cr ; +gui_data.edit_rvt_no.Callback = @editrvt_no ; +gui_data.edit_hrv_no.Callback = @edithrv_no ; +gui_data.edit_noise_rois_no.Callback = @editnoise_rois_no ; +gui_data.edit_movement_no.Callback = @editmovement_no ; +gui_data.edit_other_no.Callback = @editother_no ; +gui_data.edit_verbose_level.Callback = @editverbose_level ; +gui_data.edit_verbose_fig_output_file.Callback = @editverbose_fig_output_file ; +gui_data.edit_verbose_use_tabs.Callback = @editverbose_use_tabs ; set(findall(fig, '-property', 'Interruptible'), 'Interruptible', 'on') - % Make figure visible after normalizing units set(findall(fig, '-property', 'Units'), 'Units', 'Normalized') fig.Visible = 'on'; @@ -370,7 +368,6 @@ function editFDthreshold(hObject,eventdata) guidata(fig,gui_data) end - function editSPMdir(hObject,eventdata) fig = ancestor(hObject,'figure'); gui_data = guidata(fig); diff --git a/api-matlab/rtQC_display_setup.m b/api-matlab/rtQC_display_setup.m index 3c188d6..1f53e4b 100644 --- a/api-matlab/rtQC_display_setup.m +++ b/api-matlab/rtQC_display_setup.m @@ -1089,8 +1089,9 @@ % set(get(gui_data.panel_qcsummaryR,'Children'),'Enable','off') % set(children(strcmpi ( get (children,'Type'),'UIControl')),'enable','off') +%% --------------- Create UIcontrols for PRE QC tab -------------------- %% settings_tab; - +%% % Save GUI data guidata(fig, gui_data) From 1ecdcabfab0d29d717cb6247a8a1583764b8c948 Mon Sep 17 00:00:00 2001 From: "Nina Valerie Wiedemann (ninwie)" Date: Mon, 24 Feb 2020 14:26:06 +0100 Subject: [PATCH 9/9] export settings button --- api-matlab/rtQC_display.m | 30 ++++++++++++++++++++++++++++++ api-matlab/settings_tab.m | 28 +++++++++++----------------- 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/api-matlab/rtQC_display.m b/api-matlab/rtQC_display.m index 7851414..1b39dc8 100644 --- a/api-matlab/rtQC_display.m +++ b/api-matlab/rtQC_display.m @@ -145,6 +145,8 @@ function rtQC_display() gui_data.edit_verbose_fig_output_file.Callback = @editverbose_fig_output_file ; gui_data.edit_verbose_use_tabs.Callback = @editverbose_use_tabs ; +gui_data.export_settings.Callback = @export_settings; + set(findall(fig, '-property', 'Interruptible'), 'Interruptible', 'on') % Make figure visible after normalizing units set(findall(fig, '-property', 'Units'), 'Units', 'Normalized') @@ -236,6 +238,34 @@ function gotoTab2(hObject,eventdata) %%%% start settings tab functions +function export_settings(hObject,eventdata) + fig = ancestor(hObject,'figure'); + gui_data = guidata(fig); + panels = {'general', 'physio', 'new'}; + labels = {}; + values = {}; + counter = 1; + for i=1:length(panels) + children = eval(['gui_data.panel_set_' panels{i} '.Children']); + for j=1:length(children) + if strcmp(children(j).Style, 'text') + name = children(j).String; + name = strrep(name, '.', '_'); + matching_edit = eval(['gui_data.edit_' name '.String']); + labels{counter} = [panels{i} '_' name]; + values{counter} = matching_edit; + counter = counter+1; + end + end + end + % save to json file + enc = jsonencode(containers.Map(labels, values)); + fid = fopen([gui_data.qc_out_dir filesep 'settings.json'], 'wt'); + fprintf(fid, '%s', enc); + fclose(fid); + msgbox(['Saved settings in: ' gui_data.qc_out_dir], 'Success'); +end + function editphysio_save_dir (hObject,eventdata) fig = ancestor(hObject,'figure'); gui_data = guidata(fig); diff --git a/api-matlab/settings_tab.m b/api-matlab/settings_tab.m index 2dd7c0f..8f236b1 100644 --- a/api-matlab/settings_tab.m +++ b/api-matlab/settings_tab.m @@ -16,23 +16,17 @@ 'fontweight', 'bold',... 'fontsize', gui_data.standard_font_size); - -% gui_data.verbose_level = uicontrol('Parent', gui_data.panel_set_physio,... -% 'Style','text',... -% 'String','physio.verbose.level',... -% 'Units', 'Normalized',... -% 'Position',[0.02 0.55 0.15 0.05],... -% 'HorizontalAlignment', 'left',... -% 'fontsize', gui_data.small_font_size); -% gui_data.edit_verbose_level = uicontrol('Parent', gui_data.panel_set_physio,... -% 'Style', 'edit',... -% 'String', num2str(2), ... -% 'Units', 'Normalized',... -% 'Position', [0.18 0.55 0.1 0.05],... -% 'CallBack', @editverbose_level, ... -% 'HorizontalAlignment', 'right',... -% 'fontsize', gui_data.button_font_size); - +% Export Settings button: +gui_data.export_settings = uicontrol('Parent', gui_data.panel_set_general,... + 'Style', 'push',... + 'String', 'Export Settings', ... + 'Units', 'Normalized',... + 'Position', [0.8 0.06 0.18 0.225],... + 'CallBack', @export_settings, ... + 'UserData', 0,... + 'fontsize', gui_data.button_font_size); + +%% PHYSIO PANEL SETTINGS FIELDS gui_data.physio_save_dir = uicontrol('Parent', gui_data.panel_set_physio,... 'Style','text',... 'String','physio.save_dir ',...