OSCR

A transparent wheel-based platform for locomotion-on-demand and multi-view body and facial kinematics in head-fixed mice.

Code ↔ Paper

19 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 19 matches · 1 of them tie a paragraph to a whole file, not to given lines: a weak match, whose lines are not tinted
  1. [1] § Methods › Data analysis › Video preprocessing ↔ Python/reduce_video_dimensions.py, lines 5–49 · score 0.81 · INTER_AREA, OpenCV, Resized videos, dimension, downscaling, quality
  2. [2] § Methods › Data analysis › Video preprocessing ↔ Python/notebooks/optical_flow.ipynb, lines 111–198 · score 0.79 · INTER_AREA, Resized videos, pupil video, optical flow, OpenCV, suffix
  3. [3] § Methods › Data analysis › Optical flow and motion-energy extraction ↔ Python/optical_flow.py, lines 125–202 · score 0.79 · avg_u, avg_v, optical flow, motion energy, OpenCV, timestamp
  4. [4] § Methods › Data analysis › Determination of eye/pupil area ↔ Matlab/load_eye_pupil_signal.m, the whole file · a weak match · score 0.77 · eye pupil roi, eye pupil signal, pupil area, largest, hole, calibration
  5. [5] § Methods › Data analysis › Optical flow and motion-energy extraction ↔ Python/src/utils/motion_analysis.py, lines 181–247 · score 0.75 · avg_u, avg_v, motion energy, OpenCV, timestamp, pose
  6. [6] § Results › Air-induced locomotion produces reliable paw kinematics on a transparent wheel ↔ Matlab/fig_dlc.m, lines 100–183 · score 0.71 · hind left, hind right, front left, front right, tail, nose
  7. [7] § Results › Air-induced locomotion produces reliable paw kinematics on a transparent wheel ↔ Matlab/fig_dlc_n3.m, lines 17–130 · score 0.70 · hind left, hind right, front left, front right, tail, nose
  8. [8] § Methods › Data analysis › LED intensity extraction for LED-based synchronization of video streams ↔ Matlab/fig_montage_n3.m, lines 257–387 · score 0.61 · nearest DAQ sample, video frame, divergence, windows, alignment, events
  9. [9] § Results › LED-based synchronization enables alignment of air stimulus across video streams ↔ Matlab/fig_montage_n3.m, lines 257–387 · score 0.60 · nearest DAQ sample, video frame, anchoring, divergence, windows, alignment
  10. [10] § Results › LED-based synchronization enables alignment of air stimulus across video streams ↔ Matlab/fig_montage.m, lines 135–172 · score 0.58 · paws camera, air state, video stream, montages, synchronization, alignment
  11. [11] § Results › Facial and eye dynamics during air-induced locomotion ↔ Matlab/fig_motion_energy_n3.m, lines 13–127 · score 0.56 · Optical flow, motion energy, LED signal, air onset, SEM, cm
  12. [12] § Methods › Data analysis › ROI selection and metadata ↔ Python/spyder_extract_led_signal.py, lines 13–86 · score 0.54 · interactive ROI, OpenCV, selection, frame, video
  13. [13] § Methods › Data analysis › Determination of eye/pupil area ↔ Matlab/fig_pupil.m, lines 17–94 · score 0.54 · pupil area, largest, hole, calibration, segmented, rectangular
  14. [14] § Results › Air-induced locomotion produces reliable paw kinematics on a transparent wheel ↔ Matlab/fig_motion_energy.m, lines 12–104 · score 0.54 · left axis, right axis, motion energy, box, offset, LED
  15. [15] § Results › Facial and eye dynamics during air-induced locomotion ↔ Matlab/fig_motion_energy.m, lines 12–104 · score 0.53 · left axis, right axis, motion energy, box, offset, LED
  16. [16] § Methods › Data analysis › ROI selection and metadata ↔ Python/fig_show_roi.py, lines 6–66 · score 0.53 · roi.json, OpenCV, selection, rectangular, pupil, frame
  17. [17] § Results › Air-induced locomotion produces reliable paw kinematics on a transparent wheel ↔ Matlab/fig_dlc.m, lines 59–98 · score 0.51 · Tracking reliability, Bar graphs, CDFs, cumulative, likelihood, frame
  18. [18] § Results › Air-induced locomotion produces reliable paw kinematics on a transparent wheel ↔ Matlab/fig_motion_energy_n3.m, lines 13–127 · score 0.51 · optical flow speeds, motion energy, air onset, SEM, paw, animals
  19. [19] § Results › Air-induced locomotion produces reliable paw kinematics on a transparent wheel ↔ Matlab/fig_dlc_F.m, lines 76–100 · score 0.50 · Tracking reliability, Bar graphs, CDFs, cumulative, likelihood, frame

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 · 673 lines · 21 KB · no license · 2 matches

  1. function fig_dlc
  2. % vp = evalin('base','vp');
  3. %
  4. % vp_l = evalin('base','vp_labeled');
  5. % vf = evalin('base','vf');
  6. % v = evalin('base','v');
  7. mD = evalin('base','mData'); colors = mD.colors; sigColor = mD.sigColor; axes_font_size = mD.axes_font_size;
  8. mData = mD;
  9. animal = evalin('base','animals(1)');
  10. % animal = evalin('base','fanimal');
  11. % physical_dist_cm = 5.0;
  12. % pixel_dist_px = 200; % Measure this from a still frame using 'imdistline'
  13. px_to_cm = 0.0114;
  14. n = 0;
  15. %%
  16. %% ---------- Load and Clean DLC Data ----------
  17. % Using the path structure you provided
  18. file_path = fullfile(animal(1).pdir,'video_20251216_165824DLC_resnet50_gcamp16declimbDec18shuffle1_185000_filtered.csv');
  19. % Set up import options to handle the triple-header (scorer, bodyparts, coords)
  20. opts = detectImportOptions(file_path);
  21. % Start reading from row 4 where the numeric data begins
  22. opts.DataLines = [4, Inf];
  23. opts.VariableNamingRule = 'preserve';
  24. tbl = readtable(file_path, opts);
  25. % Mapping likelihood columns based on your CSV image:
  26. % Column D=4 (Front Right), G=7 (Front Left), J=10 (Hind Right),
  27. % M=13 (Hind Left), P=16 (Tail Base), S=19 (Nose)
  28. lik_indices = [4, 7, 10, 13, 16, 19];
  29. bodyparts = {'Front Right', 'Front Left', 'Hind Right', 'Hind Left', 'Tail Base', 'Nose'};
  30. % Extract likelihood matrix [40748 frames x 6 bodyparts]
  31. likelihoods = table2array(tbl(:, lik_indices));
  32. %% ---------- Calculate Quality Metrics ----------
  33. p_thresh = 0.9;
  34. % Percentage of frames where p > 0.9 for each body part
  35. percent_high_conf = sum(likelihoods > p_thresh, 1) / size(likelihoods, 1) * 100;
  36. %% ---------- Updated Bodypart Colors (RGB) ----------
  37. % These values are sampled directly from the markers in your images:
  38. % Front Right (Blue/Indigo), Front Left (Sky Blue), Hind Right (Teal),
  39. % Hind Left (Bright Green), Tail Base (Orange), Nose (Red)
  40. custom_colors = [
  41. 0.20, 0.00, 1.00; % Front Right (Dark Blue/Indigo)
  42. 0.00, 0.60, 1.00; % Front Left (Sky Blue)
  43. 0.00, 0.80, 0.75; % Hind Right (Teal)
  44. 0.60, 1.00, 0.40; % Hind Left (Bright Green)
  45. 1.00, 0.60, 0.00; % Tail Base (Orange)
  46. 1.00, 0.00, 0.00 % Nose (Red)
  47. ];
  48. %% ---------- PANEL C: DLC Quality Analysis ----------
  49. magfac = mD.magfac;
  50. ff = makeFigureRowsCols(110, [3 5 4 1.5], 'RowsCols', [1 2], ...
  51. 'spaceRowsCols', [0.05 0.1], 'rightUpShifts', [0.1 0.1]);
  52. % --- C1: Bar Graph (% Frames > 0.9) ---
  53. subplot(1,2,1);
  54. hold on;
  55. for i = 1:6
  56. % Plot each bar individually to apply specific color
  57. bar(i, percent_high_conf(i), 'FaceColor', custom_colors(i,:), 'EdgeColor', 'none');
  58. end
  59. set(gca, 'XTick', 1:6, 'XTickLabel', bodyparts, 'XTickLabelRotation', 45);
  60. ylabel('% Frames (p > 0.9)');
  61. ht = title('DLC Tracking Reliability'); set(ht,'FontWeight','Normal');
  62. ylim([0 105]);
  63. box off;
  64. format_axes(gca);
  65. % --- C2: Likelihood CDF (Multi-line) ---
  66. subplot(1,2,2);
  67. hold on;
  68. for i = 1:6
  69. [f, x] = ecdf(likelihoods(:, i));
  70. plot(x, f, 'LineWidth', 2, 'Color', custom_colors(i,:));
  71. end
  72. % Reference line at 0.9 threshold
  73. line([p_thresh p_thresh], [0 1], 'Color', [0.5 0.5 0.5], 'LineStyle', '--', 'LineWidth', 1);
  74. xlabel('Likelihood');
  75. ylabel('Cumulative Probability');
  76. % legend(bodyparts, 'Location', 'northwest', 'FontSize', 7, 'Box', 'off');
  77. ht = title('Likelihood CDF'); set(ht,'FontWeight','Normal');
  78. grid on;
  79. box off;
  80. format_axes(gca);
  81. % Save to your designated PDF folder
  82. save_pdf(ff.hf, mD.pdf_folder, 'DLC_Quality_Analysis_Colored.pdf', 600);
  83. %% ---------- Setup & Data Loading ----------
  84. file_path = fullfile(animal(1).pdir, 'video_20251216_165824DLC_resnet50_gcamp16declimbDec18shuffle1_185000_filtered.csv');
  85. opts = detectImportOptions(file_path);
  86. opts.DataLines = [4, Inf];
  87. opts.VariableNamingRule = 'preserve';
  88. tbl = readtable(file_path, opts);
  89. % Define indices for X and Y based on your CSV structure
  90. % x: Col 2, 5, 8, 11, 14, 17 | y: Col 3, 6, 9, 12, 15, 18
  91. x_idx = [2, 5, 8, 11, 14, 17];
  92. y_idx = [3, 6, 9, 12, 15, 18];
  93. likelihood_idx = [4, 7, 10, 13, 16, 19];
  94. bodyparts = {'Front Right', 'Front Left', 'Hind Right', 'Hind Left', 'Tail Base', 'Nose'};
  95. % ---------- 1. Re-establish Time Base ----------
  96. N_sig = 40746;
  97. % If you have your sampling frequency (e.g., 30 fps or 60 fps)
  98. % If unknown, we can infer it if 'b.fs' exists from your earlier code
  99. if exist('b','var') && isfield(b,'fs')
  100. fs = b.fs;
  101. else
  102. fs = 60; % Defaulting to 30 fps; change this to your actual video FPS
  103. end
  104. fs = animal(1).video.specs.paws.fps;
  105. % Create time vector in seconds
  106. time_sec = (0:N_sig-1)' / fs;
  107. tmin = time_sec / 60; % Convert to minutes for plotting
  108. % Extract and truncate to match your signal time base (40745 samples)
  109. N_target = length(time_sec);
  110. X_coords = table2array(tbl(1:N_target, x_idx));
  111. Y_coords = table2array(tbl(1:N_target, y_idx));
  112. L = table2array(tbl(1:N_target, likelihood_idx));
  113. % Use the custom colors from the mouse markers
  114. custom_colors = [
  115. 0.20, 0.00, 1.00; % Front Right (Blue/Indigo)
  116. 0.00, 0.60, 1.00; % Front Left (Sky Blue)
  117. 0.00, 0.80, 0.75; % Hind Right (Teal)
  118. 0.60, 1.00, 0.40; % Hind Left (Bright Green)
  119. 1.00, 0.60, 0.00; % Tail Base (Orange)
  120. 1.00, 0.00, 0.00 % Nose (Red)
  121. ];
  122. % ---------- Likelihood filtering ----------
  123. lik_thresh = 0.9;
  124. low_conf = L < lik_thresh;
  125. X_coords(low_conf) = NaN;
  126. Y_coords(low_conf) = NaN;
  127. % ---------- Interpolate missing values ----------
  128. X_coords = fillmissing(X_coords,'linear');
  129. Y_coords = fillmissing(Y_coords,'linear');
  130. % ---------- No Smoothing ----------
  131. X_coordsS = X_coords;
  132. Y_coordsS = Y_coords;
  133. % ---------- Smooth coordinates ----------
  134. X_coordsS = movmedian(X_coords,5);
  135. Y_coordsS = movmedian(Y_coords,5);
  136. % X_coordsS = movmean(X_coordsS,5);
  137. % Y_coordsS = movmean(Y_coordsS,5);
  138. % Convert coordinates to cm
  139. X_cm = X_coordsS * px_to_cm;
  140. Y_cm = Y_coordsS * px_to_cm;
  141. fs = 60;
  142. % Compute velocity
  143. Vx = [zeros(1,6); diff(X_cm) * fs];
  144. Vy = [zeros(1,6); diff(Y_cm) * fs];
  145. % remove impossible spikes
  146. max_speed = 100; % cm/s
  147. Vx(abs(Vx) > max_speed) = NaN;
  148. Vy(abs(Vy) > max_speed) = NaN;
  149. %%
  150. T = animal(1).b.led_sig.paws;
  151. % t_paws = T.t_led/60;
  152. air_paws = double(T.is_on);
  153. %% ---------- Plotting: Trajectories vs Time ----------
  154. magfac = mD.magfac;
  155. tmin = time_sec / 60; % Time in minutes for the x-axis
  156. ff = makeFigureRowsCols(111, [3 5 6.9 1.5], 'RowsCols', [1 2], ...
  157. 'spaceRowsCols', [0.1 5], 'rightUpShifts', [0.1 0.2],'widthHeightAdjustment',[0 -300]);
  158. MY = 1920; ysp = 0.15285; mY = -2.5; titletxt = ''; ylabeltxt = {'PDF'}; % for all cells (vals) MY = 80
  159. stp = 0.35*magfac; widths = [3.12 3.12 2.85 1]*magfac; gap = 0.25*magfac;
  160. adjust_axes(ff,[mY MY],stp,widths,gap,{''});
  161. % axes_title_shifts_line = [0 0.55 0 0]; axes_title_shifts_text = [0.02 0.1 0 0]; xs_gaps = [1 2];
  162. % --- Subplot 1: X-Coordinates vs Time ---
  163. axes(ff.h_axes(1,1))
  164. hold on;
  165. for i = 1:6
  166. miny(i) = min(X_coords(:,i)); maxy(i) = max(X_coords(:,i));
  167. plot(tmin, X_coords(:,i), 'Color', custom_colors(i,:), 'LineWidth', 0.25);
  168. end
  169. % ylim([200 1400])
  170. ylims = ylim;
  171. plot(t_paws,air_paws*ylims(2),'k','LineWidth',0.25)
  172. ylabel('X Pixel Value');xlabel('Time (min)');
  173. % title('Horizontal Position (X) over Time');
  174. % legend(bodyparts, 'Location', 'eastoutside', 'FontSize', 7, 'Box', 'off');
  175. % box off; format_axes(gca);
  176. xlim([0 3]);
  177. onsets = find_rising_edge(air_paws,0.5,-1);
  178. offsets = find_falling_edge(air_paws,-0.5,1);
  179. ylims = ylim;
  180. [TLx TLy] = ds2nfu(time_sec(onsets(1)),ylims(2)-0);
  181. % axes(ff.h_axes(1,1));ylims = ylim;
  182. [BLx BLy] = ds2nfu(time_sec(onsets(1)),ylims(1));
  183. aH = (TLy - BLy);
  184. len = sum(find(time_sec(onsets)<3,1,'last'));
  185. for ii = 1:len%gth(onsets)
  186. [BRx BRy] = ds2nfu(time_sec(offsets(ii)),ylims(1));
  187. [BLx BLy] = ds2nfu(time_sec(onsets(ii)),ylims(1));
  188. aW = (BRx-BLx);
  189. annotation('rectangle',[BLx BLy aW aH],'facealpha',0.2,'linestyle','none','facecolor','k');
  190. end
  191. box off
  192. format_axes(gca)
  193. % --- Subplot 2: Y-Coordinates vs Time ---
  194. axes(ff.h_axes(1,2))
  195. hold on;
  196. for i = 1:6
  197. plot(tmin, Y_coords(:,i), 'Color', custom_colors(i,:), 'LineWidth', 0.25);
  198. end
  199. % ylim([10 1000])
  200. ylims = ylim;
  201. plot(t_paws,air_paws*ylims(2),'k','LineWidth',0.25)
  202. ylabel('Y Pixel Value');
  203. xlabel('Time (min)');
  204. % title('Vertical Position (Y) over Time');
  205. % box off; format_axes(gca);
  206. xlim([0 3]);
  207. onsets = find_rising_edge(air_paws,0.5,-1);
  208. offsets = find_falling_edge(air_paws,-0.5,1);
  209. ylims = ylim;
  210. [TLx TLy] = ds2nfu(time_sec(onsets(1)),ylims(2)-0);
  211. % axes(ff.h_axes(1,1));ylims = ylim;
  212. [BLx BLy] = ds2nfu(time_sec(onsets(1)),ylims(1));
  213. aH = (TLy - BLy);
  214. len = sum(find(time_sec(onsets)<3,1,'last'));
  215. for ii = 1:len%gth(onsets)
  216. [BRx BRy] = ds2nfu(time_sec(offsets(ii)),ylims(1));
  217. [BLx BLy] = ds2nfu(time_sec(onsets(ii)),ylims(1));
  218. aW = (BRx-BLx);
  219. annotation('rectangle',[BLx BLy aW aH],'facealpha',0.2,'linestyle','none','facecolor','k');
  220. end
  221. box off
  222. format_axes(gca)
  223. % Save the trajectory plot
  224. save_pdf(ff.hf, mD.pdf_folder, 'DLC_Trajectories.pdf', 600);
  225. %% ---------- Plotting: Inst Vel vs Time ----------
  226. magfac = mD.magfac;
  227. tmin = time_sec / 60; % Time in minutes for the x-axis
  228. ff = makeFigureRowsCols(111, [3 5 6.9 1.5], 'RowsCols', [1 2], ...
  229. 'spaceRowsCols', [0.1 0.061], 'rightUpShifts', [0.051 0.2],'widthHeightAdjustment',[-60 -300]);
  230. MY = 1920; ysp = 0.15285; mY = -2.5; titletxt = ''; ylabeltxt = {'PDF'}; % for all cells (vals) MY = 80
  231. stp = 0.1*magfac; widths = [3.12 3.12 2.85 1]*magfac; gap = 0.25*magfac;
  232. % adjust_axes(ff,[mY MY],stp,widths,gap,{''});
  233. % axes_title_shifts_line = [0 0.55 0 0]; axes_title_shifts_text = [0.02 0.1 0 0]; xs_gaps = [1 2];
  234. % --- Subplot 1: X-Coordinates vs Time ---
  235. axes(ff.h_axes(1,1))
  236. hold on;
  237. for i = 1:6
  238. miny(i) = min(Vx(:,i)); maxy(i) = max(Vx(:,i));
  239. plot(tmin, Vx(:,i), 'Color', custom_colors(i,:), 'LineWidth', 0.25);
  240. end
  241. ylim([min(miny) max(maxy)])
  242. ylims = ylim;
  243. % plot(t_paws,air_paws*ylims(2),'k','LineWidth',0.25)
  244. ylabel('Vx (cm/s)');xlabel('Time (min)');
  245. % title('Horizontal Position (X) over Time');
  246. % legend(bodyparts, 'Location', 'eastoutside', 'FontSize', 7, 'Box', 'off');
  247. % box off; format_axes(gca);
  248. xlim([0 3]);
  249. onsets = find_rising_edge(air_paws,0.5,-1);
  250. offsets = find_falling_edge(air_paws,-0.5,1);
  251. ylims = ylim;
  252. [TLx TLy] = ds2nfu(tmin(onsets(1)),ylims(2)-0);
  253. % axes(ff.h_axes(1,1));ylims = ylim;
  254. [BLx BLy] = ds2nfu(tmin(onsets(1)),ylims(1));
  255. aH = (TLy - BLy);
  256. len = sum(find(tmin(onsets)<3,1,'last'));
  257. for ii = 1:len%gth(onsets)
  258. [BRx BRy] = ds2nfu(tmin(offsets(ii)),ylims(1));
  259. [BLx BLy] = ds2nfu(tmin(onsets(ii)),ylims(1));
  260. aW = (BRx-BLx);
  261. annotation('rectangle',[BLx BLy aW aH],'facealpha',0.2,'linestyle','none','facecolor','k');
  262. end
  263. box off
  264. format_axes(gca)
  265. % --- Subplot 2: Y-Coordinates vs Time ---
  266. axes(ff.h_axes(1,2))
  267. hold on;
  268. for i = 1:6
  269. minyy(i) = min(Vy(:,i)); maxyy(i) = max(Vy(:,i));
  270. plot(tmin, Vy(:,i), 'Color', custom_colors(i,:), 'LineWidth', 0.25);
  271. end
  272. ylim([min(minyy) max(maxyy)])
  273. ylims = ylim;
  274. % plot(t_paws,air_paws*ylims(2),'k','LineWidth',0.25)
  275. ylabel('Vy (cm/s)');
  276. xlabel('Time (min)');
  277. % title('Vertical Position (Y) over Time');
  278. % box off; format_axes(gca);
  279. xlim([0 3]);
  280. onsets = find_rising_edge(air_paws,0.5,-1);
  281. offsets = find_falling_edge(air_paws,-0.5,1);
  282. ylims = ylim;
  283. [TLx TLy] = ds2nfu(tmin(onsets(1)),ylims(2)-0);
  284. % axes(ff.h_axes(1,1));ylims = ylim;
  285. [BLx BLy] = ds2nfu(tmin(onsets(1)),ylims(1));
  286. aH = (TLy - BLy);
  287. len = sum(find(tmin(onsets)<3,1,'last'));
  288. for ii = 1:len%gth(onsets)
  289. [BRx BRy] = ds2nfu(tmin(offsets(ii)),ylims(1));
  290. [BLx BLy] = ds2nfu(tmin(onsets(ii)),ylims(1));
  291. aW = (BRx-BLx);
  292. annotation('rectangle',[BLx BLy aW aH],'facealpha',0.2,'linestyle','none','facecolor','k');
  293. end
  294. box off
  295. format_axes(gca);
  296. % axes(ff.h_axes(1,1))
  297. % ylim([min([miny minyy]) max([maxy maxyy])])
  298. % axes(ff.h_axes(1,2))
  299. % ylim([min([miny minyy]) max([maxy maxyy])])
  300. % Save the trajectory plot
  301. save_pdf(ff.hf, mD.pdf_folder, 'DLC_Trajectories.pdf', 600);
  302. %% ---------- 1. Calculate Speeds for All Body Parts ----------
  303. % Ensure fs is defined (sampling rate)
  304. if ~exist('fs','var'), fs = 60; end
  305. dt = 1/fs;
  306. % Initialize speed matrix [Frames x 6 bodyparts]
  307. DLC_speeds = nan(size(X_coords));
  308. for i = 1:6
  309. % Calculate velocity (difference between frames)
  310. dx = diff(X_coords(:,i)) * fs; % Change in pixels per second
  311. dy = diff(Y_coords(:,i)) * fs;
  312. % Collapse X and Y into Speed (Magnitude of Velocity Vector)
  313. % We pad with a NaN at the start to maintain vector length
  314. DLC_speeds(2:end, i) = sqrt(dx.^2 + dy.^2);
  315. end
  316. % physical_dist_cm = 5.0;
  317. % pixel_dist_px = 200; % Measure this from a still frame using 'imdistline'
  318. px_to_cm = 0.0114;
  319. % Update the speeds by multiplying pixels by the calibration factor
  320. DLC_speeds_cm = DLC_speeds * px_to_cm;
  321. %% ---------- 2. Plot: Speeds vs Time (Panel F Style) ----------
  322. magfac = mD.magfac;
  323. tmin = time_sec / 60;
  324. magfac = mD.magfac;
  325. ff = makeFigureRowsCols(107,[3 5 6.5 1.5],'RowsCols',[1 1],'spaceRowsCols',[0.01 -0.02],'rightUpShifts',[0.2 0.22],'widthHeightAdjustment',[10 -250]);
  326. MY = 100; ysp = 0.15285; mY = -2.5; titletxt = ''; ylabeltxt = {'PDF'}; % for all cells (vals) MY = 80
  327. stp = 0.35*magfac; widths = [6.4 1 2.85 1]*magfac; gap = 0.115*magfac; adjust_axes(ff,[mY MY],stp,widths,gap,{''});
  328. axes_title_shifts_line = [0 0.55 0 0]; axes_title_shifts_text = [0.02 0.1 0 0]; xs_gaps = [1 2];
  329. % --- Subplot 1: Individual Speed Traces ---
  330. axes(ff.h_axes(1,1))
  331. hold on;
  332. for i = 1:6
  333. plot(tmin, DLC_speeds_cm(:,i), 'Color', custom_colors(i,:), 'LineWidth', 0.8);
  334. end
  335. ylabel('Speed (pixels/s)');
  336. title('DLC Speed: All Body Parts');
  337. % legend(bodyparts, 'Location', 'eastoutside', 'FontSize', 7, 'Box', 'off');
  338. box off; format_axes(gca);
  339. ylim([0 200]);xlim([0 3]);
  340. ylims = ylim;
  341. plot(t_paws,air_paws*ylims(2),'k')
  342. onsets = find_rising_edge(air_paws,0.5,-1);
  343. offsets = find_falling_edge(air_paws,-0.5,1);
  344. xlims = xlim;
  345. [TLx TLy] = ds2nfu(time_sec(onsets(1)),ylims(2)-0);
  346. % axes(ff.h_axes(1,1));ylims = ylim;
  347. [BLx BLy] = ds2nfu(time_sec(onsets(1)),ylims(1));
  348. aH = (TLy - BLy);
  349. len = sum(find(time_sec(onsets)<xlims(2),1,'last'));
  350. for ii = 1:len%gth(onsets)
  351. [BRx BRy] = ds2nfu(time_sec(offsets(ii)),ylims(1));
  352. [BLx BLy] = ds2nfu(time_sec(onsets(ii)),ylims(1));
  353. aW = (BRx-BLx);
  354. annotation('rectangle',[BLx BLy aW aH],'facealpha',0.2,'linestyle','none','facecolor','k');
  355. end
  356. box off
  357. format_axes(gca)
  358. save_pdf(ff.hf, mD.pdf_folder, 'DLC_Speeds_Combined.pdf', 600);
  359. %% ---------- 3. Statistical Comparison (Air-ON vs Air-OFF) ----------
  360. % Align with air epochs
  361. is_on = air_paws(1:length(avg_speed)) > 0;
  362. speed_on = avg_speed(is_on & isfinite(avg_speed));
  363. speed_off = avg_speed(~is_on & isfinite(avg_speed));
  364. if ~isempty(speed_on) && ~isempty(speed_off)
  365. [~, p_speed] = ttest2(speed_on, speed_off);
  366. fprintf('Global DLC Speed: Air-ON vs OFF, p = %.2e\n', p_speed);
  367. end
  368. %% ===================== DLC SPEED + AIR ON/OFF =====================
  369. % Inputs assumed from your script:
  370. % X_coords (N x 6), Y_coords (N x 6)
  371. % time_sec (N x 1) in seconds (DLC time base)
  372. % T = animal(1).b.led_sig.paws; T.time, T.is_on (LED time base)
  373. % bodyparts (1x6 cell), custom_colors (6x3)
  374. % ---- 0) Basic checks
  375. N = size(X_coords,1);
  376. assert(numel(time_sec)==N, 'time_sec length must match X_coords rows.');
  377. % ---- 1) Resample/align air signal to DLC time base
  378. % LED time is in seconds already (but you divided by 60 earlier for t_paws)
  379. % t_led = double(T.time(:)); % seconds
  380. t_led = double(T.t_led(:));
  381. air_led = double(strcmpi(string(T.is_on), "True") | double(T.is_on)); % robust
  382. % If T.is_on is already logical numeric, above still works.
  383. % Make sure time vectors are monotonic
  384. [~, idxSort] = sort(t_led);
  385. t_led = t_led(idxSort);
  386. air_led = air_led(idxSort);
  387. % Resample LED air to DLC time points
  388. air_dlc = interp1(t_led, air_led, time_sec, 'previous', 0);
  389. air_dlc(isnan(air_dlc)) = 0;
  390. air_dlc = air_dlc > 0.5;
  391. % ---- 2) Compute per-bodypart speed in pixels/s
  392. fs_dlc = 1/median(diff(time_sec)); % inferred FPS from DLC time base
  393. dx = [zeros(1,6); diff(X_coords,1,1)];
  394. dy = [zeros(1,6); diff(Y_coords,1,1)];
  395. speed_pix_s = sqrt(dx.^2 + dy.^2) * fs_dlc * 0.0114 ; % N x 6
  396. % Optional smoothing (helps readability)
  397. speed_pix_s_sm = movmedian(speed_pix_s, 5, 1);
  398. % ---- 3) Find air epochs on DLC time base
  399. air = air_dlc(:);
  400. on_idx = find(diff([0; air])== 1); % rising edges
  401. off_idx = find(diff([air; 0])==-1); % falling edges
  402. nTr = min(numel(on_idx), numel(off_idx));
  403. on_idx = on_idx(1:nTr);
  404. off_idx = off_idx(1:nTr);
  405. % sanity: ensure each onset precedes offset
  406. good = off_idx > on_idx;
  407. on_idx = on_idx(good);
  408. off_idx = off_idx(good);
  409. nTr = numel(on_idx);
  410. % ---- 4) Trial-wise paired comparison: Air-ON vs preceding Air-OFF window
  411. % Define a "pre" window immediately before each onset (e.g., 1.0 s)
  412. preWin_s = 1.0;
  413. preSamp = max(1, round(preWin_s * fs_dlc));
  414. mean_on = nan(nTr,6);
  415. mean_off = nan(nTr,6);
  416. for k = 1:nTr
  417. idx_on = on_idx(k):off_idx(k);
  418. idx_off = max(1, on_idx(k)-preSamp):on_idx(k)-1;
  419. if isempty(idx_off) || numel(idx_on) < 3
  420. continue
  421. end
  422. mean_on(k,:) = mean(speed_pix_s_sm(idx_on,:), 1, 'omitnan');
  423. mean_off(k,:) = mean(speed_pix_s_sm(idx_off,:), 1, 'omitnan');
  424. end
  425. % Drop trials with NaNs
  426. validTr = all(isfinite(mean_on),2) & all(isfinite(mean_off),2);
  427. mean_on = mean_on(validTr,:);
  428. mean_off = mean_off(validTr,:);
  429. nValid = size(mean_on,1);
  430. % Paired t-test per bodypart
  431. p_t = nan(1,6);
  432. tstat = nan(1,6);
  433. for i = 1:6
  434. [~, p_t(i), ~, stats] = ttest(mean_on(:,i), mean_off(:,i)); % paired
  435. tstat(i) = stats.tstat;
  436. end
  437. % ---- 5) Plot 1: Speed time-series with shaded air epochs
  438. figure(501); clf
  439. tmin = time_sec/60;
  440. for i = 1:6
  441. subplot(3,2,i); hold on
  442. % Shaded air windows
  443. yl = [0, max(speed_pix_s_sm(:,i), [], 'omitnan')*1.05 + eps];
  444. ylim(yl)
  445. for k = 1:nTr
  446. x1 = time_sec(on_idx(k))/60;
  447. x2 = time_sec(off_idx(k))/60;
  448. patch([x1 x2 x2 x1], [yl(1) yl(1) yl(2) yl(2)], ...
  449. 'k', 'FaceAlpha', 0.12, 'EdgeColor', 'none');
  450. end
  451. plot(tmin, speed_pix_s_sm(:,i), 'Color', custom_colors(i,:), 'LineWidth', 0.5);
  452. xlim([0 3]) % match your 3-min window
  453. xlabel('Time (min)')
  454. ylabel('Speed (px/s)')
  455. title(sprintf('%s', bodyparts{i}))
  456. box off
  457. end
  458. sgtitle('DLC point speed over time (shaded = Air ON)')
  459. % ---- 6) Plot 2: Onset-aligned speed (mean ± SD)
  460. win_pre = 2; % seconds before onset
  461. win_post = 5; % seconds after onset
  462. Lpre = round(win_pre * fs_dlc);
  463. Lpost = round(win_post * fs_dlc);
  464. t_rel = (-Lpre:Lpost)'/fs_dlc;
  465. % Build onset-aligned matrices: (time x trials x bodyparts)
  466. M = numel(t_rel);
  467. speed_onset = nan(M, nTr, 6);
  468. for k = 1:nTr
  469. c = on_idx(k);
  470. idx = (c-Lpre):(c+Lpost);
  471. if idx(1) < 1 || idx(end) > N
  472. continue
  473. end
  474. speed_onset(:,k,:) = speed_pix_s_sm(idx,:);
  475. end
  476. figure(502); clf
  477. for i = 1:6
  478. subplot(3,2,i); hold on
  479. X = squeeze(speed_onset(:,:,i)); % M x nTr
  480. mu = mean(X, 2, 'omitnan');
  481. sd = std(X, 0, 2, 'omitnan');
  482. plot(t_rel, mu, 'Color', custom_colors(i,:), 'LineWidth', 1.5);
  483. plot(t_rel, mu+sd, '--', 'Color', custom_colors(i,:), 'LineWidth', 0.75);
  484. plot(t_rel, mu-sd, '--', 'Color', custom_colors(i,:), 'LineWidth', 0.75);
  485. xline(0, 'k-');
  486. xlabel('Time from air onset (s)')
  487. ylabel('Speed (px/s)')
  488. title(bodyparts{i})
  489. box off
  490. end
  491. sgtitle('Onset-aligned DLC speed (mean ± SD)')
  492. % ---- 7) Plot 3: Trial-wise Air-ON vs Air-OFF (paired) bar + dots
  493. % figure(503); clf
  494. % tiledlayout(1,6,'Padding','compact','TileSpacing','tight');
  495. %%
  496. magfac = mD.magfac;
  497. ff = makeFigureRowsCols(107,[3 5 6.75 1.5],'RowsCols',[1 6],'spaceRowsCols',[0.01 0.04],'rightUpShifts',[0.051 0.2],...
  498. 'widthHeightAdjustment',[-45 -500]);
  499. for i = 1:6
  500. % subplot(1,6,i);
  501. axes(ff.h_axes(1,i));% nexttile
  502. hold on
  503. mOn = mean(mean_on(:,i), 'omitnan');
  504. mOff = mean(mean_off(:,i), 'omitnan');
  505. allmOn(i) = mOn;
  506. allmOff(i) = mOff;
  507. seOn = std(mean_on(:,i), 'omitnan');%/sqrt(nValid);
  508. seOff = std(mean_off(:,i), 'omitnan');%/sqrt(nValid);
  509. allseOn(i) = seOn;
  510. allseOff(i) = seOff;
  511. hb = bar([1 2], [mOff mOn]); % OFF then ON
  512. errorbar([1 2], [mOff mOn], [seOff seOn], 'k.', 'LineWidth', 1);
  513. set(hb,'FaceColor',custom_colors(i,:))
  514. % paired dots
  515. for k = 1:nValid
  516. plot([1 2], [mean_off(k,i) mean_on(k,i)], '-', 'Color', [0 0 0 0.15]);
  517. end
  518. set(gca,'XTick',[1 2],'XTickLabel',{'Air-OFF','Air-ON'});xtickangle(30)
  519. if i == 1
  520. ylabel('Mean speed (cm/s)')
  521. end
  522. % title(sprintf('%s | p=%.3g', bodyparts{i}, p_t(i)))
  523. ht = title(sprintf('%s | p<0.001', bodyparts{i})); set(ht,'FontWeight','Normal')
  524. box off
  525. format_axes(gca)
  526. end
  527. ht = sgtitle(sprintf('Paired Air-ON vs pre-Air-ON (Representative Animal, n = 34 trials)', nValid));set(ht,'FontSize',8,'FontWeight','Normal')
  528. save_pdf(gcf, mD.pdf_folder, 'DLC_bar_air_on_vs_off.pdf', 600);
  529. %% ---------- 1. Parameter Setup ----------
  530. win_pre = 5; % seconds
  531. win_post = 5; % seconds
  532. fs = 60; % Sampling rate (frames per second)
  533. Npre = round(win_pre * fs);
  534. Npost = round(win_post * fs);
  535. signal = DLC_speeds_cm(:,6); % Your data vector
  536. % Initialize arrays for mean values
  537. pre_means = [];
  538. post_means = [];
  539. % ---------- 2. Extraction Loop ----------
  540. for i = 1:length(onsets)
  541. idx = onsets(i);
  542. % Ensure the window is within the bounds of the signal
  543. if idx > Npre && idx + Npost <= length(signal)
  544. % Extract the pre-event segment (5s before onset)
  545. pre_segment = signal(idx - Npre : idx - 1);
  546. % Extract the post-event segment (5s starting at onset)
  547. post_segment = signal(idx : idx + Npost);
  548. % Calculate and store the mean for this specific trial
  549. pre_means(end+1) = mean(pre_segment, 'omitnan');
  550. post_means(end+1) = mean(post_segment, 'omitnan');
  551. end
  552. end
  553. % Display results for verification
  554. fprintf('Extracted means for %d valid trials.\n', length(pre_means));

