| name | bio-genome-annotation-ncrna-annotation |
| description | Identify non-coding RNAs including tRNAs, rRNAs, snoRNAs, and regulatory RNAs using Infernal covariance model searches against Rfam and tRNAscan-SE for tRNA prediction. Use when performing genome-wide ncRNA annotation with assembly input producing GFF output. |
| tool_type | cli |
| primary_tool | Infernal |
Non-Coding RNA Annotation
Identify and annotate non-coding RNAs in genome assemblies using Infernal (general ncRNAs via Rfam covariance models) and tRNAscan-SE (specialized tRNA detection).
Infernal / cmscan
Infernal uses covariance models (CMs) from Rfam to identify ncRNA families by both sequence and secondary structure similarity.
Rfam Database Setup
wget https://ftp.ebi.ac.uk/pub/databases/Rfam/CURRENT/Rfam.cm.gz
gunzip Rfam.cm.gz
cmpress Rfam.cm
wget https://ftp.ebi.ac.uk/pub/databases/Rfam/CURRENT/Rfam.clanin
Basic cmscan
cmscan \
--cut_ga \
--rfam \
--nohmmonly \
--tblout ncrna_hits.tbl \
--fmt 2 \
--cpu 16 \
--clanin Rfam.clanin \
Rfam.cm \
genome.fasta > ncrna_hits.out
Key Options
| Option | Description |
|---|
--cut_ga | Use Rfam gathering threshold (recommended) |
--rfam | Speed optimization for Rfam-scale searches |
--nohmmonly | Force CM-only scoring (more sensitive for structured RNAs) |
--clanin | Rfam clan file for resolving overlapping hits |
--tblout | Tabular output file |
--fmt 2 | Extended table format with accessions |
--cpu | CPU threads |
-E | E-value threshold (default: 10; --cut_ga is preferred) |
Convert cmscan Output to GFF3
grep -v '^#' ncrna_hits.tbl | \
awk 'BEGIN{OFS="\t"} {
if ($10 == "+") strand = "+"; else strand = "-";
if ($10 == "+") {start=$8; end=$9} else {start=$9; end=$8};
print $4, "Infernal", "ncRNA", start, end, $17, strand, ".", "ID="$2";Name="$3";rfam_acc="$2";evalue="$17
}' > ncrna_infernal.gff3
E-value Guidelines
| Category | Typical E-value | Notes |
|---|
| High confidence | < 1e-10 | Unambiguous family assignment |
| Moderate | 1e-10 to 1e-5 | Likely real, verify context |
| Rfam GA threshold | family-specific | Recommended cutoff with --cut_ga |
| Marginal | > 1e-3 | May be pseudogenes or degraded copies |
tRNAscan-SE
Specialized tRNA detector using covariance models. More sensitive and specific for tRNAs than Infernal alone.
Basic Usage
tRNAscan-SE -B -o trna_results.txt --gff trna.gff3 genome.fasta
tRNAscan-SE -E -o trna_results.txt --gff trna.gff3 genome.fasta
tRNAscan-SE -G -o trna_results.txt --gff trna.gff3 genome.fasta
Key Options
| Option | Description |
|---|
-B | Bacterial mode |
-A | Archaeal mode |
-E | Eukaryotic mode |
-G | General (mixed/unknown) mode |
-o | Tabular output |
--gff | GFF3 output |
--detail | Detailed output with isotype info |
--thread | CPU threads |
-Q | Covariance model scoring only (slower, more accurate) |
Domain-Specific Models
| Domain | Flag | Notes |
|---|
| Bacteria | -B | Shorter introns, smaller genomes |
| Archaea | -A | Split tRNAs, bulge-helix-bulge introns |
| Eukaryota | -E | Longer introns, pseudogenes common |
| Organelle | -O | Mitochondrial/chloroplast tRNAs |
| Mitochondrial | -M | Mammalian mitochondrial-specific |
Expected tRNA Counts
| Organism Type | Expected tRNAs | Notes |
|---|
| Bacteria | 30-90 | Fewer isotypes, some shared |
| Archaea | 30-60 | Similar to bacteria |
| Yeast | 275-400 | Many isodecoders |
| Nematode | 600-900 | Gene family expansion |
| Mammal | 400-600 | Many pseudogenes |
| Plant | 500-1,000+ | Large gene families |
barrnap (rRNA Detection)
barrnap predicts rRNA genes using HMM models. Note: barrnap has been unmaintained since 2018. Bakta handles rRNA detection internally for prokaryotes.
barrnap --kingdom bac genome.fasta > rrna.gff3
barrnap --kingdom euk --threads 4 genome.fasta > rrna.gff3
Combining ncRNA Annotations
import pandas as pd
from collections import defaultdict
def parse_infernal_tbl(tbl_file):
'''Parse Infernal cmscan tabular output.'''
hits = []
with open(tbl_file) as f:
for line in f:
if line.startswith('#'):
continue
parts = line.split()
if len(parts) < 18:
continue
strand = '+' if parts[9] == '+' else '-'
start, end = (int(parts[7]), int(parts[8])) if strand == '+' else (int(parts[8]), int(parts[7]))
hits.append({
'target': parts[0],
'rfam_acc': parts[1],
'rfam_name': parts[2],
'seqid': parts[3],
'start': start,
'end': end,
'strand': strand,
'evalue': (parts[]),
: (parts[]),
: classify_rfam(parts[]),
})
pd.DataFrame(hits)
():
name_lower = rfam_name.lower()
name_lower name_lower name_lower:
name_lower:
name_lower name_lower name_lower:
name_lower:
name_lower name_lower:
name_lower name_lower:
():
trnas = []
(gff_file) f:
line f:
line.startswith():
parts = line.strip().split()
(parts) < parts[] != :
attrs = (item.split() item parts[].split() item)
trnas.append({
: parts[],
: (parts[]),
: (parts[]),
: parts[],
: attrs.get(, ),
: attrs.get(, ),
: (parts[]) parts[] != ,
: ,
})
pd.DataFrame(trnas)
():
infernal_df = parse_infernal_tbl(infernal_tbl)
trna_df = parse_trnascan_gff(trnascan_gff)
infernal_no_trna = infernal_df[infernal_df[] != ]
summary = defaultdict()
rna_type infernal_no_trna[].unique():
summary[rna_type] = (infernal_no_trna[infernal_no_trna[] == rna_type])
summary[] = (trna_df)
()
rna_type, count (summary.items()):
()
()
infernal_no_trna, trna_df, summary
Troubleshooting
cmscan Is Slow
- Use
--rfam flag for Rfam-mode optimizations
- Use
--FZ 2 to further speed up (less sensitive)
- Split genome into chunks and run in parallel
Missing Expected ncRNAs
- Verify Rfam.cm is current version
- Check that cmpress was run successfully (look for .i1m, .i1p, .i1f, .i1i files)
- For mitochondrial/chloroplast ncRNAs, search organelle sequence separately
tRNAscan-SE Finds Too Many Pseudogenes
- Normal for eukaryotic genomes (especially mammals)
- Filter by score: high-confidence tRNAs typically score > 50 bits
- Use
--detail flag to identify pseudogenes in output
Related Skills
- prokaryotic-annotation - Bakta includes ncRNA annotation
- eukaryotic-gene-prediction - Gene prediction excludes ncRNAs
- rna-structure/ncrna-search - Targeted ncRNA homology searches