En parcourant le contenu de notre blogue en plein croissance (beau travail, collègues !), je me rends compte qu’aucun de nous n’a encore publié un article en rapport avec la fantastique ressource bioinformatique qu’est pyGeno (qui plus est, un logiciel maison).
Il se trouve qu’en plus d’être mon tour de publier un article, je dois justement faire usage de pyGeno afin de générer un jeu de données, quelle merveilleuse coïncidence !

Je concentrerai cet article sur l’écriture d’un SNP filter, tâche qui peut s’avérer étrange aux premiers abords.

Pour débuter, si vous ne l’avez pas encore fait, veuillez survoler les procédures d’installation et d’importation car elles ne seront pas discutées ici. Je dirai simplement que je travaillerai sur le génome humain GRCh38.83 avec dbSNP149 et un jeu de SNPs spécifique à mon échantillon tel qu’identifié à l’aide de freebayes, jeu que je nommerai ici sampleSNPs.

Donc, pour une raison que je ne citerai pas, je dois filtrer les SNPs présents dans le sous-ensemble common de dbSNP de mes sampleSNPs et utiliser ceux qui restent afin de créer le proteome personnalisé que les collègues de protéomique nécessitent pour rouler leurs pipeline d’identification.
Je pourrais utiliser des outils tels que les excellents SnpSift/SnpEff pour pré-traiter mon ensemble de SNPs, mais où serait le plaisir ? 😉
Sans compter que les SNP Filters de pyGeno sont parfaits pour cette tâche !

Voici l’exemple que la documentation de pyGeno nous fournit:


class MyFilter(SNPFilter) :
    def __init__(self, thres) :
        self.thres = thres
        
    def filter(chromosome, SNP_Set1 = None, SNP_Set2 = None ) :
        if SNP_Set1.alt is not None \
                and (SNP_Set1.alt == SNP_Set2.alt) \
                and SNP_Set1.Qmax_gt > self.thres:
            return SequenceSNP(SNP_Set1.alt)
        
        return None

Assez générique.. Mais tout de même un bon point de départ.
Modifions le un peu afin de filtrer les entrées connues de dbSNP149 et ne conserver que les entrées sampleSNPs présentant une qualité supérieure à un seuil pré-défini.


class PseudoSomaticFilter(SNPFilter) :
    def __init__(self, thres) :
        self.thres = thres
        
    def filter(chromosome, sampleSNPs = None, dbSNP149 = None ) :
        if dbSNP149 is None and sampleSNPs.quality > self.thres:
            return SequenceSNP(sampleSNPs.alt)
        
        return None

# instancier l'objet Genome
genome = Genome(species='human', name='GRCh38.83', SNPs=['sampleSNPs', 'dbSNP149'], 
                SNPFilter=PseudoSomaticFilter(20))
# et faire un peu de travail...

Tel que mentionné plus haut, quelques petits trucs peuvent sembler étranges de prime abord. Regardons les plus en détails:

Primo, il est important de comprendre à quel moment la methode filter est appelée.
Voici, grosso-modo, ce qui se produit:

  • Pour chaque position chromosomique couverte par l’objet sous investigation (proteine, transcrit, etc..)
  • pyGeno cherche la présence de SNPs à cette position dans n’importe lequel des ensembles de SNPs en mémoire
  • Si un SNP est trouvé, pyGeno soumet une valeur pour chaque ensemble de SNP à la méthode filter

Secundo, semble un peu étrange que l’on fasse usage des noms de nos ensembles de SNPs comme paramètres de la methode filter, n’est-ce pas ?.
Ceci est du au fait que, à l’interne, pyGeno appelle filter en lui passant un dictionnaire qui utilise le nom de l’ensemble comme clé de l’instance du SNP lui-même (ie: {'sampleSNPs': pyGeno_SNP_entry, 'dbSNP149': pyGeno_SNP_entry}), et expand le dictionnaire automatiquement à l’aide de l’opérateur **. du langage Python.
Voici certainement l’aspect qui m’a donné le plus de fil à retordre lors de mes premières expériences avec ;es SNP Filters de pyGeno et sous-tend malheureusement que ceux-ci ne sont pas des composants entièrement réutilisables. Mais maintenant que vous en êtes informés, cet aspect ne devrait plus vous dérouter !

Tertio, comme vous pouvez le voir, j’accède l’attribut quality de mon sampleSNPs afin de le comparer à mon seuil et il n’y a rien de bizarre là-dedans. Il faut cependant garder en tête que tous les types de SNPs ne présentent pas tous les même attributs. Dans ce cas-ci, dbSNP149 est un dbSNPSNP et sampleSNPs est un AgnosticSNP. PyGeno supporte plusieurs types de SNPs pour importation et il est important de savoir à quel type vous accédez en écrivant votre SNPFilter afin de vous assurer d’avoir accès aux attributs auxquels vous vous attendez.

Finalement, afin de respecter la signature de la fonction, il est important pour notre SNPFilter de retourner l’une des entités suivantes:

  • SequenceSNP
  • SequenceInsert
  • SequenceDel
  • None

Alors voilà, un joli SNP Filter pour moi et des maux de tête de débutants d’évités pour vous 🙂
Amusez-vous avec pyGeno !