OSCR

MEG-SCANS - A comprehensive magnetoencephalography speech dataset with Stories, Chirps and Noisy Sentences

Code ↔ Paper

16 matches between paragraphs of the paper and lines of its authors' code, computed by the harvester (lexical-v1). Click a colored paragraph or line to see its counterpart.

The 16 matches · 3 of them tie a paragraph to a whole file, not to given lines: weak matches, whose lines are not tinted
  1. [1] § Technical Validation › Cross-correlation analysis › Signal Processing ↔ speech/crosscorrelation/plot_crosscorr.m, lines 487–557 · score 0.93 · 160–230 ms, 50–90 ms, cross correlation function, 160 ms, alpha, window
  2. [2] § Technical Validation › Cross-correlation analysis › Signal Processing ↔ helper_functions/cal_envelope.m, the whole file · a weak match · score 0.90 · Hilbert Transform, low pass filtered, half wave, onset envelope, audio signal, rectified
  3. [3] § Technical Validation › Chirps › Signal Processing ↔ chirps/sourcelevel/plot_dipolfit_grouplevel.m, lines 1–25 · score 0.88 · outlier dipoles, poor fits, dipole positions, dipole moments, dipole fit, chirp stimuli
  4. [4] § Data Records › Derived Data ↔ maxfilter/apply_maxfilter_parallel.py, lines 262–301 · score 0.86 · Power Spectral Densities, MaxFilter, Maxwell filter, head position, MNE, tSSS
  5. [5] § Technical Validation ↔ speech/decoding/training_decoding.m, lines 1–27 · score 0.85 · temporal response function, mTRF, speech envelope, OLSA sentences, backward, trained
  6. [6] § Technical Validation › Chirps › Signal Processing ↔ chirps/sensorlevel/compute_aefs.m, lines 1–21 · score 0.84 · auditory evoked fields, baseline corrected, FieldTrip, chirp stimuli, AEFs, rejection
  7. [7] § Technical Validation › Decoding analysis › Signal Processing ↔ speech/decoding/training_decoding.m, lines 1–27 · score 0.80 · cross validation, speech envelopes, OLSA sentences, optimal, held, training
  8. [8] § Technical Validation ↔ speech/settings_speech.m, the whole file · a weak match · score 0.73 · mTRF, cross correlation, Pearson, backward, Spearman, decoder
  9. [9] § Data Records › Behavioral Data ↔ behavioral/plot_audiograms.m, lines 78–98 · score 0.73 · Pure tone, hearing thresholds, right ear, audiogram, Behavioral
  10. [10] § Technical Validation › Decoding analysis › Signal Processing ↔ helper_functions/cal_envelope.m, the whole file · a weak match · score 0.70 · Gammatone filterbank, power, hearing, segmented, onset, 5000 Hz
  11. [11] § Technical Validation › Cross-correlation analysis › Results ↔ speech/crosscorrelation/plot_crosscorr.m, lines 1–39 · score 0.67 · anatomical region, cross correlation, butterfly, waveforms, clusters, permutation
  12. [12] § Technical Validation › Chirps › Results ↔ chirps/sourcelevel/plot_dipolfit_grouplevel.m, lines 1–25 · score 0.59 · right hemispheres, dipole fit, standard error, components, template, grand
  13. [13] § Methods › Procedure › Study Design ↔ maxfilter/apply_maxfilter_parallel.py, lines 180–219 · score 0.58 · HPI coil, Head position, channels, MEG
  14. [14] § Methods › Subjects ↔ behavioral/plot_audiograms.m, lines 78–98 · score 0.55 · pure tone, audiogram, HL, hearing, sub
  15. [15] § Background & Summary ↔ chirps/sourcelevel/plot_dipolfit_subjectlevel.m, lines 1–35 · score 0.55 · brain regions, activity, reconstruction, linear, anatomical, MRI
  16. [16] § Methods › Procedure › Study Design ↔ chirps/sourcelevel/compute_headmodel_sourcemodel.m, lines 1–36 · score 0.53 · T1 weighted anatomical, MRIs, MEG

Paper

Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC

The paper is loaded when this pane is shown.

The authors' code

