Skip to content

[3/3] Fastgraph: Plot Fastgraphs#916

Open
chinmaychinara91 wants to merge 14 commits into
brainstorm-tools:masterfrom
chinmaychinara91:plot-fastgraphs
Open

[3/3] Fastgraph: Plot Fastgraphs#916
chinmaychinara91 wants to merge 14 commits into
brainstorm-tools:masterfrom
chinmaychinara91:plot-fastgraphs

Conversation

@chinmaychinara91

@chinmaychinara91 chinmaychinara91 commented May 1, 2026

Copy link
Copy Markdown
Member

This PR is the 3rd and final part required for Fastgraph. It implements Fastgraph plotting, where each Fastgraph is a stacked area plot showing the distribution of stimulation-evoked responses across anatomical brain regions.

As the name suggests, Fastgraph stands for Functional-Anatomical STacked area graph. Each plot represents how stimulation of one site affects activity across other regions of the brain.

Prerequisite: Follow steps in PR #912

The GUI

image

Inputs

  • Select scouts: The atlas (and optional scouts) used to plot the Fastgraphs.
  • Color Fastgraph by region or by label: Selecting Region uses the region colors for the plot, and Label uses the above selected atlas label colors.
  • Select region(s) to include: Only shows plots with colors from these selected region.
  • Select method to sort the data This is for sorting the channel data within each hemisphere using one of the methods (RMS or Max Abs).
  • Choose range to sort over The range to the above data sorting. Based on the paper, there are 3 ranges, early (0-60 ms), middle (60-250 ms) and late (250 to 600 ms) latencies. These latencies are the time delay between the stimulation trigger pulse and the measured brain response. Ideally, the middle latency is where we get the most significant response.
  • Plot range: The range of the plot window.
  • Edge transparency of plot: The alpha value of the boundaries in the stacked area plots per graph.
  • Exclusion zone radius: Exclude analysis of contacts within this distance from the stimulation site. As per the paper 20mm is considered close as the contacts close to the stim site will always give very high response so it needs to be ignored.

