Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
1c268bb
Add `subtightplot` external module
chinmaychinara91 Apr 29, 2026
81f6f3c
Add `ChanTable` to `export_channel_atlas` output
chinmaychinara91 Apr 29, 2026
2a135eb
Merge remote-tracking branch 'upstream/master' into plot-fastgraphs
chinmaychinara91 Apr 30, 2026
85ae038
Add `process_fastgraph` for plotting Fastgraph
chinmaychinara91 May 1, 2026
fe624c2
Add Fastgraph tutorial script
chinmaychinara91 May 1, 2026
1bbc413
Tutorial: Use `regexp` for getting stim site info
chinmaychinara91 May 1, 2026
62a0457
Tutorial: Add comments
chinmaychinara91 May 1, 2026
2e7b4e8
Merge remote-tracking branch 'upstream/master' into plot-fastgraphs
chinmaychinara91 Jun 11, 2026
0142d57
Move to subgroup `FAST graph`
chinmaychinara91 Jun 11, 2026
005acb6
Use type as `scout` instead of `atlas`
chinmaychinara91 Jun 17, 2026
8b3f628
Clean up
chinmaychinara91 Jun 17, 2026
f052c0f
Remove duplicate `process_channel_addloc` call
chinmaychinara91 Jun 17, 2026
46fbdf8
`channel_add_loc`: Explicitly check for channel type in the imported…
chinmaychinara91 Jun 17, 2026
e95a1da
Refactor tutorial script
chinmaychinara91 Jun 17, 2026
90d7342
Typo: Should be `Hz`
chinmaychinara91 Jun 18, 2026
7f05e98
Use `radio_label` for `SortMethod`
chinmaychinara91 Jun 19, 2026
7e55eea
Use `list_horizontal` type for regions list
chinmaychinara91 Jun 19, 2026
09a4617
Use `radio_linelabel` type for `colorscheme`
chinmaychinara91 Jun 19, 2026
e7d6085
Merge the consecutive labels
chinmaychinara91 Jun 19, 2026
e1a0f21
Bugfix: Handle region list
chinmaychinara91 Jun 19, 2026
78deddf
Use `FastGraph` capitalization in comments
chinmaychinara91 Jun 19, 2026
3cbdd5b
Merge remote-tracking branch 'upstream/master' into plot-fastgraphs
chinmaychinara91 Jun 23, 2026
d7ac485
Tutorial: Update to `process_cutstim`
chinmaychinara91 Jun 24, 2026
0943606
Tutorial: Update to `process_detrend_emd`
chinmaychinara91 Jun 24, 2026
8e4fe5f
Update header comments
chinmaychinara91 Jul 16, 2026
145e396
Validate all input files share the same channel file
chinmaychinara91 Jul 16, 2026
59ab031
Validate that all comments have valid bipolar channel names
chinmaychinara91 Jul 16, 2026
3056d8d
`5mm` radius for bipolar contacts
chinmaychinara91 Jul 17, 2026
39bf0dc
FG subplot grid: Keep it simple
chinmaychinara91 Jul 17, 2026
3ed0828
Clean
chinmaychinara91 Jul 21, 2026
c7a7dfe
Refine FastGraph axes and legend rendering
chinmaychinara91 Jul 22, 2026
7171dd5
Simplify cortex snapshot capture
chinmaychinara91 Jul 22, 2026
2eb5129
Add `Plot FastGraphs` to context menu
chinmaychinara91 Jul 22, 2026
ca0cdaa
Clean
chinmaychinara91 Jul 22, 2026
787ff28
Update GUI in `process_fastgraph.m`
rcassani Jul 22, 2026
90ec8a7
Update `tutorial_fastgraph.m`
rcassani Jul 22, 2026
ec162ff
Merge remote-tracking branch 'brainstorm-tools/master' into plot-fast…
rcassani Jul 27, 2026
162d8a3
GUI: Improve labels
rcassani Jul 27, 2026
6a5f959
Bugfix: Left groups END with an apostrophe
rcassani Jul 28, 2026
471cb40
Same output for `GroupSeegContacts` with or without locations
rcassani Jul 28, 2026
077d56f
Clean up
rcassani Jul 28, 2026
05d4723
Show figure when complete
rcassani Jul 28, 2026
342c1d9
`GetOptions`, same order as in GUI process options
rcassani Jul 28, 2026
8ba8ad4
Bugfix: Do not use hardcoded values to compute
rcassani Jul 28, 2026
4f964e6
Bugfix: Check for regions only for `region` color scheme
rcassani Jul 28, 2026
2f16fca
GUI: Input time windows in `[ms]`
rcassani Jul 28, 2026
31f91d1
Merge remote-tracking branch 'upstream/master' into plot-fastgraphs
rcassani Jul 28, 2026
0189ccb
Export channel atlas: Allow filtering which atlases to use
rcassani Jul 28, 2026
7813043
Bugfix: Do not use hardcoded values to compute window samples (Part2)
rcassani Jul 28, 2026
87aa6ae
Use Group name to sort SEEG contacts IFF for SEEG contacts w/o Loc
rcassani Aug 6, 2026
3c1ba57
Clean up
rcassani Aug 6, 2026
aba0a53
Reorganize
rcassani Aug 6, 2026
8ce75c3
Refactor
rcassani Aug 6, 2026
bffced1
Improve performance on linking axes
rcassani Aug 6, 2026
39ceb53
Improve messages in the command window
rcassani Aug 6, 2026
d6adfbe
Remove unused input argument
rcassani Aug 6, 2026
21a0d10
Simplify indexing and functions inputs
rcassani Aug 6, 2026
5b02a5a
Process: Add `anatparcel` process option
rcassani Aug 12, 2026
079c9de
Store SEEG contact Name and Scout together. Remove unnecessary indexing
rcassani Aug 13, 2026
cf102a2
Refactor to use Anatomical Atlas (volatlas) instead of Surf Atlas
rcassani Aug 14, 2026
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
26 changes: 26 additions & 0 deletions external/subtightplot/license.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
Copyright (c) 2012, Felipe G. Nievinski
Copyright (c) 2010, Pekka Kumpulainen
Copyright (c) 2011, Nikolay S.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
67 changes: 67 additions & 0 deletions external/subtightplot/subtightplot.m

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is code to do this in Brainstorm. There is no need to add this external code.

