ribo-seq/ribosome-periodicity/SKILL.md
Validate Ribo-seq library quality by measuring 3-nucleotide periodicity and calibrating read-length-specific P-site offsets. Use when checking whether footprints capture genuine translation, determining P-site offsets for downstream ORF/TE/stalling analysis, or deciding which read lengths to keep.
npx skillsauth add GPTomics/bioSkills bio-ribo-seq-ribosome-periodicityInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Reference examples tested with: riboWaltz 2.0+, plastid 0.6+, numpy 1.26+, scipy 1.12+, pysam 0.22+
Before using code patterns, verify installed versions match. If versions differ:
packageVersion('<pkg>') then ?function_name to verify parameterspip show <package> then help(module.function) to check signatures<tool> --version then <tool> --help to confirm flagsIf code throws ImportError, AttributeError, or TypeError, introspect the installed package and adapt the example to match the actual API rather than retrying.
"Check if my Ribo-seq data shows triplet periodicity and get my P-site offsets" -> Confirm footprints carry codon phase (the signature of genuine elongating ribosomes) and compute the read-length-specific offset from the read end to the P-site codon, the prerequisite for every codon-resolution analysis.
riboWaltz for P-site offset calibration and per-length periodicity (the de-facto standard)plastid metagene + psite CLI scripts as the alternative pathAn elongating ribosome advances exactly one codon (3 nt) per translocation, so P-site-assigned footprints over a CDS pile up in one reading frame (frame 0 >> frames +1/+2). This sub-codon comb is what distinguishes Ribo-seq from RNA-seq, and a library without it cannot support frame-based ORF calling, TE, or dwell-time work regardless of read depth. Contamination (rRNA/tRNA), degraded RNA, and over-digestion all give phase-free, RNA-seq-like coverage.
The ribosome has three tRNA sites: A (aminoacyl, decodes the incoming codon), P (peptidyl, holds the nascent chain), E (exit). Codon position is reported at the P-site, which sits at a fixed OFFSET inside the ~28-30 nt footprint. The offset is the distance from the mapped read end to the first nucleotide of the P-site codon. A-site offset = P-site + 3; E-site = P-site - 3. The A-site is the relevant site for tRNA/decoding effects (see ribosome-stalling).
| Method | Map from | Best when | Caveat | |--------|----------|-----------|--------| | 5'-end + offset | 5' end | sharp 5' ends, classic RNase I libraries (~+12 for 28 nt) | breaks if the 5' end is ragged/variably trimmed | | 3'-end + offset | 3' end | variable 5' trimming, sharper 3' end; standard for bacteria/MNase | offset still length-dependent; verify per length | | auto (riboWaltz) | 5' or 3', chosen per length | default; let the data pick the more consistent end | reports both, decides per read-length population | | center (plastid) | both ends | very noisy ends | loses sub-codon sharpness |
The canonical ~+12 nt offset for 28-29 nt mammalian footprints is a STARTING expectation, not a constant. Offsets are read-length-specific and dataset-specific and must be calibrated empirically; a fixed lookup table silently misassigns codons.
| Tool | Language | Role |
|------|----------|------|
| riboWaltz | R | offset calibration + per-length frame % (primary) |
| plastid | Python | metagene/psite CLI offsets + count vectors |
| Ribo-seQC | R | one-shot HTML QC report (P-site, region, periodicity) |
| ribotricer | Python | phase-score check that is robust to P-site shift |
Goal: Determine the per-read-length P-site offset and the frame-0 fraction that together certify the library.
Approach: Convert BAMs to riboWaltz tables, filter lengths by periodicity, compute offsets with extremity="auto", then read off frame percentages per length.
library(riboWaltz)
annotation <- create_annotation(gtfpath = "annotation.gtf")
reads <- bamtolist(bamfolder = "bams", annotation = annotation)
# Keep only read lengths with strong frame-0 enrichment
# periodicity_threshold is a frame-0 percentage (here 50%); tune per dataset
reads <- length_filter(reads, length_filter_mode = "periodicity",
periodicity_threshold = 50)
# extremity="auto" picks the 5' or 3' end giving the most consistent per-length offset;
# the corrected offset refines the temporary one to the local maximum (occupancy correction)
offsets <- psite(reads, flanking = 6, extremity = "auto")
reads_psite <- psite_info(reads, offsets)
# Frame-0 fraction per read length is the primary, defensible periodicity metric
frames_by_length <- frame_psite_length(reads_psite, annotation,
sample = names(reads)[1])
Goal: Decide pass/fail and which lengths to retain.
Approach: Use the frame-0 fraction as the headline number and the metaheatmap/metaprofile as visual confirmation.
# Pooled frame distribution and the start/stop metaprofile
frames <- frame_psite(reads_psite, annotation, sample = names(reads)[1])
metaprofile_psite(reads_psite, annotation, sample = names(reads)[1],
utr5l = 25, cdsl = 40, utr3l = 25)
metaheatmap_psite(reads_psite, annotation, sample = names(reads)[1])
Frame-0 fraction rule of thumb: good libraries put roughly >60-70% of in-CDS P-sites in frame 0 (vs the 33% null); ~45-60% is marginal; near-uniform 33/33/33 is uninterpretable at codon level. Report per read length, not just pooled.
If NO read length clears the periodicity threshold (length_filter returns empty), the library is RNA-seq-like and supports only gene-level counting, not codon-resolution ORF/TE/stalling analysis; that is the verdict, not a reason to keep lowering the threshold. Lower it only to inspect the best-available length, not to rescue an aperiodic library.
A bimodal length distribution is expected, not an error: alongside the ~28-30 nt footprint there is a ~21 nt population from ribosomes with an open (empty) A-site (Lareau 2014). Inspect the ~21 nt class per length rather than discarding it as contamination; its phase and offset differ from the long footprints and it carries elongation-state information.
Goal: Get per-length offsets without R, using plastid's verified workflow.
Approach: Build a start-codon ROI with metagene generate, then run the psite script, which writes an offsets table and per-length profile plots.
# CLI-first: there is NO top-level plastid.metagene_analysis() function
metagene generate cds_start --landmark cds_start --annotation_files annotation.gtf
psite cds_start_rois.txt psite_out --min_length 26 --max_length 34 \
--require_upstream --count_files riboseq.bam
# Apply the calibrated offsets in Python
from plastid import BAMGenomeArray, VariableFivePrimeMapFactory, GTF2_TranscriptAssembler
ga = BAMGenomeArray('riboseq.bam')
ga.set_mapping(VariableFivePrimeMapFactory.from_file(open('psite_out_p_offsets.txt')))
transcripts = list(GTF2_TranscriptAssembler('annotation.gtf'))
# Per-transcript P-site counts: vec = transcript.get_counts(ga)
Goal: Quantify periodicity strength from the CDS body, not the initiation peak.
Approach: Build per-nucleotide P-site coverage along the CDS, trim the start/stop peaks, then take the frame-0 fraction or the spectral power at period 3.
import numpy as np
def body_frame_fraction(psite_coverage, trim_start=45, trim_stop=15):
'''Frame-0 fraction over CDS-body P-site coverage.
The start (initiation) and stop (termination) peaks dwarf the body and carry
their own phase, so they are trimmed (trim in nt; ~15 codons start, ~5 codons stop).
'''
body = psite_coverage[trim_start:len(psite_coverage) - trim_stop]
frames = [body[f::3].sum() for f in range(3)]
total = sum(frames)
return frames[0] / total if total else 0.0
Running an FFT on the start-codon metagene is the wrong signal: that profile is dominated by a single initiation peak, not sustained codon phase. The spectral test must run on uniform CDS-body P-site coverage; otherwise report the frame-0 fraction directly.
| Symptom | Cause | Fix |
|---------|-------|-----|
| ImportError: cannot import name 'metagene_analysis' | No such function exists in plastid | Use the metagene generate + psite CLI, or riboWaltz |
| Periodicity "score" always ~0 or meaningless | FFT run on the start-codon metagene, or frames never populated | Score CDS-body P-site coverage; use frame_psite_length |
| Offset works for one length, breaks others | A single hardcoded offset (e.g. 12) applied to all lengths | Calibrate per read length; A-site = P-site + 3 |
| Strong "periodicity" that is just the start peak | Start/stop codon peaks not trimmed | Trim ~15 codons at start, ~5 at stop before scoring |
| Bacterial library looks aperiodic | MNase data with ragged 5' ends mapped 5'-anchored | Anchor on the 3' end; expect weaker periodicity than RNase I |
| Short/long read lengths dilute the signal | Phase-free length tails kept in the analysis | length_filter mode "periodicity"; analyze per length |
tools
End-to-end CLIP-seq pipeline from FASTQ to ENCODE-compliant binding sites, single-nucleotide crosslink maps, annotation, motifs, and (optionally) differential binding. Use when running the full Yeo lab eCLIP / iCLIP / iCLIP2 / iCLIP3 / irCLIP / PAR-CLIP analysis with SMInput control, protocol-specific UMI extraction, ENCODE STAR parameters, CLIPper or Skipper peak calling with stringent log2 FC and -log10 p thresholds, IDR rescue and self-consistency QC, and downstream motif registration with mCross or PEKA.
development
Detect, date, and contextualize whole-genome duplication (WGD / paleopolyploidy) events using wgd v2 (Chen et al 2024), KsRates (Sensalari 2022 substitution-rate-corrected Ks dating), DupGen_finder (Qiao 2019), MAPS (Li 2018 phylogenomic), POInT (Conant 2008 ordered-block), SLEDGe (2024 ML-based), Whale.jl (Bayesian DL+WGD), and synteny-anchored paranome construction. Use when identifying ancient polyploidy from Ks distributions and synteny block analysis, positioning WGD events relative to speciation, distinguishing tandem from segmental from WGD duplications, dating the 2R/3R vertebrate / fish / salmonid WGDs, building paranome and Ks-age mixture models, applying KsRates substitution-rate correction across lineages, or testing alternative biased-fractionation / dosage-balance models post-WGD.
tools
Build whole-genome alignments using Progressive Cactus (Armstrong 2020 reference-free clade-level WGA), Minigraph-Cactus (Hickey 2024 pangenome-aware), LASTZ chain/net (UCSC pipeline), MUMmer4 (Marçais 2018 pairwise), minimap2 -x asm5/10/20 (Li 2018 fast pairwise), AnchorWave (Song 2022 WGD-aware), and Mauve / progressiveMauve (bacterial). Operates the HAL toolkit (Hickey 2013) for downstream extraction including halSynteny, halLiftover, halBranchMutations, and hal2maf. Use when constructing multi-species alignments for comparative-annotation projection (TOGA), synteny detection, conservation analyses (phyloP / PhastCons), or pangenome graph construction; selecting between reference-free (Cactus) and reference-anchored (LASTZ chains/nets) approaches; tuning sensitivity for closely vs distantly related genomes; or producing HAL files for genome-wide downstream tools.
development
Detect syntenic blocks and structural rearrangements between genomes using MCScanX (Wang 2012), JCVI/MCScan (Tang 2008 Python), GENESPACE (Lovell 2022) for orthology-anchored riparian visualization, SyRI for structural variation, AnchorWave for sequence-level synteny, i-ADHoRe 3.0 for highly diverged species, SynNet for synteny networks, and ntSynt for multi-genome macrosynteny. Use when identifying collinear gene blocks across species, distinguishing macrosynteny from microsynteny, detecting inversions/translocations/duplications, anchoring orthology in WGD lineages, producing publication riparian plots, computing synteny block age via Ks (cross-references whole-genome-duplication), or running synteny-aware ortholog inference in polyploids.