OSCR

Dynamic representations of valence in anterior cingulate cortex in mice.

Code ↔ Paper

2 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 2 matches
  1. [1] § Results › ACC represents aspects of the US ↔ analyze_ideas_traces_final.py, lines 343–417 · score 0.59 · peak offset, peak onset, peak amplitude, AUC, error
  2. [2] § Materials and methods › Data analysis and statistics › Event-related (peri-event) activity ↔ analyze_ideas_traces_final.py, lines 343–417 · score 0.56 · peak onset, Peak amplitudes, window, offset, baseline, trace

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

Python · 674 lines · 20 KB · CC-BY-4.0 · 2 matches

  1. import re
  2. import time
  3. import traceback
  4. from pathlib import Path
  5. import numpy as np
  6. import pandas as pd
  7. import matplotlib.pyplot as plt
  8. # ======================================================
  9. # CONFIG
  10. # ======================================================
  11. ALLCELLS_INPUT_DIR = Path(r"C:\Users\pgoswamee\Desktop\new EAPA traces_ALL CELLS")
  12. LCR_INPUT_DIR = Path(r"C:\Users\pgoswamee\Desktop\new EAPA trace-LCR")
  13. # ---- COLUMN INDICES (0-based) ----
  14. COL_TIME = 0
  15. COL_BASE_TRUE = 1 # Column B
  16. COL_UP_TRUE = 3 # Column D
  17. COL_DOWN_TRUE = 5 # Column F
  18. # ---- Analysis parameters ----
  19. MOVING_AVG_WINDOW = 5
  20. BASELINE_START = -20.0
  21. BASELINE_END = 0.0
  22. PEAK_SEARCH_START = 0.0
  23. PEAK_SEARCH_END = 20.0
  24. ONSET_MIN_TIME = -20.0
  25. SKIP_EXISTING_ANALYSIS_OUTPUTS = True
  26. # ---- Summary config ----
  27. LCR_DESIRED_CONDITIONS = [
  28. "D2RD3-EARLY", "D2RD3-LATE",
  29. "D3RD2-EARLY", "D3RD2-LATE",
  30. "D3RD4-EARLY", "D3RD4-LATE",
  31. "D4RD3-EARLY", "D4RD3-LATE",
  32. "D4RD5-EARLY", "D4RD5-LATE",
  33. "D5RD4-EARLY", "D5RD4-LATE",
  34. ]
  35. ALLCELLS_DESIRED_ORDER = [
  36. "D2-EARLY", "D2-LATE",
  37. "D3-EARLY", "D3-LATE",
  38. "D4-EARLY", "D4-LATE",
  39. "D5-EARLY", "D5-LATE",
  40. ]
  41. PREFERRED_ROW = "BASE"
  42. POSSIBLE_PEAK_COLS = [
  43. "Peak_Amplitude_diff",
  44. "Peak_Amplitude",
  45. ]
  46. POSSIBLE_AUC_COLS = [
  47. "AUC_dynamic_diff",
  48. "AUC_baseline_subtracted",
  49. "AUC_diff",
  50. "AUC",
  51. ]
  52. # ======================================================
  53. # COMMON UTILS
  54. # ======================================================
  55. def ensure_dir(path: Path):
  56. path.mkdir(parents=True, exist_ok=True)
  57. def try_write_csv(df: pd.DataFrame, path: Path) -> bool:
  58. for i in range(10):
  59. try:
  60. df.to_csv(path, index=True)
  61. return True
  62. except PermissionError:
  63. print(f" File locked, retrying ({i+1}/10)... {path.name}")
  64. time.sleep(1)
  65. print(f" ERROR: Could not save {path}, file is locked.")
  66. return False
  67. def moving_average(x, w=5):
  68. """Centered moving average, preserving your current analysis logic."""
  69. if w <= 1:
  70. return x
  71. return np.convolve(x, np.ones(w) / w, mode="same")
  72. def compute_baseline(trace, time_vec, t_start, t_end):
  73. mask = (time_vec >= t_start) & (time_vec <= t_end)
  74. if not np.any(mask):
  75. return np.nan
  76. return float(np.nanmean(trace[mask]))
  77. def find_peak(trace, time_vec, t_start, t_end):
  78. mask = (time_vec >= t_start) & (time_vec <= t_end)
  79. idxs = np.where(mask)[0]
  80. if len(idxs) == 0:
  81. return None, None, None
  82. sliced = trace[idxs]
  83. if np.all(np.isnan(sliced)):
  84. return None, None, None
  85. try:
  86. peak_local = int(np.nanargmax(sliced))
  87. except ValueError:
  88. return None, None, None
  89. peak_idx = idxs[peak_local]
  90. peak_val = float(trace[peak_idx])
  91. peak_time = float(time_vec[peak_idx])
  92. return peak_idx, peak_val, peak_time
  93. def find_onset_offset(trace, time_vec, baseline, peak_idx):
  94. n = len(trace)
  95. onset_idx = None
  96. for i in range(peak_idx, -1, -1):
  97. if time_vec[i] < ONSET_MIN_TIME:
  98. break
  99. if not np.isnan(trace[i]) and trace[i] <= baseline:
  100. onset_idx = i
  101. break
  102. if onset_idx is None:
  103. valid_idxs = np.where(time_vec >= ONSET_MIN_TIME)[0]
  104. onset_idx = int(valid_idxs[0]) if len(valid_idxs) > 0 else 0
  105. offset_idx = None
  106. for j in range(peak_idx, n):
  107. if time_vec[j] > PEAK_SEARCH_END:
  108. break
  109. if not np.isnan(trace[j]) and trace[j] <= baseline:
  110. offset_idx = j
  111. break
  112. if offset_idx is None:
  113. valid_idxs = np.where(time_vec <= PEAK_SEARCH_END)[0]
  114. offset_idx = int(valid_idxs[-1]) if len(valid_idxs) > 0 else (n - 1)
  115. return onset_idx, offset_idx
  116. def compute_auc_baseline_subtracted(trace, time_vec, baseline, onset_idx, offset_idx):
  117. if onset_idx is None or offset_idx is None or offset_idx <= onset_idx:
  118. return np.nan
  119. sliced_t = time_vec[onset_idx:offset_idx + 1]
  120. sliced_y = trace[onset_idx:offset_idx + 1] - baseline
  121. if len(sliced_t) < 2 or np.all(np.isnan(sliced_y)):
  122. return np.nan
  123. return float(np.trapz(sliced_y, sliced_t))
  124. def pick_metric(row: pd.Series, candidates):
  125. for c in candidates:
  126. if c in row.index:
  127. return row[c]
  128. return np.nan
  129. def compute_stats_over_subjects(table: pd.DataFrame):
  130. rows = []
  131. for cond in table.columns:
  132. vals = pd.to_numeric(table[cond], errors="coerce").values
  133. vals = vals[~np.isnan(vals)]
  134. n = len(vals)
  135. if n == 0:
  136. mean = np.nan
  137. sem = np.nan
  138. elif n == 1:
  139. mean = float(vals[0])
  140. sem = np.nan
  141. else:
  142. mean = float(np.mean(vals))
  143. sem = float(np.std(vals, ddof=1) / np.sqrt(n))
  144. rows.append({
  145. "condition": cond,
  146. "Mean": mean,
  147. "SEM": sem,
  148. "N": n,
  149. })
  150. return pd.DataFrame(rows).set_index("condition")
  151. def write_summary_workbook(out_xlsx: Path, tables: dict):
  152. with pd.ExcelWriter(out_xlsx, engine="xlsxwriter") as writer:
  153. for sheet_name, df in tables.items():
  154. df.to_excel(writer, sheet_name=sheet_name[:31])
  155. def make_mean_sem_plot(stats_df: pd.DataFrame, title: str, ylabel: str, out_png: Path):
  156. if stats_df.empty:
  157. print(f" WARNING: stats table empty for {out_png.name}, skipping figure.")
  158. return
  159. means = pd.to_numeric(stats_df["Mean"], errors="coerce").values
  160. sems = pd.to_numeric(stats_df["SEM"], errors="coerce").values
  161. labels = list(stats_df.index)
  162. if len(labels) == 0 or np.all(np.isnan(means)):
  163. print(f" WARNING: no plottable values for {out_png.name}, skipping figure.")
  164. return
  165. plt.figure(figsize=(12, 5))
  166. x = np.arange(len(labels))
  167. plt.bar(x, means, yerr=sems, capsize=4)
  168. plt.xticks(x, labels, rotation=45, ha="right")
  169. plt.ylabel(ylabel)
  170. plt.title(title)
  171. plt.tight_layout()
  172. plt.savefig(out_png, dpi=300, bbox_inches="tight")
  173. plt.close()
  174. print(f" Wrote figure: {out_png.name}")
  175. def make_condition_order(conditions_in_data, desired_order):
  176. final = []
  177. for c in desired_order:
  178. if c in conditions_in_data and c not in final:
  179. final.append(c)
  180. for c in sorted(conditions_in_data):
  181. if c not in final:
  182. final.append(c)
  183. return final
  184. # ======================================================
  185. # FLEXIBLE FILENAME NORMALIZATION / PARSING
  186. # ======================================================
  187. def clean_stem_for_parsing(stem: str) -> str:
  188. """
  189. Normalize filename stem to make parsing separator-agnostic.
  190. """
  191. stem = re.sub(r"(_baseline)?_analysis_output$", "", stem, flags=re.IGNORECASE)
  192. # Convert underscores and hyphens to spaces
  193. stem = stem.replace("_", " ").replace("-", " ")
  194. # Collapse repeated spaces
  195. stem = re.sub(r"\s+", " ", stem).strip()
  196. return stem.upper()
  197. def extract_subject(cleaned_stem: str):
  198. """
  199. Extract WTIN subject and normalize to 'WTIN 005'
  200. """
  201. m = re.search(r"\bWTIN\s*(\d+)\b", cleaned_stem)
  202. if not m:
  203. return None
  204. num = m.group(1)
  205. return f"WTIN {num}"
  206. def extract_epoch(cleaned_stem: str):
  207. if re.search(r"\bEARLY\b", cleaned_stem):
  208. return "EARLY"
  209. if re.search(r"\bLATE\b", cleaned_stem):
  210. return "LATE"
  211. return None
  212. def extract_lcr_condition(cleaned_stem: str):
  213. """
  214. Detect session-pair tokens like:
  215. D2RD3
  216. D4RD5
  217. Also tolerates split tokens:
  218. D2 RD3
  219. D2 RD D3
  220. """
  221. # Direct compact form
  222. m = re.search(r"\b(D[2-5]RD[2-5])\b", cleaned_stem)
  223. if m:
  224. return m.group(1)
  225. # Split form: D2 RD3
  226. m = re.search(r"\b(D[2-5])\s*RD\s*(D[2-5])\b", cleaned_stem)
  227. if m:
  228. return f"{m.group(1)}R{m.group(2)}".replace("R", "RD", 1)
  229. # Split form: D2 RD D3
  230. m = re.search(r"\b(D[2-5])\s*RD\s*(D[2-5])\b", cleaned_stem)
  231. if m:
  232. return f"{m.group(1)}RD{m.group(2)[1:]}"
  233. return None
  234. def extract_single_day_condition(cleaned_stem: str):
  235. """
  236. Detect single-session day token like D2, D3, D4, D5
  237. but avoid misreading D2RD3 as D2.
  238. """
  239. # Remove any LCR tokens first so we do not double-detect
  240. temp = re.sub(r"\bD[2-5]RD[2-5]\b", " ", cleaned_stem)
  241. temp = re.sub(r"\bD[2-5]\s*RD\s*D[2-5]\b", " ", temp)
  242. m = re.search(r"\b(D[2-5])\b", temp)
  243. if not m:
  244. return None
  245. return m.group(1)
  246. def parse_subject_and_condition_allcells_flexible(stem: str):
  247. cleaned = clean_stem_for_parsing(stem)
  248. subject = extract_subject(cleaned)
  249. epoch = extract_epoch(cleaned)
  250. day = extract_single_day_condition(cleaned)
  251. if subject is None or epoch is None or day is None:
  252. return None, None
  253. return subject, f"{day}-{epoch}"
  254. def parse_subject_and_condition_lcr_flexible(stem: str):
  255. cleaned = clean_stem_for_parsing(stem)
  256. subject = extract_subject(cleaned)
  257. epoch = extract_epoch(cleaned)
  258. pair = extract_lcr_condition(cleaned)
  259. if subject is None or epoch is None or pair is None:
  260. return None, None
  261. return subject, f"{pair}-{epoch}"
  262. # ======================================================
  263. # PER-FILE ANALYSIS
  264. # ======================================================
  265. def analyze_single_trace_file(csv_path: Path, analysis_output_dir: Path):
  266. print(f"\nProcessing raw trace file: {csv_path.name}")
  267. df = pd.read_csv(csv_path)
  268. df.columns = df.columns.str.strip()
  269. if "time" in df.columns:
  270. time_vec = pd.to_numeric(df["time"], errors="coerce").values
  271. else:
  272. time_vec = pd.to_numeric(df.iloc[:, COL_TIME], errors="coerce").values
  273. if np.all(np.isnan(time_vec)):
  274. raise ValueError("time column is all NaN")
  275. results = {}
  276. trace_specs = [
  277. ("BASE", COL_BASE_TRUE),
  278. ("UP", COL_UP_TRUE),
  279. ("DOWN", COL_DOWN_TRUE),
  280. ]
  281. for label, col_true in trace_specs:
  282. if col_true >= df.shape[1]:
  283. print(f" WARNING: column {col_true} out of range for {csv_path.name}, skipping {label}")
  284. continue
  285. true_raw = pd.to_numeric(df.iloc[:, col_true], errors="coerce").values
  286. true_sm = moving_average(true_raw, MOVING_AVG_WINDOW)
  287. baseline = compute_baseline(true_sm, time_vec, BASELINE_START, BASELINE_END)
  288. if np.isnan(baseline):
  289. print(f" WARNING: could not compute baseline for {label} in {csv_path.name}, skipping {label}.")
  290. continue
  291. peak_idx, peak_val, peak_time = find_peak(
  292. true_sm, time_vec, PEAK_SEARCH_START, PEAK_SEARCH_END
  293. )
  294. if peak_idx is None:
  295. print(f" WARNING: could not find peak for {label} in {csv_path.name}, skipping {label}.")
  296. continue
  297. peak_amp = peak_val - baseline
  298. onset_idx, offset_idx = find_onset_offset(true_sm, time_vec, baseline, peak_idx)
  299. onset_time = float(time_vec[onset_idx])
  300. offset_time = float(time_vec[offset_idx])
  301. auc = compute_auc_baseline_subtracted(true_sm, time_vec, baseline, onset_idx, offset_idx)
  302. results[label] = {
  303. "Baseline": baseline,
  304. "Peak_Amplitude": peak_amp,
  305. "Peak_Time": peak_time,
  306. "Peak_Onset_Time": onset_time,
  307. "Peak_Offset_Time": offset_time,
  308. "AUC_baseline_subtracted": auc,
  309. }
  310. if not results:
  311. print(" No valid traces analyzed for this file, skipping save.")
  312. return None
  313. out_df = pd.DataFrame(results).T
  314. out_name = csv_path.stem + "_baseline_analysis_output.csv"
  315. out_path = analysis_output_dir / out_name
  316. if SKIP_EXISTING_ANALYSIS_OUTPUTS and out_path.exists():
  317. print(f" Output already exists, skipping write: {out_path.name}")
  318. return out_path
  319. if try_write_csv(out_df, out_path):
  320. print(f" -> wrote {out_path.name}")
  321. return out_path
  322. else:
  323. print(f" -> FAILED to write {out_path.name}")
  324. return None
  325. def run_analysis_stage(input_dir: Path, analysis_output_dir: Path):
  326. ensure_dir(analysis_output_dir)
  327. raw_csv_paths = sorted(
  328. [p for p in input_dir.iterdir() if p.is_file() and p.suffix.lower() == ".csv"],
  329. key=lambda p: p.name
  330. )
  331. if not raw_csv_paths:
  332. print(f"No raw .csv files found in {input_dir}")
  333. return []
  334. print(f"\nFound {len(raw_csv_paths)} raw CSV files in {input_dir}:")
  335. for p in raw_csv_paths:
  336. print(" ", p.name)
  337. generated = []
  338. for csv_path in raw_csv_paths:
  339. try:
  340. out_path = analyze_single_trace_file(csv_path, analysis_output_dir)
  341. if out_path is not None:
  342. generated.append(out_path)
  343. except Exception as e:
  344. print(f" ERROR while processing {csv_path.name}: {e}")
  345. traceback.print_exc()
  346. print(" Skipping this file and continuing...")
  347. continue
  348. print(f"\n=== ANALYSIS STAGE DONE for {input_dir.name} ===")
  349. print(f"Generated/available per-file outputs: {len(generated)}")
  350. return generated
  351. # ======================================================
  352. # ALL-CELLS SUMMARY
  353. # ======================================================
  354. def run_summary_stage_allcells(analysis_output_dir: Path, summary_dir: Path, figure_dir: Path):
  355. ensure_dir(summary_dir)
  356. ensure_dir(figure_dir)
  357. summary_xlsx = summary_dir / "EAPA_summary_tables.xlsx"
  358. csv_paths = sorted(
  359. analysis_output_dir.glob("*_analysis_output.csv"),
  360. key=lambda p: p.name
  361. )
  362. if not csv_paths:
  363. print(f"No *_analysis_output.csv files found in {analysis_output_dir}")
  364. return
  365. records = []
  366. skipped = []
  367. for p in csv_paths:
  368. subj, cond = parse_subject_and_condition_allcells_flexible(p.stem)
  369. if subj is None or cond is None:
  370. skipped.append(p.name)
  371. continue
  372. try:
  373. df = pd.read_csv(p, index_col=0)
  374. except Exception as e:
  375. print(f" ERROR reading {p.name}: {e}")
  376. continue
  377. row = df.loc[PREFERRED_ROW] if PREFERRED_ROW in df.index else df.iloc[0]
  378. records.append({
  379. "subject": subj,
  380. "condition": cond,
  381. "peak": pick_metric(row, POSSIBLE_PEAK_COLS),
  382. "auc": pick_metric(row, POSSIBLE_AUC_COLS),
  383. })
  384. print(f"\nALL-CELLS summary parsed records: {len(records)}")
  385. if skipped:
  386. print(f"ALL-CELLS skipped files: {len(skipped)}")
  387. for name in skipped[:10]:
  388. print(" skipped:", name)
  389. if not records:
  390. print("No all-cells records parsed; no workbook or figures generated.")
  391. return
  392. rec_df = pd.DataFrame(records)
  393. subjects = sorted(rec_df["subject"].unique())
  394. cond_seen = sorted(rec_df["condition"].unique())
  395. final_conditions = make_condition_order(cond_seen, ALLCELLS_DESIRED_ORDER)
  396. peak_table = pd.DataFrame(data=np.nan, index=subjects, columns=final_conditions)
  397. auc_table = pd.DataFrame(data=np.nan, index=subjects, columns=final_conditions)
  398. for _, row in rec_df.iterrows():
  399. peak_table.loc[row["subject"], row["condition"]] = row["peak"]
  400. auc_table.loc[row["subject"], row["condition"]] = row["auc"]
  401. peak_stats = compute_stats_over_subjects(peak_table)
  402. auc_stats = compute_stats_over_subjects(auc_table)
  403. write_summary_workbook(summary_xlsx, {
  404. "PeakAmp": peak_table,
  405. "AUC": auc_table,
  406. "PeakAmp_stats": peak_stats,
  407. "AUC_stats": auc_stats,
  408. })
  409. print(f"Wrote ALL-CELLS workbook: {summary_xlsx}")
  410. make_mean_sem_plot(
  411. peak_stats,
  412. title="All-Cells Peak Amplitude Summary",
  413. ylabel="Peak Amplitude",
  414. out_png=figure_dir / "ALLCELLS_Peak_Amplitude_summary.png"
  415. )
  416. make_mean_sem_plot(
  417. auc_stats,
  418. title="All-Cells AUC Summary",
  419. ylabel="AUC",
  420. out_png=figure_dir / "ALLCELLS_AUC_summary.png"
  421. )
  422. # ======================================================
  423. # LCR SUMMARY
  424. # ======================================================
  425. def run_summary_stage_lcr(analysis_output_dir: Path, summary_dir: Path, figure_dir: Path):
  426. ensure_dir(summary_dir)
  427. ensure_dir(figure_dir)
  428. summary_xlsx = summary_dir / "LR_summary_metrics.xlsx"
  429. csv_paths = sorted(
  430. analysis_output_dir.glob("*_analysis_output.csv"),
  431. key=lambda p: p.name
  432. )
  433. if not csv_paths:
  434. print(f"No *_analysis_output.csv files found in {analysis_output_dir}")
  435. return
  436. records = []
  437. skipped = []
  438. for p in csv_paths:
  439. subj, cond = parse_subject_and_condition_lcr_flexible(p.stem)
  440. if subj is None or cond is None:
  441. skipped.append(p.name)
  442. continue
  443. try:
  444. df = pd.read_csv(p, index_col=0)
  445. except Exception as e:
  446. print(f" ERROR reading {p.name}: {e}")
  447. continue
  448. row = df.loc[PREFERRED_ROW] if PREFERRED_ROW in df.index else df.iloc[0]
  449. records.append({
  450. "subject": subj,
  451. "condition": cond,
  452. "peak": pick_metric(row, POSSIBLE_PEAK_COLS),
  453. "auc": pick_metric(row, POSSIBLE_AUC_COLS),
  454. })
  455. print(f"\nLCR summary parsed records: {len(records)}")
  456. if skipped:
  457. print(f"LCR skipped files: {len(skipped)}")
  458. for name in skipped[:10]:
  459. print(" skipped:", name)
  460. if not records:
  461. print("No LCR records parsed; no workbook or figures generated.")
  462. return
  463. rec_df = pd.DataFrame(records)
  464. subjects = sorted(rec_df["subject"].unique())
  465. cond_seen = sorted(rec_df["condition"].unique())
  466. final_conditions = make_condition_order(cond_seen, LCR_DESIRED_CONDITIONS)
  467. peak_table = pd.DataFrame(data=np.nan, index=subjects, columns=final_conditions)
  468. auc_table = pd.DataFrame(data=np.nan, index=subjects, columns=final_conditions)
  469. for _, row in rec_df.iterrows():
  470. peak_table.loc[row["subject"], row["condition"]] = row["peak"]
  471. auc_table.loc[row["subject"], row["condition"]] = row["auc"]
  472. peak_stats = compute_stats_over_subjects(peak_table)
  473. auc_stats = compute_stats_over_subjects(auc_table)
  474. write_summary_workbook(summary_xlsx, {
  475. "Peak_Amplitude": peak_table,
  476. "AUC": auc_table,
  477. "Peak_Amplitude_stats": peak_stats,
  478. "AUC_stats": auc_stats,
  479. })
  480. print(f"Wrote LCR workbook: {summary_xlsx}")
  481. make_mean_sem_plot(
  482. peak_stats,
  483. title="LCR Peak Amplitude Summary",
  484. ylabel="Peak Amplitude",
  485. out_png=figure_dir / "LCR_Peak_Amplitude_summary.png"
  486. )
  487. make_mean_sem_plot(
  488. auc_stats,
  489. title="LCR AUC Summary",
  490. ylabel="AUC",
  491. out_png=figure_dir / "LCR_AUC_summary.png"
  492. )
  493. # ======================================================
  494. # DRIVER
  495. # ======================================================
  496. def process_root(input_dir: Path, mode: str):
  497. if not input_dir.exists():
  498. print(f"\nWARNING: input directory does not exist, skipping: {input_dir}")
  499. return
  500. analysis_output_dir = input_dir / "analysis_output_baseline"
  501. summary_dir = input_dir / "summary_outputs"
  502. figure_dir = summary_dir / "figures"
  503. ensure_dir(analysis_output_dir)
  504. ensure_dir(summary_dir)
  505. ensure_dir(figure_dir)
  506. print("\n" + "=" * 80)
  507. print(f"PROCESSING MODE: {mode}")
  508. print(f"INPUT ROOT: {input_dir}")
  509. print("=" * 80)
  510. run_analysis_stage(input_dir, analysis_output_dir)
  511. if mode == "ALLCELLS":
  512. run_summary_stage_allcells(analysis_output_dir, summary_dir, figure_dir)
  513. elif mode == "LCR":
  514. run_summary_stage_lcr(analysis_output_dir, summary_dir, figure_dir)
  515. else:
  516. print(f"Unknown mode: {mode}")
  517. def main():
  518. process_root(ALLCELLS_INPUT_DIR, "ALLCELLS")
  519. process_root(LCR_INPUT_DIR, "LCR")
  520. print("\n=== PIPELINE COMPLETE ===")
  521. print(f"All-cells root processed: {ALLCELLS_INPUT_DIR}")
  522. print(f"LCR root processed : {LCR_INPUT_DIR}")
  523. if __name__ == "__main__":
  524. main()

