Skip to content

Commit

Permalink
GUI: Edit interactively max distance for interpolation iEEG-cortex
Browse files Browse the repository at this point in the history
  • Loading branch information
ftadel committed Jan 28, 2023
1 parent f62b0d2 commit 40fd14e
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 21 deletions.
2 changes: 1 addition & 1 deletion doc/license.html
Expand Up @@ -5,7 +5,7 @@
<body alink="#fff000" link="#fff000" vlink="#fff000">
<h4><span style="font-family: Arial Black; color: #ffffff;"><strong>THERE IS NO UNDO BUTTON!<BR>SET UP A <FONT color=red>BACKUP</FONT> OF YOUR DATABASE</strong></span></h4>
<HR>
<!-- LICENCE_START -->Version: 3.230127 (27-Jan-2023)<br>
<!-- LICENCE_START -->Version: 3.230128 (28-Jan-2023)<br>
<span style="font-style: italic;">COPYRIGHT &copy; 2000-2023
USC &amp; McGill University.<br>
</span>
Expand Down
2 changes: 1 addition & 1 deletion doc/version.txt
@@ -1,2 +1,2 @@
% Brainstorm
% v. 3.230127 (27-Jan-2023)
% v. 3.230128 (28-Jan-2023)
8 changes: 4 additions & 4 deletions toolbox/core/bst_colormaps.m
Expand Up @@ -636,7 +636,7 @@ function CreateColormapMenu(jMenu, ColormapType, DisplayUnits)
IconLoader.ICON_COLORMAP_PARULA, IconLoader.ICON_COLORMAP_MAGMA, IconLoader.ICON_COLORMAP_ROYAL_GRAMMA, IconLoader.ICON_COLORMAP_VIRIDIS2, IconLoader.ICON_COLORMAP_VIRIDIS, IconLoader.ICON_COLORMAP_DORY];
for i = 1:length(cmapList_seq)
% If the colormap #i is currently used for this surface : check the menu
isSelected = strcmpi(cmapList_seq{i}, sColormap.Name);
isSelected = ~isempty(sColormap.Name) && strcmpi(cmapList_seq{i}, sColormap.Name);
% Create menu item
cmapDispName = strrep(cmapList_seq{i}, 'cmap_', '');
jItem = gui_component('CheckBoxMenuItem', jMenuSeq, [], cmapDispName, iconList_seq(i), [], @(h,ev)SetColormapName(ColormapType, cmapList_seq{i}));
Expand All @@ -648,7 +648,7 @@ function CreateColormapMenu(jMenu, ColormapType, DisplayUnits)
IconLoader.ICON_COLORMAP_MANDRILL,IconLoader.ICON_COLORMAP_NEUROSPEED, IconLoader.ICON_COLORMAP_NEUROSPEED, IconLoader.ICON_COLORMAP_NEUROSPEED];
for i = 1:length(cmapList_div)
% If the colormap #i is currently used for this surface : check the menu
isSelected = strcmpi(cmapList_div{i}, sColormap.Name);
isSelected = ~isempty(sColormap.Name) && strcmpi(cmapList_div{i}, sColormap.Name);
% Create menu item
cmapDispName = strrep(cmapList_div{i}, 'cmap_', '');
jItem = gui_component('CheckBoxMenuItem', jMenuDiv, [], cmapDispName, iconList_div(i), [], @(h,ev)SetColormapName(ColormapType, cmapList_div{i}));
Expand All @@ -660,7 +660,7 @@ function CreateColormapMenu(jMenu, ColormapType, DisplayUnits)
IconLoader.ICON_COLORMAP_RAINRAMP, IconLoader.ICON_COLORMAP_SPECTRUM, IconLoader.ICON_COLORMAP_ATLAS, IconLoader.ICON_COLORMAP_TURBO];
for i = 1:length(cmapList_rainbow)
% If the colormap #i is currently used for this surface : check the menu
isSelected = strcmpi(cmapList_rainbow{i}, sColormap.Name);
isSelected = ~isempty(sColormap.Name) && strcmpi(cmapList_rainbow{i}, sColormap.Name);
% Create menu item
cmapDispName = strrep(cmapList_rainbow{i}, 'cmap_', '');
jItem = gui_component('CheckBoxMenuItem', jMenuRainbow, [], cmapDispName, iconList_rainbow(i), [], @(h,ev)SetColormapName(ColormapType, cmapList_rainbow{i}));
Expand All @@ -675,7 +675,7 @@ function CreateColormapMenu(jMenu, ColormapType, DisplayUnits)
isCustom = 0;
for i = 1:length(CustomColormaps)
% If the colormap #i is currently used for this surface : check the menu
isSelected = strcmpi(CustomColormaps(i).Name, sColormap.Name);
isSelected = ~isempty(sColormap.Name) && strcmpi(CustomColormaps(i).Name, sColormap.Name);
if isSelected
isCustom = 1;
end
Expand Down
36 changes: 30 additions & 6 deletions toolbox/core/bst_get.m
Expand Up @@ -145,8 +145,9 @@
% - bst_get('SystemMemory') : Amount of memory available, in Mb
% - bst_get('ByteOrder') : {'l','b'} - Byte order used to read and save binary files
% - bst_get('TSDisplayMode') : {'butterfly','column'}
% - bst_get('ElectrodeConfig', Modality) : Structure describing the current display values for SEEG/ECOG/EEG contacts
% - bst_get('AutoUpdates') : {0,1} - If 1, check automatically for updates at startup
% - bst_get('ElectrodeConfig', Modality) : Structure describing the display values for SEEG/ECOG/EEG contacts
% - bst_get('ElecInterpDist', Modality) : Structure describing the maximum distance for interpolating SEEG/ECOG/EEG values onto a surface
% - bst_get('AutoUpdates') : {0,1} - If 1, check automatically for updates at startup
% - bst_get('ForceMatCompression') : {0,1} - If 1, always save mat-files using the v7 format instead of v6
% - bst_get('IgnoreMemoryWarnings') : {0,1} - If 1, do not display memory warnings at the Brainstorm startup
% - bst_get('ExpertMode') : {0,1} - If 1, show advanced options that regular user do not see
Expand Down Expand Up @@ -2832,9 +2833,10 @@
case 'ElectrodeConfig'
% Get modality
Modality = varargin{2};
if isempty(Modality) || ~ismember(Modality, {'EEG','ECOG','SEEG','ECOG+SEEG'})
disp(['GET> Invalid modality: ' Modality]);
Modality = 'EEG';
if isequal(Modality, 'ECOG+SEEG')
Modality = 'ECOG_SEEG';
elseif isempty(Modality) || ~ismember(Modality, {'EEG','ECOG','SEEG'})
error(['Invalid modality: ' Modality]);
end
% Value was saved previously
if isfield(GlobalData, 'Preferences') && isfield(GlobalData.Preferences, 'ElectrodeConfig') && isfield(GlobalData.Preferences.ElectrodeConfig, Modality) && isfield(GlobalData.Preferences.ElectrodeConfig.(Modality), 'ContactDiameter')
Expand All @@ -2854,7 +2856,7 @@
ElectrodeConfig.ContactLength = 0.001;
ElectrodeConfig.ElecDiameter = 0.0005;
ElectrodeConfig.ElecLength = [];
case {'SEEG','ECOG+SEEG'}
case {'SEEG','ECOG_SEEG'}
ElectrodeConfig.Type = 'seeg';
ElectrodeConfig.ContactDiameter = 0.0008;
ElectrodeConfig.ContactLength = 0.002;
Expand All @@ -2864,6 +2866,28 @@
argout1 = ElectrodeConfig;
end

