2626% =============================================================================@
2727%
2828% Authors: John Mosher, Takfarinas Medani, Francois Tadel, 2020
29-
29+ % Juan Garcia-Prieto : add logarithmic scale for LF vectors
3030
3131%% ===== PARSE INPUTS =====
3232if ischar(HeadmodelFiles )
149149
150150%% ===== DISPLAY LEADFIELD =====
151151% Current sensor
152+ useLogScale = false ;
153+ useLogScaleLegendMsg = ' Off' ;
152154iChannel = 1 ;
155+ % initial value for the quiver display
156+ quiverSize = 1 ;
157+ quiverWidth = 1 ;
158+ thresholdAmplitude = 1 ; % ratio of the amplitude
159+ thresholdBalance = 0 ; % orientation of the threshold "<" or " >"
153160DrawArrows();
154161bst_progress(' stop' );
155162
156-
157-
158163%% =================================================================================
159164% === INTERNAL CALLBACKS ==========================================================
160165% =================================================================================
163168 function KeyPress_Callback(hFig , keyEvent )
164169 switch (keyEvent .Key)
165170 % === LEFT, RIGHT, PAGEUP, PAGEDOWN : Processed by TimeWindow ===
166- case {' leftarrow' , ' space' , ' uparrow' }
167- iChannel = iChannel - 1 ;
168- case ' pagedown'
169- iChannel = iChannel - 10 ;
170- case {' rightarrow' , ' downarrow' }
171- iChannel = iChannel + 1 ;
172- case ' pageup'
173- iChannel = iChannel + 10 ;
171+ case {' leftarrow' ,}
172+ if ismember(' shift' , keyEvent .Modifier)
173+ quiverSize = quiverSize / 1.2 ;
174+ elseif ismember(' control' , keyEvent .Modifier)
175+ quiverWidth = quiverWidth / 1.2 ;
176+ elseif ismember(' alt' , keyEvent .Modifier)
177+ thresholdAmplitude = thresholdAmplitude - 0.01 ;
178+ else
179+ iChannel = iChannel - 1 ;
180+ end
181+ case {' rightarrow' }
182+ if ismember(' shift' , keyEvent .Modifier)
183+ quiverSize = quiverSize * 1.2 ;
184+ elseif ismember(' control' , keyEvent .Modifier)
185+ quiverWidth = quiverWidth * 1.2 ;
186+ elseif ismember(' alt' , keyEvent .Modifier)
187+ thresholdAmplitude = thresholdAmplitude + 0.01 ;
188+ else
189+ iChannel = iChannel + 1 ;
190+ end
191+ case ' uparrow'
192+ if ismember(' shift' , keyEvent .Modifier)
193+ quiverSize = quiverSize * 1.2 ;
194+ elseif ismember(' control' , keyEvent .Modifier)
195+ quiverWidth = quiverWidth * 1.2 ;
196+ elseif ismember(' alt' , keyEvent .Modifier)
197+ thresholdAmplitude = thresholdAmplitude + 0.01 ;
198+ else
199+ if ~isempty(iRef )
200+ iRef = iRef + 1 ;
201+ end
202+ end
203+ case ' downarrow'
204+ if ismember(' shift' , keyEvent .Modifier)
205+ quiverSize = quiverSize / 1.2 ;
206+ elseif ismember(' control' , keyEvent .Modifier)
207+ quiverWidth = quiverWidth / 1.2 ;
208+ elseif ismember(' alt' , keyEvent .Modifier)
209+ thresholdAmplitude = thresholdAmplitude - 0.01 ;
210+ else
211+ if ~isempty(iRef )
212+ iRef = iRef - 1 ;
213+ end
214+ end
174215 case ' r' %% not for MEG
175216 SelectReference();
217+ case ' t' %% not for MEG
218+ SelectTarget();
176219 case ' s'
177220 if ~isempty(findobj(hFig , ' Tag' , ' SetVertices' ))
178221 delete(findobj(hFig , ' Tag' , ' SetVertices' ))
179222 else
180- hold on ;
181223 plot3(HeadmodelMat{1 }.GridLoc(: ,1 ), HeadmodelMat{1 }.GridLoc(: ,2 ), HeadmodelMat{1 }.GridLoc(: ,3 ), ' r.' , ...
182224 ' Parent' , hAxes , ...
183225 ' Tag' , ' SetVertices' );
184226 end
185227 case ' e'
186- hold on ;
187- % Plot sensors
188- if ~isempty(findobj(hAxes , ' Tag' , ' allChannel' ))
189- delete(findobj(hAxes , ' Tag' , ' allChannel' ))
228+ if ~ismember(' shift' , keyEvent .Modifier)
229+ % Plot sensors
230+ if ~isempty(findobj(hAxes , ' Tag' , ' allChannel' ))
231+ delete(findobj(hAxes , ' Tag' , ' allChannel' ))
232+ else
233+ if length(Channels ) > 10
234+ hSensors = figure_3d(' PlotSensorsNet' , hAxes , markersLocs , 0 , 0 );
235+ set(hSensors , ' LineWidth' , 1 , ' MarkerSize' , 5 ,' Tag' ,' allChannel' );
236+ end
237+ end
190238 else
191- if length(Channels ) > 10
192- hSensors = figure_3d(' PlotSensorsNet' , hAxes , markersLocs , 0 , 0 );
193- set(hSensors , ' LineWidth' , 1 , ' MarkerSize' , 5 ,' Tag' ,' allChannel' );
239+ % Plot sensors name
240+ if ~isempty(findobj(hAxes , ' Tag' , ' allChannelName' ))
241+ delete(findobj(hAxes , ' Tag' , ' allChannelName' ))
242+ else
243+ if length(Channels ) > 10
244+ % hSensors = figure_3d('PlotSensorsNet', hAxes, markersLocs, 0, 0);
245+ % set(hSensors,'Tag','allChannelName');
246+ channelAllName = cell(length(Channels ),1 );
247+ for iChan = 1 : length(Channels )
248+ channelAllName{iChan } = Channels(iChan ).Name;
249+ end
250+ text(markersLocs(: ,1 ), markersLocs(: ,2 ), markersLocs(: ,3 ),channelAllName ,...
251+ ' color' ,' y' ,...
252+ ' Parent' , hAxes , ...
253+ ' Tag' , ' allChannelName' );
254+ end
194255 end
195256 end
196257 case ' m'
@@ -201,18 +262,54 @@ function KeyPress_Callback(hFig, keyEvent)
201262 if ~isempty(findobj(hAxes , ' Tag' , ' allChannel' ))
202263 delete(findobj(hAxes , ' Tag' , ' allChannel' ))
203264 end
265+
266+ case ' l'
267+ if ismember(' shift' , keyEvent .Modifier)
268+ useLogScale = ~useLogScale ;
269+ if (useLogScale )
270+ useLogScaleLegendMsg = ' On' ;
271+ else
272+ useLogScaleLegendMsg = ' Off' ;
273+ end
274+ end
275+
276+ case ' return'
277+ if ismember(' shift' , keyEvent .Modifier)
278+ useLogScale = ~useLogScale ;
279+ if (useLogScale )
280+ useLogScaleLegendMsg = ' On' ;
281+ else
282+ useLogScaleLegendMsg = ' Off' ;
283+ end
284+ elseif ismember(' alt' , keyEvent .Modifier)
285+ thresholdBalance = ~thresholdBalance ;
286+ else
287+ return ;
288+ end
204289 case ' h'
205290 java_dialog(' msgbox' , [' <HTML><TABLE>' ...
206- ' <TR><TD><B>Left arrow</B></TD><TD>Previous channel</TD></TR>' ....
207- ' <TR><TD><B>Right arrow</B></TD><TD>Next channel</TD></TR>' ....
208- ' <TR><TD><B>Page up</B></TD><TD>Previous 10th channel</TD></TR>' ....
209- ' <TR><TD><B>Page down</B></TD><TD>Next 10th channel</TD></TR>' ....
291+ ' <TR><TD><B>Left arrow</B></TD><TD>Previous target channel (red color)</TD></TR>' ....
292+ ' <TR><TD><B>Right arrow</B></TD><TD>Next target channel (red color)</TD></TR>' ....
293+ ' <TR><TD><B>Up arrow</B></TD><TD>Previous ref channel (green color)</TD></TR>' ....
294+ ' <TR><TD><B>Down arrow</B></TD><TD>Next ref channel (green color)</TD></TR>' ....
295+ ' <TR><TD><B>Shift + uparrow</B></TD><TD>Increase the vector length</TD></TR>' ...
296+ ' <TR><TD><B>Shift + downarrow</B></TD><TD>Decrease the vector length</TD></TR>' ...
297+ ' <TR><TD><B>Shift + L</B></TD><TD>Toggle on/off logarithmic scale</TD></TR>' ...
298+ ' <TR><TD><B>Control + uparrow</B></TD><TD>Increase the vector width</TD></TR>' ...
299+ ' <TR><TD><B>Control + downarrow</B></TD><TD>Decrease the vector width</TD></TR>' ...
300+ ' <TR><TD><B>Alt + Enter </B></TD><TD>Toggle to superior/inferior for LF threshold</TD></TR>' ...
301+ ' <TR><TD><B>Alt + uparrow </B></TD><TD>Increase Amplitude threshold</TD></TR>' ...
302+ ' <TR><TD><B>Alt + downarrow </B></TD><TD>Decrease Amplitude threshold</TD></TR>' ...
210303 ' <TR><TD><B>M</B></TD><TD>Change the <B>M</B>odality (MEG, EEG, SEEG, ECOG)</TD></TR>' ....
211- ' <TR><TD><B>R</B></TD><TD>Change the <B>R</B>eference electrode</TD></TR>' ....
304+ ' <TR><TD><B>R</B></TD><TD>Select the <B>R</B>eference channel</TD></TR>' ....
305+ ' <TR><TD><B>T</B></TD><TD>Select the <B>T</B>arget channel</TD></TR>' ....
212306 ' <TR><TD><B>S</B></TD><TD>Show/hide the source grid</TR>' ....
213- ' <TR><TD><B>E</B></TD><TD>Show/hide the sensors</TD></TR></TABLE>' ], ' Keyboard shortcuts' );
307+ ' <TR><TD><B>E</B></TD><TD>Show/hide the sensors</TD></TR>' ...
308+ ' <TR><TD><B>Shift + E</B></TD><TD>Show/hide the sensors labels</TD></TR>' ...
309+ ' <TR><TD><B>0 to 9</B></TD><TD>Change view</TD></TR>' ...
310+ ' </TABLE>' ], ' Keyboard shortcuts' );
214311 otherwise
215- KeyPressFcn_bak(hQuiver , keyEvent );
312+ KeyPressFcn_bak(hFig , keyEvent );
216313 return ;
217314 end
218315 % Redraw arrows
@@ -222,10 +319,24 @@ function KeyPress_Callback(hFig, keyEvent)
222319 if (iChannel > length(Channels ))
223320 iChannel = 1 ;
224321 end
322+ % Redraw arrows
323+ if (iRef <= 0 )
324+ iRef = length(Channels );
325+ end
326+ if (iRef > length(Channels ))
327+ iRef = 1 ;
328+ end
329+
330+ if thresholdAmplitude <= 0
331+ thresholdAmplitude = 0 ;
332+ end
333+ if thresholdAmplitude >= 1
334+ thresholdAmplitude = 1 ;
335+ end
336+
225337 DrawArrows();
226338 end
227339
228-
229340%% ===== DRAW CURRENT CHANNEL =====
230341 function DrawArrows()
231342 % Delete previous Channels and sensors
@@ -255,17 +366,39 @@ function DrawArrows()
255366 end
256367 % Display arrows
257368 LeadField = reshape(LeadField ,3 ,[])' ; % each column is a vector
369+ if (useLogScale )
370+ LeadField = LogScaleLeadfield(LeadField );
371+ end
372+
373+ % thresholding
374+ normLF = sqrt((LeadField(: ,1 ) ).^2 +(LeadField(: ,2 ) ).^2 + (LeadField(: ,3 )).^2 );
375+ [col1 , ind ] = sort(normLF , ' ascend' );
376+ LeadFieldReordered = LeadField(ind ,: );
377+ cdf = cumsum(col1 ); % Compute cdf
378+ cdf = cdf / cdf(end ); % Normalize
379+ % Find index bellow or above the thresholding
380+ if thresholdBalance == 0 % 0 ==> inferior and 1 is superior
381+ index = find(cdf <= thresholdAmplitude );
382+ iSymbole = ' <=' ;
383+ else
384+ index = find(cdf > thresholdAmplitude );
385+ iSymbole = ' >' ;
386+ end
387+ dataValue = zeros(size(LeadFieldReordered ));
388+ dataValue(index ,: ) = LeadFieldReordered(index ,: );
389+
258390 hQuiver(iLF ) = quiver3(...
259- HeadmodelMat{iLF }.GridLoc(: ,1 ), HeadmodelMat{iLF }.GridLoc(: ,2 ), HeadmodelMat{iLF }.GridLoc(: ,3 ), ...
260- LeadField(: ,1 ), LeadField(: ,2 ), LeadField(: ,3 ), ...
261- 5 , ...
391+ ...HeadmodelMat{iLF}.GridLoc(:,1), HeadmodelMat{iLF}.GridLoc(:,2), HeadmodelMat{iLF}.GridLoc(:,3), ... % These two line are remaining in order to check if the thresholding display is correct
392+ ...LeadField(:,1), LeadField(:,2), LeadField(:,3), ...
393+ HeadmodelMat{iLF }.GridLoc(ind ,1 ), HeadmodelMat{iLF }.GridLoc(ind ,2 ), HeadmodelMat{iLF }.GridLoc(ind ,3 ), ...
394+ dataValue(: ,1 ), dataValue(: ,2 ), dataValue(: ,3 ), ...
395+ quiverSize , ...
262396 ' Parent' , hAxes , ...
263- ' LineWidth' , 1 , ...
397+ ' LineWidth' , quiverWidth , ...
264398 ' Color' , ColorOrder(mod(iLF - 1 , length(ColorOrder )) + 1 , : ), ...
265399 ' Tag' , ' lfArrows' );
266400 % Arrow legends
267401 strLegend{iLF } = [SubjectName{iLF } ' : ' selectedModality ' ' HeadmodelMat{iLF }.Comment];
268- hold on
269402 end
270403
271404 % Remove previous selected sensor
@@ -299,18 +432,18 @@ function DrawArrows()
299432 end
300433 % Title bar (channel name)
301434 if isAvgRef
302- strTitle = sprintf(' Channel #%d /%d (%s ) | %s ref Channel = AvgRef' , iChannel , length(Channels ), Channels(iChannel ).Name,selectedModality );
435+ strTitle = sprintf(' Target channel(red) #%d /%d (%s ) | %s Ref Channel(green) = AvgRef | Amp threshold %s %s %% | Log. scale %s ' , iChannel , length(Channels ), Channels(iChannel ).Name,selectedModality , iSymbole , num2str( thresholdAmplitude * 100 ), useLogScaleLegendMsg );
303436 else
304- strTitle = sprintf(' Channel #%d /%d (%s ) | %s ref Channel = %s ' , iChannel , length(Channels ), Channels(iChannel ).Name,selectedModality ,Channels(iRef ).Name);
437+ strTitle = sprintf(' Target channel(red) #%d /%d (%s ) | %s Ref Channel(green) = %s | Amp threshold %s %s %% | Log. scale %s ' , iChannel , length(Channels ), Channels(iChannel ).Name,selectedModality ,Channels(iRef ).Name, iSymbole , num2str( thresholdAmplitude * 100 ), useLogScaleLegendMsg );
305438 end
306439 else
307- strTitle = sprintf(' Channel #%d /%d (%s )' , iChannel , length(Channels ), Channels(iChannel ).Name);
440+ strTitle = sprintf(' Target channel (red) #%d /%d (%s ) | Amp threshold %s %s %% |Log. scale %s ' , iChannel , length(Channels ), Channels(iChannel ).Name, iSymbole ,num2str( thresholdAmplitude * 100 ), useLogScaleLegendMsg );
308441 end
309442
310443 if (iChannel == 1 ) && (length(Channels ) > 1 )
311444 strTitle = [strTitle , ' [Press arrows for next/previous channel (or H for help)]' ];
312445 end
313- set(hLabel , ' String' , strTitle , ' Position' , [10 1 1200 35 ]);
446+ set(hLabel , ' String' , strTitle , ' Position' , [10 1 1600 35 ], ' ForegroundColor ' , [ 1 1 1 ]);
314447 % Arrows legend
315448 legend(hQuiver , strLegend , ...
316449 ' TextColor' , ' w' , ...
@@ -351,26 +484,32 @@ function DrawArrows()
351484 function isOk = SelectReference()
352485 isOk = 1 ;
353486 if ~strcmp(selectedModality ,' MEG' )
354- [isAvgRef , isCancel ] = java_dialog(' confirm' , ...
355- [' <HTML>Do you want to use the <B>average refence</B> for the ' selectedModality ' ?<BR>' ...
356- ' Otherwise you will choose one reference electrode.' ], [selectedModality ' average reference' ], [], ...
357- {' Yes, use average reference' }, 1 );
358- if isCancel
487+ % Ask for the reference electrode
488+ refChan = java_dialog(' combo' , ' <HTML>Select the reference channel (green color):<BR><BR>' , [selectedModality ' reference' ], [], {' Average Ref' , Channels .Name});
489+ if isempty(refChan )
359490 isOk = 0 ;
360491 return ;
361492 end
362- if ~isAvgRef
363- % Ask for the reference electrode
364- refChan = java_dialog(' combo' , ' <HTML>Select the reference channel:<BR><BR>' , [selectedModality ' reference' ], [], {Channels .Name});
365- if isempty(refChan )
366- isOk = 0 ;
367- return ;
368- end
369- iRef = find(strcmpi({Channels .Name}, refChan ));
493+ iRef = find(strcmpi({Channels .Name}, refChan ));
494+ if isempty(iRef )
495+ isAvgRef = 1 ;
496+ else
497+ isAvgRef = 0 ;
370498 end
371499 end
372500 end
373501
502+ %% ===== SET TARGET =====
503+ function isOk = SelectTarget()
504+ isOk = 1 ;
505+ % Ask for the target electrode
506+ trgChan = java_dialog(' combo' , ' <HTML>Select the target channel (red color):<BR><BR>' , [selectedModality ' Target' ], [], {Channels .Name});
507+ if isempty(trgChan )
508+ isOk = 0 ;
509+ return ;
510+ end
511+ iChannel = find(strcmpi({Channels .Name}, trgChan ));
512+ end
374513
375514%% ===== GET LEADFIELD =====
376515 function GetLeadField
@@ -379,4 +518,16 @@ function DrawArrows()
379518 LF_finale{iLF } = HeadmodelMat{iLF }.Gain(iChannels ,: );
380519 end
381520 end
521+
522+ %% ===== LEADFIELD TO LOG SPACE =====
523+ function lf_log = LogScaleLeadfield(lf )
524+ lf_2 = lf .^ 2 ;
525+ r = sqrt(sum(lf_2 ,2 ));
526+ rho = sqrt(lf_2(: ,1 ) + lf_2(: ,2 ));
527+ t = atan2(rho ,lf(: ,3 ));
528+ f = atan2(lf(: ,2 ),lf(: ,1 ));
529+ lf_log = [ log10(r ) .* sin(t ) .* cos(f ) ...
530+ log10(r ) .* sin(t ) .* sin(f ) ...
531+ log10(r ) .* cos(t )];
532+ end
382533end
0 commit comments