See it in: figure_timefreq('GetLayoutPositions'). This is called when TF maps for all channels.

Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
function h=subtightplot(m,n,p,gap,marg_h,marg_w,varargin)
%function h=subtightplot(m,n,p,gap,marg_h,marg_w,varargin)
%
% Functional purpose: A wrapper function for Matlab function subplot. Adds the ability to define the gap between
% neighbouring subplots. Unfotrtunately Matlab subplot function lacks this functionality, and the gap between
% subplots can reach 40% of figure area, which is pretty lavish.
%
% Input arguments (defaults exist):
% gap- two elements vector [vertical,horizontal] defining the gap between neighbouring axes. Default value
% is 0.01. Note this vale will cause titles legends and labels to collide with the subplots, while presenting
% relatively large axis.
% marg_h margins in height in normalized units (0...1)
% or [lower uppper] for different lower and upper margins
% marg_w margins in width in normalized units (0...1)
% or [left right] for different left and right margins
%
% Output arguments: same as subplot- none, or axes handle according to function call.
%
% Issues & Comments: Note that if additional elements are used in order to be passed to subplot, gap parameter must
% be defined. For default gap value use empty element- [].
%
% Usage example: h=subtightplot((2,3,1:2,[0.5,0.2])

if (nargin<4) || isempty(gap), gap=0.01; end
if (nargin<5) || isempty(marg_h), marg_h=0.05; end
if (nargin<5) || isempty(marg_w), marg_w=marg_h; end
if isscalar(gap), gap(2)=gap; end
if isscalar(marg_h), marg_h(2)=marg_h; end
if isscalar(marg_w), marg_w(2)=marg_w; end
gap_vert = gap(1);
gap_horz = gap(2);
marg_lower = marg_h(1);
marg_upper = marg_h(2);
marg_left = marg_w(1);
marg_right = marg_w(2);

%note n and m are switched as Matlab indexing is column-wise, while subplot indexing is row-wise :(
[subplot_col,subplot_row]=ind2sub([n,m],p);

% note subplot suppors vector p inputs- so a merged subplot of higher dimentions will be created
subplot_cols=1+max(subplot_col)-min(subplot_col); % number of column elements in merged subplot
subplot_rows=1+max(subplot_row)-min(subplot_row); % number of row elements in merged subplot

% single subplot dimensions:
%height=(1-(m+1)*gap_vert)/m;
%axh = (1-sum(marg_h)-(Nh-1)*gap(1))/Nh;
height=(1-(marg_lower+marg_upper)-(m-1)*gap_vert)/m;
%width =(1-(n+1)*gap_horz)/n;
%axw = (1-sum(marg_w)-(Nw-1)*gap(2))/Nw;
width =(1-(marg_left+marg_right)-(n-1)*gap_horz)/n;

% merged subplot dimensions:
merged_height=subplot_rows*( height+gap_vert )- gap_vert;
merged_width= subplot_cols*( width +gap_horz )- gap_horz;

% merged subplot position:
merged_bottom=(m-max(subplot_row))*(height+gap_vert) +marg_lower;
merged_left=(min(subplot_col)-1)*(width+gap_horz) +marg_left;
pos_vec=[merged_left merged_bottom merged_width merged_height];

% h_subplot=subplot(m,n,p,varargin{:},'Position',pos_vec);
% Above line doesn't work as subplot tends to ignore 'position' when same mnp is utilized
h=subplot('Position',pos_vec,varargin{:});

if (nargout < 1), clear h; end

end
51 changes: 44 additions & 7 deletions toolbox/io/export_channel_atlas.m
Comment thread
rcassani marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
function TsvFile = export_channel_atlas(ChannelFile, Modality, TsvFile, Radius, isProba, isInteractive)
function [TsvFile, ChanTable] = export_channel_atlas(ChannelFile, Modality, TsvFile, Radius, isProba, isInteractive, AtlasFilter)
% EXPORT_CHANNEL_ATLAS: Compute anatomical labels for SEEG/ECOG contacts from volume and surface parcellations
%
% USAGE: TsvFile = export_channel_atlas(ChannelFile, Modality='ECOG+SEEG', TsvFile=[ask], Radius=[ask], isProba=[ask], isInteractive=1)
% TsvFile = export_channel_atlas(ChannelFile, iChannels, TsvFile=[ask], Radius=[ask], isProba=[ask], isInteractive=1)
% USAGE: TsvFile = export_channel_atlas(ChannelFile, Modality='ECOG+SEEG', TsvFile=[ask], Radius=[ask], isProba=[ask], isInteractive=1, AtlasFilter='')
% TsvFile = export_channel_atlas(ChannelFile, iChannels, TsvFile=[ask], Radius=[ask], isProba=[ask], isInteractive=1, AtlasFilter='')
%
% INPUT:
% - ChannelFile : Path to Brainstorm channel file to be processed
% - Modality : String, export only the channel with the selected modality
% - iChannels : Array of integers, export only the selected channel indices
% - TsvFile : Output text file (tab-separated values)
% - Radius : Size in millimeters of the neighborhood to consider around each contact
% - isProba : If 1, for each volume atlas, add a column indicating the spatial probability (100 * nVoxelWithLabel / nVoxelsInSphere)
% - IsInteractive : If 1, display the output table at the end of the process
% : If 0, use all available Coodinates, Parcellations (anat) and Atlases (surface),
% and do not display output table
% - iChannels : Limit export to a subset of channel indices
% : If 0, use all available Coodinates, and the Parcellations (anat) and Atlases (surface) filtered by 'AtlasFilter'
% and do not display output table
% - AtlasFilter : Used with IsInteractive=0. If absent or empty, use all the Parcellations (anat) and Atlases (surface).
% Otherwise use the string in AtlasFilter to indicate the Parcellations and Atlases to return.
% OUTPUT:
% - TsvFile : Output text file (tab-separated values). Empty when no file was selected or requested.
% - ChanTable : Cell array containing the complete output table. The same information is written to TsvFile
% when an output file is requested.
% - The first column always contains channel names
% - The remaining columns contain available coordinates, anatomical labels,
% and optional probabilities corresponding to each channel
%
% REFERENCES:
% - MERCIER M, 2021:
Expand Down Expand Up @@ -47,6 +56,9 @@


% ===== PASRSE INPUTS =====
if (nargin < 7) || isempty(AtlasFilter)
AtlasFilter = [];
end
if (nargin < 6) || isempty(isInteractive)
isInteractive = 1;
end
Expand Down Expand Up @@ -78,7 +90,7 @@


% ===== SELECT OUTPUT FILE =====
if isempty(TsvFile)
if isempty(TsvFile) && isInteractive
% Get default directories and formats
LastUsedDirs = bst_get('LastUsedDirs');
% Default output filename
Expand Down Expand Up @@ -240,6 +252,31 @@
end


% ===== FILTER ATLASES =====
if ~isInteractive && ~isempty(AtlasFilter)
% === Volume ===
iColVol = find(~cellfun(@(c)isempty(strfind(c, tagVol)), Columns(:,2)));
% Try match, if nothing found, try regular expression
iVolValid = find(strcmpi(Columns(iColVol,1), AtlasFilter));
if isempty(iVolValid)
iVolValid = find(~cellfun(@isempty, regexp(Columns(iColVol,1), AtlasFilter)));
end
% Remove non-matching volume atlases
Columns(setdiff(iColVol, iColVol(iVolValid)), :) = [];
% Update iColSurf in case volumes were removed
iColSurf = find(~cellfun(@(c)isempty(strfind(c, tagSurf)), Columns(:,2)));

% === Surface ===
% Try match, if nothing found, try regular expression
iSurfValid = find(strcmpi(SurfAtlases, AtlasFilter));
if isempty(iSurfValid)
iSurfValid = find(~cellfun(@isempty, regexp(SurfAtlases, AtlasFilter)));
end
% Keep only matching surface atlases
SurfAtlases = SurfAtlases(iSurfValid);
end


% ===== SPHERE PROBE =====
% Ask sphere radius to users
if isempty(Radius)
Expand Down
Loading