fig_dlc.m at commit 5b9d1c9, no license · at the source

Overview

Authors: Pratik S. Paranjape1, Tahoura Mohammadi Ghohaki1, Samsoon Inayat1
  1. Department of Psychology, University of Nevada,Las Vegas, USA
Institutions: University of Nevada, Las Vegas (United States)
Journal: Scientific reports, volume 16, issue 1, article 26691
Dates: received 27 December 2025; accepted 4 May 2026; published online 21 May 2026
Type: Research article · Language: English
License: CC BY-NC-ND
Identifiers: DOI 10.1038/s41598-026-52322-z · PMID 42168450 · PMCID PMC13507272 · OpenAlex W7161960706
Open access: gold, a free copy (OpenAlex)
Status: code verified
Categories: other (modality), mouse (organism), methods / tools (subfield)
Methods: Connectivity, Statistics, fMRI & imaging, Physiology & signal measures
Keywords: Head-fixed locomotion, Stimulus-induced locomotion, Behavioral kinematics, Transparent running wheel, Multi-view videography, Optical flow, DeepLabCut, Mouse behavior, Biological techniques, Engineering, Neuroscience
MeSH: Face*, Locomotion*, Animals, Behavior, Animal, Biomechanical Phenomena, Male, Mice, Motion Capture, Video Recording (* major topic)
Topic: Zebrafish Biomedical Research Applications (Cell Biology, Biochemistry, Genetics and Molecular Biology), according to OpenAlex
Funding: Interdisciplinary Neuroscience Graduate Assistantship; Department of Psychology Graduate Assistantship; UNLV Internal Funding
Citations: not cited yet (Europe PMC); 32 references in the paper

