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 to 417 · score 0.59 · peak offset, peak onset, peak amplitude, AUC, error · Report a mismatch
  2. [2] § Materials and methods › Data analysis and statistics › Event-related (peri-event) activity ↔ analyze_ideas_traces_final.py, lines 343 to 417 · score 0.56 · peak onset, Peak amplitudes, window, offset, baseline, trace · Report a mismatch

Paper

Loaded from Europe PMC by your browser; OSCR does not store it: 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 (how the code is found and 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.3389/fncir.2023.1138358
Bimodal modulation of L1 interneuron activity in anterior cingulate cortex during fear conditioning.
Journal: Frontiers in neural circuits
In common: optical imaging (calcium, voltage, 2-photon), mouse, 5 references
[2] doi:10.1038/s41467-025-57041-z [code]
Processing of pain and itch information by modality-specific neurons within the anterior cingulate cortex in mice.
Journal: Nature communications
In common: pandas, NumPy, systems, mouse, 5 references
[3] doi:10.1038/s41467-023-39718-5
Systems consolidation induces multiple memory engrams for a flexible recall strategy in observational fear memory in male mice.
Journal: Nature communications
In common: mouse, 6 references
[4] doi:10.1016/j.cub.2023.07.042
Engram stability and maturation during systems consolidation.
Journal: Current biology : CB
In common: 6 references
[5] doi:10.7554/elife.105422 [code]
A contextual fear conditioning paradigm in head-fixed mice exploring virtual reality.
Journal: eLife
In common: pandas, Matplotlib, NumPy, optical imaging (calcium, voltage, 2-photon), systems, mouse, 3 references
[6] doi:10.1038/s41386-024-01825-2 [code]
Reactivation of encoding ensembles in the prelimbic cortex supports temporal associations.
Journal: Neuropsychopharmacology : official publication of the American College of Neuropsychopharmacology
In common: systems, mouse, 5 references
[7] doi:10.1038/s41586-025-09885-0 [code]
Evidence accumulation from experience and observation in the cingulate cortex.
Journal: Nature
In common: pandas, Matplotlib, NumPy, 4 references
[8] doi:10.1016/j.celrep.2024.113943
Astrocytes control recent and remote memory strength by affecting the recruitment of the CA1→ACC projection to engrams.
Journal: Cell reports
In common: 5 references
[9] doi:10.7554/elife.78542 [code]
Brain-wide screen of prelimbic cortex inputs reveals a functional shift during early fear memory consolidation.
Journal: eLife
In common: mouse, 5 references
[10] doi:10.1038/s41467-024-50388-9 [code]
Anterior cingulate cortex provides the neural substrates for feedback-driven iteration of decision and value representation.
Journal: Nature communications
In common: pandas, Matplotlib, NumPy, mouse, 3 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.

Add the badge to the code's README

OSCR: the badge of this paper

If you are an author or a maintainer of this paper's code, you can add this badge. It says what OSCR knows of the paper (its code, its validated tracing map) and links the code to this page. Paste one of these snippets under the README's title. Keep the two marks around it, so that the badge can be replaced in place and is never added twice. OSCR changes nothing in your repository.

Markdown
<!-- oscr-badge:start -->
[![OSCR](https://openscicode.org/badge/doi/10.1093/cercor/bhag062.svg)](https://openscicode.org/badge/doi/10.1093/cercor/bhag062)
<!-- oscr-badge:end -->
reStructuredText
.. oscr-badge:start

.. image:: https://openscicode.org/badge/doi/10.1093/cercor/bhag062.svg
   :target: https://openscicode.org/badge/doi/10.1093/cercor/bhag062
   :alt: OSCR

.. oscr-badge:end
HTML
<!-- oscr-badge:start -->
<a href="https://openscicode.org/badge/doi/10.1093/cercor/bhag062"><img src="https://openscicode.org/badge/doi/10.1093/cercor/bhag062.svg" alt="OSCR"></a>
<!-- oscr-badge:end -->

If you choose to, you can have the badge kept up to date for you, with oscr badge --write from the command line or with the GitHub Action in your repository's workflows. Every other form and option (a card, AsciiDoc, LaTeX, shields.io) is on the badge 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: code errors and mismatches between the code and the paper about this paper and its code, from readers and its authors, beside the paper and its tracing map.

Report a mismatch between the code and the paper · Report a code error (signed in)

Reproductions: reports from readers who ran the authors' code and did not get the paper's result, what they ran, with which environment, commit and data.

Report a reproduction failure (signed in)

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