Skip to content

Commit 39484f8

Browse files
Merge pull request #50 from markmikkelsen/upcoming-release
Release 3.5.0
2 parents b173d84 + 74f80ca commit 39484f8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+1965
-511
lines changed
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: Update bids-matlab
2+
3+
concurrency:
4+
group: ${{ github.workflow }}-${{ github.ref }}
5+
cancel-in-progress: true
6+
7+
run-name: ${{ github.actor }} is updating bids-matlab
8+
9+
on:
10+
schedule:
11+
- cron: 0 0 * * 1 # Every monday
12+
workflow_dispatch:
13+
14+
jobs:
15+
update-bids-matlab:
16+
runs-on: ubuntu-latest
17+
steps:
18+
- name: Checkout gannet repo
19+
uses: actions/checkout@v5
20+
21+
- name: Checkout bids-matlab repo
22+
uses: actions/checkout@v5
23+
with:
24+
repository: bids-standard/bids-matlab
25+
path: bids-matlab_tmp/
26+
27+
- name: Copy files from separate repo to current repo
28+
run: |
29+
rsync -av --exclude '.git' bids-matlab_tmp/ bids-matlab/
30+
rm -rf bids-matlab_tmp/
31+
32+
- name: Create pull request
33+
uses: peter-evans/create-pull-request@v7
34+
with:
35+
commit-message: Sync with bids-standard/bids-matlab repo
36+
assignees: markmikkelsen
37+
base: main
38+
delete-branch: true
39+
title: '[BOT] Update bids-matlab'
40+
body: Done by a [GitHub Action](https://github.com/markmikkelsen/Gannet/blob/main/.github/workflows/update_bids-matlab.yml)

.github/workflows/update_export_fig.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626

2727
- name: Copy files from separate repo to current repo
2828
run: |
29-
rsync -av --exclude '.git' export_fig_tmp/ export_fig/
29+
rsync -av --exclude '.git' --exclude '.ignore' export_fig_tmp/ export_fig/
3030
rm -rf export_fig_tmp/
3131
3232
- name: Create pull request

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
.DS_Store
22
.vscode/
3+
*.asv

CoRegStandAlone/CoReg.m

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
str = fread(fileID, Inf, '*uchar');
88
fclose(fileID);
99
str = char(str(:)');
10-
expression = '(?<field>MRS_struct.version.coreg = )''(?<version>.*?)''';
10+
expression = '(?<field>MRS_struct.info.version.coreg = )''(?<version>.*?)''';
1111
out = regexp(str, expression, 'names');
12-
MRS_struct.version.coreg = out.version;
12+
MRS_struct.info.version.coreg = out.version;
1313

1414
warning('off'); % temporarily suppress warning messages
1515

@@ -125,7 +125,7 @@
125125
set(ha, 'Position', [0 pos(2) 1 pos(4)]);
126126
axis off;
127127

128-
[~,tmp,tmp2] = fileparts(MRS_struct.mask.(vox{kk}).outfile{ii});
128+
[~,tmp,tmp2] = fileparts(MRS_struct.mask.(vox{kk}).fname{ii});
129129
fname = [tmp tmp2];
130130
if length(fname) > 30
131131
fname = [fname(1:12) '...' fname(end-11:end)];
@@ -157,7 +157,7 @@
157157
text(0.5, 0.15, tmp, 'Units', 'normalized', 'FontName', 'Arial', 'FontSize', 13);
158158

159159
text(0.5, 0.03, 'CoRegVer: ', 'Units', 'normalized', 'HorizontalAlignment', 'right', 'FontName', 'Arial', 'FontSize', 13);
160-
text(0.5, 0.03, [' ' MRS_struct.version.coreg], 'Units', 'normalized', 'FontName', 'Arial', 'FontSize', 13);
160+
text(0.5, 0.03, [' ' MRS_struct.info.version.coreg], 'Units', 'normalized', 'FontName', 'Arial', 'FontSize', 13);
161161

162162
hb = subplot(2,3,1:3);
163163

@@ -204,7 +204,7 @@
204204
d.width = 1;
205205
d.height = 0.02;
206206
axes('Position', [d.left d.bottom d.width d.height], 'Units', 'normalized');
207-
text(0.9925, 0, MRS_struct.version.Gannet, 'Units', 'normalized', 'FontName', 'Arial', 'FontSize', 14, 'FontWeight', 'bold', 'HorizontalAlignment', 'right');
207+
text(0.9925, 0, MRS_struct.info.version.Gannet, 'Units', 'normalized', 'FontName', 'Arial', 'FontSize', 14, 'FontWeight', 'bold', 'HorizontalAlignment', 'right');
208208
axis off;
209209

210210
% Gannet documentation

CoRegStandAlone/CoRegStandAlone.m

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,13 @@
4343
% 2023-03-13: Update CSV filenames; prevent overwriting if CSV file
4444
% already exists in the output directory
4545

46-
if nargin == 0
46+
if nargin ~= 2
4747
fprintf('\n');
48-
error('MATLAB:minrhs', 'Not enough input arguments.');
48+
error('MATLAB:minrhs', 'Incorrect number of input arguments. Expected exactly 2 arguments.');
4949
end
5050

51+
assert(iscell(metabfile) && iscell(struc), 'Inputs must be entered as cell arrays.');
52+
5153
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5254
% 1. Pre-initialise
5355
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -57,15 +59,15 @@
5759
str = fread(fileID, Inf, '*uchar');
5860
fclose(fileID);
5961
str = char(str(:)');
60-
expression = '(?<field>MRS_struct.version.Gannet = )''(?<version>.*?)''';
62+
expression = '(?<field>MRS_struct.info.version.Gannet = )''(?<version>.*?)''';
6163
out = regexp(str, expression, 'names');
62-
MRS_struct.version.Gannet = out.version;
64+
MRS_struct.info.version.Gannet = out.version;
6365

64-
expression = '(?<field>MRS_struct.version.load = )''(?<version>.*?)''';
66+
expression = '(?<field>MRS_struct.info.version.load = )''(?<version>.*?)''';
6567
out = regexp(str, expression, 'names');
66-
MRS_struct.version.load = out.version;
68+
MRS_struct.info.version.load = out.version;
6769

68-
MRS_struct.version.coregstandalone = '240504';
70+
MRS_struct.info.version.coregstandalone = '250911';
6971

7072
MRS_struct.ii = 0;
7173
if size(metabfile,2) == 1

CoRegStandAlone/Seg.m

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616
str = fread(fileID, Inf, '*uchar');
1717
fclose(fileID);
1818
str = char(str(:)');
19-
expression = '(?<field>MRS_struct.version.segment = )''(?<version>.*?)''';
19+
expression = '(?<field>MRS_struct.info.version.segment = )''(?<version>.*?)''';
2020
out = regexp(str, expression, 'names');
21-
MRS_struct.version.segment = out.version;
21+
MRS_struct.info.version.segment = out.version;
2222

2323
warning('off'); % temporarily suppress warning messages
2424

@@ -131,7 +131,7 @@
131131
% Loop over voxels if PRIAM
132132
for kk = 1:length(vox)
133133

134-
voxmaskvol = spm_vol(cell2mat(MRS_struct.mask.(vox{kk}).outfile(ii)));
134+
voxmaskvol = spm_vol(cell2mat(MRS_struct.mask.(vox{kk}).fname(ii)));
135135
[a,b,c] = fileparts(voxmaskvol.fname);
136136

137137
% GM
@@ -235,7 +235,7 @@
235235
text(0.5, text_pos-0.6, tmp, 'Units', 'normalized', 'FontName', 'Arial', 'VerticalAlignment', 'top', 'FontSize', 13);
236236

237237
text(0.5, text_pos-0.72, 'SegmentVer: ', 'Units', 'normalized', 'FontName', 'Arial', 'HorizontalAlignment','right', 'VerticalAlignment', 'top', 'FontSize', 13);
238-
text(0.5, text_pos-0.72, [' ' MRS_struct.version.segment], 'Units', 'normalized', 'FontName', 'Arial', 'VerticalAlignment', 'top', 'FontSize', 13);
238+
text(0.5, text_pos-0.72, [' ' MRS_struct.info.version.segment], 'Units', 'normalized', 'FontName', 'Arial', 'VerticalAlignment', 'top', 'FontSize', 13);
239239

240240
if isfield(MRS_struct.p,'TablePosition')
241241
voxoff = MRS_struct.p.voxoff(ii,:) + MRS_struct.p.TablePosition(ii,:);
@@ -276,7 +276,7 @@
276276
d.width = 1;
277277
d.height = 0.02;
278278
axes('Position', [d.left d.bottom d.width d.height], 'Units', 'normalized');
279-
text(0.9925, 0, MRS_struct.version.Gannet, 'Units', 'normalized', 'FontName', 'Arial', 'FontSize', 14, 'FontWeight', 'bold', 'HorizontalAlignment', 'right');
279+
text(0.9925, 0, MRS_struct.info.version.Gannet, 'Units', 'normalized', 'FontName', 'Arial', 'FontSize', 14, 'FontWeight', 'bold', 'HorizontalAlignment', 'right');
280280
axis off;
281281

282282
% Gannet documentation

ExportToCSV.m

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
n_rep = [size(MRS_struct.metabfile,2) 1];
77
end
88
out.MATLAB_ver = cellstr(repmat(version('-release'), n_rep));
9-
out.Gannet_ver = cellstr(repmat(MRS_struct.version.Gannet, n_rep));
9+
out.Gannet_ver = cellstr(repmat(MRS_struct.info.version.Gannet, n_rep));
1010
out.date_of_analysis = cellstr(repmat(char(datetime('now','Format','y-MM-dd')), n_rep));
1111

1212

@@ -74,14 +74,19 @@
7474
if isfield(MRS_struct.out.(vox), 'csv_name')
7575
csv_name = MRS_struct.out.(vox).csv_name;
7676
else
77-
csv_name = fullfile(pwd, 'Gannet_output.csv');
77+
if ~MRS_struct.p.bids
78+
out_dir = pwd;
79+
else % BIDSify
80+
out_dir = fullfile(MRS_struct.out.BIDS.pth, 'derivatives', 'Gannet_output');
81+
end
82+
csv_name = fullfile(out_dir, 'Gannet_output.csv');
7883
if exist(csv_name, 'file')
7984
run_count = 1;
80-
csv_name = fullfile(pwd, ['Gannet_output' num2str(run_count) '.csv']);
85+
csv_name = fullfile(out_dir, ['Gannet_output' num2str(run_count) '.csv']);
8186
while 1
8287
if exist(csv_name, 'file')
8388
run_count = run_count + 1;
84-
csv_name = fullfile(pwd, ['Gannet_output' num2str(run_count) '.csv']);
89+
csv_name = fullfile(out_dir, ['Gannet_output' num2str(run_count) '.csv']);
8590
else
8691
break
8792
end

GEDeIdentify.m

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ function GEDeIdentify(fnames)
3838
% 2020-10-23: + Added support for rdbm_rev_num 27.x
3939
% 2023-07-28: + Added support for rdbm_rev_num 30
4040
% 2024-08-27: + Display a disclaimer when running GEDeIdentify
41+
% 2025-09-10: + Improved input argument validation
4142

4243
DeIdentifyDisclaimer;
4344

@@ -56,6 +57,8 @@ function GEDeIdentify(fnames)
5657
end
5758

5859
else % De-identify P-files user has listed in fnames
60+
61+
assert(iscell(fnames), 'Input must be entered as a cell array.')
5962

6063
% Check if filenames include a .7 extension
6164
for ii = 1:length(fnames)

GannetCoRegister.m

Lines changed: 51 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,29 @@
11
function MRS_struct = GannetCoRegister(MRS_struct, struc)
22
% Co-registration of MRS voxel volumes to imaging datasets, based on headers.
33

4-
if nargin < 2
4+
if nargin < 1 || ...
5+
(nargin < 2 && ~(isfield(MRS_struct, 'p') && isfield(MRS_struct.p, 'bids') && MRS_struct.p.bids))
56
fprintf('\n');
6-
error('MATLAB:minrhs', 'Not enough input arguments.');
7+
error('MATLAB:minrhs', ['Not enough input arguments. ' ...
8+
'GannetCoRegister requires two arguments (MRS_struct, struc), ' ...
9+
'unless processing a BIDS dataset, in which case only MRS_struct ' ...
10+
'is required.']);
711
end
812

913
if ~isstruct(MRS_struct)
1014
fprintf('\n');
11-
error('The first input argument ''%s'' must be a structure.', MRS_struct);
15+
error('The first input argument must be a structure, but received %s.', class(MRS_struct));
1216
end
1317

14-
if ~iscell(struc)
15-
fprintf('\n');
16-
error('The second input argument ''%s'' must be a structure.', struc);
18+
if nargin == 2
19+
if ~iscell(struc)
20+
fprintf('\n');
21+
error('The second input argument ''%s'' must be a structure.', struc);
22+
end
1723
end
1824

19-
MRS_struct.version.coreg = '250805';
25+
MRS_struct.info.datetime.coreg = datetime('now');
26+
MRS_struct.info.version.coreg = '250911';
2027

2128
warning('off'); % temporarily suppress warning messages
2229

@@ -41,7 +48,26 @@
4148
vox = MRS_struct.p.vox(1);
4249
end
4350

44-
struc = GetFullPath(struc);
51+
% Find MR images if processing a BIDS dataset
52+
if MRS_struct.p.bids
53+
struc = cell(MRS_struct.p.numScans,1);
54+
for ii = 1:MRS_struct.p.numScans
55+
bids_file = bids.File(MRS_struct.metabfile{ii});
56+
if ~exist(fullfile(MRS_struct.out.BIDS.pth, 'derivatives', 'Gannet_output', bids_file.bids_path), 'dir')
57+
bids.util.mkdir(fullfile(MRS_struct.out.BIDS.pth, 'derivatives', 'Gannet_output', bids_file.bids_path));
58+
end
59+
metadata = bids.internal.get_metadata(bids.internal.get_meta_list(MRS_struct.metabfile{ii}));
60+
try
61+
struc{ii} = bids.internal.resolve_bids_uri(metadata.AnatomicalImage, MRS_struct.out.BIDS);
62+
catch
63+
fprintf('\n');
64+
error(['No valid structural images found for ''%s''.' ...
65+
'\nCheck that its JSON sidecar file has an entry for ''AnatomicalImage''.'], bids_file.filename);
66+
end
67+
end
68+
else
69+
struc = GetFullPath(struc);
70+
end
4571

4672
if MRS_struct.p.numScans ~= length(struc)
4773
fprintf('\n');
@@ -154,8 +180,8 @@
154180
set(ha, 'Position', [0 pos(2) 1 pos(4)]);
155181
axis off;
156182

157-
[~,tmp,tmp2] = fileparts(MRS_struct.mask.(vox{kk}).outfile{ii});
158-
fname = [tmp tmp2];
183+
[~,name,ext] = fileparts(MRS_struct.mask.(vox{kk}).fname{ii});
184+
fname = [name ext];
159185
if length(fname) > 30
160186
fname = [fname(1:12) '...' fname(end-11:end)];
161187
end
@@ -165,42 +191,42 @@
165191
text(0.5, 0.63, 'Spatial parameters: ', 'Units', 'normalized', 'HorizontalAlignment', 'right', 'FontName', 'Arial', 'FontSize', 13);
166192
text(0.5, 0.63, ' [LR, PA, SI]', 'Units', 'normalized', 'FontName', 'Arial', 'FontSize', 13);
167193

168-
tmp = [' ' num2str(MRS_struct.p.voxdim(ii,1)) ' \times ' num2str(MRS_struct.p.voxdim(ii,2)) ' \times ' num2str(MRS_struct.p.voxdim(ii,3)) ' mm^{3}'];
194+
str = [' ' num2str(MRS_struct.p.voxdim(ii,1)) ' \times ' num2str(MRS_struct.p.voxdim(ii,2)) ' \times ' num2str(MRS_struct.p.voxdim(ii,3)) ' mm^{3}'];
169195
text(0.5, 0.51, 'Dimensions: ', 'Units', 'normalized', 'HorizontalAlignment', 'right', 'FontName', 'Arial', 'FontSize', 13);
170-
text(0.5, 0.51, tmp, 'Units', 'normalized', 'FontName', 'Arial', 'FontSize', 13, 'Interpreter', 'tex');
196+
text(0.5, 0.51, str, 'Units', 'normalized', 'FontName', 'Arial', 'FontSize', 13, 'Interpreter', 'tex');
171197

172-
tmp = [' ' num2str(prod(MRS_struct.p.voxdim(ii,:))/1e3) ' mL'];
198+
str = [' ' num2str(prod(MRS_struct.p.voxdim(ii,:))/1e3) ' mL'];
173199
text(0.5, 0.39, 'Volume: ', 'Units', 'normalized', 'HorizontalAlignment', 'right', 'FontName', 'Arial', 'FontSize', 13);
174-
text(0.5, 0.39, tmp, 'Units', 'normalized', 'FontName', 'Arial', 'FontSize', 13);
200+
text(0.5, 0.39, str, 'Units', 'normalized', 'FontName', 'Arial', 'FontSize', 13);
175201

176-
tmp = [' [' num2str(MRS_struct.p.voxoff(ii,1), '%3.1f') ', ' num2str(MRS_struct.p.voxoff(ii,2), '%3.1f') ', ' num2str(MRS_struct.p.voxoff(ii,3), '%3.1f') '] mm'];
202+
str = [' [' num2str(MRS_struct.p.voxoff(ii,1), '%3.1f') ', ' num2str(MRS_struct.p.voxoff(ii,2), '%3.1f') ', ' num2str(MRS_struct.p.voxoff(ii,3), '%3.1f') '] mm'];
177203
text(0.5, 0.27, 'Position: ', 'Units', 'normalized', 'HorizontalAlignment', 'right', 'FontName', 'Arial', 'FontSize', 13);
178-
text(0.5, 0.27, tmp, 'Units', 'normalized', 'FontName', 'Arial', 'FontSize', 13);
204+
text(0.5, 0.27, str, 'Units', 'normalized', 'FontName', 'Arial', 'FontSize', 13);
179205

180206
if any(strcmp(MRS_struct.p.vendor, {'Philips', 'Philips_data'}))
181-
tmp = [' [' num2str(MRS_struct.p.voxang(ii,2), '%3.1f') ', ' num2str(MRS_struct.p.voxang(ii,1), '%3.1f') ', ' num2str(MRS_struct.p.voxang(ii,3), '%3.1f') '] deg'];
207+
str = [' [' num2str(MRS_struct.p.voxang(ii,2), '%3.1f') ', ' num2str(MRS_struct.p.voxang(ii,1), '%3.1f') ', ' num2str(MRS_struct.p.voxang(ii,3), '%3.1f') '] deg'];
182208
else
183-
tmp = [' [' num2str(MRS_struct.p.voxang(ii,1), '%3.1f') ', ' num2str(MRS_struct.p.voxang(ii,2), '%3.1f') ', ' num2str(MRS_struct.p.voxang(ii,3), '%3.1f') '] deg'];
209+
str = [' [' num2str(MRS_struct.p.voxang(ii,1), '%3.1f') ', ' num2str(MRS_struct.p.voxang(ii,2), '%3.1f') ', ' num2str(MRS_struct.p.voxang(ii,3), '%3.1f') '] deg'];
184210
end
185211
text(0.5, 0.15, 'Angulation: ', 'Units', 'normalized', 'HorizontalAlignment', 'right', 'FontName', 'Arial', 'FontSize', 13);
186-
text(0.5, 0.15, tmp, 'Units', 'normalized', 'FontName', 'Arial', 'FontSize', 13);
212+
text(0.5, 0.15, str, 'Units', 'normalized', 'FontName', 'Arial', 'FontSize', 13);
187213

188214
text(0.5, 0.03, 'CoRegVer: ', 'Units', 'normalized', 'HorizontalAlignment', 'right', 'FontName', 'Arial', 'FontSize', 13);
189-
text(0.5, 0.03, [' ' MRS_struct.version.coreg], 'Units', 'normalized', 'FontName', 'Arial', 'FontSize', 13);
215+
text(0.5, 0.03, [' ' MRS_struct.info.version.coreg], 'Units', 'normalized', 'FontName', 'Arial', 'FontSize', 13);
190216

191217
hb = subplot(2,3,1:3);
192218

193219
if strcmp(MRS_struct.p.vendor, 'Siemens_rda')
194-
[~,tmp,tmp2] = fileparts(MRS_struct.metabfile{1,ii*2-1});
220+
[~,name,ext] = fileparts(MRS_struct.metabfile{1,ii*2-1});
195221
else
196-
[~,tmp,tmp2] = fileparts(MRS_struct.metabfile{1,ii});
222+
[~,name,ext] = fileparts(MRS_struct.metabfile{1,ii});
197223
end
198-
fname = [tmp tmp2];
224+
fname = [name ext];
199225
if length(fname) > 30
200226
fname = [fname(1:12) '...' fname(end-11:end)];
201227
end
202-
[~,tmp3,tmp4] = fileparts(MRS_struct.mask.(vox{kk}).T1image{ii});
203-
T1image = [tmp3 tmp4];
228+
[~,name,ext] = fileparts(MRS_struct.mask.(vox{kk}).T1image{ii});
229+
T1image = [name ext];
204230
if length(T1image) > 30
205231
T1image = [T1image(1:12) '...' T1image(end-11:end)];
206232
end

0 commit comments

Comments
 (0)