OSCR

Gene regulatory innovations from transposable elements in primate cerebellum development.

Code ↔ Paper

18 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 18 matches
  1. [1] § Methods › Regression analysis of sequence conservation at high attribution sites ↔ 03_HERVL/08_nucleotide_preservation.ipynb, lines 417–510 · score 0.97 · hot encoded nucleotide, absolute attribution score, low attribution positions, high attribution, outcome variable, linear regression
  2. [2] § Results › Lineage-specific co-option of TE subfamilies as regulatory elements ↔ 02_CRE_potential_screening/03_visualize_screening_candidates.ipynb, lines 159–172 · score 0.76 · LTR9B, MLT1M, ERVL B4, LTR1A2, MER72, MER130
  3. [3] § Results › Complex cis-regulatory sequences in ancestral TE sequences facilitate co-option of TEs ↔ 02_CRE_potential_screening/03_visualize_screening_candidates.ipynb, lines 159–172 · score 0.76 · LTR9B, MLT1M, ERVL B4, LTR1A2, MER72, MER130
  4. [4] § Methods › Logistic regression analysis of TE–cCRE overlap ↔ 01_CRE_TE_overlap/06a_regression_analysis_human.ipynb, lines 334–368 · score 0.74 · log_dist_TSS, GC_content, TE_overlap, regression model, mappability
  5. [5] § Methods › Logistic regression analysis of TE–cCRE overlap ↔ 01_CRE_TE_overlap/06b_regression_analysis_marmoset.ipynb, lines 334–368 · score 0.74 · log_dist_TSS, GC_content, TE_overlap, regression model, mappability
  6. [6] § Methods › Overlap between TEs and cCREs in mammalian cerebellum development ↔ 01_CRE_TE_overlap/01_make_repeat_beds.ipynb, lines 142–149 · score 0.70 · nf LO, liftOver, chain, transposable element, UCSC, Dfam
  7. [7] § Results › Complex cis-regulatory sequences in ancestral TE sequences facilitate co-option of TEs ↔ 03_HERVL/01_find_accessible_copies.py, lines 393–431 · score 0.67 · MamRTE1, MamTip2b, MLT1M, ancestral sequence, MER130, copies
  8. [8] § Results › Lineage-specific co-option of TE subfamilies as regulatory elements ↔ 03_HERVL/01_find_accessible_copies.py, lines 433–482 · score 0.65 · MamRTE1, MamTip2b, MLT1M, MER130, TEs, mice
  9. [9] § Methods › Logistic regression analysis of TE–cCRE overlap ↔ 01_CRE_TE_overlap/07_regression_analysis_catlas.ipynb, lines 233–254 · score 0.64 · accessibility_class, phyloP, GC_content, TE_overlap, regression, model
  10. [10] § Results › Determinants of copy-level TE co-option ↔ 03_HERVL/08_nucleotide_preservation.ipynb, lines 417–510 · score 0.58 · high attribution positions, linear regression, HERVL copies, ancestral sequences, motif, scores
  11. [11] § Methods › Logistic regression analysis of TE copy accessibility ↔ 01_CRE_TE_overlap/06a_regression_analysis_human.ipynb, lines 334–368 · score 0.58 · Odds ratios, GC content, confidence intervals, coefficients, TSS, fitted
  12. [12] § Methods › Logistic regression analysis of TE copy accessibility ↔ 01_CRE_TE_overlap/06b_regression_analysis_marmoset.ipynb, lines 334–368 · score 0.58 · Odds ratios, GC content, confidence intervals, coefficients, TSS, fitted
  13. [13] § Methods › Logistic regression analysis of TE–cCRE overlap ↔ 01_CRE_TE_overlap/03a_celltype_specific_peaks_human.ipynb, lines 113–138 · score 0.57 · peakType, n_NMF, intronic, exonic, distal, TE overlap
  14. [14] § Methods › Logistic regression analysis of TE–cCRE overlap ↔ 01_CRE_TE_overlap/06a_regression_analysis_human.ipynb, lines 523–558 · score 0.57 · n_NMF, postnatal, embryonic, adult, fetal, cons
  15. [15] § Methods › Evaluation of the contributions of species-specific TE copies to cross-species gene expression divergence ↔ 03_HERVL/14_HERVL_gene_expression.ipynb, lines 140–154 · score 0.55 · cross species comparisons, gene expression, macaque, marmoset, mouse, cells
  16. [16] § Methods › Mapping chromatin accessibility to the consensus sequences and identifying accessible copies of the screened TE subfamilies ↔ 03_HERVL/01_find_accessible_copies.py, lines 152–163 · score 0.54 · pyBigWig, tracks, copies, accessibility, cell
  17. [17] § Methods › Single-cell multi-omics atlas of cerebellum development ↔ 03_HERVL/11_distance_analysis.ipynb, lines 31–34 · score 0.52 · cross species comparison, highly variable, distance, NMF, peaks, human
  18. [18] § Results › Lineage-specific co-option of TE subfamilies as regulatory elements ↔ 03_HERVL/03_HERVL_accessibilitiy.ipynb, lines 424–438 · score 0.51 · UBC_diff, GC_diff_1, GCP, accessibility, HERVL

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

