|
3 | 3 | % Creates a figure showing a histogram of the content of a set of ROIs used on |
4 | 4 | % a set of data files. |
5 | 5 | % |
| 6 | + % ROI label is extracted from the label entity in the BIDS filename. |
| 7 | + % |
6 | 8 | % USAGE:: |
7 | 9 | % |
8 | | - % figHandle = plotDataInRoi(dataImages, roiImages) |
| 10 | + % figHandle = plotDataInRoi(dataImages, roiImages, ... |
| 11 | + % 'scaleFactor', 1, ... |
| 12 | + % 'roiAs', 'rows', ... |
| 13 | + % 'dataLabel', {}) |
9 | 14 | % |
10 | 15 | % :param dataImages: |
11 | 16 | % :type dataImages: path or cellstr of paths |
12 | 17 | % |
13 | 18 | % :param roiImages: |
14 | 19 | % :type roiImages: path or cellstr of paths |
15 | 20 | % |
| 21 | + % :param scaleFactor: value to scale the factor by. Default to 1. |
| 22 | + % :type scaleFactor: numerical |
| 23 | + % |
| 24 | + % :param roiAs: Determine if the ROI are supposed to be organized by rows or |
| 25 | + % columns. |
| 26 | + % Default to 'rows'. |
| 27 | + % :type roiAs: 'rows' or 'cols' |
| 28 | + % |
| 29 | + % :param dataLabel: strings to use to label the data rows or columns. |
| 30 | + % :type dataLabel: cellstr |
| 31 | + % |
16 | 32 | % |
17 | 33 | % EXAMPLE:: |
18 | 34 | % |
|
33 | 49 | defaultNbBins = 100; |
34 | 50 |
|
35 | 51 | isFile = @(x) iscellstr(x) || exist(x, 'file') == 2; |
| 52 | + rowOrCol = @(x) ismember(x, {'rows', 'cols'}); |
36 | 53 |
|
37 | 54 | args = inputParser; |
38 | 55 |
|
39 | 56 | args.addRequired('dataImages', isFile); |
40 | 57 | args.addRequired('roiImages', isFile); |
| 58 | + args.addParameter('scaleFactor', 1, @isnumeric); |
| 59 | + args.addParameter('roiAs', 'rows', rowOrCol); |
| 60 | + args.addParameter('dataLabel', {}, @iscellstr); |
41 | 61 |
|
42 | 62 | args.parse(varargin{:}); |
43 | 63 |
|
44 | 64 | dataImages = args.Results.dataImages; |
45 | 65 | roiImages = args.Results.roiImages; |
| 66 | + scaleFactor = args.Results.scaleFactor; |
| 67 | + roiAs = args.Results.roiAs; |
| 68 | + dataLabel = args.Results.dataLabel; |
46 | 69 |
|
47 | 70 | if ischar(dataImages) |
48 | 71 | dataImages = {dataImages}; |
|
55 | 78 | nbRois = numel(roiImages); |
56 | 79 | nbData = numel(dataImages); |
57 | 80 |
|
58 | | - if nbRois == 1 || nbData == 1 |
59 | | - [rows, cols] = optimizeSubplotNumber(nbRois * nbData); |
60 | | - else |
| 81 | + if numel(dataLabel) ~= nbData |
| 82 | + warning('numel dataLabel must be equal to numel dataImages'); |
| 83 | + dataLabel = {}; |
| 84 | + end |
| 85 | + |
| 86 | + if strcmp(roiAs, 'rows') |
61 | 87 | rows = nbRois; |
62 | 88 | cols = nbData; |
| 89 | + elseif strcmp(roiAs, 'cols') |
| 90 | + cols = nbRois; |
| 91 | + rows = nbData; |
63 | 92 | end |
64 | 93 |
|
65 | | - figHandle = figure('position', [50 50 300 * rows 300 * cols]); |
| 94 | + figHandle = figure('position', [50 50 300 * cols 300 * rows]); |
66 | 95 |
|
67 | 96 | %% collect info to adapt the graphs later on |
68 | 97 |
|
69 | | - % y scale |
| 98 | + % max of scale for data values |
70 | 99 | maxVox = []; |
71 | 100 |
|
72 | | - % x axis |
| 101 | + % limit axis of axis for ROI (as nb of voxels) |
73 | 102 | MIN = []; |
74 | 103 | MAX = []; |
75 | 104 |
|
76 | 105 | % use the same number of bins for all graphs |
77 | | - % based on the minimum number of unique values across all the datasets |
| 106 | + % based on the number of unique values across all the datasets |
78 | 107 | nbBins = []; |
79 | 108 |
|
80 | 109 | % to plot all the modes |
|
84 | 113 |
|
85 | 114 | idxSubplot = 1; |
86 | 115 |
|
87 | | - for iRoi = 1:nbRois |
| 116 | + for iRow = 1:rows |
88 | 117 |
|
89 | | - for iData = 1:nbData |
| 118 | + for iCol = 1:cols |
90 | 119 |
|
91 | | - data{idxSubplot} = spm_summarise(spm_vol(dataImages{iData}), roiImages{iRoi}); |
| 120 | + if strcmp(roiAs, 'rows') |
| 121 | + data{idxSubplot} = spm_summarise(spm_vol(dataImages{iCol}), roiImages{iRow}) * scaleFactor; |
| 122 | + elseif strcmp(roiAs, 'cols') |
| 123 | + data{idxSubplot} = spm_summarise(spm_vol(dataImages{iRow}), roiImages{iCol}) * scaleFactor; |
| 124 | + end |
92 | 125 |
|
93 | | - [~, bins] = hist(data{idxSubplot}, defaultNbBins); |
| 126 | + if isempty(data{idxSubplot}) |
| 127 | + bins = nan; |
| 128 | + else |
| 129 | + [~, bins] = hist(data{idxSubplot}, defaultNbBins); |
| 130 | + end |
94 | 131 | MAX(end + 1) = max(bins); |
95 | 132 | MIN(end + 1) = min(bins); |
96 | 133 |
|
97 | 134 | % modes and nbBins work better on rounded values |
98 | 135 | modes(end + 1) = mode(round(data{idxSubplot})); |
99 | 136 | nbBins(end + 1) = numel(unique(round(data{idxSubplot}))); |
100 | 137 |
|
101 | | - subplotList(iRoi, iData) = idxSubplot; |
| 138 | + subplotList(iRow, iCol) = idxSubplot; |
102 | 139 |
|
103 | 140 | idxSubplot = idxSubplot + 1; |
104 | 141 |
|
105 | 142 | end |
106 | 143 |
|
107 | 144 | end |
108 | 145 |
|
109 | | - nbBins = min(nbBins); |
| 146 | + nbBins = max(nbBins); |
110 | 147 |
|
111 | 148 | for i = 1:numel(data) |
112 | 149 | tmp = hist(data{i}, nbBins); |
113 | | - maxVox(end + 1) = max(tmp); |
| 150 | + if isempty(tmp) |
| 151 | + maxVox(end + 1) = nan; |
| 152 | + else |
| 153 | + maxVox(end + 1) = max(tmp); |
| 154 | + end |
114 | 155 | end |
115 | 156 |
|
116 | 157 | %% plot histogram and mode |
117 | 158 |
|
118 | 159 | idxSubplot = 1; |
119 | 160 |
|
120 | | - for iRoi = 1:nbRois |
| 161 | + for iRow = 1:rows |
121 | 162 |
|
122 | | - for iData = 1:nbData |
| 163 | + for iCol = 1:cols |
123 | 164 |
|
124 | 165 | subplot(rows, cols, idxSubplot); |
125 | 166 |
|
126 | 167 | hold on; |
127 | 168 |
|
128 | | - hist(data{idxSubplot}, nbBins); |
| 169 | + if ~isempty(data{idxSubplot}) |
| 170 | + |
| 171 | + hist(data{idxSubplot}, nbBins); |
129 | 172 |
|
130 | | - plot([modes(idxSubplot) modes(idxSubplot)], ... |
131 | | - [0 max(maxVox)], ... |
132 | | - '--r', ... |
133 | | - 'linewidth', 1); |
| 173 | + plot([modes(idxSubplot) modes(idxSubplot)], ... |
| 174 | + [0 max(maxVox)], ... |
| 175 | + '--r', ... |
| 176 | + 'linewidth', 1); |
134 | 177 |
|
135 | | - bf = bids.File(roiImages{iRoi}); |
136 | | - title(['roi: ' bf.entities.label]); |
| 178 | + t = text(max(MAX) * 0.5, ... |
| 179 | + max(maxVox) * 0.85, ... |
| 180 | + sprintf('mean=%0.2f', mean(data{idxSubplot}))); |
| 181 | + |
| 182 | + set(t, 'FontSize', 10); |
| 183 | + |
| 184 | + end |
137 | 185 |
|
138 | 186 | axis([min(MIN) max(MAX) 0 max(maxVox)]); |
139 | 187 |
|
|
143 | 191 |
|
144 | 192 | end |
145 | 193 |
|
146 | | - for i = 1:cols |
147 | | - subplot(rows, cols, subplotList(end, i)); |
148 | | - xlabel('intensities'); |
149 | | - end |
| 194 | + %% label axis |
| 195 | + |
| 196 | + if strcmp(roiAs, 'rows') |
| 197 | + |
| 198 | + for i = 1:cols |
| 199 | + subplot(rows, cols, subplotList(end, i)); |
| 200 | + xlabel('intensities'); |
| 201 | + end |
| 202 | + |
| 203 | + for i = 1:rows |
| 204 | + |
| 205 | + subplot(rows, cols, subplotList(i, 1)); |
| 206 | + |
| 207 | + bf = bids.File(roiImages{i}); |
| 208 | + l = ylabel(sprintf('roi: %s\nnb voxels', bf.entities.label)); |
| 209 | + set(l, 'FontWeight', 'bold'); |
| 210 | + |
| 211 | + end |
| 212 | + |
| 213 | + else |
| 214 | + |
| 215 | + for i = 1:cols |
| 216 | + |
| 217 | + subplot(rows, cols, subplotList(1, i)); |
| 218 | + |
| 219 | + bf = bids.File(roiImages{i}); |
| 220 | + title(sprintf('roi: %s', bf.entities.label)); |
| 221 | + |
| 222 | + subplot(rows, cols, subplotList(end, i)); |
| 223 | + |
| 224 | + xlabel('nb voxels'); |
| 225 | + |
| 226 | + end |
| 227 | + |
| 228 | + for i = 1:rows |
| 229 | + |
| 230 | + subplot(rows, cols, subplotList(i, 1)); |
| 231 | + |
| 232 | + label = ''; |
| 233 | + if ~isempty(dataLabel) |
| 234 | + label = dataLabel{i}; |
| 235 | + end |
| 236 | + l = ylabel(sprintf('%s', label)); |
| 237 | + set(l, 'FontWeight', 'bold'); |
| 238 | + |
| 239 | + end |
150 | 240 |
|
151 | | - for i = 1:rows |
152 | | - subplot(rows, cols, subplotList(i, 1)); |
153 | | - ylabel('nb voxels'); |
154 | 241 | end |
155 | 242 |
|
156 | 243 | end |
0 commit comments