Skip to content

[ENH] update plotDataInRoi #42

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
190 changes: 152 additions & 38 deletions src/roi/plotDataInRoi.m
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,40 @@
% Creates a figure showing a histogram of the content of a set of ROIs used on
% a set of data files.
%
% ROI label is extracted from the label entity in the BIDS filename.
%
% USAGE::
%
% figHandle = plotDataInRoi(dataImages, roiImages)
% figHandle = plotDataInRoi(dataImages, roiImages, ...
% 'scaleFactor', 1, ...
% 'roiAs', 'rows', ...
% 'dataLabel', {})
%
% :param dataImages:
% :type dataImages: path or cellstr of paths
%
% :param roiImages:
% :type roiImages: path or cellstr of paths
%
% :param scaleFactor: value to scale the factor by. Default to 1.
% :type scaleFactor: numerical
%
% :param roiAs: Determine if the ROI are supposed to be organized by rows or
% columns.
% Default to 'rows'.
% :type roiAs: 'rows' or 'cols'
%
% :param dataLabel: strings to use to label the data rows or columns.
% :type dataLabel: cellstr
%
% :param maxVox: max of scale for nb of voxels. Default to [].
% :type maxVox: positive integer
%
% :param nbBins: use the same number of bins for all graphs.
% By default based on the number of unique values across all
% the datasets.
% :type nbBins: positive integer
%
%
% EXAMPLE::
%
Expand All @@ -33,16 +57,26 @@
defaultNbBins = 100;

isFile = @(x) iscellstr(x) || exist(x, 'file') == 2;
rowOrCol = @(x) ismember(x, {'rows', 'cols'});

args = inputParser;

args.addRequired('dataImages', isFile);
args.addRequired('roiImages', isFile);
args.addParameter('scaleFactor', 1, @isnumeric);
args.addParameter('roiAs', 'rows', rowOrCol);
args.addParameter('dataLabel', {}, @iscellstr);
args.addParameter('maxVox', [], @isnumeric);
args.addParameter('nbBins', [], @isnumeric);

args.parse(varargin{:});

dataImages = args.Results.dataImages;
roiImages = args.Results.roiImages;
scaleFactor = args.Results.scaleFactor;
roiAs = args.Results.roiAs;
dataLabel = args.Results.dataLabel;
nbBins = args.Results.nbBins;

if ischar(dataImages)
dataImages = {dataImages};
Expand All @@ -55,85 +89,100 @@
nbRois = numel(roiImages);
nbData = numel(dataImages);

if nbRois == 1 || nbData == 1
[rows, cols] = optimizeSubplotNumber(nbRois * nbData);
else
if numel(dataLabel) ~= nbData
warning('numel dataLabel must be equal to numel dataImages');
dataLabel = {};
end

if strcmp(roiAs, 'rows')
rows = nbRois;
cols = nbData;
elseif strcmp(roiAs, 'cols')
cols = nbRois;
rows = nbData;
end

figHandle = figure('position', [50 50 300 * rows 300 * cols]);
figHandle = figure('position', [50 50 300 * cols 300 * rows]);

%% collect info to adapt the graphs later on

% y scale
maxVox = [];
nbBinsList = [];

% x axis
% limit axis of axis for ROI (nb of voxels)
MIN = [];
MAX = [];

% use the same number of bins for all graphs
% based on the minimum number of unique values across all the datasets
nbBins = [];

% to plot all the modes
modes = [];

subplotList = [];

idxSubplot = 1;

for iRoi = 1:nbRois
for iRow = 1:rows

for iData = 1:nbData
for iCol = 1:cols

data{idxSubplot} = spm_summarise(spm_vol(dataImages{iData}), roiImages{iRoi});
if strcmp(roiAs, 'rows')
data{idxSubplot} = spm_summarise(spm_vol(dataImages{iCol}), roiImages{iRow}) * scaleFactor;
elseif strcmp(roiAs, 'cols')
data{idxSubplot} = spm_summarise(spm_vol(dataImages{iRow}), roiImages{iCol}) * scaleFactor;
end

[~, bins] = hist(data{idxSubplot}, defaultNbBins);
if isempty(data{idxSubplot})
bins = nan;
else
[~, bins] = hist(data{idxSubplot}, defaultNbBins);
end
MAX(end + 1) = max(bins);
MIN(end + 1) = min(bins);