Jupyter notebook · 582 lines · 18 KB · CC-BY-NC-SA-4.0 · 3 matches

  1. # %%
  2. import pandas as pd
  3. import numpy as np
  4. import pyranges as pr
  5. import pyBigWig
  6. from Bio import SeqIO
  7. from Bio.SeqUtils import gc_fraction as calc_GC
  8. from scipy import stats
  9. import statsmodels.api as sm
  10. import statsmodels.formula.api as smf
  11. from statsmodels.stats.outliers_influence import variance_inflation_factor
  12. # %%
  13. path_to_lsdf2 = '/work/tetsuya/sds/sd17d003/'
  14. # %% [markdown]
  15. # ## 1. Load data
  16. # %%
  17. # Load CREs
  18. cCREs = pr.read_bed(f"{path_to_lsdf2}/Ioannis/Comparative_Cereb/peak_annotations/Human/human_peaks.bed")
  19. print(f"Loaded {len(cCREs)} CREs")
  20. # Load TEs
  21. TEs = pr.read_bed(f"{path_to_lsdf2}/Tetsuya/data/transposable_elements/dfam/3.8/annotations/hg38/hg38.nrph.hits.te.bed")
  22. print(f"Loaded {len(TEs)} TEs")
  23. # %%
  24. TEs
  25. # %% [markdown]
  26. # ## 2. Create random background regions
  27. # %%
  28. def create_random_regions(n_regions, width, genome_file, exclude_regions=None):
  29. """
  30. Create random genomic regions
  31. Parameters:
  32. n_regions: number of regions to create
  33. width: width of each region (500 for your case)
  34. genome_file: path to chromosome sizes file
  35. exclude_regions: PyRanges object of regions to avoid
  36. """
  37. # Load chromosome sizes
  38. chrom_sizes = pd.read_csv(genome_file, sep='\t', header=None,
  39. names=['Chromosome', 'End'])
  40. chrom_sizes['Start'] = 0
  41. # Filter to main chromosomes
  42. chrom_sizes = chrom_sizes[chrom_sizes['Chromosome'].str.contains('^chr[0-9XY]+$')]
  43. regions = []
  44. attempts = 0
  45. max_attempts = n_regions * 10
  46. while len(regions) < n_regions and attempts < max_attempts:
  47. # Randomly select chromosome weighted by size
  48. weights = chrom_sizes['End'].values / chrom_sizes['End'].sum()
  49. chrom = np.random.choice(chrom_sizes['Chromosome'], p=weights)
  50. chrom_size = chrom_sizes[chrom_sizes['Chromosome'] == chrom]['End'].values[0]
  51. # Random position
  52. start = np.random.randint(0, max(1, chrom_size - width))
  53. end = start + width
  54. # Create region
  55. region = pr.PyRanges(chromosomes=[chrom], starts=[start], ends=[end])
  56. # Check if it overlaps excluded regions
  57. if exclude_regions is not None:
  58. if len(region.overlap(exclude_regions)) == 0:
  59. regions.append({'Chromosome': chrom, 'Start': start, 'End': end})
  60. else:
  61. regions.append({'Chromosome': chrom, 'Start': start, 'End': end})
  62. attempts += 1
  63. background = pr.PyRanges(pd.DataFrame(regions))
  64. return background
  65. # %%
  66. # Create background (5x CREs)
  67. np.random.seed(123)
  68. n_background = len(cCREs)
  69. background = create_random_regions(
  70. n_regions=n_background,
  71. width=500,
  72. genome_file=f'{path_to_lsdf2}/Tetsuya/data/genomes/hg38/hg38.chrom.sizes',
  73. exclude_regions=cCREs
  74. )
  75. print(f"Created {len(background)} background regions")
  76. # %% [markdown]
  77. # ## 3. Calculate TE overlap
  78. # %%
  79. def calculate_overlap(regions, features, min_overlap=250):
  80. """
  81. Calculate binary overlap: does region overlap any feature by at least min_overlap bp?
  82. Parameters:
  83. regions: PyRanges object of genomic regions
  84. features: PyRanges object of features (TEs)
  85. min_overlap: minimum overlap width in bp (default 250)
  86. Returns:
  87. PyRanges object with TE_overlap column added
  88. """
  89. # Get all overlaps
  90. overlaps = regions.join(features, how='left', suffix='_TE')
  91. if len(overlaps) == 0:
  92. # No overlaps at all
  93. regions_df = regions.df.copy()
  94. regions_df['TE_overlap'] = 0
  95. return pr.PyRanges(regions_df)
  96. # Calculate intersection width for each overlap
  97. overlaps_df = overlaps.df.copy()
  98. # Intersection start = max of the two starts
  99. # Intersection end = min of the two ends
  100. overlaps_df['intersection_start'] = overlaps_df[['Start', 'Start_TE']].max(axis=1)
  101. overlaps_df['intersection_end'] = overlaps_df[['End', 'End_TE']].min(axis=1)
  102. overlaps_df['overlap_width'] = overlaps_df['intersection_end'] - overlaps_df['intersection_start']
  103. # Filter to overlaps >= min_overlap
  104. significant_overlaps = overlaps_df[overlaps_df['overlap_width'] > min_overlap]
  105. # Get unique region indices with significant overlaps
  106. if len(significant_overlaps) > 0:
  107. # Need to match back to original regions
  108. # Create unique identifier for regions
  109. overlaps_df['region_id'] = (overlaps_df['Chromosome'].astype(str) + ':' +
  110. overlaps_df['Start'].astype(str) + '-' +
  111. overlaps_df['End'].astype(str))
  112. significant_overlaps['region_id'] = (significant_overlaps['Chromosome'].astype(str) + ':' +
  113. significant_overlaps['Start'].astype(str) + '-' +
  114. significant_overlaps['End'].astype(str))
  115. overlapped_ids = set(significant_overlaps['region_id'].unique())
  116. else:
  117. overlapped_ids = set()
  118. # Add binary overlap to original regions
  119. regions_df = regions.df.copy()
  120. regions_df['region_id'] = (regions_df['Chromosome'].astype(str) + ':' +
  121. regions_df['Start'].astype(str) + '-' +
  122. regions_df['End'].astype(str))
  123. regions_df['TE_overlap'] = regions_df['region_id'].isin(overlapped_ids).astype(int)
  124. regions_df = regions_df.drop('region_id', axis=1)
  125. return pr.PyRanges(regions_df)
  126. # %%
  127. # Calculate for both
  128. cCREs_with_TE = calculate_overlap(cCREs, TEs)
  129. background_with_TE = calculate_overlap(background, TEs)
  130. # Add group labels
  131. cCREs_df = cCREs_with_TE.df
  132. cCREs_df['is_CRE'] = 1
  133. background_df = background_with_TE.df
  134. background_df['is_CRE'] = 0
  135. # Combine
  136. all_regions_df = pd.concat([cCREs_df, background_df], ignore_index=True)
  137. print(f"Total regions: {len(all_regions_df)}")
  138. print(f"TE overlap in CREs: {all_regions_df[all_regions_df['is_CRE']==1]['TE_overlap'].mean():.3f}")
  139. print(f"TE overlap in background: {all_regions_df[all_regions_df['is_CRE']==0]['TE_overlap'].mean():.3f}")
  140. # %%
  141. len(cCREs_df[cCREs_df['TE_overlap']==1])
  142. # %% [markdown]
  143. # ## 4. Calculate GC content
  144. # %%
  145. from pyfaidx import Fasta
  146. def calculate_gc_content(regions_df, genome_fasta):
  147. """Calculate GC content for genomic regions"""
  148. genome = Fasta(genome_fasta)
  149. gc_values = []
  150. for idx, row in regions_df.iterrows():
  151. chrom = row['Chromosome']
  152. start = row['Start']
  153. end = row['End']
  154. try:
  155. seq = genome[chrom][start:end].seq.upper()
  156. gc = (seq.count('G') + seq.count('C')) / len(seq) if len(seq) > 0 else 0
  157. gc_values.append(gc)
  158. except:
  159. gc_values.append(np.nan)
  160. return gc_values
  161. # %%
  162. all_regions_df['GC_content'] = calculate_gc_content(all_regions_df, f'{path_to_lsdf2}/Tetsuya/data/genomes/hg38/hg38.fa')
  163. print(f"GC content calculated, mean: {all_regions_df['GC_content'].mean():.3f}")
  164. # %% [markdown]
  165. # ## 5. Calculate mappability
  166. # %%
  167. def calculate_mappability(regions_df, bigwig_file):
  168. """Calculate mean mappability score for each region"""
  169. bw = pyBigWig.open(bigwig_file)
  170. mappability_scores = []
  171. for idx, row in regions_df.iterrows():
  172. chrom = row['Chromosome']
  173. start = int(row['Start'])
  174. end = int(row['End'])
  175. try:
  176. # Get values for this region
  177. values = bw.values(chrom, start, end)
  178. # Filter out None values and calculate mean
  179. valid_values = [v for v in values if v is not None]
  180. if len(valid_values) > 0:
  181. mappability_scores.append(np.mean(valid_values))
  182. else:
  183. mappability_scores.append(0)
  184. except:
  185. mappability_scores.append(0)
  186. bw.close()
  187. return mappability_scores
  188. # %%
  189. all_regions_df['mappability'] = calculate_mappability(
  190. all_regions_df,
  191. f'{path_to_lsdf2}/Tetsuya/data/mappability/hg38.k50.Umap.MultiTrackMappability.bw'
  192. )
  193. print(f"Mappability calculated, mean: {all_regions_df['mappability'].mean():.3f}")
  194. # %% [markdown]
  195. # ## 6. Calculate distance to nearest TSS
  196. # %%
  197. def extract_tss_from_gtf(gtf_file, feature_type='gene'):
  198. """
  199. Extract TSS positions from GTF file
  200. Parameters:
  201. gtf_file: path to GTF file (e.g., gencode.v38.annotation.gtf.gz)
  202. feature_type: 'transcript' or 'gene' (transcript gives more TSSs)
  203. Returns:
  204. PyRanges object with TSS positions (single bp)
  205. """
  206. # Read GTF
  207. print(f"Reading {gtf_file}...")
  208. gtf = pr.read_gtf(gtf_file)
  209. # Filter to desired feature type
  210. features = gtf[gtf.Feature == feature_type]
  211. print(f"Found {len(features)} {feature_type} features")
  212. # Extract TSS based on strand
  213. # TSS = 5' end of transcript
  214. # For + strand: TSS = Start
  215. # For - strand: TSS = End
  216. df = features.df.copy()
  217. # Create TSS positions
  218. df['TSS'] = np.where(df['Strand'] == '+', df['Start'], df['End'])
  219. # Create single-bp regions for TSS
  220. # PyRanges uses 0-based half-open coordinates [start, end)
  221. # So a single position is represented as [pos, pos+1)
  222. tss_df = pd.DataFrame({
  223. 'Chromosome': df['Chromosome'],
  224. 'Start': df['TSS'],
  225. 'End': df['TSS'] + 1,
  226. 'Strand': df['Strand'],
  227. 'gene_id': df.get('gene_id', ''),
  228. 'gene_name': df.get('gene_name', ''),
  229. 'transcript_id': df.get('transcript_id', '')
  230. })
  231. # Remove duplicates (same TSS position)
  232. tss_df = tss_df.drop_duplicates(subset=['Chromosome', 'Start', 'End'])
  233. print(f"Extracted {len(tss_df)} unique TSS positions")
  234. return pr.PyRanges(tss_df)
  235. def calculate_distance_to_tss(regions, gtf_file):
  236. """
  237. Calculate distance from regions to nearest TSS
  238. Parameters:
  239. regions: PyRanges object of genomic regions
  240. gtf_file: path to GTF annotation file
  241. Returns:
  242. Array of distances to nearest TSS
  243. """
  244. # Extract TSS positions
  245. tss = extract_tss_from_gtf(gtf_file, feature_type='transcript')
  246. # Find nearest TSS for each region
  247. print("Calculating distances to nearest TSS...")
  248. nearest = regions.nearest(tss, overlap=True)
  249. # Extract distances
  250. # PyRanges nearest() returns Distance column
  251. # Negative distances mean overlap (upstream/downstream)
  252. # We want absolute distance
  253. distances = nearest.df['Distance'].abs().values
  254. return distances
  255. # %%
  256. # Usage
  257. gtf_file = f"{path_to_lsdf2}/Ioannis/Comparative_Cereb/genome_annotations/Human/hg38_ens92_filtered.gtf"
  258. all_regions_pr = pr.PyRanges(all_regions_df[['Chromosome', 'Start', 'End']])
  259. all_regions_df['dist_to_TSS'] = calculate_distance_to_tss(all_regions_pr, gtf_file)
  260. print(f"Distance to TSS - median: {np.median(all_regions_df['dist_to_TSS']):.0f} bp")
  261. print(f"Distance to TSS - mean: {np.mean(all_regions_df['dist_to_TSS']):.0f} bp")
  262. # %% [markdown]
  263. # ## 7. Main regression model
  264. # %%
  265. import statsmodels.api as sm
  266. # Remove any rows with missing data
  267. df_clean = all_regions_df.dropna(subset=['TE_overlap', 'is_CRE', 'GC_content', 'mappability', 'dist_to_TSS'])
  268. df_clean['log_dist_TSS'] = np.log(df_clean['dist_to_TSS'] + 1)
  269. # Main model: GC + mappability
  270. formula_main = 'TE_overlap ~ is_CRE + GC_content + mappability + log_dist_TSS'
  271. model_main = smf.logit(formula_main, data=df_clean).fit()
  272. print("\n" + "="*60)
  273. print("MAIN MODEL: TE_overlap ~ is_CRE + GC_content + mappability + log_dist_TSS")
  274. print("="*60)
  275. print(model_main.summary())
  276. # Get odds ratios
  277. odds_ratios = np.exp(model_main.params)
  278. conf_int = np.exp(model_main.conf_int())
  279. conf_int['OR'] = odds_ratios
  280. conf_int.columns = ['2.5%', '97.5%', 'OR']
  281. print("\nOdds Ratios and 95% Confidence Intervals:")
  282. print(conf_int)
  283. # Focus on is_CRE coefficient
  284. or_cre = odds_ratios['is_CRE']
  285. ci_low = conf_int.loc['is_CRE', '2.5%']
  286. ci_high = conf_int.loc['is_CRE', '97.5%']
  287. pval = model_main.pvalues['is_CRE']
  288. print(f"\nCRE effect: OR = {or_cre:.3f}, 95% CI: [{ci_low:.3f}, {ci_high:.3f}], P = {pval:.2e}")
  289. # %%
  290. print(model_main.pvalues)
  291. # %% [markdown]
  292. # ---
  293. # %% [markdown]
  294. # # Within cCRE comparisons:
  295. # %%
  296. human_peaks = pd.read_csv(f'{path_to_lsdf2}/Tetsuya/project/cerebellum/ioannis/Comparative_Cereb/peak_annotations/Human/human_peaks_repeat_overlap.tsv',
  297. sep='\t')
  298. human_peaks['Name'] = human_peaks['peak'].str.replace('hg38_', '')
  299. # %%
  300. human_peaks = human_peaks.merge(all_regions_df[all_regions_df['is_CRE']==1][['Name', 'TE_overlap', 'GC_content', 'mappability', 'dist_to_TSS']],
  301. how='left', on='Name')
  302. # %%
  303. mapping = {
  304. 1: "human_specific",
  305. 3: "primate_specific",
  306. 7: "conserved",
  307. }
  308. human_peaks["Cons_group_label"] = human_peaks["Cons_group"].map(mapping).fillna("others")
  309. # Set "Others" as reference
  310. human_peaks['Cons_group_label'] = pd.Categorical(
  311. human_peaks['Cons_group_label'],
  312. categories=['others', 'human_specific', 'primate_specific', 'conserved'],
  313. ordered=False
  314. )
  315. human_peaks.to_csv(f'{path_to_lsdf2}/Tetsuya/project/cerebellum/ioannis/Comparative_Cereb/peak_annotations/Human/human_peaks_regression.tsv',
  316. sep='\t', index=False)
  317. # %%
  318. human_peaks
  319. # %%
  320. print("\n" + "="*70)
  321. print("MAIN MODEL: Peak Type + Conservation + Covariates")
  322. print("="*70)
  323. formula = 'TE_overlap ~ C(peakType) + C(Cons_group_label) + GC_content'
  324. model_main = smf.logit(formula, data=human_peaks).fit()
  325. print(model_main.summary())
  326. # Get odds ratios
  327. odds_ratios = np.exp(model_main.params)
  328. conf_int = np.exp(model_main.conf_int())
  329. conf_int['OR'] = odds_ratios
  330. conf_int.columns = ['2.5%', '97.5%', 'OR']
  331. print("\n" + "="*70)
  332. print("ODDS RATIOS AND 95% CONFIDENCE INTERVALS")
  333. print("="*70)
  334. print(conf_int)
  335. model_main.pvalues
  336. # %% [markdown]
  337. # ### n_NMF
  338. # %%
  339. human_peaks = pd.read_csv(f'{path_to_lsdf2}/Tetsuya/project/cerebellum/ioannis/Comparative_Cereb/peak_annotations/Human/human_peaks_regression.tsv',
  340. sep='\t')
  341. # %%
  342. nmf_list = [f'NMF_{i}' for i in range(1, 19)]
  343. nmf_size_list = []
  344. for nmf in nmf_list:
  345. nmf_peak_df = pd.read_csv(f'{path_to_lsdf2}/Ioannis/Comparative_Cereb/crossSpecies_comparisons/atac_nmf/allFilteredPeaks_nnls/human/{nmf}.bed',
  346. sep='\t', names=['chrom', 'start', 'end', 'peak'])
  347. print(f'{nmf}: {len(nmf_peak_df)}')
  348. nmf_size_list.append(len(nmf_peak_df))
  349. nmf_peak_df[nmf] = 1
  350. human_peaks = human_peaks.merge(nmf_peak_df[['peak', nmf]], on='peak', how='left')
  351. human_peaks[nmf] = human_peaks[nmf].fillna(0).astype(int)
  352. human_peaks['n_NMF'] = human_peaks[nmf_list].sum(axis=1)
  353. human_peaks
  354. # %%
  355. # Add n_NMF_label column with classification
  356. human_peaks_subset = human_peaks[human_peaks['n_NMF'] > 0].copy()
  357. human_peaks_subset['n_NMF_label'] = human_peaks_subset['n_NMF'].apply(
  358. lambda x: str(int(x)) if x < 10 else '>9'
  359. )
  360. # Set "Others" as reference
  361. human_peaks_subset['Cons_group_label'] = pd.Categorical(
  362. human_peaks_subset['Cons_group_label'],
  363. categories=['others', 'human_specific', 'primate_specific', 'conserved'],
  364. ordered=False
  365. )
  366. # Convert to categorical with '0' as the reference level
  367. human_peaks_subset['n_NMF_label'] = pd.Categorical(
  368. human_peaks_subset['n_NMF_label'],
  369. categories=['1', '2', '3', '4', '5', '6', '7', '8', '9', '>9'],
  370. ordered=True
  371. )
  372. # %%
  373. print("\n" + "="*70)
  374. print("MAIN MODEL: Peak Type + Conservation + Covariates")
  375. print("="*70)
  376. formula = 'TE_overlap ~ C(peakType) + C(Cons_group_label) + C(n_NMF_label) + GC_content'
  377. model_main = smf.logit(formula, data=human_peaks_subset).fit()
  378. print(model_main.summary())
  379. # Get odds ratios
  380. odds_ratios = np.exp(model_main.params)
  381. conf_int = np.exp(model_main.conf_int())
  382. conf_int['OR'] = odds_ratios
  383. conf_int.columns = ['2.5%', '97.5%', 'OR']
  384. print("\n" + "="*70)
  385. print("ODDS RATIOS AND 95% CONFIDENCE INTERVALS")
  386. print("="*70)
  387. print(conf_int)
  388. model_main.pvalues
  389. # %% [markdown]
  390. # ### Highly variable NMF
  391. # %%
  392. nmf_list = [f'NMF_{i}' for i in range(1, 19)]
  393. nmf_size_list = []
  394. for nmf in nmf_list:
  395. nmf_peak_df = pd.read_csv(f'{path_to_lsdf2}/Ioannis/Comparative_Cereb/crossSpecies_comparisons/atac_nmf/highly_variable_peaks/human/{nmf}.bed',
  396. sep='\t', names=['chrom', 'start', 'end', 'peak'])
  397. print(f'{nmf}: {len(nmf_peak_df)}')
  398. nmf_size_list.append(len(nmf_peak_df))
  399. nmf_peak_df[nmf] = 1
  400. human_peaks = human_peaks.merge(nmf_peak_df[['peak', nmf]], on='peak', how='left')
  401. human_peaks[nmf] = human_peaks[nmf].fillna(0).astype(int)
  402. human_peaks['n_NMF'] = human_peaks[nmf_list].sum(axis=1)
  403. human_peaks
  404. # %%
  405. peak_info = pd.read_csv(f'{path_to_lsdf2}/Ioannis/Comparative_Cereb/peak_annotations/Human/human_peaks_info.txt',
  406. sep='\t')
  407. peak_info['maxAcc_devState'] = peak_info['maxAcc_Sample'].str.split(':', expand=True)[1]
  408. peak_info_subset = peak_info[['peak', 'maxAcc_devState']].copy()
  409. peak_info_subset
  410. # %%
  411. human_peaks_subset = human_peaks[human_peaks['n_NMF'] > 0]
  412. dev_state_mapping = {
  413. 'CS18-19': 'embryonic',
  414. 'CS20': 'embryonic',
  415. 'CS22-23': 'embryonic',
  416. '11wpc': 'fetal',
  417. '15-17wpc': 'fetal',
  418. 'newborn': 'postnatal',
  419. 'infant': 'postnatal',
  420. 'toddler': 'postnatal',
  421. 'adult': 'adult',
  422. 'adult_DN': 'adult'
  423. }
  424. # Map developmental states to numeric values
  425. peak_info_subset['dev_state_label'] = peak_info_subset['maxAcc_devState'].map(dev_state_mapping)
  426. human_peaks_subset = human_peaks_subset.merge(peak_info_subset[['peak', 'dev_state_label']], on='peak', how='left')
  427. # Set "Others" as reference
  428. human_peaks_subset['Cons_group_label'] = pd.Categorical(
  429. human_peaks_subset['Cons_group_label'],
  430. categories=['others', 'human_specific', 'primate_specific', 'conserved'],
  431. ordered=False
  432. )
  433. # Convert to categorical with '0' as the reference level
  434. human_peaks_subset['dev_state_label'] = pd.Categorical(
  435. human_peaks_subset['dev_state_label'],
  436. categories=['adult', 'postnatal', 'fetal', 'embryonic'],
  437. ordered=True
  438. )
  439. human_peaks_subset
  440. # %%
  441. print("\n" + "="*70)
  442. print("MAIN MODEL: Peak Type + Conservation + Covariates")
  443. print("="*70)
  444. formula = 'TE_overlap ~ C(peakType) + C(Cons_group_label) + C(dev_state_label) + GC_content'
  445. model_main = smf.logit(formula, data=human_peaks_subset).fit()
  446. print(model_main.summary())
  447. # Get odds ratios
  448. odds_ratios = np.exp(model_main.params)
  449. conf_int = np.exp(model_main.conf_int())
  450. conf_int['OR'] = odds_ratios
  451. conf_int.columns = ['2.5%', '97.5%', 'OR']
  452. print("\n" + "="*70)
  453. print("ODDS RATIOS AND 95% CONFIDENCE INTERVALS")
  454. print("="*70)
  455. print(conf_int)
  456. # %%
  457. model_main.pvalues

