Metadata-Version: 2.4
Name: multiqc-mapper
Version: 0.2.0
Summary: Normalize MultiQC metrics across tools into a unified long-format table
Requires-Python: >=3.9
Requires-Dist: pandas>=1.5
Requires-Dist: pyarrow>=12.0
Requires-Dist: pyyaml>=6.0
Description-Content-Type: text/markdown

# multiqc-mapper

Normalize MultiQC metrics across tools into a unified long-format table.

MultiQC parses each tool independently. This package adds a semantic mapping
layer so that equivalent metrics (e.g. "total reads" from samtools *and*
RSeQC) resolve to a single canonical concept.

## Install

```bash
uv add multiqc-mapper          # inside an existing uv project
uv tool install multiqc-mapper # as a standalone CLI tool
```

## Quickstart

```bash
# 1. Auto-discover all metrics from a MultiQC output directory
multiqc-mapper discover ./multiqc_data -o concepts.yaml

# 2. Edit concepts.yaml — merge equivalent cross-tool metrics under one key

# 3. Validate the mapping is complete
multiqc-mapper validate ./multiqc_data concepts.yaml

# 4. Resolve to a unified long-format table
multiqc-mapper resolve ./multiqc_data concepts.yaml -o unified.tsv
```

## Python API

```python
from multiqc_mapper import ConceptRegistry, resolve

registry = ConceptRegistry.from_yaml("concepts.yaml")
df = resolve("./multiqc_data", registry)

# One row per (sample, concept, tool)
df[df["concept"] == "total_reads"]
#    sample     concept     tool              metric  val_raw unit
# ERR188383 total_reads samtools raw_total_sequences  98732.0 reads
# ERR188383 total_reads    rseqc       total_records 100826.0 reads
```

## Output schema

| column       | description |
|---|---|
| `sample`     | Sample name |
| `concept`    | Canonical concept key from `concepts.yaml` |
| `tool`       | Tool that reported this observation |
| `anchor`     | MultiQC anchor (plot/table id) |
| `section_key`| MultiQC section key |
| `metric`     | Original MultiQC metric key |
| `val_raw`    | Raw numeric value |
| `val_fmt`    | Formatted display string from MultiQC |
| `unit`       | Unit from concept definition |
| `title`      | Human-readable metric title |
| `description`| Metric description |

## concepts.yaml format

The mapping file is the single source of truth. Only `anchor` and `metric`
under each source are used for resolution; all other fields are documentation.

```yaml
version: "1.0"

concepts:
  total_reads:
    title: "Total reads"
    description: "Total reads in the BAM file"
    unit: reads
    category: alignment
    shared_key: read_count     # MultiQC shared_key (unit hint)
    notes: "samtools counts raw sequences; RSeQC counts BAM records"
    sources:
      - anchor: samtools-stats-dp
        metric: raw_total_sequences
        tool: samtools           # documentation only
        title: "Total sequences"
      - anchor: rseqc_bam_stat
        metric: total_records
        tool: rseqc
        title: "Total records"
```

To extend for a new tool: add a `sources:` entry to the relevant concept.
To add a new concept: add a new top-level key under `concepts:`.

## CLI reference

```
multiqc-mapper discover <multiqc_data_dir> [-o concepts.yaml]
multiqc-mapper resolve  <multiqc_data_dir> <concepts.yaml> [-o out.tsv] [--format tsv|csv|parquet] [--drop-unresolved]
multiqc-mapper validate <multiqc_data_dir> <concepts.yaml>
multiqc-mapper list-metrics <multiqc_data_dir> [--shared-key]
```

## Requirements

- Python ≥ 3.9
- MultiQC ≥ 1.25 (parquet output required)
