You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: code/enrichment/sldsc_enrichment.ipynb
+81-11Lines changed: 81 additions & 11 deletions
Original file line number
Diff line number
Diff line change
@@ -409,7 +409,11 @@
409
409
},
410
410
"source": [
411
411
"##### 1.2 joint tau\n",
412
-
"with more than one annotation as the input"
412
+
"with more than one annotation as the input\n",
413
+
"\n",
414
+
"`--snp_list <file>` is **optional** and **orthogonal to single/joint**: it restricts which SNP *rows* are written to the `.l2.ldscore` output (HM3-style restriction) — it does **not** change the LD-score *values* of retained SNPs (the r²-window still uses all `.bim` SNPs), nor `.l2.M` / `.l2.M_5_50`. With `--snp_list` the step runs polyfun's `ldsc.py --print-snps` and emits `.l2.ldscore.gz` (without it: `compute_ldscores.py` → `.l2.ldscore.parquet`), and the target annot is normalized to the plink `.bim`. Downstream `get_heritability` / `postprocess` **commands are unchanged** — they just read whichever `.l2.ldscore.{gz,parquet}` exists; the regression runs on the intersection sumstats ∩ baseline ∩ weights ∩ target, so for the HM3 restriction to take full effect the baseline & weights LD scores should also be HM3-restricted.\n",
415
+
"\n",
416
+
"**Which polyfun script & what to align.** `--snp_list` present → step 1 runs `ldsc.py --l2 --print-snps` (output `.l2.ldscore.gz`); absent → `compute_ldscores.py` (output `.l2.ldscore.parquet`). `ldsc.py` requires the target annot to line up with the plink `.bim` — **same SNP set and same row order**. The pipeline handles this internally (`normalize_for_ldsc` re-expands the annot onto the `.bim` rows, filling 0), but if you assemble inputs by hand, keep the **plink `.bim`, `.frq`, target annot, and baseline annot all on the same reference panel with consistent SNP set/order**: target and baseline annot row counts must match (polyfun hstacks them), and the `.frq` MAF filter (`--frqfile-chr`, m50) plus the by-SNP merge in `get_heritability` both assume a consistent panel. Mixing panels (e.g. 1000G plink with an ADSP-derived annot, or a `.frq` whose row count/order differs from the annot) is the most common source of wrong `Prop_SNPs` / Enrichment.\n"
413
417
]
414
418
},
415
419
{
@@ -493,7 +497,8 @@
493
497
" --weight-name weights_chr \\\n",
494
498
" --annotation-name my_analysis \\\n",
495
499
" --cwd output/heritability \\\n",
496
-
" --maf-cutoff 0.05"
500
+
" --maf-cutoff 0.05\n",
501
+
"# (allm variant: use --maf-cutoff 0 — no MAF filter; polyfun then uses --not-M-5-50)\n"
497
502
]
498
503
},
499
504
{
@@ -508,7 +513,9 @@
508
513
"(which contains the $N$ single-target subdirectories and optionally the\n",
509
514
"joint subdirectory) and calls `pecotmr::sldsc_postprocessing_pipeline()`\n",
510
515
"to produce per-trait standardized tables and the default random-effects\n",
511
-
"meta across all traits."
516
+
"meta across all traits.\n",
517
+
"\n",
518
+
"Use `--target-categories-label` (same order as `--target-categories`) to give the target annotations friendly names in the output — e.g. `--target-categories ANNOT_1_0 ANNOT_2_0 --target-categories-label quantile_eQTL eQTL` makes the `target` column read `quantile_eQTL` / `eQTL` instead of `ANNOT_1_0` / `ANNOT_2_0` (the original names are kept in `params$target_categories_orig`). Omit it to keep the polyfun `.results` names.\n"
512
519
]
513
520
},
514
521
{
@@ -524,16 +531,25 @@
524
531
"# pecotmr::sldsc_postprocessing_pipeline. Single and joint target subdirectories\n",
525
532
"# are auto-detected from <annotation_name>_single_<i> and <annotation_name>_joint.\n",
526
533
"\n",
534
+
"# --target-categories: the joint-run target columns as they appear in the .results \"Category\"\n",
535
+
"# column. The 2-target joint dir here has columns ANNOT_1, ANNOT_2 (compute_ldscores.py keeps\n",
536
+
"# the annot col names) and polyfun appends \"_0\" (target = ref-ld file 0) -> \"ANNOT_1_0\", \"ANNOT_2_0\".\n",
537
+
"# (Single-target dirs would be \"ANNOT_0\"; with --snp_list/ldsc.py and a single annot it is \"L2_0\".)\n",
538
+
"# You can drop --target-categories entirely to auto-detect from the joint-run results.\n",
539
+
"# --target-categories-label (optional, same order as --target-categories): friendly display\n",
540
+
"# names; renames the \"target\" column in the output (originals kept in params$target_categories_orig).\n",
527
541
"sos run pipeline/sldsc_enrichment.ipynb postprocess \\\n",
"parameter: baseline_name = \"baseline_chr\" # Prefix of baseline annotation files\n",
612
628
"parameter: weight_name = \"weights_chr\" # Prefix of LD weights files\n",
613
-
"parameter: Mref = -1 # Reference number of SNPs in our panel (MAF > maf_cutoff). If > 0, use provided value; if <= 0, auto-calculate from ldscore files\n",
614
629
"parameter: n_blocks = 200\n",
615
630
"\n",
616
631
"# Number of threads\n",
@@ -664,6 +679,33 @@
664
679
"# Run on a NEW annotation_file with the K selected annotations\n",
665
680
"# -> 1 joint dir with the conditional model.\n",
666
681
"\n",
682
+
"#\n",
683
+
"# --- snplist (--snp_list) vs no-snplist: which polyfun script, output format,\n",
684
+
"# column name, and the CM requirement ---\n",
685
+
"# --snp_list given -> ldsc.py --l2 --print-snps -> output .l2.ldscore.gz\n",
"# index 1 = the baseline file -> \"base_1\",\"Coding_UCSC_1\", ... (the 97 baseline annots)\n",
1124
+
"# So in this pipeline the suffix is only ever 0 (target) or 1 (baseline); it would\n",
1125
+
"# continue 0,1,2,... only if you handed `ldsc.py --ref-ld-chr` more than two sources.\n",
1126
+
"# (Why ANNOT_0 vs L2_0: see the [make_annotation_files_ldscore] header — ldsc.py's\n",
1127
+
"# \"n_annot == 1 -> column name 'L2'\" quirk vs compute_ldscores.py keeping the annot\n",
1128
+
"# column name.) [postprocess] auto-detects the target Category; if you instead pass\n",
1129
+
"# --target-categories, the names must match this column exactly.\n",
1130
+
"#\n",
1070
1131
"parameter: target_anno_dirs = paths()\n",
1071
1132
"parameter: all_traits = []\n",
1072
1133
"\n",
@@ -1173,6 +1234,10 @@
1173
1234
"parameter: traits_file = path() # text file: one trait sumstats filename per line\n",
1174
1235
"parameter: heritability_cwd = path() # parent directory of [get_heritability] outputs (contains <annotation_name>_single_<i>/ subdirs and optionally <annotation_name>_joint/)\n",
1175
1236
"parameter: target_categories = [] # target annotation names. Auto-detected from the joint-run results if empty.\n",
1237
+
"parameter: target_categories_label = [] # optional display names, same order as target_categories;\n",
1238
+
" # when given, every \"target\" column / tau*-block colname in\n",
1239
+
" # the output RDS is renamed to these (params$target_categories\n",
1240
+
" # holds the labels, params$target_categories_orig the originals).\n",
1176
1241
"parameter: target_anno_dir = path() # directory of target .annot.gz files used for sd_C and binary detection (typically the joint dir, since it carries all target columns)\n",
1177
1242
"\n",
1178
1243
"input: traits_file\n",
@@ -1184,6 +1249,7 @@
1184
1249
"\n",
1185
1250
" traits <- readLines(\"${traits_file}\")\n",
1186
1251
" target_cats <- c(${\",\".join('\"%s\"' % c for c in target_categories)})\n",
1252
+
" target_lab <- c(${\",\".join('\"%s\"' % c for c in target_categories_label)})\n",
1187
1253
"\n",
1188
1254
" # Auto-detect single-target and joint-target output directories.\n",
1189
1255
" her_root <- \"${heritability_cwd}\"\n",
@@ -1218,7 +1284,8 @@
1218
1284
" frqfile_dir = \"${frqfile_dir}\",\n",
1219
1285
" plink_name = \"${plink_name}\",\n",
1220
1286
" maf_cutoff = ${maf_cutoff},\n",
1221
-
" target_categories = if (length(target_cats) > 0) target_cats else NULL\n",
1287
+
" target_categories = if (length(target_cats) > 0) target_cats else NULL,\n",
1288
+
" target_labels = if (length(target_lab) > 0) target_lab else NULL\n",
1222
1289
" )\n",
1223
1290
"\n",
1224
1291
" saveRDS(res, \"${_output[0]}\")\n",
@@ -1241,6 +1308,9 @@
1241
1308
"parameter: subset_traits_file = path() # text file: one trait id per line, subset of those passed to [postprocess]\n",
1242
1309
"parameter: subset_name = str # label used in the output filename\n",
1243
1310
"parameter: target_categories = [] # target annotation names to meta on; if empty, uses all from postprocess output\n",
1311
+
"# If [postprocess] was run with --target-categories-label, the cached RDS already\n",
1312
+
"# carries the display names (params$target_categories = the labels), so leave\n",
1313
+
"# --target-categories empty here (or pass the labels, not the original ANNOT_* names).\n",
0 commit comments