06a_regression_analysis_human.ipynb at commit d89c357, under CC-BY-NC-SA-4.0 · at the source

Overview

  1. Center for Molecular Biology of Heidelberg University (ZMBH), DKFZ-ZMBH Alliance, Heidelberg, Germany
  2. Present Address: Centre of Genomics, Evolution and Medicine (cGEM), Institute of Genomics, University of Tartu, Tartu, Estonia
  3. Present Address: Wellcome Sanger Institute, Cambridge, UK
  4. Present Address: Cambridge Stem Cell Institute and Department of Medicine, University of Cambridge, Cambridge, UK
Institutions: Heidelberg University (Germany); DKFZ-ZMBH Alliance (Germany); University of Tartu (Estonia); Wellcome/MRC Cambridge Stem Cell Institute (United Kingdom); University of Cambridge (United Kingdom); Wellcome Sanger Institute (United Kingdom)
Journal: Nature communications, volume 17, issue 1, article 7598
Dates: received 12 September 2025; accepted 8 July 2026; published online 30 July 2026
Type: Research article · Language: English
License: CC BY
Identifiers: DOI 10.1038/s41467-026-75700-7 · PMID 42527403 · PMCID PMC13421694 · OpenAlex W7171675596
Open access: gold, a free copy (OpenAlex)
Status: code verified
Categories: genetics / omics (modality), human (organism), mouse (organism), non-human primate (organism), cellular / molecular (subfield)
Methods: Connectivity, Statistics, Smoothing, state filtering, decompositions, Machine learning, fMRI & imaging
Keywords: Gene regulation, Evolutionary genetics, Transcriptomics, Machine learning, Genetics of the nervous system
MeSH: Cerebellum*, DNA Transposable Elements*, Gene Regulatory Networks*, Primates*, Animals, Callithrix, Chromatin, Evolution, Molecular, Gene Expression Regulation, Developmental, Humans, Macaca, Mice (* major topic)
Topic: Chromosomal and Genetic Variations (Plant Science, Agricultural and Biological Sciences), according to OpenAlex
Funding: European Research Council (101019268); European Molecular Biology Organization (EMBO) (Scientific Exchange Grant (9231), Postdoctoral Fellowship (ALTF 769-2022))
Citations: cited by 1 paper (Europe PMC); 124 references in the paper