analyze_ideas_traces_final.py, under CC-BY-4.0 · at the source

Overview

Authors: Priyodarshan Goswamee1,2, Nilanjana Saferin1, Radha Shah3, Jorge S Seoane1, Kamalika Ganguly1, Kari L Neifer1, Robert A Pearce4, James P Burkett1
ORCID iDs: James P Burkett
  1. Department of Neuroscience and Psychiatry, University of Toledo College of Medicine and Life Sciences, Toledo, OH, United States
  2. Department of Neuroscience and Anatomy, Virginia Commonwealth University School of Medicine, Richmond, VA, United States (current)
  3. College of Pharmacy and Pharmaceutical Sciences, University of Toledo, Toledo, OH, United States
  4. Department of Anesthesiology, University of Wisconsin-Madison, Madison, WI, United States
Institutions: Virginia Commonwealth University (United States); University of Toledo (United States); University of Wisconsin–Madison (United States)
Journal: Cerebral cortex (New York, N.Y. : 1991), volume 36, issue 5, article bhag062
Dates: received 6 January 2026; accepted 23 April 2026; published online 22 May 2026; in print May 2026
Type: Research article · Language: English
License: CC BY-NC
Identifiers: DOI 10.1093/cercor/bhag062 · PMID 42172105 · PMCID PMC13196587 · OpenAlex W7162084222
Open access: hybrid, a free copy (OpenAlex)
Status: code verified
Categories: optical imaging (calcium, voltage, 2-photon) (modality), mouse (organism), systems (subfield)
Methods: Statistics, Evoked potentials, Machine learning, fMRI & imaging, Single-unit activity, calcium imaging
Keywords: calcium imaging, ensemble activity, fear conditioning, longitudinal recording, threat appraisal
MeSH: Conditioning, Classical*, Fear*, Gyrus Cinguli*, Mental Recall*, Neurons*, Acoustic Stimulation, Animals, Male, Mice, Mice, Inbred C57BL, Mice, Transgenic (* major topic)
Topic: Memory and Neural Mechanisms (Cognitive Neuroscience, Neuroscience), according to OpenAlex
Funding: UToledo Medical Student Research Program fellowship
Citations: not cited yet (Europe PMC); 47 references in the paper