case 'ElecInterpDist'
% Get modality
Modality = varargin{2};
if isequal(Modality, 'ECOG+SEEG')
Modality = 'ECOG_SEEG';
elseif isempty(Modality) || ~ismember(Modality, {'EEG','ECOG','SEEG','MEG'})
error(['Invalid modality: ' Modality]);
end
% Value was saved previously
if isfield(GlobalData, 'Preferences') && isfield(GlobalData.Preferences, 'ElecInterpDist') && isfield(GlobalData.Preferences.ElecInterpDist, Modality)
argout1 = GlobalData.Preferences.ElecInterpDist.(Modality);
% Get default value
else
switch (Modality)
case 'EEG', argout1 = .3;
case 'ECOG', argout1 = .015;
case 'SEEG', argout1 = .015;
case 'ECOG_SEEG', argout1 = .015;
case 'MEG', argout1 = .5;
end
end

case 'UseSigProcToolbox'
% In a parfor loop: GlobalData is empty => Check only if the toolbox is installed (ignore user preferences)
if isempty(GlobalData) || ~isfield(GlobalData, 'Program') || ~isfield(GlobalData.Program, 'HasSigProcToolbox')
Expand Down
17 changes: 15 additions & 2 deletions toolbox/core/bst_set.m
Expand Up @@ -43,6 +43,7 @@ function bst_set( varargin )
% - bst_set('InterfaceScaling', InterfaceScaling)
% - bst_set('TSDisplayMode', TSDisplayMode) : {'butterfly','column'}
% - bst_set('ElectrodeConfig', ElectrodeConfig, Modality)
% - bst_set('ElecInterpDist', ElecInterpDist, Modality)
% - bst_set('DefaultFormats' defaultFormats)
% - bst_set('BFSProperties', [scalpCond,skullCond,brainCond,scalpThick,skullThick])
% - bst_set('ImportEegRawOptions', ImportEegRawOptions)
Expand Down Expand Up @@ -247,11 +248,23 @@ function bst_set( varargin )
case 'ElectrodeConfig'
Modality = varargin{2};
ElectrodeConf = varargin{3};
if ~ismember(Modality, {'EEG','SEEG','ECOG'})
if isequal(Modality, 'ECOG+SEEG')
Modality = 'ECOG_SEEG';
elseif ~ismember(Modality, {'EEG','SEEG','ECOG','MEG'})
error(['Invalid modality: ' Modality]);
end
GlobalData.Preferences.(contextName).(Modality) = ElectrodeConf;