Abstract

The abstract is not reproduced here: the paper's license (CC BY-NC-ND) 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 19 matches between paragraphs and lines of code.

OSF k9j3b

License: none: the authors keep all their rights
State: the link answers, verified on 28 September 2026
Evidence: files inventoried
Size: 7 files, 0 scripts
Software Heritage: not checked
Found in: “Data availability”
Not found: README, license file, CITATION.cff, environment file, tests, continuous integration, documentation
Availability: 1 check, the latest on 28 September 2026: the link answers (HTTP 200)
  • 28 September 2026: the link answers (HTTP 200)
At the source: osf.io/k9j3b

neuromomentumlab/AIR_Wheel_Methods

License: none: the authors keep all their rights
State: the link answers, verified on 28 September 2026
Evidence: files inventoried
Commit: 5b9d1c94237197f3c21d7a9dd9459c1f5e15f62f, 1 May 2026
Languages: MATLAB (45), Python (15), Jupyter (4)
Size: 84 files, 64 scripts
Software Heritage: not archived
Found in: “Data availability”
Holds: 4 notebooks
Not found: README, license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: OpenCV (10 files), Image Processing Toolbox (6 files), Statistics and Machine Learning Toolbox (5 files), NumPy (5 files), shadedErrorBar (5 files), Matplotlib (3 files), pandas (2 files), Signal Processing Toolbox (1 file), SciPy (1 file)
Availability: 1 check, the latest on 28 September 2026: the link answers
  • 28 September 2026: the link answers