Abstract

While the contributions of hippocampus and amygdala to fear memory are well established, the role of anterior cingulate cortex in recall of recent fear memory remains unclear. Here we longitudinally recorded anterior cingulate cortex neural activity using single-photon calcium imaging in freely-moving male mice undergoing auditory fear conditioning. During pre-exposure to the conditioned stimulus, neural responses were strongest to novel conditioned stimulus presentations and declined with repetition. During acquisition, responses emerged late in training as the conditioned stimulus became shock-predictive. Ensemble analysis identified subpopulations of “freezing on” and “freezing off” cells whose activation coincided with decreased population activity and increased neural synchrony. During 24 and 48-h recall, responses were robust during early unreinforced conditioned stimulus presentations and declined with repetition; similarly, a subpopulation of neurons emerged that was consistently upmodulated by the conditioned stimulus in early 24 and 48-h recall and suppressed in late epochs. Our results demonstrate that the anterior cingulate cortex neural response to a cue reorganizes within and across sessions, with dynamic changes in population activity, recruitment, and synchrony that mirror changes in salience relative to novelty and both conditioned and unconditioned negative valence. This response pattern is consistent with a role for anterior cingulate cortex as a flexible hub that dynamically represents cue salience.

Reproduced under the paper's license (CC BY-NC), from the paper cited above.