MATLAB · 607 lines · 23 KB · BSD-3-Clause · 2 matches

  1. %--------------------------------------------------------------------------
  2. % Till Habersetzer, 01.07.2025
  3. % Communication Acoustics, CvO University Oldenburg
  4. % [email hidden]
  5. %
  6. % Description:
  7. % This script performs a comprehensive analysis and visualization of MEG
  8. % cross-correlation data. It focuses on comparing a primary experimental
  9. % condition ('sorted') against a shuffled null condition to identify
  10. % statistically significant differences. The analysis uses FieldTrip's
  11. % cluster-based permutation statistics and generates a wide range of plots
  12. % to inspect the data at both the grand-average and single-subject level.
  13. %
  14. % Key Features & Visualizations:
  15. % 1. Data Loading: Imports pre-computed cross-correlation results for
  16. % individual subjects and the grand average.
  17. % 2. Trial Count Summary: Plots a bar chart of the number of trials
  18. % retained for each subject.
  19. % 3. Waveform Visualization: Creates topographical plots of grand-average
  20. % waveforms for both magnetometers and gradiometers, overlaying the
  21. % sorted, shuffled, and difference waves.
  22. % 4. Statistical Analysis: Conducts a cluster-based permutation t-test
  23. % to find significant time-channel clusters where the sorted and
  24. % shuffled conditions differ.
  25. % 5. Statistical Visualization:
  26. % - Generates topographical plots of t-values, highlighting
  27. % significant clusters within specific time windows.
  28. % - Plots the full time-course of the statistical results.
  29. % 6. Detailed Channel Plots: For a selection of channels, it visualizes
  30. % the time-series showing the grand-average with SEM error bands and
  31. % the data from all individual subjects.
  32. % 7. Butterfly Plots: Overlays the waveforms from all sensors to provide
  33. % a global view, including a version where channels are color-coded
  34. % by their anatomical region (e.g., temporal, frontal).
  35. %--------------------------------------------------------------------------
  36. close all
  37. clearvars
  38. clc
  39. %% Import main settings
  40. %--------------------------------------------------------------------------
  41. current_dir = pwd;
  42. cd(fullfile('..'))
  43. settings_speech
  44. cd(current_dir)
  45. % Addpath for additional functions
  46. addpath(fullfile(settings.path2project,'analysis','helper_functions'))
  47. %% Script settings
  48. %--------------------------------------------------------------------------
  49. % Choose subject for plotting
  50. subjects = 1:24;
  51. n_subj = length(subjects);
  52. %% Import data
  53. %--------------------------------------------------------------------------
  54. avgs_crosscorr = cell(1,n_subj);
  55. avgs_crosscorr_shuffled = cell(1,n_subj);
  56. n_trials = zeros(1,n_subj);
  57. subjectnames = cell(1,n_subj);
  58. for sub_idx = 1:n_subj
  59. subject = sprintf('sub-%02d',subjects(sub_idx));
  60. subjectnames{sub_idx} = subject;
  61. data = importdata(fullfile(settings.path2derivatives,subject,'speech',sprintf('%s_crosscorr.mat',subject)));
  62. avgs_crosscorr{sub_idx} = data.avg_crosscorr;
  63. avgs_crosscorr_shuffled{sub_idx} = data.avg_crosscorr_shuffled;
  64. n_trials(sub_idx) = data.n_trials;
  65. clear data
  66. fprintf('%s loaded.\n',subject)
  67. end
  68. % Import grand average over all subjects
  69. %---------------------------------------
  70. subject = 'grandaverage';
  71. data = importdata(fullfile(settings.path2derivatives,subject,'speech',sprintf('%s_crosscorr.mat',subject)));
  72. gavg_crosscorr = data.gavg_crosscorr;
  73. gavg_crosscorr_shuffled = data.gavg_crosscorr_shuffled;
  74. n_subj_gavg = data.n_subjects;
  75. clear data
  76. if ~isequal(n_subj_gavg,n_subj)
  77. error('Unexpected number of subjects for group analysis! Recompute grandaverage!')
  78. end
  79. % Compute raweffect
  80. %------------------
  81. cfg = [];
  82. cfg.operation = 'subtract';
  83. cfg.parameter = 'avg';
  84. gavg_crosscorr_raweffect = ft_math(cfg,gavg_crosscorr,gavg_crosscorr_shuffled);
  85. %% Plot kept trials
  86. %--------------------------------------------------------------------------
  87. figure;
  88. b1 = bar(1:n_subj, n_trials, 'FaceColor', [0.8 0.8 0.8]); % Light grey
  89. ax = gca;
  90. ax.XTick = 1:n_subj;
  91. ax.XTickLabel = subjectnames;
  92. ax.XTickLabelRotation = 45;
  93. title(sprintf('Number of trials (Trialduration: %is)',settings.crosscorr.trialdur));
  94. ylabel('Number of Trials');
  95. xlabel('Subject');
  96. grid on;
  97. %% Plot crosscorrelations for all sensors arranged topographically
  98. %--------------------------------------------------------------------------
  99. figure
  100. cfg = [];
  101. cfg.showlabels = 'yes';
  102. cfg.fontsize = 6;
  103. cfg.layout = 'neuromag306mag_helmet.lay';
  104. cfg.linestyle = {'--','-.','-'};
  105. cfg.linecolor = 'rmb';
  106. ft_multiplotER(cfg, gavg_crosscorr,gavg_crosscorr_shuffled,gavg_crosscorr_raweffect);
  107. title('gavg: magnetometer')
  108. % Gradiometer
  109. %------------
  110. figure
  111. cfg = [];
  112. cfg.showlabels = 'yes';
  113. cfg.fontsize = 6;
  114. cfg.layout = 'neuromag306planar_helmet.lay';
  115. cfg.linestyle = {'--','-.','-'};
  116. cfg.linecolor = 'rmb';
  117. ft_multiplotER(cfg, gavg_crosscorr,gavg_crosscorr_shuffled,gavg_crosscorr_raweffect);
  118. title('gavg: gradiometer')
  119. %% Calculate cluster-based permutation statistic and show clusters
  120. %--------------------------------------------------------------------------
  121. % Within-subjects experiment (within-UO design)
  122. % null hypothesis: the probability distribution of the condition-specific averages
  123. % is independent of the experimental conditions.
  124. % choose sensors
  125. %---------------
  126. % you may need to change alpha value and cfg.minnbchan
  127. sensortype = 'megmag';
  128. cfg = [];
  129. switch sensortype
  130. case 'megmag'
  131. layout = 'neuromag306mag_helmet.mat';
  132. cfg.channel = sensortype;
  133. cfg.method = 'template';
  134. cfg.template = 'neuromag306mag_neighb.mat';
  135. neighbours = ft_prepare_neighbours(cfg);
  136. case 'megplanar'
  137. layout = 'neuromag306planar_helmet.mat';
  138. cfg.channel = sensortype;
  139. cfg.method = 'template';
  140. cfg.template = 'neuromag306planar_neighb.mat';
  141. neighbours = ft_prepare_neighbours(cfg);
  142. end
  143. cfg.neighbours = neighbours;
  144. cfg.grad = avgs_crosscorr{1}.grad;
  145. ft_neighbourplot(cfg)
  146. cfg = [];
  147. cfg.channel = sensortype;
  148. cfg.method = 'montecarlo';
  149. cfg.statistic = 'depsamplesT'; % the dependent samples T-statistic (within-UO)
  150. cfg.correctm = 'cluster'; % MCP by calculating a so-called cluster-based test statistic
  151. cfg.clusteralpha = 0.05; % alpha level of the sample-specific test statistic that will be used for thresholding
  152. cfg.clusterstatistic = 'maxsum';
  153. cfg.minnbchan = 2; % megmag = 2, megplanar 3, meg = 4 / % minimum number of neighborhood channels that is required for a selected sample to be included
  154. cfg.tail = 0; % -1, 1 or 0 (default = 0); one-sided or two-sided test
  155. cfg.clustertail = 0;
  156. cfg.alpha = 0.025; % alpha level of the permutation test
  157. cfg.numrandomization = 5000;
  158. cfg.neighbours = neighbours;
  159. design = zeros(2,2*n_subj);
  160. design(1,:) = [1:n_subj 1:n_subj];
  161. design(2,:) = [ones(1,n_subj) ones(1,n_subj)*2];
  162. cfg.design = design;
  163. cfg.uvar = 1; % row of design matrix that contains unit of observation
  164. cfg.ivar = 2; % row of design matrix that contains independent variable
  165. stat = ft_timelockstatistics(cfg,avgs_crosscorr{:},avgs_crosscorr_shuffled{:});
  166. % Show a specific cluster
  167. %--------------------------------------------------------------------------
  168. cluster_number = 1;
  169. pos = any(ismember(stat.posclusterslabelmat,cluster_number),2);
  170. neg = any(ismember(stat.negclusterslabelmat,cluster_number),2);
  171. % stat.selected_cluster = pos;
  172. stat.selected_cluster = neg;
  173. figure('Color', 'w');
  174. cfg = [];
  175. cfg.xlim = [0.06,0.1];
  176. cfg.parameter = 'stat';
  177. cfg.comment = 'no';
  178. cfg.highlight = 'on';
  179. cfg.highlightchannel = stat.label(stat.selected_cluster);
  180. cfg.highlightcolor = 'k';
  181. cfg.highlightsize = 60;
  182. cfg.highlightsymbol = '.';
  183. cfg.layout = layout;
  184. cfg.interactive = 'no';
  185. ft_topoplotER(cfg,stat);
  186. colormap(bluewhitered)
  187. %% Visualize Statistic over time
  188. %--------------------------------------------------------------------------
  189. % Set alpha-value for mask
  190. %-------------------------
  191. alpha_mask = 0.025;
  192. mask = give_stat_mask(stat,alpha_mask);
  193. stat.mask = mask;
  194. % Plot mask
  195. % imagesc(mask);
  196. % colormap(gray);
  197. % Time windows for topoplots
  198. %---------------------------
  199. timewindows_statistic = [50, 90; 160, 230]/1000; % sec
  200. time_idx = dsearchn(stat.time',reshape(timewindows_statistic,1,numel(timewindows_statistic))');
  201. time_idx = reshape(time_idx,size(timewindows_statistic,1),size(timewindows_statistic,2));
  202. minval = min(gavg_crosscorr_raweffect.avg(:));
  203. maxval = max(gavg_crosscorr_raweffect.avg(:));
  204. % Plot over statistic
  205. %--------------------
  206. % First ensure the channels to have the same order in the average and in the statistical output.
  207. % This might not be the case, because ft_math might shuffle the order
  208. [i1,i2] = match_str(gavg_crosscorr_raweffect.label, stat.label);
  209. figure('Color', 'w')
  210. % Pre-allocate an array to store the handles of the subplots
  211. ax = gobjects(1, size(timewindows_statistic,1));
  212. for p_idx = 1:size(timewindows_statistic,1)
  213. chan2highlight = zeros(numel(gavg_crosscorr_raweffect.label),1);
  214. chan2highlight(i1) = all(stat.mask(i2, time_idx(p_idx,1):time_idx(p_idx,2)), 2);
  215. % less strict
  216. % chan2highlight(i1) = any(stat.mask(i2,time_idx(p_idx,1):time_idx(p_idx,2)), 2);
  217. % Store the handle of the current subplot
  218. ax(p_idx) = subplot(1,2,p_idx);
  219. cfg = [];
  220. cfg.xlim = timewindows_statistic(p_idx,:);
  221. cfg.zlim = [minval,maxval];
  222. cfg.highlight = 'on';
  223. cfg.highlightchannel = find(chan2highlight);
  224. cfg.highlightcolor = 'k';
  225. cfg.highlightsize = 50;
  226. cfg.highlightsymbol = '.';
  227. cfg.comment = 'xlim';
  228. cfg.commentpos = 'title';
  229. cfg.layout = layout;
  230. cfg.interactive = 'no';
  231. cfg.figure = gca; % Use the current axes handle
  232. ft_topoplotER(cfg, gavg_crosscorr_raweffect);
  233. colormap(bluewhitered)
  234. end
  235. % Get the position of the second subplot using its stored handle
  236. pos2 = get(ax(2), 'Position'); % [left, bottom, width, height]
  237. c = colorbar;
  238. c.Position = [pos2(1) + pos2(3) + 0.02, pos2(2), 0.03, pos2(4)]; % [left, bottom, width, height]
  239. c.LineWidth = 1;
  240. c.FontSize = 15;
  241. title(c, '$\hat{R}$', 'fontweight', 'bold', 'Interpreter', 'latex');
  242. sgtitle(sprintf('%s: Correlation-values condition contrast', sensortype), 'fontweight', 'bold', 'FontSize', 20);
  243. % Crosscorrelation timeseries with statistic
  244. %-------------------------------------------
  245. cfg = [];
  246. cfg.layout = 'neuromag306all_helmet.mat';
  247. cfg.parameter = 'stat';
  248. cfg.maskparameter = 'mask';
  249. cfg.graphcolor = 'r';
  250. figure('Color', 'w')
  251. ft_multiplotER(cfg,stat);
  252. sgtitle(sprintf('%s: Cluster-based permutation test ',sensortype),'fontweight','bold','FontSize',20)
  253. %% Visualize cross correlation timeseries of both conditions
  254. %--------------------------------------------------------------------------
  255. % Compute standard error of mean
  256. gavg_crosscorr_sem = sqrt(gavg_crosscorr.var) ./ sqrt(gavg_crosscorr.dof);
  257. gavg_crosscorr_shuffled_sem = sqrt(gavg_crosscorr_shuffled.var) ./ sqrt(gavg_crosscorr_shuffled.dof);
  258. % Plot selected channels for grand average (order not important) with
  259. % standard error of mean (sem) and individual time courses (optional)
  260. %--------------------------------------------------------------------------
  261. % channels to plot
  262. chan2plot = {'MEG0341','MEG1221','MEG0231','MEG1341','MEG1611','MEG2421'};
  263. n_chan = length(chan2plot);
  264. error_alpha = 0.2; % Shaded error area transparency
  265. timevec = gavg_crosscorr.time*1000;
  266. subject_alpha = 0.6;
  267. subject_color = [0.8, 0.8, 0.8];
  268. subject_color_shuffled = [0.5, 0.5, 0.5];
  269. axis_font_size = 16;
  270. legend_font_size = 18;
  271. title_font_size = 14;
  272. xlims = [-100,900];
  273. idx = find(contains(gavg_crosscorr.label,chan2plot));
  274. minval = min(gavg_crosscorr.avg(idx,:)-gavg_crosscorr_sem(idx,:),[],'all');
  275. maxval = max(gavg_crosscorr.avg(idx,:)+gavg_crosscorr_sem(idx,:),[],'all');
  276. % ylims = [-0.02,0,0.02];
  277. figure('Color', 'w')
  278. t = tiledlayout(3, 2, 'TileSpacing', 'compact', 'Padding', 'compact');
  279. axis_handles = gobjects(1, n_chan); % Pre-allocate an array for axis handles
  280. for ch_idx = 1:n_chan
  281. chan_name = chan2plot{ch_idx};
  282. idx = find(contains(gavg_crosscorr.label,chan_name));
  283. % Go to the next tile (subplot)
  284. axis_handles(ch_idx) = nexttile;
  285. hold on;
  286. % Plot individual subjects
  287. for sub_idx = 1:n_subj
  288. plot(timevec, avgs_crosscorr_shuffled{sub_idx}.avg(idx,:),'LineWidth', 1,'Color', [subject_color_shuffled,subject_alpha], 'LineStyle', '-','HandleVisibility', 'off');
  289. plot(timevec, avgs_crosscorr{sub_idx}.avg(idx,:),'LineWidth', 1,'Color', [subject_color,subject_alpha], 'LineStyle', '-','HandleVisibility', 'off');
  290. % update minval, maxval
  291. % minval = min([minval,min([avgs_crosscorr_shuffled{sub_idx}.avg(idx,:),avgs_crosscorr{sub_idx}.avg(idx,:)])]);
  292. % maxval = max([maxval,max([avgs_crosscorr_shuffled{sub_idx}.avg(idx,:),avgs_crosscorr{sub_idx}.avg(idx,:)])]);
  293. end
  294. ft_plot_vector(timevec, [gavg_crosscorr_shuffled.avg(idx,:) + gavg_crosscorr_shuffled_sem(idx,:); gavg_crosscorr_shuffled.avg(idx,:) - gavg_crosscorr_shuffled_sem(idx,:)], 'highlightstyle', 'difference', 'facealpha', error_alpha, 'facecolor', 'r')
  295. plt1 = ft_plot_vector(timevec, gavg_crosscorr_shuffled.avg(idx,:), 'color', 'r', 'linewidth', 2, 'style', '--');
  296. ft_plot_vector(timevec, [gavg_crosscorr.avg(idx,:) + gavg_crosscorr_sem(idx,:); gavg_crosscorr.avg(idx,:) - gavg_crosscorr_sem(idx,:)], 'highlightstyle', 'difference', 'facealpha', error_alpha, 'facecolor', 'b')
  297. plt2 = ft_plot_vector(timevec, gavg_crosscorr.avg(idx,:), 'color', 'b', 'linewidth', 2, 'style', '-');
  298. if ch_idx > 4
  299. xlabel('t / ms')
  300. end
  301. ylabel('$\hat{R}$','Interpreter','Latex')
  302. title(chan_name, 'FontSize', title_font_size)
  303. xticks(xlims(1):200:xlims(2)); % Set x-axis ticks in steps of 100 ms
  304. % yticks(ylims);
  305. set(gca, 'FontSize', axis_font_size); % Set font size for axis values
  306. grid on;
  307. grid minor;
  308. box on;
  309. % Add legend only for the first subplot
  310. if ch_idx == 1
  311. legend([plt1, plt2],{'shuffled','sorted'},'Interpreter', 'none','Location','Southeast','FontSize',legend_font_size)
  312. end
  313. if ch_idx <= 4
  314. xticklabels([]); % Hides the numbers, but keeps grid lines
  315. end
  316. end
  317. % Link the X-axes of all subplots
  318. linkaxes(axis_handles, 'xy');
  319. % Setting it on one linked axis will propagate to all others
  320. ylims = [minval, maxval]; % Centralized Y-axis limits
  321. set(axis_handles, 'XLim', xlims, 'YLim', ylims);
  322. % Cross-correlation timeseries
  323. %-----------------------------
  324. figure('Color', 'w')
  325. cfg = [];
  326. cfg.showlabels = 'yes';
  327. cfg.fontsize = 6;
  328. cfg.layout = 'neuromag306mag_helmet.lay';
  329. % cfg.layout = 'neuromag306planar_helmet.lay';
  330. cfg.linestyle = {'-','-'};
  331. cfg.linecolor = 'rb'; % shuffled: red, sorted: blue
  332. cfg.showlabels = 'on';
  333. cfg.showcomment = 'off';
  334. cfg.showscale = 'off';
  335. cfg.linewidth = 1;
  336. ft_multiplotER(cfg,gavg_crosscorr_shuffled,gavg_crosscorr);
  337. %% Visualize cross correlations
  338. %--------------------------------------------------------------------------
  339. sensortype = 'megmag';
  340. % sensortype = 'megplanar';
  341. switch sensortype
  342. case 'megmag'
  343. is_sensor = endsWith(gavg_crosscorr.label, '1');
  344. is_sensor2 = endsWith(gavg_crosscorr_shuffled.label, '1');
  345. case 'megplanar'
  346. is_sensor = endsWith(gavg_crosscorr.label, '2') | endsWith(gavg_crosscorr.label, '3');
  347. is_sensor2 = endsWith(gavg_crosscorr_shuffled.label, '2') | endsWith(gavg_crosscorr_shuffled.label, '3');
  348. end
  349. % Check if the two logical arrays are identical. If not, throw an error.
  350. if ~isequal(is_sensor, is_sensor2)
  351. error('Mismatch in sensor labels: The order or type of channels in the two datasets does not match.');
  352. end
  353. n_channels = sum(is_sensor);
  354. timevec = gavg_crosscorr.time*1000;
  355. xlims = [-100,900];
  356. axis_font_size = 16;
  357. legend_font_size = 16;
  358. title_font_size = 18;
  359. % All channels same color
  360. %--------------------------------------------------------------------------
  361. figure;
  362. h1 = plot(timevec, gavg_crosscorr.avg(is_sensor,:), 'b', 'LineWidth', 1);
  363. hold on;
  364. h2 = plot(timevec, gavg_crosscorr_shuffled.avg(is_sensor,:), 'r', 'LineWidth', 1);
  365. hold off;
  366. xlabel('t / ms')
  367. ylabel('$\hat{R}$','Interpreter','Latex')
  368. title('Comparison of Original and Shuffled Cross-Correlations');
  369. xticks(xlims(1):200:xlims(2)); % Set x-axis ticks in steps of 100 ms
  370. set(gca, 'FontSize', axis_font_size); % Set font size for axis values
  371. legend([h1(1), h2(1)], {'Sorted', 'Shuffled'}, 'Location', 'Southeast');
  372. grid on;
  373. grid minor;
  374. box on;
  375. % Color grouped by sensor location
  376. %--------------------------------------------------------------------------
  377. channel_layout_meg = importdata('channel_layout_meg.mat');
  378. channel_subsets = cell(1,4);
  379. channel_subsets{4} = unique([channel_layout_meg.occipital_left(:); channel_layout_meg.occipital_right(:)]); % occipital_channels
  380. channel_subsets{3} = unique([channel_layout_meg.parietal_left(:); channel_layout_meg.parietal_right(:)]); % parietal_channels
  381. channel_subsets{2} = unique([channel_layout_meg.frontal_left(:); channel_layout_meg.frontal_right(:)]); % frontal channels
  382. channel_subsets{1} = unique([channel_layout_meg.temporal_left(:); channel_layout_meg.temporal_right(:)]); % temporal channels
  383. channel_subsets_label = {'Sorted (temporal)','Sorted (frontal)','Sorted (parietal)','Sorted (occipital)'};
  384. cmap = [
  385. 0.0000 0.2980 0.5294; % Dark Blue (#004C87)
  386. 0.2000 0.7451 0.9333; % Cyan (#33BEE7)
  387. 0.4660 0.6740 0.1880; % Green (#77AB30)
  388. 0.9290 0.5940 0.1920 % Orange (#ED9731)
  389. ];
  390. line_styles = {'-','--',':','-.'};
  391. % line_styles = {'-','-','-','-'};
  392. % Compute limits
  393. %---------------
  394. all_data = [gavg_crosscorr.avg(is_sensor,:); gavg_crosscorr_shuffled.avg(is_sensor,:)];
  395. % 2. Find the absolute min and max across all the data
  396. min_val = min(all_data(:));
  397. max_val = max(all_data(:));
  398. clear all_data
  399. data_range = max_val - min_val;
  400. padding = 0.05 * data_range;
  401. yLims = [min_val - padding, max_val + padding];
  402. figure;
  403. subplot(2,1,1)
  404. hold on;
  405. % Pre-allocate a vector to store plot handles for the legend
  406. h = gobjects(1, length(channel_subsets) + 2);
  407. for loc_idx = 1:length(channel_subsets)
  408. subset_idx = contains(gavg_crosscorr.label, channel_subsets{loc_idx});
  409. chan_idx = and(is_sensor,subset_idx); % channel type + subsets
  410. plot_handles = plot(timevec, gavg_crosscorr.avg(chan_idx,:), 'color', cmap(loc_idx,:), 'LineWidth', 1, 'LineStyle', line_styles{loc_idx});
  411. % Save only the FIRST handle from this group for the legend
  412. if ~isempty(plot_handles)
  413. h(loc_idx) = plot_handles(1);
  414. end
  415. end
  416. plot_handles = plot(timevec, gavg_crosscorr_shuffled.avg(is_sensor,:), 'color', 'r', 'LineWidth', 1);
  417. h(length(channel_subsets)+1) = plot_handles(1);
  418. % Define patch properties
  419. patchColor = [1, 1, 0]; % A light, transparent yellow
  420. patchAlpha = 0.2;
  421. % Create the first patch for the 50-90ms window
  422. p1 = patch([timewindows_statistic(1,1), timewindows_statistic(1,2), timewindows_statistic(1,2), timewindows_statistic(1,1)]*1000, [yLims(1), yLims(1), yLims(2), yLims(2)], ...
  423. patchColor, 'FaceAlpha', patchAlpha, 'EdgeColor', 'none');
  424. h(end) = p1;
  425. % Create the second patch for the 160-230ms window
  426. p2 = patch([timewindows_statistic(2,1), timewindows_statistic(2,2), timewindows_statistic(2,2), timewindows_statistic(2,1)]*1000, [yLims(1), yLims(1), yLims(2), yLims(2)], ...
  427. patchColor, 'FaceAlpha', patchAlpha, 'EdgeColor', 'none');
  428. % Send the patches to the background, behind the data lines
  429. uistack([p1, p2], 'bottom');
  430. hold off;
  431. xlabel('t / ms')
  432. ylabel('$\hat{R}$','Interpreter','Latex')
  433. title('Butterfly plot cross-correlation functions');
  434. xticks(xlims(1):200:xlims(2)); % Set x-axis ticks in steps of 100 ms
  435. set(gca, 'FontSize', axis_font_size); % Set font size for axis values
  436. ylim(yLims)
  437. legend(h, [channel_subsets_label, 'Shuffled', 'time window statistic'], 'Location', 'Southeast', 'NumColumns', 5);
  438. grid on;
  439. grid minor;
  440. box on;
  441. % Create dummy data for mapping color coding of sensors
  442. %------------------------------------------------------
  443. dummy_data = gavg_crosscorr_raweffect;
  444. dummy_data.time = 0;
  445. dummy_data.avg = zeros(306,1);
  446. for loc_idx = 1:length(channel_subsets)
  447. subset_idx = contains(dummy_data.label, channel_subsets{loc_idx});
  448. dummy_data.avg(subset_idx) = loc_idx;
  449. end
  450. % Highlight channels in topoplot
  451. %-------------------------------
  452. fig = figure('Color', 'w');
  453. hold on
  454. cfg = [];
  455. cfg.comment = 'no';
  456. cfg.xlim = [0,0];
  457. cfg.markersize = 20;
  458. cfg.markersymbol = '.';
  459. cfg.highlight = 'on';
  460. cfg.highlightchannel = chan2plot;
  461. cfg.highlightcolor = 'k';
  462. cfg.highlightsize = 50;
  463. cfg.highlightsymbol = '.';
  464. cfg.layout = 'neuromag306mag_helmet.lay';
  465. cfg.interactive = 'no';
  466. cfg.colorbar = 'yes';
  467. cfg.interpolation = 'nearest';
  468. cfg.figure = fig;
  469. ft_topoplotER(cfg,dummy_data); % plot difference
  470. colormap(cmap)
  471. %% Functions
  472. %--------------------------------------------------------------------------
  473. function mask = give_stat_mask(stat,alpha)
  474. %--------------------------------------------------------------------------
  475. % Till Habersetzer, 01.07.2025
  476. % Communication Acoustics, CvO University Oldenburg
  477. % [email hidden]
  478. %
  479. % MASK = GIVE_STAT_MASK(STAT, ALPHA) takes the output of a FieldTrip
  480. % cluster-based permutation analysis (STAT) and a desired alpha-value.
  481. % It returns a binary mask (MASK) where significant clusters (p < ALPHA)
  482. % are marked with 'true' and non-significant areas with 'false'.
  483. % This mask can be used for visualizing statistically significant regions.
  484. %
  485. % Inputs:
  486. % stat - Structure array containing the results of ft_timelockstatistics
  487. % or ft_sourcestatistics, including cluster information.
  488. % alpha - Desired significance level (e.g., 0.05) for thresholding the clusters.
  489. %
  490. % Output:
  491. % mask - A logical array (binary mask) indicating the significant
  492. % clusters. True for significant, false for non-significant.
  493. %
  494. % Example Usage for plotting the mask:
  495. % Assuming 'stat' is the result of a FieldTrip cluster analysis
  496. % and 'alpha' is your significance level (e.g., 0.05)
  497. % mask = give_stat_mask(stat, alpha);
  498. % figure;
  499. % imagesc(mask);
  500. % colormap(gray); % or any suitable colormap for binary masks
  501. %--------------------------------------------------------------------------
  502. % positive clusters
  503. %------------------
  504. pos_cluster_pvals = [stat.posclusters(:).prob];
  505. pos_signif_clust = find(pos_cluster_pvals < alpha);
  506. pos = ismember(stat.posclusterslabelmat, pos_signif_clust);
  507. % negative clusters
  508. %------------------
  509. neg_cluster_pvals = [stat.negclusters(:).prob];
  510. neg_signif_clust = find(neg_cluster_pvals < alpha);
  511. neg = ismember(stat.negclusterslabelmat, neg_signif_clust);
  512. % combine clusters
  513. %-----------------
  514. mask = or(neg,pos);
  515. end

plot_crosscorr.m at commit 32bfc69, under BSD-3-Clause · at the source

Overview

Authors: Till Habersetzer1, Svea Steuer1,2, Andreas Radeloff3, Bernd T Meyer1
  1. Communication Acoustics, Department of Medical Physics and Acoustics and Cluster of Excellence ”Hearing4all”, Carl von Ossietzky Universität Oldenburg, Oldenburg, Germany
  2. TUD Dresden University of Technology, Dresden, Germany
  3. Department of Otolaryngology, Head and Neck Surgery, Carl von Ossietzky Universität Oldenburg, Oldenburg, Germany
Journal: n/a, volume 12, issue 1, article 1938
Dates: received 20 August 2025; accepted 28 November 2025; published online 9 December 2025
Type: Data paper · Language: English
License: none stated
Identifiers: DOI 10.1038/s41597-025-06397-4 · PMCID PMC12695901 · OpenAlex W4417167534
Open access: gold, a free copy (OpenAlex)
Status: code verified
Categories: structural MRI / diffusion (modality), MEG (modality), human (organism), methods / tools (subfield)
Methods: Spectral & time-frequency, Single-unit activity, calcium imaging
Keywords: Databases, Cortex
MeSH: Magnetoencephalography*, Speech*, Speech Perception*, Brain, Humans, Magnetic Resonance Imaging (* major topic)
Topic: Neuroscience and Music Perception (Cognitive Neuroscience, Neuroscience), according to OpenAlex
Funding: Deutsche Forschungsgemeinschaft (German Research Foundation) (Germany's Excellence Strategy- EXC 2177/1- Project ID 390895286)
Citations: cited by 1 paper (Europe PMC); 75 references in the paper

Abstract

The abstract is not reproduced here: the paper's license (none stated) does not allow it. Read it in the paper, at the publisher or on Europe PMC.

Repositories

Its files are read in the Code ↔ Paper reader above, with 16 matches between paragraphs and lines of code.

tillhabersetzer/MEG-SCANS

License: BSD-3-Clause
State: the link answers, verified on 26 September 2026
Evidence: files inventoried
Commit: 32bfc690e28e7591b45d96615c59b2d53b6a7165, 10 December 2025
Languages: MATLAB (42), Python (3)
Size: 52 files, 45 scripts
Software Heritage: not archived
Found in: “Code availability”
Holds: README, license file
Not found: CITATION.cff, environment file, tests, continuous integration, documentation
Tools: FieldTrip (25 files), Statistics and Machine Learning Toolbox (3 files), NumPy (3 files), Parallel Computing Toolbox (2 files), Signal Processing Toolbox (2 files), Matplotlib (2 files), pandas (2 files), SciPy (2 files), MNE-Python (1 file)
Availability: 1 check, the latest on 26 September 2026: the link answers
  • 26 September 2026: the link answers
47 files

Zenodo 17397581

License: BSD-3-Clause
State: the link answers, verified on 26 September 2026
Evidence: files inventoried
Size: 1 file
Software Heritage: not checked
Found in: the references
Not found: README, license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: FieldTrip (25 files), Statistics and Machine Learning Toolbox (3 files), NumPy (3 files), Parallel Computing Toolbox (2 files), Signal Processing Toolbox (2 files), Matplotlib (2 files), pandas (2 files), SciPy (2 files), MNE-Python (1 file)
Availability: 1 check, the latest on 26 September 2026: the link answers (HTTP 200)
  • 26 September 2026: the link answers (HTTP 200)
47 files
At the source:

Code availability statement

The paper has a code availability statement. Its license (none stated) does not allow reproducing it here; in short, from what the harvester recognized in it:

Read it in the paper: doi.org/10.1038/s41597-025-06397-4.

Tracing map

Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.

What the map holds:

  • 2 repositories of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
  • 90 scripts, each with its path and the digest of its content;
  • 16 matches between paragraphs of the paper and lines of the code (method lexical-v1);
  • neither the text of the paper nor the code itself.

Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.

Data

Datasets cited

Data availability statement

The paper has a data availability statement. Its license (none stated) does not allow reproducing it here; in short, from what the harvester recognized in it:

  • no repository, dataset or request procedure was recognized in it

Read it in the paper: doi.org/10.1038/s41597-025-06397-4.

Versions

The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.

Version 1, 27 September 2026: the first record

Recorded: type, language, journal, volume, issue, pages, dates, 4 authors, 2 keywords, 6 MeSH terms, 1 funder, 61 references.

Cite

This paper

Habersetzer, T., Steuer, S., Radeloff, A., & Meyer, B. T. (2025). MEG-SCANS - A comprehensive magnetoencephalography speech dataset with Stories, Chirps and Noisy Sentences. Scientific Data, 12(1), 1938. https://doi.org/10.1038/s41597-025-06397-4

BibTeX

@article{habersetzer2025meg,
author = {Habersetzer, Till and Steuer, Svea and Radeloff, Andreas and Meyer, Bernd T},
title = {{MEG-SCANS - A comprehensive magnetoencephalography speech dataset with Stories, Chirps and Noisy Sentences}},
journal = {Scientific Data},
year = {2025},
volume = {12},
number = {1},
pages = {1938},
publisher = {Nature Publishing Group},
issn = {2052-4463},
doi = {10.1038/s41597-025-06397-4},
url = {https://doi.org/10.1038/s41597-025-06397-4},
pmcid = {PMC12695901}
}

RIS

TY - JOUR
AU - Habersetzer, Till
AU - Steuer, Svea
AU - Radeloff, Andreas
AU - Meyer, Bernd T
TI - MEG-SCANS - A comprehensive magnetoencephalography speech dataset with Stories, Chirps and Noisy Sentences
T2 - Scientific Data
J2 - Sci Data
PY - 2025
DA - 2025
VL - 12
IS - 1
SP - 1938
SN - 2052-4463
PB - Nature Publishing Group
DO - 10.1038/s41597-025-06397-4
UR - https://doi.org/10.1038/s41597-025-06397-4
LA - en
ER -

CSL-JSON

{
"id": "10.1038/s41597-025-06397-4",
"type": "article-journal",
"title": "MEG-SCANS - A comprehensive magnetoencephalography speech dataset with Stories, Chirps and Noisy Sentences",
"container-title": "Scientific Data",
"author": [
{
"family": "Habersetzer",
"given": "Till"
},
{
"family": "Steuer",
"given": "Svea"
},
{
"family": "Radeloff",
"given": "Andreas"
},
{
"family": "Meyer",
"given": "Bernd T"
}
],
"container-title-short": "Sci Data",
"volume": "12",
"issue": "1",
"page": "1938",
"DOI": "10.1038/s41597-025-06397-4",
"PMCID": "PMC12695901",
"ISSN": "2052-4463",
"publisher": "Nature Publishing Group",
"URL": "https://doi.org/10.1038/s41597-025-06397-4",
"language": "en",
"issued": {
"date-parts": [
[
2025
]
]
}
}

The tracing map gets a citation of its own once an author has validated it and it has a DOI.

Similar papers

The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.

[1] doi:10.1523/eneuro.0069-26.2026 [code]
Electrophysiological Indices of Hierarchical Speech Processing Differentially Reflect the Comprehension of Speech in Noise.
Journal: eNeuro
In common: Statistics and Machine Learning Toolbox, 12 references
[2] doi:10.1038/s41597-026-07215-1 [code]
The Brain, Body, and Behavior Dataset (BBBD): Multimodal Recordings during Educational Videos.
Journal: Scientific data
In common: MNE-Python, Signal Processing Toolbox, Statistics and Machine Learning Toolbox, 4 other tools, methods / tools, 4 references
[3] doi:10.1111/ejn.70598 [code]
Enhanced Time-Locked Decoding for Spoken Words but Not Environmental Sounds in Natural-Like Auditory Conditions.
Journal: The European journal of neuroscience
In common: MEG, 8 references
[4] doi:10.1162/imag.a.1227 [code]
Large language models reveal the neural tracking of linguistic context in attended and unattended multi-talker speech.
Journal: Imaging neuroscience (Cambridge, Mass.)
In common: MNE-Python, pandas, SciPy, 2 other tools, 5 references
[5] doi:10.1162/imag.a.1040 [code]
Novel 4 He-OPMs support waveform-specific beta burst analysis comparable to SQUID-MEG
Journal: n/a
In common: FieldTrip, MNE-Python, Signal Processing Toolbox, 5 other tools, MEG, 2 references
[6] doi:10.1038/s41597-026-07350-9 [code]
An open multi-center MEG-EEG dataset for studying conscious visual perception.
Journal: Scientific data
In common: MNE-Python, Statistics and Machine Learning Toolbox, pandas, 3 other tools, MEG, structural MRI / diffusion, 4 references
[7] doi:10.1038/s41467-026-73553-8 [code]
Universal rhythmic architecture uncovers two modes of neural dynamics.
Journal: Nature communications
In common: FieldTrip, MNE-Python, Signal Processing Toolbox, 5 other tools, 3 references
[8] doi:10.1162/imag.a.1269 [code]
From early to contemporary normative modeling: Mapping individual differences in neurophysiological signals.
Journal: Imaging neuroscience (Cambridge, Mass.)
In common: MNE-Python, pandas, SciPy, 2 other tools, MEG, 6 references
[9] doi:10.1111/ejn.70538 [code]
Neural Tracking of Sustained Attention, Attention Switching, and Natural Conversation in Audiovisual Environments Using Wearable EEG.
Journal: The European journal of neuroscience
In common: MNE-Python, pandas, SciPy, 2 other tools, 5 references
[10] doi:10.1038/s41597-025-05174-7 [code]
A large-scale MEG and EEG dataset for object recognition in naturalistic scenes
Journal: n/a
In common: MNE-Python, pandas, SciPy, 2 other tools, MEG, methods / tools, 4 references

Contribute

The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.

Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.

Request its removal

To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).

Discussion, reproductions, activity

Discussion: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.

Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.

Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.