Back to the main page.

Bug 348 - make spatial clustering on 2D 'meshes' more general

Status CLOSED FIXED
Reported 2010-12-30 09:55:00 +0100
Modified 2014-01-15 14:42:03 +0100
Product: FieldTrip
Component: core
Version: unspecified
Hardware: All
Operating System: All
Importance: P1 enhancement
Assigned to: Jan-Mathijs Schoffelen
URL:
Tags:
Depends on:
Blocks:
See also:

Jan-Mathijs Schoffelen - 2010-12-30 09:55:20 +0100

This in order to also support clustering on cortical meshes. As such, the cfg.neighbours defined for sensor-level data could be considered to be replaced by a sparse connectivity matrix. Or it could exist as an alternative to the neighbourhood structure. To do: -investigate the clustering code and see what is needed to directly use a connectivity matrix in the input -implement it To do2 (side project): -write a converter from mne2fieldtrip to get a datatype source representation of the MNE-data.


Jan-Mathijs Schoffelen - 2010-12-30 10:17:27 +0100

Addressing this would also take away the need to have the additional 'issource', 1 key-value pair in statistics_montecarlo


Jan-Mathijs Schoffelen - 2010-12-30 10:41:54 +0100

This is a reply by stephan moretti: Dear Hanneke, Actually I do this kind of analysis using the MNE solution from the Brainstrom pipeline. I do the following. First you have to determine a connectivity matrix that determines which vertices of your cortical mesh are neighbors. I do that with a brainstrom script called tess_vertices_connectivity.m. You can download brainstrom for free. Let's call the connectivity matrix C. If C(i,j) = 1 then vertices i and j are connected, if C(i,j) = 0, then not. Later I changed the clusterstat.m of FT a little bit: lines 38 to 48 I changed: if isfield(cfg, 'neighbours') && ~isempty(cfg.neighbours) && ~isfield(cfg,'connectivity') channeighbstructmat = makechanneighbstructmat(cfg); issource = 0; elseif isfield(cfg, 'connectivity') disp('Using precomputed connectivity matrix !'); channeighbstructmat = cfg.connectivity; % connectivity has been already computed this is what I introduced issource = 0; else issource = 1; % cfg contains dim and inside that are needed for reshaping the data to a volume, and inside should behave as a index vector cfg = fixinside(cfg, 'index'); end By doing so, FT does not calculate a connectivity matrix based on distance, but using directly your connectivity matrix C (see below): The next trick is to create a FT data structure from your MNE data, so that you can use ft_timelockstatistics.m. As a cortical mesh has the same 3d coordinates as a sensor helmet, I "press" my MNE surface data in a sensor data structure that I can use later with ft_timelockstatistic.m. This could look like this: MneERF1.grad.pnt=brain.vert; %brain.vert contains the vertices of my cortical mesh; be sure that the unit is cm for i = 1:7000 MneERF1.label{i}=sprintf('A%g',i); end MneERF1.grad.label = MneERF1.label; MneERF1.grad.tra = eye(7000); MneERF1.cfg.channel = UmneERF1.label; MneERF1.grad.ori = zeros(7000,3); for i = 1:23 MneERF1.individual(i,:,:) = squeeze(MNEsolution(:,i,:)); % Here I put the individual MNE solutions if I have 23 subjects; this depends a little bit of your data matrix end MneERF1.dimord= 'subj_chan_time; Now you can use timelockstatistic.m as described in the FT tutorial on sensor space data to calculate a non-parametric cluster based permutation statistic on your MNE surface data (for example MneERF1, MneERF2 are two conditions that you want to compare). The only difference is that you would introduce cfg.connectivity = C;, so that later clusterstat.m uses your C matrix to determine your neighbours. I hope that helps, Best, Stephan


Jan-Mathijs Schoffelen - 2013-11-05 16:38:30 +0100

Notes to self: -It seems that the subfunction makechanneighbstructmat in clusterstat is the same code as the private function channelconnectivity. Verify this and merge. -The help to findcluster states that the neighbourhood matrix is assumed to be upper triangular. According to the code the matrix that enters the function isn't. Check whether the statement in the help is indeed assumed, and/or if the output changes according to the input being or not being upper triangular -Add a function triangleconnectivity that creates a connectivity matrix based on a triangulation. -Clean up the issource functionality for the statistics functions


Jan-Mathijs Schoffelen - 2013-11-05 21:38:14 +0100

NOTE added: ft_statistics_montecarlo has an option randomseed, but uses old-fashioned initialization of rand, and not Johanna's function. Probably this should be replaced while we are at it.


Jan-Mathijs Schoffelen - 2013-11-06 15:12:03 +0100

(In reply to comment #3) Discussed in FT-meeting -It seems that the subfunction makechanneighbstructmat in clusterstat is the same code as the private function channelconnectivity. Verify this and merge. Yes, agreed it can be merged. -The help to findcluster states that the neighbourhood matrix is assumed to be upper triangular. According to the code the matrix that enters the function isn't. Check whether the statement in the help is indeed assumed, and/or if the output changes according to the input being or not being upper triangular It doesn't seem to matter whether a triangular matrix (either upper or lower) of a full symmetric matrix is in input. Nor for the mex file as for the native m file. Will remove statement in the documentation section -Add a function triangleconnectivity that creates a connectivity matrix based on a triangulation. Function is created, will be added. -Clean up the issource functionality for the statistics functions To be done. (In reply to comment #4) Check where the randomseed functionality is dealt with: could be a preamble. If so, check whether preamble is correctly used within function and remove code. Otherwise replace with randomseed, or implement correct handling of preambles


Jan-Mathijs Schoffelen - 2013-11-07 11:23:37 +0100

svn commit -m "enhancement - restructured some code to also deal with clustering based on a triangulation, bug348" ft_statistics_montecarlo.m private/statistics_wrapper.m private/clusterstat.m private/findcluster.m private/triangle2connectivity.m test/test_ft_statistics_montecarlo.m Sending ft_statistics_montecarlo.m Sending private/clusterstat.m Sending private/findcluster.m Sending private/statistics_wrapper.m Adding private/triangle2connectivity.m Adding test/test_ft_statistics_montecarlo.m Transmitting file data ...... Committed revision 8729. Quite some changes: -added pre and postambles in ft_statistics_montecarlo (the ones that I think apply, including the randomseed) -tried to make the clustering more generic: create cfg.connectivity in ft_statistics_montecarlo, if clustering is required. -statistics_wrapper is still very ugly... Created a test-function that is simulating some data and then testing the functionality of the clustering on channel and source level, with two types of sourcemodels, a 3d grid and a mesh. For now, the only thing which is 'tested' is whether it runs through. Visual inspection of the results looks OK however.