Steps to use

  1. Follow steps as in PR [2/3] Fastgraph: Remove SPES artifacts using EMD #912

  2. Drag the artifact removed blocks (| rm spes | emd) to Process1 tab > Run > Import > Import recordings > Import MEG/EEG: Events. Set event name as STIM and epoch time -100 to 900 ms. For this sample data, we will be importing all the STIM events with a 1s epoch. The reason we chose this is due to the range of latencies (early, middle, late) mentioned above. Also note that appending the per session (represented by #1, #2) stim site info to the STIM events of the stimulation block earlier now helps in creating separate groups, else all would have clustered under one.
    image

  3. Drag the STIM groups to Process1 tab and average them by trial to get as under.
    image

  4. Ideally do it for all the stimulation blocks, but above just shows a sample of the data where A11-A12 shows low response and B3-B4 and B'3-B'4 show high response. To see the results, just drag the averaged trials to Process1 tab > Run > FAST graph > Plot Fastgraphs and set the values as shown in the process GUI image above to get the plot as under.
    image

  • The plots (Fastgraphs) are sorted from top left to bottom right in the order of Left hemisphere contacts (arranged anterior to posterior) followed by right hemisphere contacts (arranged anterior to posterior). The image below shows the implantation (taken from the paper).
    image
  • Each of the subplot (Fastgraph) has the data sorted as per the method we chose (here, RMS).
  • The responses in each subplot above the x-axis represent the left hemisphere responses and below it represents the right hemisphere responses.
  • Each subplot also tells which region gave the highest response. For e.g. in the Avg: STIM B'3-B'4 #1 Fastgraph, the parahippocampal L gave the highest response, in Avg: STIM B3-B4 #1 it was parahippocampal R and in Avg: STIM A11-A12 #1 it was superiortemporal R
  • The bottom right most image is the legend that gives the color and region information for the plots, the time and amplitude ranges and also the L and R indicating above the x-axis represent the left hemisphere responses and below it represents the right hemisphere responses.

Some more examples

  • Color by Region | Select region(s) to include: Frontal and Temporal
    image

  • Color by Label | Select region(s) to include: Select all
    image

  • Color by Label | Select region(s) to include: Frontal and Temporal
    image

  • Select scouts: parahippocampal L, parahippocampal R, superiortemporal R | Color by Region | Select region(s) to include: Select all
    image

  • Select scouts: parahippocampal L, parahippocampal R, superiortemporal R | Color by Label | Select region(s) to include: Select all
    image

Associated PRs

  1. [1/3] Fastgraph: Customize SPES (Nihon Kohden) #911
  2. [2/3] Fastgraph: Remove SPES artifacts using EMD #912

Checklist

@jcmosher @Nastaranlotfi @yashvakilna

- Adds `subtightplot.m`, A wrapper function for `subplot`. Adds the ability to define the gap between neighbouring subplots.
- `subplot`  prior to R2019b  lacked this functionality, and the gap between subplots can reach 40% of figure area, which is pretty lavish.
- In 2019b, MATLAB introduced `tiledLayout` and `nexttile` that can achieve the same but for backward compatibility it would be good to just stick to this external module.
Required for plotting Fastgraph as it uses the anatomical labels based on the atlas chosen by the user
@chinmaychinara91
chinmaychinara91 marked this pull request as ready for review May 1, 2026 20:53
@rcassani

rcassani commented Jun 9, 2026

Copy link
Copy Markdown
Member

@chinmaychinara91, To be reviewed, this PR should updated to be compatible with the changes in PR #911 and PR #912

@rcassani
rcassani marked this pull request as draft June 9, 2026 13:59
@chinmaychinara91
chinmaychinara91 marked this pull request as ready for review June 18, 2026 02:47

@rcassani rcassani left a comment

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.

Please address the comments and perform the required changes.

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.

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.

Need to update the header comments


% Process: Remove drift EMD
sFilesStimStartEmd = bst_process('CallProcess', 'process_remove_drift_emd', sFilesStimStartRmSpes, [], ...
'cutoff', 2); % in ms

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.

These are Hz

sProcess.options.label5.Comment = '<U><B>Select method to sort the data:</U></B>';
sProcess.options.label5.Type = 'label';
sProcess.options.sortmethod.Comment = {'Root Mean Square', 'Max Absolute'};
sProcess.options.sortmethod.Type = 'radio';

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.

Use radio_label

Comment on lines +59 to +81
sProcess.options.label3.Comment = '<U><B>Select region(s) to include:</U></B>';
sProcess.options.label3.Type = 'label';
sProcess.options.regionprefrontal.Comment = '1: Prefrontal';
sProcess.options.regionprefrontal.Type = 'checkbox';
sProcess.options.regionprefrontal.Value = 1;
sProcess.options.regionfrontal.Comment = '2: Frontal';
sProcess.options.regionfrontal.Type = 'checkbox';
sProcess.options.regionfrontal.Value = 1;
sProcess.options.regioncentral.Comment = '3: Central';
sProcess.options.regioncentral.Type = 'checkbox';
sProcess.options.regioncentral.Value = 1;
sProcess.options.regionparietal.Comment = '4: Parietal';
sProcess.options.regionparietal.Type = 'checkbox';
sProcess.options.regionparietal.Value = 1;
sProcess.options.regiontemporal.Comment = '5: Temporal';
sProcess.options.regiontemporal.Type = 'checkbox';
sProcess.options.regiontemporal.Value = 1;
sProcess.options.regionoccipital.Comment = '6: Occipital';
sProcess.options.regionoccipital.Type = 'checkbox';
sProcess.options.regionoccipital.Value = 1;
sProcess.options.regionlimbic.Comment = '7: Limbic';
sProcess.options.regionlimbic.Type = 'checkbox';
sProcess.options.regionlimbic.Value = 1;

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.

Use either list_vertical or list_horizontal, example in:
https://github.com/thuy-n/bst-neuromaps/blob/main/process/process_nmp_fetch_maps.m

In FastGraph case it is simpler as they regions are hard coded, there is no need of dynamic regions


Why do we need the numbers in the regions?

plotWindowIdx = OPTIONS.PlotWindow(1) + 101 : OPTIONS.PlotWindow(2) + 101;
timeMs = seegData{iSubplot}.Time(plotWindowIdx) * 1000;

fprintf('\n===== Fastgraph %d/%d: Stimulation site "%s" =====\n', iSubplot, numel(sInputs), sInputs(iSubplot).Comment)

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.

No needed

Comment on lines +699 to +708
% Capture image
img = out_figure_image(hFigSurf);
% Crop background
bgColor = img(1,1,:);
mask = (img(:,:,1) == bgColor(1)) & ...
(img(:,:,2) == bgColor(2)) & ...
(img(:,:,3) == bgColor(3));
goodRows = any(~mask, 2);
goodCols = any(~mask, 1);
imgCortex = img(goodRows, goodCols, :);

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.

Change the background in the figure, then get the image 😉

subtightplot(nRows, nCols, iSubplot+1, gap, horzMargin, vertMargin);
% Plot the reference panel with the cortex snapshot and axis labels
axSubplots(iSubplot+1) = gca;
PlotLegend(axSubplots(iSubplot+1), imgCortex, round(axSubplots(1).XLim), [0 1], 'Time (ms)', 'Voltage (mV)');

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.

Axis labels, and the L/R indicator should be for every figure, except for the "legend" on. Not the the opposite


%% ===== ADD 'L/R' HEMISPHERE LABELS IN THE LEGEND =====
% Add 'L/R' hemisphere labels to the legend axes
function AddLegendHemisphereLabels(axSubplotLegend, xRange, yRange)

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.

This functions is way simpler by using normalized units for the place of the L/R labels in the figure

% Keep the original axes limits fixed so the image does not alter them
axis(axSubplotLegend, 'manual');
% Initial placement
UpdateLegendImage(axSubplotLegend, axImg, brainImg);

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 are tools in Brainstorm to do these changes, no need to reinvent the wheel.

  • Set the lateral view
  • Apply zoom

See figure_3d.m

@rcassani

Copy link
Copy Markdown
Member

@chinmaychinara91, the file tutorial_fastgraph.m needs to be updated:

  1. The process process_remove_spes_artifacts() was removed due to redundancy, the action is now performed with process_cutstim()
    See commit: 804e2fb in master

  2. The process process_remove_drift_emd() was renamed to process_detrend_emd()
    See commit: 4d0a37f in master

@rcassani

Copy link
Copy Markdown
Member

@chinmaychinara91, any update on this PR?

@chinmaychinara91

Copy link
Copy Markdown
Member Author

@rcassani apologies for the delay. I will have it ready by end of this week.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants