Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SamReader — validation et classification de fichiers SAM

SamReader est un analyseur en ligne de commande écrit en Python. Il lit un fichier SAM (Sequence Alignment/Map), vérifie sa structure, classe les alignements primaires au niveau des reads et des paires, puis produit soit un résumé, soit un dossier complet contenant les données regroupées, les diagnostics, les métadonnées et trois figures.

Le programme accepte aussi les SAM compressés ou placés dans des archives. Le format est reconnu à partir du contenu binaire, et non à partir de l'extension du fichier.

Version du programme : 0.1.0
Python : 3.10 ou version ultérieure
Interface principale : SamReader.py

Sommaire

  1. Objectif et périmètre
  2. Démarrage rapide
  3. Concepts biologiques et format SAM
  4. Choix de classification
  5. Architecture du projet
  6. Données et formats pris en charge
  7. Installation
  8. Utilisation détaillée
  9. Dossier de résultats
  10. Résultats de référence
  11. Discussion des résultats
  12. Validation et tests
  13. Erreurs, sécurité et résolution de problèmes
  14. Limites et hors périmètre
  15. Utilisation comme module Python
  16. Licence

1. Objectif et périmètre

1.1 Problème traité

Un fichier SAM décrit des alignements de séquences, appelées ici reads, sur une séquence de référence. Dans un fichier réel, il faut distinguer plusieurs situations :

  • un read peut être aligné sur toute sa longueur utile ;
  • une partie de ses bases peut avoir été coupée de l'alignement ;
  • le read peut ne pas être aligné ;
  • deux reads peuvent constituer une paire valide ;
  • une paire peut être incomplète ou incohérente ;
  • une même séquence peut posséder des alignements primaire, secondaire ou supplémentaire ;
  • le SAM peut être brut, compressé, archivé ou porter une extension trompeuse.

SamReader transforme ces situations en catégories explicites, exclusives et reproductibles. Il répond ainsi à quatre besoins :

  1. valider le contenu avant de calculer des statistiques ;
  2. classer chaque alignement primaire selon une règle documentée ;
  3. regrouper les paires et signaler leurs anomalies ;
  4. exporter des résultats lisibles par un humain et réutilisables par un programme.

1.2 Ce que produit le programme

Deux modes sont proposés :

  • le mode résumé écrit seulement les compteurs dans le terminal ou dans un fichier texte ;
  • le mode dossier de résultats produit les résumés, les reads classés, les paires, les diagnostics, les métadonnées et les figures.

1.3 Principes directeurs

Le comportement a été conçu autour des principes suivants :

  • l'extension ne prouve jamais qu'une entrée est un SAM ;
  • une ligne invalide interrompt le traitement au lieu d'être ignorée ;
  • chaque read primaire appartient à un seul statut individuel ;
  • chaque paire valide appartient à une seule catégorie de paire ;
  • les alignements secondaires et supplémentaires ne contaminent pas les statistiques principales ;
  • les lignes SAM exportées restent identiques aux lignes d'origine, y compris leurs champs optionnels ;
  • une destination existante n'est jamais écrasée ;
  • un dossier incomplet n'est jamais publié comme un résultat valide.

2. Démarrage rapide

Depuis la racine du projet :

conda env create --file environment.yml
conda activate samreader

Analyser la petite fixture de démonstration et afficher son résumé :

python SamReader.py \
    --input datas/classification_cases.sam \
    --no-progress

Générer un dossier complet de résultats :

python SamReader.py \
    --input datas/classification_cases.sam \
    --results-dir classification_results \
    --progress

La destination classification_results ne doit pas exister avant la commande. Après une exécution réussie, elle contient 18 fichiers répartis entre les résumés, les reads, les paires, les diagnostics et les figures.

Pour afficher toutes les options :

python SamReader.py --help

3. Concepts biologiques et format SAM

3.1 Read, alignement et enregistrement SAM

Un read est une séquence issue d'un processus de séquençage. Un alignement décrit la manière dont cette séquence est placée sur une référence. Une ligne SAM est plus précisément un enregistrement d'alignement : un même read peut être représenté par plusieurs lignes si un aligneur fournit des alignements secondaires ou supplémentaires.

Dans ce projet, le mot « read » désigne généralement un enregistrement SAM primaire lorsqu'il est question des compteurs individuels. Cette convention est importante : SamReader ne tente pas de reconstruire une molécule biologique à partir de tous ses alignements possibles.

3.2 Organisation générale d'un SAM

Un fichier SAM est un fichier texte tabulé. Il peut commencer par un en-tête, puis contient les alignements :

@HD    VN:1.6
@SQ    SN:chr1    LN:1000
read_1 99 chr1 101 60 100M = 301 300 ACTG... IIII...

Les tabulations ont été représentées par des espaces dans cet exemple pour en faciliter la lecture. Dans un véritable SAM, les colonnes sont séparées par le caractère de tabulation.