case 'ElecInterpDist'
Modality = varargin{2};
ElecInterpDist = varargin{3};
if isequal(Modality, 'ECOG+SEEG')
Modality = 'ECOG_SEEG';
elseif ~ismember(Modality, {'EEG','SEEG','ECOG','MEG'})
error(['Invalid modality: ' Modality]);
end
GlobalData.Preferences.(contextName).(Modality) = ElecInterpDist;

case {'UniformizeTimeSeriesScales', 'XScale', 'YScale', 'FlipYAxis', 'AutoScaleY', 'ShowXGrid', 'ShowYGrid', 'ShowZeroLines', 'ShowEventsMode', ...
'Resolution', 'AutoUpdates', 'ExpertMode', 'DisplayGFP', 'ForceMatCompression', 'GraphicsSmoothing', 'DownsampleTimeSeries', ...
'DisableOpenGL', 'InterfaceScaling', 'TSDisplayMode', 'UseSigProcToolbox', 'LastUsedDirs', 'DefaultFormats', ...
Expand Down
33 changes: 33 additions & 0 deletions toolbox/gui/figure_3d.m
Expand Up @@ -1773,6 +1773,11 @@ function DisplayFigurePopup(hFig)
jItem = gui_component('MenuItem', jMenuChannels, [], 'SEEG contacts', IconLoader.ICON_CHANNEL, [], @(h,ev)view_channels(ChannelFile, 'SEEG', 1, 0, hFig, 1));
jItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_L, KeyEvent.CTRL_MASK));
end
% Edit interpolation distance
if ~isempty(Modality) && ismember(Modality, {'ECOG','SEEG','ECOG+SEEG'}) && isequal(TessInfo(1).DataSource.Type, 'Data')
jMenuChannels.addSeparator();
gui_component('MenuItem', jMenuChannels, [], 'Edit interpolation distance', IconLoader.ICON_SURFACE_CORTEX, [], @(h,ev)EditInterpDist(Modality));
end
end
end