Abstract

Transposable elements are hypothesized to have driven gene regulatory innovation, yet their contributions to primate brain development at the cell type level remain underexplored. Here, we use single-cell multiomics data from human, macaque, marmoset, and mouse cerebella to show that transposable element contributions to different cell types are shaped by varying degrees of constraints across cell types, as well as the preferential co-option of certain transposable elements in specific cell states. Using a sequence-based deep-learning model that predicts cell-type-specific chromatin accessibility, we systematically assess the co-option potential of transposable elements into cerebellar gene regulatory networks, identifying twelve transposable element subfamilies with complex regulatory sequences in their ancestral states that facilitate their co-option as cell-type-specific cis-regulatory elements. Preservation of these ancestral regulatory sequences, as well as the active chromatin environment surrounding the insertion site, is the major determinant of the accessibility of extant copies. Lineage-specific accessible copies contribute to human-specific gene expression. Broadly, we demonstrate how transposable elements can be flexibly co-opted into cell-type-specific gene regulatory networks, and introduce a generalizable analytical framework for dissecting their contribution to mammalian regulatory evolution.

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

Repositories

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

kaessmannlab/cerebellum_te

License: CC-BY-NC-SA-4.0
State: the link answers, verified on 27 September 2026
Evidence: files inventoried
Commit: d89c3571724b09827196d19ed0ca22d19a6cd6aa, 10 June 2026
Languages: Jupyter (30), Python (2)
Size: 35 files, 32 scripts
Software Heritage: not archived
Found in: “Code availability”
Holds: README, license file, 30 notebooks
Not found: CITATION.cff, environment file, tests, continuous integration, documentation
Tools: pandas (32 files), NumPy (30 files), Matplotlib (27 files), seaborn (27 files), BEDTools (21 files), Biopython (19 files), SciPy (19 files), pysam (13 files), statsmodels (8 files), TensorFlow (2 files), Keras (1 file), scikit-learn (1 file), SHAP (1 file)
Availability: 1 check, the latest on 27 September 2026: the link answers
  • 27 September 2026: the link answers