SamReader reconnaît les types d'en-tête suivants :

  • @HD : métadonnées générales du fichier ;
  • @SQ : description d'une séquence de référence ;
  • @RG : groupe de reads ;
  • @PG : programme ayant produit ou transformé le SAM ;
  • @CO : commentaire.

Les lignes d'en-tête doivent précéder les alignements. Un SAM composé seulement d'un en-tête valide est accepté et produit des compteurs nuls. Un fichier totalement vide est refusé, car son contenu ne permet pas de l'identifier comme un SAM.

3.3 Les onze champs obligatoires

Chaque ligne d'alignement contient au moins onze champs :

Champ Rôle simplifié Utilisation dans SamReader
1 QNAME identifiant du read ou de la paire regroupement des deux membres d'une paire
2 FLAG masque de bits décrivant l'enregistrement statut non aligné, primaire et position dans la paire
3 RNAME nom de la référence validation structurelle
4 POS première position alignée sur la référence validation numérique
5 MAPQ confiance de l'aligneur dans le placement conservé, mais non utilisé pour la classification
6 CIGAR description compacte de l'alignement validation et détection du clipping
7 RNEXT référence du partenaire validation structurelle
8 PNEXT position du partenaire validation numérique
9 TLEN longueur observée du fragment validation numérique
10 SEQ séquence du read validation de longueur et de contenu
11 QUAL qualités des bases validation de longueur et de caractères

Les champs situés après QUAL sont des champs optionnels. SamReader les préserve dans les fichiers de reads générés, mais n'interprète pas leur sémantique.

3.4 Le champ FLAG

FLAG est un entier utilisé comme masque de bits. Plusieurs propriétés peuvent donc être vraies simultanément.

Bit Valeur Signification utile dans ce projet
0x1 1 le read appartient à une paire
0x4 4 le read lui-même n'est pas aligné
0x40 64 premier membre de la paire
0x80 128 second membre de la paire
0x100 256 alignement secondaire
0x800 2048 alignement supplémentaire

Le bit 0x2, souvent appelé properly paired, n'est pas utilisé pour décider si un read est entier ou partiel. Il traduit une décision de l'aligneur sur la paire, alors que la classification de SamReader décrit la couverture du read par son propre CIGAR.

3.5 Le champ CIGAR

Un CIGAR est une succession de couples « longueur + opération ». Par exemple, 5S95M signifie que cinq bases sont soft-clippées, puis que 95 positions sont alignées.

Opération Définition Consomme des bases de SEQ Consomme la référence Rend le read partiel ici
M correspondance ou différence oui oui non
I insertion par rapport à la référence oui non non
D délétion par rapport à la référence non oui non
N région sautée sur la référence non oui non
S soft clipping oui non oui
H hard clipping non, les bases sont absentes de SEQ non oui
P remplissage non non non
= correspondance explicite oui oui non
X différence explicite oui oui non

Cette distinction explique deux exemples parfois contre-intuitifs :

  • 50M1I49M consomme 100 bases du read, mais 99 positions de référence ;
  • 55M1D45M consomme 100 bases du read, mais 101 positions de référence.

Dans les deux cas, les 100 bases observées du read sont décrites dans le chemin d'alignement. L'insertion et la délétion signalent une différence entre le read et la référence ; elles ne signifient pas qu'une extrémité du read a été retirée de l'alignement. Elles restent donc classées comme alignements entiers selon le choix du projet.

À l'inverse, 5S95M et 95M5S indiquent explicitement qu'une partie du read n'est pas intégrée à l'alignement principal. Le hard clipping porte la même information, mais les bases coupées ne sont même plus présentes dans SEQ.

3.6 Alignements primaires, secondaires et supplémentaires

SamReader réserve les statistiques principales aux alignements primaires :

  • un alignement 0x100 est secondaire ;
  • un alignement 0x800 est supplémentaire ;
  • un alignement ne portant aucun de ces bits est primaire.

Les alignements secondaire et supplémentaire sont conservés dans les diagnostics du mode complet, mais ne sont pas comptés parmi les trois statuts de reads ni dans les catégories de paires.

3.7 Données single-end et paired-end

En single-end, chaque fragment est représenté par un read individuel. Il est classé parmi les reads, mais ne contribue pas aux statistiques de paires.

En paired-end, deux reads partagent normalement le même QNAME. Les bits 0x40 et 0x80 indiquent respectivement le premier et le second membre. Les deux statuts individuels sont combinés pour obtenir une catégorie de paire.

4. Choix de classification

4.1 Classification individuelle

Chaque alignement primaire appartient à exactement l'un des trois statuts.

flowchart TD
    A[Alignement primaire validé] --> B{FLAG contient 0x4 ?}
    B -- Oui --> U[NON_ALIGNE]
    B -- Non --> C{CIGAR contient S ou H ?}
    C -- Oui --> P[PARTIELLEMENT_ALIGNE]
    C -- Non --> E[ENTIEREMENT_ALIGNE]