Expand Down Expand Up @@ -4606,6 +4611,34 @@ function PlotCoils(hFig, Modality, isDetails)
end


%% ===== EDIT INTERPOLATION ELECTRODE-SURFACE DISTANCE =====
function EditInterpDist(Modality)
% Get current value
val = bst_get('ElecInterpDist', Modality);
% Ask new value to user
newVal = java_dialog('input', ['Maximum distance when interpolating ' Modality ' on surface (millimeters):'], 'Interpolation distance', [], num2str(val * 1000));
if isempty(newVal) || isnan(str2double(newVal)) || (str2double(newVal) <= 0)
return;
end
val = str2double(newVal) / 1000;
% Set value
bst_set('ElecInterpDist', Modality, val);
% Update figures
hFigures = bst_figures('GetFiguresByType', '3DViz');
for iFig = 1:length(hFigures)
TessInfo = getappdata(hFigures(iFig), 'Surface');
for iTess = 1:length(TessInfo)
if isequal(TessInfo(iTess).DataSource.Type, 'Data') && ~isempty(TessInfo(iTess).DataWmat)
% Remove interpolation and recompute it
TessInfo(iTess).DataWmat = [];
setappdata(hFigures(iFig), 'Surface', TessInfo);
panel_surface('UpdateSurfaceData', hFigures(iFig), iTess);
end
end
end
end


%% ===== SAVE SURFACE =====
function SaveSurface(TessInfo)
% Progress bar
Expand Down
14 changes: 7 additions & 7 deletions toolbox/gui/panel_surface.m
Expand Up @@ -1911,19 +1911,19 @@ function UpdateSurfaceProperties()
(size(TessInfo.DataWmat,2) ~= length(selChan)) || ...
(size(TessInfo.DataWmat,1) ~= length(Vertices))
% EEG: Use smoothed display, as in 2D/3D topography
if strcmpi(GlobalData.DataSet(iDS).Figure(iFig).Id.Modality, 'eeg')
if strcmpi(GlobalData.DataSet(iDS).Figure(iFig).Id.Modality, 'EEG')
TopoInfo.UseSmoothing = 1;
TopoInfo.Modality = GlobalData.DataSet(iDS).Figure(iFig).Id.Modality;
Faces = get(TessInfo.hPatch, 'Faces');
[bfs_center, bfs_radius] = bst_bfs(Vertices);
TessInfo.DataWmat = figure_topo('GetInterpolation', iDS, iFig, TopoInfo, Vertices, Faces, bfs_center, bfs_radius, chan_loc);
else
switch lower(GlobalData.DataSet(iDS).Figure(iFig).Id.Modality)
case 'eeg', excludeParam = .3;
case 'ecog', excludeParam = -.015;
case 'seeg', excludeParam = -.015;
case 'ecog+seeg', excludeParam = -.015;
case 'meg', excludeParam = .5;
switch (GlobalData.DataSet(iDS).Figure(iFig).Id.Modality)
case 'EEG', excludeParam = bst_get('ElecInterpDist', 'EEG'); % Should never reach this statement, already taken care of above
case 'ECOG', excludeParam = -bst_get('ElecInterpDist', 'ECOG');
case 'SEEG', excludeParam = -bst_get('ElecInterpDist', 'SEEG');
case 'ECOG+SEEG', excludeParam = -bst_get('ElecInterpDist', 'ECOG+SEEG');
case 'MEG', excludeParam = bst_get('ElecInterpDist', 'MEG');
otherwise, excludeParam = 0;
end
nbNeigh = 4;
Expand Down

0 comments on commit 40fd14e

Please sign in to comment.