Repository

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

Zenodo 19339357

License: CC-BY-4.0
State: the link answers, verified on 27 September 2026
Evidence: files inventoried
Languages: Python (1)
Size: 2 files, 1 script
Software Heritage: not checked
Found in: “Data availability”
Not found: README, license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: Matplotlib (1 file), NumPy (1 file), pandas (1 file)
Availability: 1 check, the latest on 27 September 2026: the link answers (HTTP 200)
  • 27 September 2026: the link answers (HTTP 200)
1 file

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:

  • 1 repository of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
  • 1 script, each with its path and the digest of its content;
  • 2 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.

Data availability

All raw data, metadata, and custom analysis scripts are freely available for download on Zenodo (“Dynamic representations of valence in anterior cingulate cortex in mice,” version v2, doi:10.5281/zenodo.19339357 (http://dx.doi.org/10.5281/zenodo.19339357)).

Reproduced under the paper's license (CC BY-NC), from the paper cited above.

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, 8 authors, 5 keywords, 11 MeSH terms, 1 funder, 46 references.

Cite

This paper

Goswamee, P., Saferin, N., Shah, R., Seoane, J. S., Ganguly, K., Neifer, K. L., Pearce, R. A., & Burkett, J. P. (2026). Dynamic representations of valence in anterior cingulate cortex in mice. Cerebral cortex (New York, N.Y. : 1991), 36(5), bhag062. https://doi.org/10.1093/cercor/bhag062

BibTeX

@article{goswamee2026dynamic,
author = {Goswamee, Priyodarshan and Saferin, Nilanjana and Shah, Radha and Seoane, Jorge S and Ganguly, Kamalika and Neifer, Kari L and Pearce, Robert A and Burkett, James P},
title = {{Dynamic representations of valence in anterior cingulate cortex in mice}},
journal = {Cerebral cortex (New York, N.Y. : 1991)},
year = {2026},
month = may,
volume = {36},
number = {5},
pages = {bhag062},
publisher = {Oxford University Press},
issn = {1047-3211},
doi = {10.1093/cercor/bhag062},
url = {https://doi.org/10.1093/cercor/bhag062},
pmid = {42172105},
pmcid = {PMC13196587}
}

RIS

TY - JOUR
AU - Goswamee, Priyodarshan
AU - Saferin, Nilanjana
AU - Shah, Radha
AU - Seoane, Jorge S
AU - Ganguly, Kamalika
AU - Neifer, Kari L
AU - Pearce, Robert A
AU - Burkett, James P
TI - Dynamic representations of valence in anterior cingulate cortex in mice
T2 - Cerebral cortex (New York, N.Y. : 1991)
J2 - Cereb Cortex
PY - 2026
DA - 2026/05/01
VL - 36
IS - 5
SP - bhag062
SN - 1047-3211
PB - Oxford University Press
DO - 10.1093/cercor/bhag062
UR - https://doi.org/10.1093/cercor/bhag062
LA - en
ER -

CSL-JSON

{
"id": "10.1093/cercor/bhag062",
"type": "article-journal",
"title": "Dynamic representations of valence in anterior cingulate cortex in mice",
"container-title": "Cerebral cortex (New York, N.Y. : 1991)",
"author": [
{
"family": "Goswamee",
"given": "Priyodarshan"
},
{
"family": "Saferin",
"given": "Nilanjana"
},
{
"family": "Shah",
"given": "Radha"
},
{
"family": "Seoane",
"given": "Jorge S"
},
{
"family": "Ganguly",
"given": "Kamalika"
},
{
"family": "Neifer",
"given": "Kari L"
},
{
"family": "Pearce",
"given": "Robert A"
},
{
"family": "Burkett",
"given": "James P"
}
],
"container-title-short": "Cereb Cortex",
"volume": "36",
"issue": "5",
"page": "bhag062",
"DOI": "10.1093/cercor/bhag062",
"PMID": "42172105",
"PMCID": "PMC13196587",
"ISSN": "1047-3211",
"publisher": "Oxford University Press",
"URL": "https://doi.org/10.1093/cercor/bhag062",
"language": "en",
"issued": {
"date-parts": [
[
2026,
5,
1
]
]
}
}

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.1038/s41467-026-77318-1 [code]
Offline generative network reconfiguration guides insight-like accelerated learning by assimilation into schema in rats.
Journal: Nature communications
In common: pandas, Matplotlib, systems, 3 references
[2] doi:10.7554/elife.105528 [code]
Functional specialization of mPFC-BLA and mPFC-NAc pathways in affective state representation.
Journal: eLife
In common: pandas, Matplotlib, NumPy, mouse, 2 references
[3] doi:10.7554/elife.105774 [code]
Anterior cingulate cortex monitors action state and action content in complex associative learning.
Journal: eLife
In common: mouse, 3 references
[4] doi:10.1038/s41598-026-56980-x
Sustained Notch activation depletes adult neural stem cells and impairs cognitive function.
Journal: Scientific reports
In common: mouse, 3 references
[5] doi:10.1038/s41593-026-02292-2
Individual differences in prosocial learning are represented in the hippocampal dorsal CA1.
Journal: Nature neuroscience
In common: systems, mouse, 2 references
[6] doi:10.1038/s41467-026-75706-1 [code]
Dissociable roles of prefrontal plasticity in decision-making strategy and execution of habitual behavior.
Journal: Nature communications
In common: pandas, Matplotlib, NumPy, mouse, 1 reference
[7] doi:10.1371/journal.pbio.3003824 [code]
Flexible goal learning involves coordinated population activity in dCA1 and medial orbitofrontal cortex.
Journal: PLoS biology
In common: pandas, Matplotlib, NumPy, systems, 1 reference
[8] doi:10.1111/ejn.70582 [code]
Multifiber Array-Based Photometry System for Multiregional Functional Mapping in the Mouse Brain.
Journal: The European journal of neuroscience
In common: pandas, Matplotlib, NumPy, optical imaging (calcium, voltage, 2-photon), systems, mouse
[9] doi:10.7554/elife.110277 [code]
Functional imaging of nine distinct neuronal populations under a miniscope in freely behaving animals.
Journal: eLife
In common: pandas, Matplotlib, NumPy, optical imaging (calcium, voltage, 2-photon), systems, mouse
[10] doi:10.1038/s41593-026-02315-y [code]
The representational geometry of emotional states in basolateral amygdala.
Journal: Nature neuroscience
In common: pandas, Matplotlib, NumPy, mouse, 1 reference

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.