Loading
Statut Condition exacte Exemples de CIGAR
NON_ALIGNE le bit 0x4 est présent ; cette règle est prioritaire généralement *
PARTIELLEMENT_ALIGNE pas de bit 0x4, et présence de S ou H 5S95M, 95M5S, 10H90M
ENTIEREMENT_ALIGNE pas de bit 0x4, ni S ni H 100M, 50M1I49M, 55M1D45M, 50=1X49=

La priorité du bit 0x4 évite de présenter comme partiellement aligné un read que le SAM déclare explicitement non aligné, même si son CIGAR est inhabituel.

4.2 Informations volontairement non utilisées

SamReader ne décide pas qu'un read est entier à partir :

  • de MAPQ : une faible confiance n'est pas synonyme de clipping ;
  • du bit 0x2 : il décrit la cohérence de la paire selon l'aligneur ;
  • d'un CIGAR égal à 100M : tous les reads ne mesurent pas 100 bases ;
  • du nombre de différences, insertions ou délétions : ces événements restent décrits par l'alignement.

Cette stratégie mesure donc la complétude géométrique du read dans son alignement, pas la qualité, l'identité ni la vérité biologique du placement.

4.3 Classification des paires

L'ordre des membres ne change pas la catégorie. Un couple « entier + partiel » est donc classé ENTIER_PARTIEL, que le read partiel soit le premier ou le second membre.

Premier statut Second statut Catégorie
entier entier ENTIER_ENTIER
entier partiel ENTIER_PARTIEL
entier non aligné ENTIER_NON_ALIGNE
partiel partiel PARTIEL_PARTIEL
partiel non aligné PARTIEL_NON_ALIGNE
non aligné non aligné NON_ALIGNE_NON_ALIGNE

La matrice symétrique correspondante est :

Entier Partiel Non aligné
Entier ENTIER_ENTIER ENTIER_PARTIEL ENTIER_NON_ALIGNE
Partiel ENTIER_PARTIEL PARTIEL_PARTIEL PARTIEL_NON_ALIGNE
Non aligné ENTIER_NON_ALIGNE PARTIEL_NON_ALIGNE NON_ALIGNE_NON_ALIGNE

4.4 Paires incomplètes et incohérentes

Une paire valide doit contenir exactement deux alignements primaires de même QNAME, l'un marqué 0x40, l'autre 0x80.

SamReader compte séparément :

  • une paire incomplète lorsqu'un seul membre primaire apparié est présent ;
  • une paire incohérente lorsque les indicateurs ne permettent pas de former un premier et un second membre uniques, par exemple deux premiers membres, deux seconds membres, aucun numéro de membre ou plus de deux alignements primaires pour le même QNAME.

Un read associé à une paire anormale reste valide au niveau individuel. Il est donc inclus dans son statut de read, mais aucune catégorie de paire valide ne lui est attribuée.

5. Architecture du projet

5.1 Fichiers principaux

.
├── SamReader.py                 # programme et point d'entrée unique
├── environment.yml              # environnement Conda reproductible
├── README.md                    # documentation d'installation et d'usage
├── LICENCE                      # licence CC BY-SA 4.0
├── datas/
│   ├── classification_cases.sam # petite fixture exhaustive
│   └── mapping.sam              # jeu de validation de grande taille
└── tests/
    ├── expected_results.json    # contrat chiffré de la petite fixture
    ├── EXPECTED_RESULTS.md      # description lisible de ce contrat
    ├── helpers.py               # création des variantes compressées
    └── test_*.py                # suite unittest

SamReader.py reste volontairement le seul point d'entrée. Les responsabilités sont néanmoins séparées en classes et fonctions internes afin que validation, classification, progression et écriture puissent être testées indépendamment.

5.2 Chaîne de traitement