34 files

Zenodo 19354896

License: CC-BY-4.0
State: the link answers, verified on 27 September 2026
Evidence: files inventoried
Size: 1 file
Software Heritage: not checked
Found in: the references
Not found: README, license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: pandas (22 files), NumPy (20 files), Matplotlib (17 files), seaborn (17 files), BEDTools (16 files), Biopython (13 files), SciPy (10 files), pysam (8 files), statsmodels (6 files), SHAP (1 file), TensorFlow (1 file)
Availability: 1 check, the latest on 27 September 2026: the link answers (HTTP 200)
  • 27 September 2026: the link answers (HTTP 200)
22 files
At the source:

Code availability

All original code is available on GitLab [https://gitlab.com/kaessmannlab/cerebellum_te]. An archived snapshot corresponding to the manuscript is deposited on Zenodo [10.5281/zenodo.19354896]124.

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

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;
  • 54 scripts, each with its path and the digest of its content;
  • 18 matches between paragraphs of the paper and lines of the code (method lexical-v1);
  • neither the text of the paper nor the code itself.

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

Data

Datasets cited

Data Availability Statement

Previously published datasets used in this study are available in the ArrayExpress database under accession codes E-MTAB-9765 (https://www.ebi.ac.uk/biostudies/ArrayExpress/studies/E-MTAB-9765) and E-MTAB-10533 (https://www.ebi.ac.uk/biostudies/ArrayExpress/studies/E-MTAB-10533)37, and in the heiData repository under accession codes QDOC4E (https://doi.org/10.11588/data/QDOC4E)38,122 and GDSZG9 (https://doi.org/10.11588/DATA/GDSZG9)39,123. Source data are provided with this paper.

All original code is available on GitLab [https://gitlab.com/kaessmannlab/cerebellum_te]. An archived snapshot corresponding to the manuscript is deposited on Zenodo [10.5281/zenodo.19354896]124.

Reproduced under the paper's license (CC BY), 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, 4 authors, 5 keywords, 12 MeSH terms, 2 funders, 116 references.

Cite

This paper

Yamada, T., Sepp, M., Sarropoulos, I., & Kaessmann, H. (2026). Gene regulatory innovations from transposable elements in primate cerebellum development. Nature communications, 17(1), 7598. https://doi.org/10.1038/s41467-026-75700-7

BibTeX

@article{yamada2026gene,
author = {Yamada, Tetsuya and Sepp, Mari and Sarropoulos, Ioannis and Kaessmann, Henrik},
title = {{Gene regulatory innovations from transposable elements in primate cerebellum development}},
journal = {Nature communications},
year = {2026},
month = jul,
volume = {17},
number = {1},
pages = {7598},
publisher = {Nature Publishing Group},
issn = {2041-1723},
doi = {10.1038/s41467-026-75700-7},
url = {https://doi.org/10.1038/s41467-026-75700-7},
pmid = {42527403},
pmcid = {PMC13421694}
}

RIS

TY - JOUR
AU - Yamada, Tetsuya
AU - Sepp, Mari
AU - Sarropoulos, Ioannis
AU - Kaessmann, Henrik
TI - Gene regulatory innovations from transposable elements in primate cerebellum development
T2 - Nature communications
J2 - Nat Commun
PY - 2026
DA - 2026/07/30
VL - 17
IS - 1
SP - 7598
SN - 2041-1723
PB - Nature Publishing Group
DO - 10.1038/s41467-026-75700-7
UR - https://doi.org/10.1038/s41467-026-75700-7
LA - en
ER -

CSL-JSON

{
"id": "10.1038/s41467-026-75700-7",
"type": "article-journal",
"title": "Gene regulatory innovations from transposable elements in primate cerebellum development",
"container-title": "Nature communications",
"author": [
{
"family": "Yamada",
"given": "Tetsuya"
},
{
"family": "Sepp",
"given": "Mari"
},
{
"family": "Sarropoulos",
"given": "Ioannis"
},
{
"family": "Kaessmann",
"given": "Henrik"
}
],
"container-title-short": "Nat Commun",
"volume": "17",
"issue": "1",
"page": "7598",
"DOI": "10.1038/s41467-026-75700-7",
"PMID": "42527403",
"PMCID": "PMC13421694",
"ISSN": "2041-1723",
"publisher": "Nature Publishing Group",
"URL": "https://doi.org/10.1038/s41467-026-75700-7",
"language": "en",
"issued": {
"date-parts": [
[
2026,
7,
30
]
]
}
}

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/s41592-026-03057-2 [code]
CREsted: modeling genomic and synthetic cell-type-specific enhancers across tissues and species.
Journal: Nature methods
In common: pysam, Biopython, BEDTools, 9 other tools, genetics / omics, mouse, 8 references
[2] doi:10.1186/s13059-026-04177-w [code]
Genomic sequence evolution underlying human neocortical interareal diversification.
Journal: Genome biology
In common: pysam, BEDTools, TensorFlow, 6 other tools, non-human primate, genetics / omics, mouse, 1 other category, 6 references
[3] doi:10.1186/s13059-026-04050-w
Transposable element-mediated evolutionary expansion of Sox2- and Brn2-binding regulatory modules for mammalian neural-cell differentiation.
Journal: Genome biology
In common: 12 references
[4] doi:10.1038/s42003-026-10462-y [code]
SpaDC enables sequence-based integrative analysis and regulatory inference of spatial chromatin accessibility data.
Journal: Communications biology
In common: pysam, Biopython, SHAP, 6 other tools, genetics / omics, mouse, 3 references
[5] doi:10.1126/sciadv.aed2952 [code]
Activation of transposable elements is linked to a region- and cell type-specific interferon response in Parkinson's disease.
Journal: Science advances
In common: pysam, Biopython, BEDTools, 5 other tools, cellular / molecular, 4 references
[6] doi:10.1038/s42003-026-10957-8 [code]
Brain defence by the extracellular matrix protein Cochlin.
Journal: Communications biology
In common: Biopython, SHAP, Keras, 8 other tools, mouse, cellular / molecular
[7] doi:10.1016/j.celrep.2026.117110 [code]
Single-nucleus multiome analysis in the human prefrontal cortex identifies gene expression and cis-regulatory elements associated with aging.
Journal: Cell reports
In common: pysam, BEDTools, statsmodels, 5 other tools, genetics / omics, cellular / molecular, 3 references
[8] doi:10.1038/s44400-026-00094-8 [code]
Haplotype-resolved DNA methylation at the &lt;i&gt;APOE&lt;/i&gt; locus identifies allele-specific epigenetic signatures relevant to Alzheimer's disease risk.
Journal: NPJ dementia
In common: pysam, BEDTools, statsmodels, 6 other tools, genetics / omics, cellular / molecular, 2 references
[9] doi:10.1016/j.xhgg.2026.100629 [code]
Positive selection on brain cis-regulatory elements in the human lineage drives changes in gene expression and susceptibility to neuropsychiatric disorders.
Journal: HGG advances
In common: Biopython, statsmodels, seaborn, 5 other tools, cellular / molecular, 3 references
[10] doi:10.1038/s41592-026-03211-w [code]
Spatial isoform sequencing at single-cell resolution reveals cell-type-specific spatial isoform variability in multiple brain cell types.
Journal: Nature methods
In common: pysam, Biopython, BEDTools, 7 other tools, genetics / omics, mouse

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.