64 files

The paper's code and data availability statement is in the Data section.

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;
  • 64 scripts, each with its path and the digest of its content;
  • 19 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

No dataset and no data link were found in the paper.

Code and data availability statement

The paper has a code and data availability statement. Its license (CC BY-NC-ND) does not allow reproducing it here; in short, from what the harvester recognized in it:

Read it in the paper: doi.org/10.1038/s41598-026-52322-z.

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, 28 September 2026: the first record

Recorded: type, language, journal, volume, issue, pages, dates, 3 authors, 11 keywords, 9 MeSH terms, 3 funders, 32 references.

Cite

This paper

Paranjape, P. S., Ghohaki, T. M., & Inayat, S. (2026). A transparent wheel-based platform for locomotion-on-demand and multi-view body and facial kinematics in head-fixed mice. Scientific reports, 16(1), 26691. https://doi.org/10.1038/s41598-026-52322-z

BibTeX

@article{paranjape2026transparent,
author = {Paranjape, Pratik S. and Ghohaki, Tahoura Mohammadi and Inayat, Samsoon},
title = {{A transparent wheel-based platform for locomotion-on-demand and multi-view body and facial kinematics in head-fixed mice}},
journal = {Scientific reports},
year = {2026},
month = may,
volume = {16},
number = {1},
pages = {26691},
publisher = {Nature Publishing Group},
issn = {2045-2322},
doi = {10.1038/s41598-026-52322-z},
url = {https://doi.org/10.1038/s41598-026-52322-z},
pmid = {42168450},
pmcid = {PMC13507272}
}

RIS

TY - JOUR
AU - Paranjape, Pratik S.
AU - Ghohaki, Tahoura Mohammadi
AU - Inayat, Samsoon
TI - A transparent wheel-based platform for locomotion-on-demand and multi-view body and facial kinematics in head-fixed mice
T2 - Scientific reports
J2 - Sci Rep
PY - 2026
DA - 2026/05/21
VL - 16
IS - 1
SP - 26691
SN - 2045-2322
PB - Nature Publishing Group
DO - 10.1038/s41598-026-52322-z
UR - https://doi.org/10.1038/s41598-026-52322-z
LA - en
ER -

CSL-JSON

{
"id": "10.1038/s41598-026-52322-z",
"type": "article-journal",
"title": "A transparent wheel-based platform for locomotion-on-demand and multi-view body and facial kinematics in head-fixed mice",
"container-title": "Scientific reports",
"author": [
{
"family": "Paranjape",
"given": "Pratik S."
},
{
"family": "Ghohaki",
"given": "Tahoura Mohammadi"
},
{
"family": "Inayat",
"given": "Samsoon"
}
],
"container-title-short": "Sci Rep",
"volume": "16",
"issue": "1",
"page": "26691",
"DOI": "10.1038/s41598-026-52322-z",
"PMID": "42168450",
"PMCID": "PMC13507272",
"ISSN": "2045-2322",
"publisher": "Nature Publishing Group",
"URL": "https://doi.org/10.1038/s41598-026-52322-z",
"language": "en",
"issued": {
"date-parts": [
[
2026,
5,
21
]
]
}
}

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.7554/elife.109717 [code]
Retrosplenial cortex enables context-dependent goal-directed sensorimotor transformation.
Journal: eLife
In common: OpenCV, Statistics and Machine Learning Toolbox, pandas, 3 other tools, mouse, 5 references
[2] doi:10.1038/s41467-026-75347-4 [code]
Sleep reveals dynamics integrating and segregating movement and stimulus representations in V1.
Journal: Nature communications
In common: Image Processing Toolbox, Signal Processing Toolbox, Statistics and Machine Learning Toolbox, 4 other tools, mouse, 3 references
[3] doi:10.1038/s41467-026-71725-0 [code]
Interactions across hemispheres in prefrontal cortex reflect global cognitive processing.
Journal: Nature communications
In common: Image Processing Toolbox, Signal Processing Toolbox, Statistics and Machine Learning Toolbox, 4 other tools, 3 references
[4] doi:10.1038/s41467-026-76581-6 [code]
Thalamocortical bursts encode reward contingencies and drive associative learning.
Journal: Nature communications
In common: OpenCV, Image Processing Toolbox, Signal Processing Toolbox, 5 other tools, mouse, 1 reference
[5] doi:10.1038/s41593-026-02232-0 [code]
Entorhinal cortex represents task-relevant remote locations independently of CA1.
Journal: Nature neuroscience
In common: OpenCV, Image Processing Toolbox, Signal Processing Toolbox, 5 other tools, mouse, 1 reference
[6] doi:10.1038/s41467-026-73476-4 [code]
Developmental molecular signatures define de novo cortico-brainstem circuit for skilled forelimb movement.
Journal: Nature communications
In common: OpenCV, Image Processing Toolbox, Signal Processing Toolbox, 3 other tools, mouse, 2 references
[7] doi:10.1016/j.neuron.2026.03.034 [code]
Dentate gyrus interneurons modulate winner-take-all network dynamics in freely behaving mice.
Journal: Neuron
In common: shadedErrorBar, Image Processing Toolbox, Signal Processing Toolbox, 5 other tools, mouse
[8] doi:10.1038/s41593-026-02255-7 [code]
Neural circuits encode prior knowledge of temporal statistics.
Journal: Nature neuroscience
In common: shadedErrorBar, Image Processing Toolbox, Signal Processing Toolbox, 5 other tools, mouse
[9] doi:10.7554/elife.108663 [code]
The Crunchometer, a low-cost, open-source acoustic analysis of feeding microstructure.
Journal: eLife
In common: OpenCV, Image Processing Toolbox, Signal Processing Toolbox, 5 other tools, methods / tools, mouse
[10] doi:10.1126/sciadv.adv5652 [code]
The anterior cingulate cortex modulates pupil-linked arousal.
Journal: Science advances
In common: OpenCV, pandas, SciPy, 2 other 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.