flowchart LR
    I[Fichier fourni] --> D[Détection par signature]
    D --> C[Décompression récursive]
    C --> A[Sélection du membre d'archive]
    A --> V[Décodage UTF-8 et validation SAM]
    V --> R[Classification des reads primaires]
    R --> P[Regroupement et classification des paires]
    R --> S[Compteurs et progression]
    P --> S
    S --> M{Mode choisi}
    M -- Résumé --> T[stdout ou summary.txt]
    M -- Dossier complet --> O[Reads, paires, diagnostics et résumés]
    O --> F[Figures PNG]
    F --> X[Publication atomique du dossier]
Loading

5.3 Responsabilités internes

Composant Responsabilité principale
SamRecord parser et valider les champs obligatoires d'un alignement
MappingStatus représenter les trois statuts individuels
ReadPair et PairCategory combiner deux statuts dans l'une des six catégories
AnalysisSummary conserver les compteurs finaux
analyze_sam_lines() parcourir et analyser un flux textuel SAM
open_sam_input() préparer une entrée brute, compressée ou archivée
ProgressReporter afficher des compteurs temporisés sur stderr
ProgressSampler conserver au maximum 500 points pour la figure de progression
ResultWriter écrire les reads, les paires et les diagnostics
generate_figures() générer les trois PNG avec le moteur non interactif Agg
generate_results() construire puis publier atomiquement le dossier complet

5.4 Traitement en flux et mémoire

Les alignements sont lus ligne par ligne. Les séquences complètes du SAM ne sont pas accumulées en mémoire. Pour chaque paire, seules les métadonnées utiles sont conservées : QNAME, numéro du membre et statut de classification.

La mémoire dépend donc principalement du nombre de paires distinctes encore référencées, et non de la somme des longueurs de toutes les séquences. Les QNAME d'une paire n'ont pas besoin d'être adjacents dans le fichier, mais cette souplesse implique de conserver les métadonnées des paires jusqu'à la fin du parsing.

Pour les couches compressées, des fichiers temporaires sont utilisés afin de ne pas charger le contenu décompressé en mémoire. L'espace disque temporaire doit donc être suffisant pour les données décompressées.

5.5 Écriture atomique

En mode complet, SamReader :

  1. refuse une destination déjà existante ;
  2. crée un dossier temporaire voisin de la destination ;
  3. analyse le SAM et écrit toutes les catégories ;
  4. vérifie que les effectifs écrits correspondent aux compteurs ;
  5. génère les résumés, métadonnées et figures ;
  6. renomme le dossier temporaire vers le nom final.

Si une étape échoue, le dossier temporaire est supprimé et aucun dossier final partiel n'est publié.

6. Données et formats pris en charge

6.1 Détection par contenu

SamReader inspecte la signature binaire de l'entrée. Un fichier nommé experiment.sam peut donc être refusé s'il contient des données binaires non SAM, tandis qu'un SAM valide nommé simplement experiment est accepté.

Après chaque décompression, le contenu obtenu est inspecté de nouveau. Cette récursion permet de traiter plusieurs couches, par exemple :

reads.sam → gzip → bzip2 → reads.sam.gz.bz2

La profondeur maximale est fixée à cinq couches.

6.2 Formats acceptés

Famille Formats Extensions usuelles indicatives Remarque
texte SAM UTF-8 non compressé .sam ou aucune l'extension n'est pas utilisée comme preuve
gzip gzip et BGZF lus séquentiellement .gz, .bgz, .bgzf pris en charge par la bibliothèque standard
bzip2 bzip2 .bz2 pris en charge par la bibliothèque standard
LZMA xz et LZMA-Alone .xz, .lzma les deux signatures sont distinguées
Zstandard flux Zstandard .zst, .zstd nécessite le paquet zstandard
archive ZIP .zip les membres chiffrés ne sont pas pris en charge
archive TAR .tar seuls les fichiers réguliers sont acceptés
archive compressée tar.gz, tar.bz2, tar.xz, tar.zst .tgz, .tbz2, .txz, .tzst, etc. détectée comme plusieurs couches
multi-compression combinaisons récursives des formats précédents par exemple .sam.gz.bz2 maximum de cinq couches

BGZF est une variante structurée de gzip fréquemment utilisée en bioinformatique. SamReader le lit comme un flux gzip séquentiel ; il n'exploite pas son indexation aléatoire.

6.3 Sélection dans une archive

Sans --member, SamReader analyse le contenu des membres :

  • si un unique SAM valide est trouvé, il est sélectionné automatiquement ;
  • si aucun SAM valide n'est trouvé, l'analyse échoue ;
  • si plusieurs SAM valides sont trouvés, l'analyse échoue et demande --member.

--member doit contenir le chemin exact du membre dans l'archive, par exemple nested/sample.sam. Le nom du membre n'a pas besoin de finir par .sam si son contenu est valide.

6.4 Sécurité des archives

Les archives ne sont jamais extraites implicitement dans le dossier de travail. SamReader refuse notamment :

  • les chemins absolus ;
  • les chemins contenant .. ;
  • les liens symboliques et liens matériels ;
  • les membres spéciaux qui ne sont pas des fichiers réguliers ;
  • les noms dupliqués ;
  • les membres ZIP chiffrés ;
  • les archives corrompues ou tronquées.

6.5 Données incluses dans le projet

Fichier Taille Contenu Rôle
datas/classification_cases.sam 2 402 octets 3 en-têtes, 37 alignements dont 35 primaires fixture courte couvrant les statuts, CIGAR, paires et anomalies
datas/mapping.sam 103 614 988 octets, soit environ 98,8 Mio 2 en-têtes et 351 330 alignements primaires validation réaliste des compteurs, performances, mémoire et sorties

classification_cases.sam est une donnée de test construite pour contenir :

  • les trois statuts individuels ;
  • les six catégories de paires ;
  • les catégories mixtes dans les deux ordres ;
  • les opérations CIGAR M, I, D, N, S, H, =, X et P ;
  • un read single-end ;
  • une paire incomplète et deux incohérentes ;
  • un alignement secondaire et un supplémentaire.

mapping.sam contient 350 000 séquences de 100 bases et 1 330 séquences de 150 bases. Son en-tête désigne une référence nommée Reference. Le dépôt ne documente pas l'origine biologique, le protocole de séquençage ni les paramètres expérimentaux complets de ce fichier. Les résultats peuvent donc être discutés comme validation informatique de la classification, mais une interprétation biologique approfondie nécessiterait ces métadonnées.

Les résultats attendus de la petite fixture sont décrits dans tests/EXPECTED_RESULTS.md et sérialisés dans tests/expected_results.json.

7. Installation

Cloner le dépôt et se placer à sa racine :

git clone https://github.com/RAVAO-Ravo/fun_sam_reader.git
cd fun_sam_reader

7.1 Prérequis

  • Conda, Miniconda ou une distribution compatible ;
  • un système capable d'exécuter Python 3.10 ou plus récent ;
  • assez d'espace temporaire pour décompresser l'entrée ;
  • un terminal pour l'utilisation en ligne de commande.

Le programme ne requiert pas de compilateur et n'utilise pas pysam.

7.2 Environnement reproductible

Créer l'environnement décrit par le projet :

conda env create --file environment.yml

Puis l'activer :

conda activate samreader

Vérifier l'installation :

python --version
python -c "import matplotlib, zstandard; print(matplotlib.__version__, zstandard.__version__)"
python SamReader.py --help

7.3 Dépendances

Dépendance Version minimale Usage
Python 3.10 parsing, validation, archives, CLI et tests
Matplotlib 3.7 génération des figures PNG avec le backend Agg
zstandard 0.21 lecture des flux .zst et tar.zst

Les autres formats reposent sur la bibliothèque standard : gzip, bz2, lzma, zipfile et tarfile.

Le projet utilise uniquement environment.yml. Il ne fournit pas de requirements.txt.

7.4 Mettre à jour un environnement existant

Si l'environnement samreader existe déjà, ses dépendances peuvent être resynchronisées avec :

conda env update --name samreader --file environment.yml --prune

8. Utilisation détaillée

8.1 Syntaxe générale

SamReader.py [-h] -i INPUT [-o OUTPUT | --results-dir RESULTS_DIR]
             [--member MEMBER] [--progress | --no-progress]
Option Description
-i, --input entrée SAM brute, compressée ou archivée ; obligatoire
-o, --output écrit un nouveau fichier de résumé textuel
--results-dir génère le dossier complet de résultats
--member sélectionne le chemin exact d'un membre d'archive
--progress force l'affichage périodique sur stderr
--no-progress désactive la progression
-h, --help affiche l'aide

--output et --results-dir sont mutuellement exclusifs.

8.2 Résumé sur la sortie standard

python SamReader.py \
    --input datas/classification_cases.sam \
    --no-progress

Le résumé est écrit sur stdout. Cette séparation permet de le rediriger ou de le transmettre à un autre outil sans y mélanger la progression.

8.3 Résumé dans un fichier

python SamReader.py \
    --input datas/classification_cases.sam \
    --output classification_summary.txt \
    --no-progress

classification_summary.txt doit être absent avant l'exécution. SamReader refuse de l'écraser.

8.4 Dossier complet

python SamReader.py \
    --input datas/classification_cases.sam \
    --results-dir classification_results \
    --progress

Le dossier parent doit exister, mais classification_results lui-même doit être absent.

8.5 Entrée gzip, BGZF, bzip2, xz ou Zstandard

La commande ne change pas selon le compresseur :

python SamReader.py \
    --input sample.sam.gz \
    --output sample_summary.txt \
    --progress

La même syntaxe convient par exemple à sample.sam.bz2, sample.sam.xz ou sample.sam.zst.

8.6 Archive contenant un unique SAM

python SamReader.py \
    --input sequencing_run.tar.bz2 \
    --results-dir sequencing_run_results

Le membre est sélectionné automatiquement si lui seul contient un SAM valide.

8.7 Archive contenant plusieurs SAM

python SamReader.py \
    --input sequencing_run.zip \
    --member nested/sample_A.sam \
    --results-dir sample_A_results

Sans --member, une archive contenant plusieurs SAM valides est considérée comme ambiguë et provoque une erreur de sélection.

8.8 Progression en temps réel

Par défaut, la progression est activée lorsque stderr est connecté à un terminal interactif. Elle est désactivée automatiquement lorsque ce n'est pas le cas, sauf si --progress est fourni.

Une ligne ressemble à :

Lignes: 351,332 | Primaires: 351,330 | Entiers: 349,968 | Partiels: 47 | Non alignés: 1,315 | Paires: 175,665 | Temps: 00:00:51 | Débit: 6,813.8 reads/s

Les valeurs sont mises à jour au plus environ une fois par seconde :

  • lignes parcourues ;
  • alignements primaires ;
  • reads entiers, partiels et non alignés ;
  • paires provisoirement classées ;
  • durée ;
  • débit en reads par seconde.

La progression est écrite sur stderr. Le résumé ou le message final reste sur stdout.

9. Dossier de résultats

9.1 Arborescence

classification_results/
├── summary.txt
├── summary.tsv
├── run_metadata.json
├── reads/
│   ├── entierement_alignes.sam.gz
│   ├── partiellement_alignes.sam.gz
│   └── non_alignes.sam.gz
├── pairs/
│   ├── entier_entier.tsv.gz
│   ├── entier_partiel.tsv.gz
│   ├── entier_non_aligne.tsv.gz
│   ├── partiel_partiel.tsv.gz
│   ├── partiel_non_aligne.tsv.gz
│   └── non_aligne_non_aligne.tsv.gz
├── diagnostics/
│   ├── paires_incompletes.tsv
│   ├── paires_incoherentes.tsv
│   └── alignements_ignores.tsv
└── figures/
    ├── reads_par_statut.png
    ├── paires_par_categorie.png
    └── progression_classification.png

Les fichiers sont créés même lorsqu'une catégorie vaut zéro. L'arborescence reste ainsi stable et exploitable automatiquement.

9.2 Résumés et métadonnées

Fichier Contenu Usage principal
summary.txt résumé en français lecture humaine
summary.tsv table section, category, count import dans R, Python, tableur ou pipeline
run_metadata.json entrée, membre, couches, paramètres, durée, version et compteurs traçabilité et automatisation

Extrait de summary.tsv :

section	category	count
general	header_lines	3
reads	ENTIEREMENT_ALIGNE	15
pairs	ENTIER_PARTIEL	2
diagnostics	INCOMPLETE_PAIRS	1

run_metadata.json contient notamment :

  • le chemin absolu de l'entrée ;
  • le membre demandé et la source finalement sélectionnée ;
  • les couches détectées, dans l'ordre extérieur vers intérieur ;
  • la profondeur maximale autorisée ;
  • les dates de début et de fin et la durée ;
  • la version de SamReader ;
  • les noms des figures et le nombre d'échantillons de progression ;
  • une représentation structurée de tous les compteurs.

9.3 Fichiers de reads

Les trois fichiers reads/*.sam.gz :

  • contiennent uniquement les alignements primaires du statut correspondant ;
  • recopient les lignes d'en-tête SAM dans chaque fichier ;
  • préservent intégralement les onze champs obligatoires et les champs optionnels ;
  • utilisent une compression gzip.

Ils constituent donc des sous-SAM directement réutilisables par des outils qui acceptent un SAM gzip séquentiel.

9.4 Fichiers de paires

Chaque fichier pairs/*.tsv.gz possède les colonnes suivantes :

qname	first_status	second_status

Il contient une ligne par paire valide. Les statuts du premier et du second membre sont conservés même si la catégorie elle-même est indépendante de l'ordre.

9.5 Diagnostics

paires_incompletes.tsv et paires_incoherentes.tsv utilisent les colonnes :

qname	member_count	mate_numbers	statuses

alignements_ignores.tsv décrit les alignements secondaires et supplémentaires :

line_number	qname	flag	reasons

Ces fichiers permettent de distinguer une absence biologique ou technique de mapping d'un problème de structure des paires.

9.6 Figures

Matplotlib utilise le backend non interactif Agg, ce qui permet de générer les figures sur un serveur sans interface graphique.

Figure Représentation Détails de lecture
reads_par_statut.png barres des trois statuts affiche les effectifs exacts et les pourcentages
paires_par_categorie.png barres des six catégories affiche chaque valeur, y compris zéro
progression_classification.png courbes cumulées pendant le parsing permet de voir quand les statuts apparaissent dans le fichier

Lorsque les effectifs positifs diffèrent d'un facteur d'au moins 100, une échelle symlog est utilisée. Elle rend visibles les petites catégories tout en conservant la valeur zéro.

La progression n'enregistre pas un point par read. Elle utilise un échantillonnage adaptatif limité à 500 points : lorsque la limite approche, les anciens points sont espacés davantage, et le dernier point reste toujours le compte final exact.

10. Résultats de référence

10.1 Fixture classification_cases.sam

La petite fixture sert de contrat fonctionnel. Elle contient 37 alignements, dont 35 primaires.

Reads primaires

Statut Effectif
ENTIEREMENT_ALIGNE 15
PARTIELLEMENT_ALIGNE 11
NON_ALIGNE 9
Total 35

Paires valides

Catégorie Effectif
ENTIER_ENTIER 1
ENTIER_PARTIEL 2
ENTIER_NON_ALIGNE 2
PARTIEL_PARTIEL 1
PARTIEL_NON_ALIGNE 2
NON_ALIGNE_NON_ALIGNE 1
Total 9

Cas particuliers

Mesure Effectif
reads single-end 11
paires incomplètes 1
paires incohérentes 2
alignements secondaires ignorés 1
alignements supplémentaires ignorés 1

10.2 Jeu mapping.sam

Les 351 330 alignements sont primaires et forment 175 665 paires valides. Aucun read single-end et aucune paire anormale ne sont présents.

Reads primaires

Statut Effectif Pourcentage
ENTIEREMENT_ALIGNE 349 968 99,6123 %
PARTIELLEMENT_ALIGNE 47 0,0134 %
NON_ALIGNE 1 315 0,3743 %
Total 351 330 100 %

Paires valides

Catégorie Effectif Pourcentage
ENTIER_ENTIER 174 968 99,6032 %
ENTIER_PARTIEL 32 0,0182 %
ENTIER_NON_ALIGNE 0 0 %
PARTIEL_PARTIEL 0 0 %
PARTIEL_NON_ALIGNE 15 0,0085 %
NON_ALIGNE_NON_ALIGNE 650 0,3700 %
Total 175 665 100 %

Ces valeurs ont été vérifiées sur l'entrée brute et sur les variantes compressées prises en charge.

11. Discussion des résultats

11.1 Cohérence arithmétique

Dans mapping.sam, tous les alignements primaires appartiennent à des paires valides. Les statistiques individuelles se reconstruisent donc exactement à partir des catégories de paires :

reads entiers     = 2 × 174 968 + 32 = 349 968
reads partiels    = 32 + 15           =      47
reads non alignés = 2 × 650 + 15      =   1 315

Cette égalité constitue un contrôle indépendant de l'absence de double comptage. Elle montre aussi que les 1 315 reads non alignés se répartissent en 650 paires entièrement non alignées et 15 paires associant un read non aligné à un read partiel.

11.2 Profil général du jeu de validation

La très grande majorité des reads, 99,6123 %, ne contient ni soft clipping ni hard clipping et n'est pas marquée non alignée. De même, 99,6032 % des paires sont ENTIER_ENTIER.

Les événements rares restent visibles grâce aux effectifs exacts et à l'échelle adaptée des figures :

  • 47 reads seulement sont partiellement alignés ;
  • 1 315 reads sont non alignés ;
  • aucune paire ENTIER_NON_ALIGNE n'est observée ;
  • aucune paire PARTIEL_PARTIEL n'est observée ;
  • 15 paires sont PARTIEL_NON_ALIGNE.

Une catégorie nulle n'est ni supprimée ni considérée comme une erreur. Son absence peut être informative et l'arborescence stable facilite les analyses comparatives entre plusieurs échantillons.

11.3 Ce que ces résultats ne démontrent pas

Le terme ENTIEREMENT_ALIGNE ne signifie pas « alignement biologiquement correct » ou « alignement parfait ». Un read peut contenir des mismatches, des insertions, des délétions ou une faible valeur MAPQ tout en appartenant à cette catégorie.

Inversement, un read partiel n'est pas nécessairement de mauvaise qualité : le clipping peut provenir d'un adaptateur, d'une variation structurale, d'une séquence chimérique, d'une limite de la référence ou d'une décision normale de l'aligneur.

Une interprétation biologique des proportions demanderait au minimum :

  • l'origine de l'échantillon ;
  • le protocole et la plateforme de séquençage ;
  • la préparation des reads ;
  • la référence utilisée ;
  • le logiciel d'alignement et ses paramètres ;
  • les distributions de MAPQ et les champs optionnels pertinents.

Ces informations ne sont pas toutes documentées dans le dépôt. Les résultats présentés ici doivent donc être compris avant tout comme une validation robuste du système de classification choisi.

11.4 Performances observées pendant la validation

Sur le jeu mapping.sam, l'activation de la progression temporisée a produit le même résumé que l'exécution silencieuse. Lors d'une mesure indicative, elle a ajouté environ 8,6 % au temps d'analyse. Cette valeur dépend de la machine, du système de fichiers et du terminal ; elle ne constitue pas une garantie de performance.

Un contrôle avec 10 000 alignements et des séquences logiquement multipliées par 1 000, de 0,2 Mo à 200 Mo de SEQ + QUAL, a augmenté le pic mémoire suivi d'environ 6,8 % seulement. Ce résultat est cohérent avec l'architecture en flux. La mémoire continue toutefois de croître avec le nombre de QNAME de paires, car leurs métadonnées doivent être conservées jusqu'à la fin.

12. Validation et tests

12.1 Lancer la suite complète

Après activation de l'environnement :

python -m unittest discover -v

La suite actuelle contient 78 tests couvrant :

  • le parsing du CIGAR ;
  • les trois statuts individuels ;
  • les six catégories de paires ;
  • les ordres des catégories mixtes ;
  • les reads single-end, paires incomplètes et incohérentes ;
  • les alignements secondaires et supplémentaires ;
  • les champs SAM invalides ;
  • les entrées brutes, compressées, multicompressées et archivées ;
  • Zstandard, BGZF, ZIP et TAR ;
  • la sélection et la sécurité des membres d'archive ;
  • la CLI, les codes de sortie et la progression ;
  • l'écriture atomique du dossier de résultats ;
  • la structure et la lisibilité des trois PNG ;
  • la borne mémoire de l'échantillonnage de progression.

12.2 Vérifier la syntaxe Python

python -m py_compile SamReader.py

12.3 Rejouer le contrat de la petite fixture

python SamReader.py \
    --input datas/classification_cases.sam \
    --no-progress

Le résultat doit correspondre à tests/expected_results.json et aux tableaux de la section Résultats de référence.

13. Erreurs, sécurité et résolution de problèmes

13.1 Codes de sortie

Code Signification
0 exécution réussie
2 utilisation incorrecte de la CLI, produite par argparse
3 entrée absente, binaire, non UTF-8 ou SAM invalide
4 sélection d'archive impossible ou ambiguë
5 erreur de création ou de publication d'une sortie

13.2 Diagnostics SAM

Une erreur structurelle indique autant que possible :

  • le chemin de l'entrée ;
  • le membre d'archive concerné ;
  • le numéro de ligne ;
  • la cause, par exemple un CIGAR invalide ou un nombre de colonnes insuffisant.

Exemple de forme générale :

Erreur d'entrée : sample.sam, line 42: an alignment requires at least 11 columns

Le traitement s'arrête immédiatement afin d'éviter de publier des compteurs calculés sur une entrée partiellement valide.

13.3 La destination existe déjà

SamReader n'écrase ni un fichier --output, ni un dossier --results-dir. Choisir un nouveau chemin ou déplacer explicitement l'ancien résultat avant de relancer l'analyse.

13.4 Plusieurs SAM dans une archive

Relancer la commande avec le chemin exact du membre :

python SamReader.py \
    --input sequencing_run.zip \
    --member nested/sample_A.sam \
    --no-progress

13.5 Matplotlib ne peut pas être chargé

Le mode résumé n'importe pas Matplotlib. Le mode dossier complet en a besoin pour les figures. Resynchroniser l'environnement :

conda env update --name samreader --file environment.yml --prune

13.6 Zstandard n'est pas disponible

Cette erreur ne concerne que les entrées Zstandard. Vérifier l'environnement :

python -c "import zstandard; print(zstandard.__version__)"

13.7 Fichier corrompu ou extension incorrecte

Changer l'extension ne convertit pas un fichier. Un BAM renommé .sam reste un BAM et sera refusé. Il faut convertir les formats binaires avec un outil dédié avant de lancer SamReader.

14. Limites et hors périmètre

La version actuelle ne prend pas en charge :

  • BAM et CRAM, qui sont des formats d'alignement distincts et non de simples compressions de SAM ;
  • les archives RAR et 7z ;
  • l'analyse de plusieurs SAM d'une archive en une seule exécution ;
  • les membres ZIP chiffrés ;
  • une interface graphique ou un serveur web ;
  • l'interprétation biologique de MAPQ, des variants ou des champs optionnels ;
  • le calcul de couverture le long de la référence ;
  • le tri ou l'indexation des alignements.

Autres limites à connaître :

  • le texte SAM doit être décodable en UTF-8 ;
  • l'imbrication est limitée à cinq couches ;
  • aucun plafond explicite de taille décompressée n'est appliqué ; il faut donc rester prudent avec des archives provenant d'une source non fiable ;
  • l'espace temporaire peut approcher la taille des couches décompressées ;
  • la mémoire dépend du nombre de paires distinctes, même si elle ne dépend pas de la somme de toutes les séquences ;
  • seuls les champs SAM nécessaires sont validés sémantiquement ; les champs optionnels sont préservés, mais pas interprétés ;
  • la définition de « partiellement aligné » est un choix de ce projet fondé sur S et H, pas une catégorie imposée par la spécification SAM.

15. Utilisation comme module Python

La CLI est l'interface recommandée pour une analyse reproductible. Les principales fonctions peuvent néanmoins être importées :

from SamReader import MappingStatus, analyze_path

summary = analyze_path("datas/classification_cases.sam", progress=False)

print(summary.primary_records)
print(summary.read_counts[MappingStatus.ENTIEREMENT_ALIGNE])
print(summary.as_dict())

Pour produire le dossier complet depuis Python :

from SamReader import generate_results

summary = generate_results(
    "datas/classification_cases.sam",
    "classification_results",
    progress=True,
)

Comme avec la CLI, la destination ne doit pas exister.

16. Licence

Le projet est distribué sous la licence Creative Commons Attribution-ShareAlike 4.0 International, abrégée CC BY-SA 4.0. Le texte fourni avec le projet se trouve dans LICENCE.

Cette licence autorise notamment à :

  • copier et redistribuer le matériel ;
  • adapter, transformer et construire à partir du matériel ;
  • utiliser tout format ou médium.

Sous réserve notamment de :

  • fournir une attribution appropriée ;
  • indiquer les modifications effectuées ;
  • fournir un lien vers la licence ;
  • redistribuer les adaptations sous la même licence.

La licence n'apporte aucune garantie et ne remplace pas les autres droits qui pourraient s'appliquer aux données. Pour les conditions juridiquement complètes, consulter le fichier LICENCE et le texte officiel CC BY-SA 4.0.

About

SamReader est un analyseur en ligne de commande écrit en Python.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages