Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Import transcript-level quantifications from Salmon/kallisto into R for gene-level analysis with DESeq2/edgeR using tximport or tximeta. Use when importing transcript counts into R for DESeq2/edgeR.
.claude/skills/bio-rna-quantification-tximport-workflow/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-03 | ✗→✓ | ▲ Improved | 11% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 56% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 71% | 0% |
| case-13 | ✗→✓ | ▲ Improved | 105% | 0% |
| case-18 | ✗→✓ | ▲ Improved | 39% | 0% |
<!--
#
#
-->
Import transcript-level estimates from Salmon, kallisto, or other quantifiers into R for gene-level differential expression analysis.
rlibrary(tximport) # Define sample files files <- c( sample1 = 'sample1_quant/quant.sf', sample2 = 'sample2_quant/quant.sf', sample3 = 'sample3_quant/quant.sf' ) # Load transcript-to-gene mapping tx2gene <- read.csv('tx2gene.csv') # columns: TXNAME, GENEID # Import at gene level txi <- tximport(files, type = 'salmon', tx2gene = tx2gene)
rlibrary(GenomicFeatures) txdb <- makeTxDbFromGFF('annotation.gtf') k <- keys(txdb, keytype = 'TXNAME') tx2gene <- select(txdb, k, 'GENEID', 'TXNAME')
rlibrary(biomaRt) mart <- useMart('ensembl', dataset = 'hsapiens_gene_ensembl') tx2gene <- getBM( attributes = c('ensembl_transcript_id_version', 'ensembl_gene_id_version'), mart = mart ) colnames(tx2gene) <- c('TXNAME', 'GENEID')
rquant <- read.table('sample1_quant/quant.sf', header = TRUE) tx2gene <- data.frame( TXNAME = quant$Name, GENEID = gsub('\\..*', '', quant$Name) # Remove version )
r# Summarize transcripts to gene level txi <- tximport(files, type = 'salmon', tx2gene = tx2gene) # Returns: counts, abundance (TPM), length at gene level
r# Keep transcript-level estimates txi <- tximport(files, type = 'salmon', txOut = TRUE) # Returns: counts, abundance, length at transcript level
r# Gene-level TPM txi <- tximport(files, type = 'salmon', tx2gene = tx2gene, countsFromAbundance = 'scaledTPM')
rtxi <- tximport(files, type = 'salmon', tx2gene = tx2gene)
rtxi <- tximport(files, type = 'kallisto', tx2gene = tx2gene)
rtxi <- tximport(files, type = 'rsem', tx2gene = tx2gene)
rtxi <- tximport(files, type = 'stringtie', tx2gene = tx2gene)
rlibrary(DESeq2) # Create sample metadata coldata <- data.frame( condition = factor(c('control', 'control', 'treated', 'treated')), row.names = names(files) ) # Create DESeqDataSet from tximport dds <- DESeqDataSetFromTximport(txi, colData = coldata, design = ~ condition) # Filter low counts dds <- dds[rowSums(counts(dds)) >= 10, ] # Run DESeq2 dds <- DESeq(dds) res <- results(dds)
rlibrary(edgeR) # Create DGEList with offset cts <- txi$counts normMat <- txi$length normMat <- normMat / exp(rowMeans(log(normMat))) o <- log(calcNormFactors(cts / normMat)) + log(colSums(cts / normMat)) y <- DGEList(cts) y$offset <- t(t(log(normMat)) + o) # Continue with edgeR analysis y <- estimateDisp(y, design)
tximeta automatically attaches transcript and gene information from the original annotation.
rlibrary(tximeta) # First time: link transcriptome to annotation makeLinkedTxome( indexDir = 'salmon_index', source = 'Ensembl', organism = 'Homo sapiens', release = '110', genome = 'GRCh38', fasta = 'transcripts.fa', gtf = 'annotation.gtf' ) # Import with full metadata coldata <- data.frame( files = files, names = names(files), condition = c('control', 'control', 'treated', 'treated') ) se <- tximeta(coldata) # Summarize to gene level gse <- summarizeToGene(se) # Convert to DESeqDataSet dds <- DESeqDataSet(gse, design = ~ condition)
rnames(txi) # [1] "abundance" "counts" "length" # [4] "countsFromAbundance" # abundance: TPM values (genes x samples) # counts: estimated counts (genes x samples) # length: effective gene lengths (genes x samples)
r# Remove version from transcript IDs tx2gene$TXNAME <- gsub('\\.\\d+$', '', tx2gene$TXNAME) # Or ignore version during import txi <- tximport(files, type = 'salmon', tx2gene = tx2gene, ignoreTxVersion = TRUE, ignoreAfterBar = TRUE)
<!-- AUTHOR_SIGNATURE: 9a7f3c2e-MD-BABU-MIA-2026-MSSM-SECURE -->
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→fail | 24,166 | 12,391 | -49% | 1 | 1 | 0% | 4,648 | 4,184 | -10% | 0 | 0 | — |
case-02 | pass→pass | 7,577 | 4,143 | -45% | 1 | 1 | 0% | 1,562 | 2,471 | +58% | 0 | 0 | — |
case-03 | fail→pass | 11,543 | 5,277 | -54% | 1 | 1 | 0% | 2,346 | 2,605 | +11% | 0 | 0 | — |
case-04 | fail→fail | 10,238 | 5,950 | -42% | 1 | 1 | 0% | 2,078 | 2,804 | +35% | 0 | 0 | — |
case-05 | pass→pass | 8,341 | 6,579 | -21% | 1 | 1 | 0% | 1,557 | 2,746 | +76% | 0 | 0 | — |
case-06 | fail→pass | 8,058 | 3,705 | -54% | 1 | 1 | 0% | 1,465 | 2,289 | +56% | 0 | 0 | — |
case-07 | pass→pass | 11,469 | 7,495 | -35% | 1 | 1 | 0% | 2,275 | 3,148 | +38% | 0 | 0 | — |
case-08 | pass→pass | 9,082 | 6,361 | -30% | 1 | 1 | 0% | 1,783 | 2,886 | +62% | 0 | 0 | — |
case-09 | pass→pass | 9,477 | 4,406 | -54% | 1 | 1 | 0% | 1,916 | 2,405 | +26% | 0 | 0 | — |
case-10 | pass→pass | 7,881 | 5,641 | -28% | 1 | 1 | 0% | 1,625 | 2,731 | +68% | 0 | 0 | — |
case-11 | fail→pass | 19,502 | 7,541 | -61% | 1 | 1 | 0% | 1,819 | 3,109 | +71% | 0 | 0 | — |
case-12 | pass→pass | 8,557 | 5,516 | -36% | 1 | 1 | 0% | 1,547 | 2,659 | +72% | 0 | 0 | — |
case-13 | fail→pass | 5,871 | 4,046 | -31% | 1 | 1 | 0% | 1,129 | 2,318 | +105% | 0 | 0 | — |
case-14 | pass→pass | 8,166 | 4,079 | -50% | 1 | 1 | 0% | 1,392 | 2,329 | +67% | 0 | 0 | — |
case-15 | pass→pass | 5,385 | 2,976 | -45% | 1 | 1 | 0% | 947 | 2,159 | +128% | 0 | 0 | — |
case-16 | pass→pass | 12,508 | 5,769 | -54% | 1 | 1 | 0% | 2,334 | 2,677 | +15% | 0 | 0 | — |
case-17 | pass→pass | 9,307 | 5,522 | -41% | 1 | 1 | 0% | 1,908 | 2,654 | +39% | 0 | 0 | — |
case-18 | fail→pass | 7,890 | 3,214 | -59% | 1 | 1 | 0% | 1,561 | 2,167 | +39% | 0 | 0 | — |
case-19 | pass→pass | 3,513 | 2,105 | -40% | 1 | 1 | 0% | 655 | 1,920 | +193% | 0 | 0 | — |
case-20 | pass→pass | 3,946 | 3,331 | -16% | 1 | 1 | 0% | 742 | 2,185 | +194% | 0 | 0 | — |
case-21 | pass→pass | 4,794 | 4,038 | -16% | 1 | 1 | 0% | 892 | 2,364 | +165% | 0 | 0 | — |
case-22 | pass→pass | 8,366 | 5,330 | -36% | 1 | 1 | 0% | 1,663 | 2,648 | +59% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +23 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
| Model | Method | Date | Lift |
|---|---|---|---|
| gemini-3.6-flash | verified | 7/26/2026 | 0% |
Other measured skills in the registry, with their headline benchmark lift.