% modes and nbBins work better on rounded values
modes(end + 1) = mode(round(data{idxSubplot}));
nbBins(end + 1) = numel(unique(round(data{idxSubplot})));
nbBinsList(end + 1) = numel(unique(round(data{idxSubplot})));

subplotList(iRoi, iData) = idxSubplot;
subplotList(iRow, iCol) = idxSubplot;

idxSubplot = idxSubplot + 1;

end

end

nbBins = min(nbBins);

for i = 1:numel(data)
tmp = hist(data{i}, nbBins);
maxVox(end + 1) = max(tmp);
if isempty(nbBins)
nbBins = max(nbBinsList);
end

maxVox = getMaxVox(args, data);

%% plot histogram and mode

idxSubplot = 1;

for iRoi = 1:nbRois
for iRow = 1:rows

for iData = 1:nbData
for iCol = 1:cols

subplot(rows, cols, idxSubplot);

hold on;

hist(data{idxSubplot}, nbBins);
if ~isempty(data{idxSubplot})

hist(data{idxSubplot}, nbBins);

plot([modes(idxSubplot) modes(idxSubplot)], ...
[0 max(maxVox)], ...
'--r', ...
'linewidth', 1);
plot([modes(idxSubplot) modes(idxSubplot)], ...
[0 max(maxVox)], ...
'--r', ...
'linewidth', 1);

bf = bids.File(roiImages{iRoi});
title(['roi: ' bf.entities.label]);
t = text(max(MAX) * 0.5, ...
max(maxVox) * 0.85, ...
sprintf('mean=%0.2f', mean(data{idxSubplot})));

set(t, 'FontSize', 10);

end

axis([min(MIN) max(MAX) 0 max(maxVox)]);

Expand All @@ -143,14 +192,79 @@

end

for i = 1:cols
subplot(rows, cols, subplotList(end, i));
xlabel('intensities');
labelAxis(roiAs, rows, cols, subplotList, roiImages, dataLabel);

end

function labelAxis(roiAs, rows, cols, subplotList, roiImages, dataLabel)

if strcmp(roiAs, 'rows')

for i = 1:cols
subplot(rows, cols, subplotList(end, i));
xlabel('intensities');
end

for i = 1:rows

subplot(rows, cols, subplotList(i, 1));

bf = bids.File(roiImages{i});
l = ylabel(sprintf('roi: %s\nnb voxels', bf.entities.label));
set(l, 'FontWeight', 'bold');

end

else

for i = 1:cols

subplot(rows, cols, subplotList(1, i));

bf = bids.File(roiImages{i});
title(sprintf('roi: %s', bf.entities.label));

subplot(rows, cols, subplotList(end, i));

xlabel('nb voxels');

end

for i = 1:rows

subplot(rows, cols, subplotList(i, 1));

label = '';
if ~isempty(dataLabel)
label = dataLabel{i};
end
l = ylabel(sprintf('%s', label));
set(l, 'FontWeight', 'bold');

end

end

for i = 1:rows
subplot(rows, cols, subplotList(i, 1));
ylabel('nb voxels');
end

function maxVox = getMaxVox(args, data)

maxVox = args.Results.maxVox;

if isempty(maxVox)

for i = 1:numel(data)

tmp = hist(data{i}, nbBins);

if isempty(tmp)
maxVox(end + 1) = nan;
else
maxVox(end + 1) = max(tmp);
end

end

end

end
20 changes: 20 additions & 0 deletions tests/test_plotRoi.m
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,26 @@ function test_test_plotDataInRoi_many_rois_and_data()

end

function test_test_plotDataInRoi_many_rois_as_cols_and_data()

mask1 = createDummyMask(1);
mask2 = createDummyMask(2);
mask3 = createDummyMask(3);
mask4 = createDummyMask(4);
data1 = createDummyData(1);
data2 = createDummyData(2);
data3 = createDummyData(3);
data4 = createDummyData(4);

mask = cellstr(cat(1, mask1, mask2, mask3, mask4));
data = cellstr(cat(1, data1, data2, data3, data4));

plotDataInRoi(data, mask, 'roiAs', 'cols');

delete *.nii;

end

function M = mat()
M = ...
[-3 0 0 84; ...
Expand Down