ISIS LOGBOOK

2014 04 18

@ QualGenerator

Drafting d'une version "Quick and dirty" de QualGenerator


In [ ]:
from random import gauss

def illumina_qualgen (m_start, m_mid, m_end, sd_start, sd_mid, sd_end, length):
    start_border = int(0.2*length)
    mid_border = int(0.66*length)
    end_border = length
    mean_qual = []
    sd_qual =[]
    
    for i in range (start_border) :
        mean_qual.append    (int(m_start + (float (m_mid - m_start))/start_border*i))
        sd_qual.append      (int(sd_start + (float (sd_mid - sd_start))/start_border*i))

    for i in range (mid_border - start_border) :
        mean_qual.append(m_mid)
        sd_qual.append(sd_mid)

    for i in range(end_border - mid_border):
        mean_qual.append    (int(m_mid + (float (m_end - m_mid)/ (end_border - mid_border)*i)))
        sd_qual.append      (int(sd_mid + (float (sd_end - sd_mid)/ (end_border - mid_border)*i)))

    return (mean_qual, sd_qual)

def random_qual_string (mean_qual, sd_qual, length):
    return [valid_qual(mean_qual[i], sd_qual[i]) for i in range (length)]

def valid_qual(mean, sd):
    while True:
        qual = int(gauss(mean, sd))
        if 0 <= qual <= 40:
            return qual

def illumina_qualgen2 (len, Q0m, Q1m, Q2m, Q3m, Q4m, Q0r, Q1r, Q2r, Q3r, Q4r, Q0f, Q1f, Q2f, Q3f, Q4f): 
    """Create a quality template for mean value and sd as """
    
    l   = [[Q0m, Q0m - Q0r/2, Q0m + Q0r/2, int(Q0f * len)],
           [Q1m, Q1m - Q1r/2, Q1m + Q1r/2, int(Q1f * len)],
           [Q2m, Q2m - Q2r/2, Q2m + Q2r/2, int(Q2f * len)],
           [Q3m, Q3m - Q3r/2, Q3m + Q3r/2, int(Q3f * len)],
           [Q4m, Q4m - Q4r/2, Q4m + Q4r/2, int(Q4f * len)]]
    
    qual_pattern = []
    
    for area in range (4):
        start_mean  = l [area] [0]
        delta_mean  = int(l [area + 1] [0] - l [area] [0])
        start_min   = l [area] [1]
        delta_min   = int(l [area + 1] [1] - l [area] [1])
        start_max   = l [area] [2]
        delta_max   = int(l [area + 1] [2] - l [area] [2])
        len_area    = l [area + 1] [3]
        
        for pos in range(len_area):
            mean_qual =  int( start_mean + (float (delta_mean)/ (len_area)*pos))
            min_qual  =  int( start_min  + (float (delta_min) / (len_area)*pos))
            max_qual  =  int( start_max  + (float (delta_max) / (len_area)*pos))
            qual_pattern.append([mean_qual, min_qual, max_qual])

    return qual_pattern

2014 04 22

@ QualGenerator

Implementation d'une classe accessoire permettant de générer des listes de score de qualité. Un pattern modèle est déterminé à l'instanciation de la classe (mean, min et max pour chaque position) à partir de paramètres donnés par l'utilisateur pour le départ, le premier quart, le milieu, le troisième quart et la fin. Pour chaque zone il faut fournir la moyenne et la sd

A partir de ce pattern, l'objet peut être appelé pour générer des listes de score de qualité suivant suivant le pattern (facteur d'attraction à la moyenne) mais avec une une part stochastique suivant une distribution Gaussienne centrée sur de 0 en variant dans l'intervalle min, max autorisé

Ci dessous voici le script utilisé pour tester le programme.


In [ ]:
from QualGenerator import QualGenerator
q = QualGenerator(100, 30,35,37,35,20, 10,4,2,6,20, 0,15,25,25,35)
with (open("test.csv", "w")) as file:
    for i in range (10):
        s =""
 	for i in q.random_qual_string():
  	    s += "{};".format(i)
	file.write(s+"\n")

Quelques modifications ont été apporté par la suite pour ne plus travailler en intervalle de qualité mais plutôt en sd directement. D'autre part, j'ai simplifié considérablement les paramètres à passer pour instancier la classe. Il s'agit désormais d'indiquer si on souhaite une qualité : "very good", "good", "medium", "bad", "very bad". Les paramètres de chaque catégorie de qualité sont inclus en dur dans la classe d'après des approximations expérimentales


In [ ]:
qual_param_dict = {
    "very_good" : [[33,38,39,38,36], [2,1,1,1,5],  [0,a1,a2,a3,a4]],
    "good"      : [[32,37,38,37,32], [2,2,1,3,10],  [0,a1,a2,a3,a4]],
    "medium"    : [[30,36,37,32,25], [4,3,2,10,10], [0,a1,a2,a3,a4]],
    "bad"       : [[25,30,32,28,20], [4,3,2,10,10], [0,a1,a2,a3,a4]],
    "very_bad"  : [[15,20,20,15,5],  [4,3,2,10,10], [0,a1,a2,a3,a4]]}

Pour chaque entrée du dictionnaire la première liste correspond à la qualité moyenne, la seconde à la sd, et la troisième à la taille en pb de la région (recalculé pour chaque longueur donnée par l'utilisateur

2014 04 23

@ QualGenerator

Il reste potentiellement encore un peu de travail sur cette classe :

  • Mieux définir les catégories de qualité
  • Permettre la création de nouveau pattern ?
  • Jouer sur le facteur d'attraction à la moyenne (mean_attraction_factor) plus le diviseur est petit et plus l'attraction est forte (Fixé à 2 pour le moment)

Reformatage du code pour se plier aux recommandations du "PEP8 style guide for python code"

Script ci dessous utilisé pour tester plus en detail QualGenerator


In [ ]:
from QualGenerator import QualGenerator
from matplotlib import pyplot

def qtester(length, quality, iteration, title):

    q = QualGenerator(length, quality)
    fig = pyplot.figure(figsize=(length/2, 10), dpi=100)
    pyplot.title(title)
    pyplot.ylabel('PHRED Quality')
    pyplot.xlabel('Position')
    position = [i+1 for i in range (length)]
    
    for i in range (iteration):
        q_list = q.random_qual_string()
        pyplot.plot(position, q_list)

    fig.savefig(title+'.png')

Exemple avec qtester(75, "good", 10, "len=75_qual=good_divider=2.png

@ ReferenceGenome

Reformatage du code pour se plier aux recommandations du "PEP8 style guide for python code"

+ FastqGenerator

Drafting d'une version "Quick and dirty" de FastqGenerator


In [ ]:
from ReferenceGenome import ReferenceGenome
from SlicePicker import SlicePicker
from QualGenerator import QualGenerator

def FastqGenerator (source, file, quality, length, mutfreq):

    g = ReferenceGenome (source, file)
    print(repr(g))
    
    s = SlicePicker ()
    print(repr(s))
    
    q = QualGenerator (length, quality)
    print(repr(q))

    read = s.pick_single(g,length,1,1,mutfreq)
    read.letter_annotations["phred_quality"] = q.random_qual_string()
    read.id = "{}|{}|loc_{}_{}_{}".format(
        read.annotations["source"],
        read.annotations["refseq"],
        read.annotations["location"][0],
        read.annotations["location"][1],
        read.annotations["orientation"])
    
    print(read)
    print(read.format("qual"))
    print(read.format("fastq-illumina"))

    return read

Pendant l'ecriture du module, il m'a semblé que la direction que j'avais prise auparavant pour SlicePicker (à savoir une classe portant les methodes pour single et pair read picking) était mauvaise. Il y a en effet beaucoup de paramètres à passer par FastqGenerator.

@ SlicePicker

Séparation de la classe en 2 sous classes SlicePickerSingle et SlicePickerPair chacune spécialisée dans les read single ou paired. Le code est mieux factorisé et lors de l'instanciation les classes auront directement plusieurs variables stockées. Pour le moment j'ai un problème à l'instanciation via init de la super classe. A revoir

2014 04 24

@ SlicePicker

Le problème venait du fait que la classe SlicePicker n'héritait pas de la classe objet qui correspond aux classe "new style" en python Normalement ça devrait être automatique depuis python 2.6 ... Le problème peut être résolu avec la solution ci dessous

Exemple:


In [ ]:
# Running this code will raise `TypeError: must be type, not classobj`
class class_A:
  def __init__( self ):
    print 'Class A'

class class_B( class_A ):
  def __init__( self ):
    print 'Class B'
    super( class_B, self ).__init__()

class_B()

# Running this code will no longer raise `TypeError: must be type, not classobj`
class class_A( object ): # < Note the inheritance of `object`. 
  def __init__( self ):
    print 'Class A'

class class_B( class_A ):
  def __init__( self ):
    print 'Class B'
    super( class_B, self ).__init__()

class_B()

Aprés un peu de débogage les classes SlicePicker, SlicePickerSingle et SlicePickerPair fonctionnent toutes 3. Voir code de la fonction draft de FastqGenerator pour les paires


In [ ]:
from ReferenceGenome import ReferenceGenome
from SlicePicker import SlicePickerPair
from QualGenerator import QualGenerator

def FastqGenerator (source, file, quality, read_len, sonic_min, sonic_max, sonic_mode, sonic_certainty, repeats, ambiguous, mut_freq):

    g = ReferenceGenome (source, file)
    print(repr(g))
    
    s = SlicePickerPair(read_len, sonic_min, sonic_max, sonic_mode, sonic_certainty, repeats, ambiguous, mut_freq)
    print(repr(s))
    
    q = QualGenerator (read_len, quality)
    print(repr(q))

    read1, read2 = s.pick_slice(g)
    read1.letter_annotations["phred_quality"] = q.random_qual_string()
    read2.letter_annotations["phred_quality"] = q.random_qual_string()
    
    read1.id = "R1"
    read2.id = "R2"

    print(read1)
    print(read2)
    
    print(read1.format("fastq-illumina"))
    print(read2.format("fastq-illumina"))
    
    return (read1, read2)

TO DO pour ce package

  • Reformatage du code pour être conforme à la norme PEP8

  • Test plus avancé des bogues possibles

2014 04 25

@ SlicePicker

Le nommage des id des reads sera fait désormais au fur et à mesure et pas uniquement dans SlicePicker. Nommage partielle dans SlicePickerPair (pas besoin dans SlicePickerSingle)

Suite formatage PEP8

@ ReferenceGenome et referenceJunction

Formatage PEP8

Ajout de commentaires dans la code

Simplification de certaines fonctions et début du nommage des id des SeqReccord.

2014 04 28

@ ConfFileParser, IsisConf

PEP8 formatting and modifications of variables

A noter qu'il existe déjà une classe de base dans python dédié au parsing des fichiers de configuration.

ConfigParser

Les 2 classes que j'ai codé semblent cependant plus adapté à mon programme, mais il faudrait peut être voir si ce n'est pas adaptable qd même.

@ SlicePicker, ReferenceGenome et ReferenceJunctions

  • Fin de formatage PEP8
  • Suppression de la mention à la source. C'est maintenant un champs dans annotations qui link directement vers l'objet contenant les références source.
  • Renommage des read générés en par des id plus simple

In [ ]:
from ReferenceGenome import ReferenceGenome
from ReferenceJunctions import ReferenceJunctions

from SlicePicker import SlicePickerSingle
from SlicePicker import SlicePickerPair

bacteria = ReferenceGenome ("datasets/Bacterial_backbone.fa")
helper = ReferenceGenome ("datasets/Helper_plasmid.fa")
junction = ReferenceJunctions(50, 200, 10, bacteria, helper, 1, 1)

slicer1 = SlicePickerSingle(200,1,1,0.1)
slicer2 = SlicePickerPair(200, 300, 700, 350, 10, 1,1,0.1)

s1b = slicer1.pick_slice (bacteria)
print "S1B\n{}\n".format(s1b)

s1j = slicer1.pick_slice (junction)
print "S1J\n{}\n".format(s1j)

s2b = slicer2.pick_slice (bacteria)
print "S2B\nR1\n{}\nR2\n{}".format(s2b[0],s2b[1])

s2j = slicer2.pick_slice (junction)
print "S2J\nR1\n{}\nR2\n{}".format(s2j[0],s2j[1])

Retour de paires sans séquence parfois pour tirage dans la référence jonction. Cela venait du fait que la junction source était trop petite en cas de grande taille de sonication. Taille minimale des jonctions = 2 taille read si single end, mais = 2 sonic_max si paired ends... Attention a faire attention dans le futur.

Script de test pour voir si plus de read vide générés après n tentatives.


In [ ]:
def test(n):
    for i in range (n):
        s2 = slicer2.pick_slice (junction)
        if len(s2 [0]) == 0:
            print "Exit at iteration {}\n".format(i)
            print("S2\nR1\n{}\nR2\n{}".format(s2[0],s2[1]))
            return
    print "All valid"
    return

@ FastQGenerator

Comme pour SlicePicker auparavant, j'ai splitté le code en 2 FastqGeneratorSingle pour les read Single et FastqGeneratorPair pour les read paired. Les classes sont fonctionnelles

@ ReferenceGenome et ReferenceJunctions

Les objets seq record possèdent désormais un compteur qui s'incrément à chaque fois qu'un read est pioché dans la référence.

@ FastqGenerator

Etant donnée que l'écriture du rapport va être plus simple maintenant, FastqGenerator va se charger de l'ecriture de n read dans le(s) fichiers de sortie. Apport des modifications nécessaires aux classes en question

Premier est grandeur nature pour les read single


In [ ]:
from ReferenceGenome import ReferenceGenome
from SlicePicker import SlicePickerSingle
from QualGenerator import QualGenerator
from FastqGenerator import FastqGeneratorSingle

helper = ReferenceGenome ("datasets/Helper_plasmid.fa")

slicer1 = SlicePickerSingle(200,1,1,0.1)
qualgen = QualGenerator (200, "good")

fast1 = FastqGeneratorSingle (slicer1, qualgen, "fastq-sanger")

fast1.write_fastq(helper, 1000, "test")

for name, rec in helper.d.items():
    print "id = {}, nb samp = {}, length = {}".format(name, rec.annotations["nb_samp"], len(rec))

Affichage de sortie

id = Helper_5, nb samp = 68, length = 1827 id = Helper_4, nb samp = 248, length = 5810 id = Helper_1, nb samp = 111, length = 2590 id = Helper_3, nb samp = 396, length = 8610 id = Helper_2, nb samp = 187, length = 3920

Le fichier fastq ont bien été créé dans le dossier. Analyse par Fastqc = très convainquant

TODO

  • Tester en pair end
  • passer en mode de génération multiproc
  • Ecrire la classe qui génére le rapport de sampling
  • Ecrire le main

2014 04 29

@ ReferenceGenome et ReferenceJunctions

Finalement j'ai remis le "name" de la source qui est en fait important pour nommer les fichiers exportés J'ai ajouté une méthode dans chacun des classe Reference pour écrire un rapport des références avec le nombre d'échantillonnage dans chacune. La fonction est différente dans ReferenceGenome et ReferenceJunctions.

Suppression de l'explication de _random_slice du code de ReferenceJunctions

Example of the strategy with size = 20 and min chimeric = 6
Junction      -----------------------------|-----------------------------
Chimeric bases                       /////////////
Start area    ///////////////ooooooo////////////////////////////////////
End area      ////////////////////////////////////ooooooo////////////////

Exemple de test de la fonction de génération de rapport de ReferenceJunctions ICI

Exemple de test de la fonction de génération de rapport de ReferenceGenome ICI

@ Isis.py

J'ai bien entamé l'écriture de la fonction principale mais il reste du boulot, notamment pour le multiprocessing et la gestion des pair vs single

2014 05 06

@ Isis.py

Ecriture des fastq directement dans une archive gz Programme fonctionnel sans utilisation de la classe de configuration, mais lent.

TODO

  • Implementer le multiprocessing
  • Simplification importante de la classe Fileparser et isisConf à l'aide de la classe de la librairie standard python ConFileParser...
  • Generation d'un rapport de distibution des fragment de sonication pour le mode pe.

2014 05 12

@ Isis.py

Implémentation de la sortie graphique de distribution de la taille des fragments avec pyplot.

Exemple de graph avec sonic min = 300, mode = 350, max = 700, certainty = 10 Pour 28 000 reads

@ IsisConf.py

Reformatage complet quasiment terminé

2014 05 13

@ IsisConf.py

Fin de reformatage de IsisConf. Desormais, la classe est plus simple et affiche seulement un message d'erreur si une option est mal paramétrée. La classe ConfFileParser a été supprimé et est maintenant remplacée par la classe de la librairy standard python ConfigParser. La gestion des exception a été ammelioré par la création d'une classe d'exception personalisée IsisConfException dont la fonction est de centralisé toute les exception possible qui peuvent intervenir pendant le parsing des options.

Reformatage en profondeur du fichier de configuration

#########################################################################################
#                                                                                      #
#   Isis.py configuration file                                                       #
#   Values can by customized with users values, but the file template must           #
#   remain unchanged                                                                   #
#   * = Changes of value are not recommended for proper programm execution           #
#                                                                                      #
#########################################################################################

[General]
### General parameters
# Overall quantity of reads (min = 1, INTEGER)
read_num : 100000
# Read length (min = 1, INTEGER)
read_len : 150
# Frequency of mutations in final reads (min = 0, max = 1, FLOAT)
mut_freq : 0.01
# Allow sampling in repeat regions identified by lowercase characters (BOOLEAN)
repeats : True
# Allow sampling in ambigous IUPAC DNA bases (BOOLEAN)
ambiguous : False

[Frequency]
### Relative frequencies of DNA source in fastq (sum of frequencies should be equal to 1)
# Host genome frequency (min = 0, max = 1, FLOAT)
freq_host : 0.49
# Virus genome frequency (min = 0, max = 1, FLOAT)
freq_virus : 0.49
# True junctions frequency (min = 0, max = 1, FLOAT)
freq_tjun : 0.01
# False junctions frequency (min = 0, max = 1, FLOAT)
freq_fjun : 0.01

[Junction]
### Parameters specific to junctions between host and viral DNA
# Minimal number bases of bases from each references in reads (min = 0, max = read size/2 for se mode, max = read_len for pe mode, INTEGER)
min_chimeric : 25
# Mean number of sampling in true junctions (min = 0, max = freq_tj * read_num, FLOAT)
samp_tjun : 20
# Mean number of sampling in false junction (min = 0, max = freq_tj * read_num, FLOAT) *
samp_fjun : 0.1

[Sonication]
## Parameters of fragment sonication distribution to set up if paired end mode
# Minimal sonication size (min = read_len + min_chimeric, max = size of reference sequences, INTEGER)
sonic_min : 200
# Minimal sonication size (min = sonic_min, max = size of reference sequences, INTEGER)
sonic_mode : 400
# Minimal sonication size (min = sonic_min, max = size of reference sequences, INTEGER)
sonic_max : 1000
# Certainty of the sonication smire (min = 5 (wide peak), max =  50 (thin peak), INTEGER) *
sonic_certainty : 8

[Quality]
# Quality score scale of fastq output file (fastq-sanger OR fastq-solexa OR fastq-illumina) *
qual_scale : fastq-sanger
# Quality range for mean Phred scores (very-good OR good OR medium OR bad OR very-bad) *
qual_range : good

Ecriture d'un petit script de test de la classe


In [ ]:
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from IsisConf import IsisConf, IsisConfException

def main ():
    """main function"""

    # Instantiate the configuration file parser/verifier
    try:
        config = IsisConf()
    except IsisConfException as E:
        print (E)
        exit (0)

    print (repr (config))

if __name__ == '__main__':
    main()

Resultats execution

./Isis.py -V Bacterial_backbone.fa -H Helper_plasmid.fa -C Conf.txt -o Test -p

Parsing and verification of config file with IsisConf
<Instance of IsisConf>
ambiguous : False
basename :  Test
conf_file : Conf.txt
host_genome :   Helper_plasmid.fa
min_chimeric :  25
mut_freq :  0.01
nread_fjun :    1000
nread_host :    49000
nread_tjun :    1000
nread_virus :   49000
pair :  True
qual_range :    good
qual_scale :    fastq-sanger
read_len :  150
read_num :  100000
repeats :   True
sonic_certainty :   8
sonic_max : 1000
sonic_min : 200
sonic_mode :    400
uniq_fjun : 10000
uniq_tjun : 50
virus_genome :  Bacterial_backbone.fa

@ Isis.py

Modification du main pour ajouter une recupération initiale de tout les paramètres utiles dans dans variables locales à partir de IsisConf

Un dossier contenant les fichiers générés par un run de test avec l'ADN genomique mm1O et le génome AAV et disponible ICI. Le temps d'execution pour les 100 000 paires de read demandé est raisonable (5 minutes) mais pourrait encore être ammelioré considérablement.

TODO

  • Verifier si le paramètre min_chimeric fonctionne corectement en pair end mode et en single end => Sortie graphique alignée sur chaque jonction ?
  • Passage en mode multi_thread de la recherche de fastq pour accelerer le traitement.

2014 05 15

En ce qui concerne la sortie permettant de verifier l'alignement sur chaque jonctions, le mieux serait de produire un fichier fasta du dictionnaire de jonctions (à implementer dans la classe Referencejunction) et un fichier SAM regroupant les reads samplés dans la jonctions en questions à partir de ça il sera simple de faire une visualisation sous igv.

2014 05 17

En reflechissant bien il serait plus pertinant de generer un graph de couverture directement dans le programme. Il me semblerait même être bien d'ajouter une option dans le fichier de configuration qui autorise on non la génération des graphiques de distribution de taille des fragments et de couverure autour des jonctions

2014 05 18

@ ReferenceJunction, ReferenceGenome, SlicePicker

La localisation des reads est maintenant donnée de façon precise pour les read issu de pair (au lieu de la position du fragment dont ils sont tirés.

La localisation est desormais toujours donnée en 5' vers 3' et l'orientation est indiquée par + ou -

@ Isis.py

Un programme tirant parti de matplotlib trace un graph de couverture à partir d'une liste indiquant la couverture à chaque position = jun_cov_graph

Les programmes write_fastq_single et write fastq_pair ont été modifié. Ils accepte maintenant une liste de source contenant : L'objet source, le nb de read a sampler et un booléen indiquant si il faut ajouter les paires au graph de couverture (True pour junctions uniquement).

Implementation de 2 options supplémentaires dans le fichier de configuration:

  • Graph : activation des sorties de visualisation graphique Si l'option est indiquée, une liste qui sera utilisée pour stocké la couverture des junction est initialisé puis complétée au fur et à mesure pendant la génération des fastq. Le graph est tracé à la fin avec la fonction jun_cov_graph Si le mode pair end est activé une distribution des fragments de sonication est également réalisé.
  • Report : Si l'option est activée un rapport d'echantillonnage dans chaque source (host, virus, tjun et fjun) est généré

Evaluation de la couverture autour de la jonction en fonction du paramètre min_chimeric:

Interpretation de la variation de min chimeric

  • En mode single end

Si min_chimeric est faible une grande latitude est laissé dans le choix de la position au dessus de la jonction. Au contraire un min_chimeric au max (read_len / 2) autorise une seule positionjuste sur le milieu de la jonction. # min_chimeric indique le minimal de base sur l'une des 2 references.#

  • En mode pair end

On observe le même phenomene, mais il y a en plus une variabilité de taille maximale causée par la distribution beta de la taille des fragments. Dans ce mode, on peut monter à max = read_len, dans ce cas, il y un read d'un coté de la jonction, et le mate toujours de l'autre coté.

2014 06 02

General modifications of read SeqRecord namming and annotations

To simplify id naming will be done just before fastq writting from the annotation dictionnary

@ ReferenceGenome and ReferenceJunction

  • Remove id naming
  • Adding object self referencement as the source of each slice generated

Exemple of origin reference sequence retrieval t


In [ ]:
s.annotations["source"] = self

In [34]:
from ReferenceGenome import ReferenceGenome as RefGen
a = RefGen("test", "../test/data/Bacterial_backbone.fa")
b = a.get_slice(100)

print(b.annotations)

str(b.annotations["source"].d[b.annotations["refseq"]].seq[b.annotations["location"][0]:b.annotations["location"][1]])


Initialisation of test...
	Extracting data
{'source': ReferenceGenome : Instance of test
ID: Bacterial_backbone
Name: Bacterial_backbone
Description: Bacterial_backbone
Number of features: 0
/nb_samp=1
Seq('atagatgatacgtagcactctaggcgtagctagactgctcgtagcatacgtacg...gca', SingleLetterAlphabet())
Lenght:1260
, 'refseq': 'Bacterial_backbone', 'orientation': '+', 'location': [465, 565]}
Out[34]:
'atacgtacgatattatcggcgatcggctaagctacgcatgactagctacgatcgtagctagctagctcgcgcatctatcagtcgactcagtagtaacgtc'

Success !!

@ SlicePicker

  • Removed source asignment as ref
  • Renaming of name

In [1]:
# VERSION SINGLE END

from ReferenceGenome import ReferenceGenome as RefGen
a = RefGen("test", "../test/data/Bacterial_backbone.fa")

from SlicePicker import SlicePickerSingle
b = SlicePickerSingle(100,1,1,0)
c = b.pick_slice(a)
print (c)

# Sequence stored in the object
print(str(c.seq))

# Sequence retrieved through annotation dictionnary
seq = c.annotations["source"].d[c.annotations["refseq"]].seq[c.annotations["location"][0]:c.annotations["location"][1]]
if c.annotations["orientation"] =='+':
    print (str(seq))
else:
    print (str(seq.reverse_complement()))


Initialisation of test...
	Extracting data
Number of features: 0
/source=<Instance of ReferenceGenome from ReferenceGenome >
/refseq=Bacterial_backbone
/Mutations=[]
/orientation=+
/location=[753, 853]
Seq('cagtcgactcagtagtaacgtcagtacgctagctcagtacgactgcatcgcgcg...cgt', SingleLetterAlphabet())
cagtcgactcagtagtaacgtcagtacgctagctcagtacgactgcatcgcgcgcatataactatctgattcggctatatatgcgcaatagatgatacgt
cagtcgactcagtagtaacgtcagtacgctagctcagtacgactgcatcgcgcgcatataactatctgattcggctatatatgcgcaatagatgatacgt

In [1]:
# VERSION PAIR END

from ReferenceGenome import ReferenceGenome as RefGen
a = RefGen("test", "../test/data/Bacterial_backbone.fa")

from SlicePicker import SlicePickerPair
b = SlicePickerPair(100,150,200,300,10,1,1,0)

c,d = b.pick_slice(a)
print (c)
print (d)

# Sequence stored in the object
print(str(c.seq))

# Sequence retrieved through annotation dictionnary
seq = c.annotations["source"].d[c.annotations["refseq"]].seq[c.annotations["location"][0]:c.annotations["location"][1]]
if c.annotations["orientation"] =='+':
    print (str(seq))
else:
    print (str(seq.reverse_complement()))

# Sequence stored in the object
print(str(d.seq))

# Sequence retrieved through annotation dictionnary
seq = d.annotations["source"].d[d.annotations["refseq"]].seq[d.annotations["location"][0]:d.annotations["location"][1]]
if d.annotations["orientation"] =='+':
    print (str(seq))
else:
    print (str(seq.reverse_complement()))


Initialisation of test...
	Extracting data
Number of features: 0
/orientation=+
/frag_len=211
/Mutations=[]
/source=<Instance of ReferenceGenome from ReferenceGenome >
/mate=R1
/location=[445, 545]
/pair_overlap=0
/refseq=Bacterial_backbone
Seq('gtagctagactgctcgtagcatacgtacgatattatcggcgatcggctaagcta...tca', SingleLetterAlphabet())
Number of features: 0
/orientation=-
/frag_len=211
/Mutations=[]
/source=<Instance of ReferenceGenome from ReferenceGenome >
/mate=R2
/location=[556, 656]
/pair_overlap=0
/refseq=Bacterial_backbone
Seq('cgcctagagtgctacgtatcatctattgcgcatatatagccgaatcagatagtt...act', SingleLetterAlphabet())
gtagctagactgctcgtagcatacgtacgatattatcggcgatcggctaagctacgcatgactagctacgatcgtagctagctagctcgcgcatctatca
gtagctagactgctcgtagcatacgtacgatattatcggcgatcggctaagctacgcatgactagctacgatcgtagctagctagctcgcgcatctatca
cgcctagagtgctacgtatcatctattgcgcatatatagccgaatcagatagttatatgcgcgcgatgcagtcgtactgagctagcgtactgacgttact
cgcctagagtgctacgtatcatctattgcgcatatatagccgaatcagatagttatatgcgcgcgatgcagtcgtactgagctagcgtactgacgttact

Possibility to recover the seq directly thought the dictionnary of annotations. Good but much heavier + do not take into acount possible mutations.

@ Isis and ReferenceJunction

Writing id generator in Isis and id origin_coord function in RefJun. Harder than I believed... It becomes insanely complicated when it comes to reads ovelapping junctions. See prototype bellow.


In [ ]:
def origin_coord (self, refseq, start, end):
        """ Return a string describing the the origin of a sequence from a
        junction of the dictionnary
        """
        # If the give coord overlap only the left reference of a junction
        if start <= end <= self.half_len:
            return ("{}-{}={}".format(
            1, end-start,
            self.coord_to_str(self.d[refseq].annotations, "ref1", start, end)))

        # If the give coord overlap only the right reference of a junction
        elif self.half_len <= start <= end:
            return ("{}-{}={}".format(
            1,end-start,
            self.coord_to_str(self.d[refseq].annotations, "ref2", start-self.half_len, end-self.half_len)))

        # If the give coord overlap both references of a junction
        else :
            return ("{}-{}={}|{}-{}={}".format(
            1,self.half_len-start,
            self.coord_to_str(self.d[refseq].annotations, "ref1", start, self.half_len-1),
            self.half_len-start+1, end-start,
            self.coord_to_str(self.d[refseq].annotations, "ref2", self.half_len, end)))

    def coord_to_str (self, d, ref, start, end, ):
        """
        """
        ref_id = d[ref+"_refseq"].id

        if d[ref+"_orientation"] == '+':
            ref_start = d[ref+"_location"][0] + start
            ref_end = d[ref+"_location"][0] + end

        else:
            ref_start = d[ref+"_location"][1] - end
            ref_end = d[ref+"_location"][1] - start

        return ("{}:{}-{}".format(ref_id, ref_start, ref_end))

 2014 06 03

@ ReferenceJunction

Test and debuging of the new functions. Few modifications had been made to the code to simplify the reaching of the original sequence through the annotation dictionnary of reads.


In [1]:
from ReferenceGenome import ReferenceGenome as RefGen
from ReferenceJunctions import ReferenceJunctions as RefJun

a = RefGen("Bact", "../test/data/Bacterial_backbone.fa")
b = RefGen("Help", "../test/data/Helper_plasmid.fa")

c = RefJun("Tjun", 50, 200, 10, a, b, 1, 1)


Initialisation of Bact...
	Extracting data
Initialisation of Help...
	Extracting data
Initialisation of Tjun...
	Creating junctions between Bact and Help

In [2]:
refseq = c.d["Junction_05"]

print ("\nJUNCTION SEQUENCE")
print (str(refseq.seq[180:219]))

print ("\nJUNCTION CARACT") 
for ref in ["ref1", "ref2"]:
    print ("{} : {} - {} ({})".format(
        refseq.annotations[ref+"_refseq"].id,
        refseq.annotations[ref+"_location"][0],
        refseq.annotations[ref+"_location"][1],
        refseq.annotations[ref+"_orientation"]))

print ("\nCOORDINATES") 
# left ref only
print(c.origin_coord(refseq, 180, 199))
# right ref only
print(c.origin_coord(refseq, 200, 219))
# Overlap both ref
print(c.origin_coord(refseq, 180, 219))


JUNCTION SEQUENCE
ctagagtgctacgtatcatcAGCGAGTATATATAGGACT

JUNCTION CARACT
Bacterial_backbone : 213 - 413 (-)
Helper_4 : 4395 - 4595 (+)

COORDINATES
0-19=Bacterial_backbone:213-233
0-19=Helper_4:4395-4415
0-19=Bacterial_backbone:213-233|20-39=Helper_4:4395-4415

 @ Isis

Test and debugging of the whole program with the the new read identifiers.

Exemple of reads extracted from R1.fastq.gz with condition that do not allow reads to overlap a junction

@virus|018|0|All=Bacterial_backbone:810-960
gatgcgcgagctagctagctacgatcgtagctagtcatgcgtagcttagccgatcgccgataatatcgtacgtatgctacgagcagtctagctacgcctagagtgctacgtatcatctattgcgcatatatagccgaatcagatagttat
+
B@?@A?A@BFFEEEEGFFFFFFFFFEEECDEEEEEDDEEEEEEEEFFFGFFEDEEEFFFFFEEEEEEDFDEFGHGGCCGFEEDDECDFHE@EGFEEEBFC?EFC:>;>E??;=F?CIHFF<?EGFDCB@AD=C>9BE8<>>?;>?GHF:;
...
@host|063|0|All=Phage_lambda_genome_J02459.1:21013-21163
AACCTGAGTCAGTTCAGTCAGGCTGGCGGCATCATTTTCCGCAAGATACGGTAATTTATTTTTCACCGTGGAAAGCCCTGCCAGCGCCGTCAGTGTCGCATTCTTCGGTTGTTTACCCGCAAGCGCGTTAGTCATGGTGGTAGCAAAATC
+
ACCBCA@B?ABBDCDGGGDFGFFFFFEFFFFFGFFFFFGFFDEEEEEEGGEBDFEEDFFGFFFGFGEFFIHIFEEEFECDECCDBFFHHGFIHFEACFGD@A<@BDFIACGCACCABA@>B>@AFDDA?C?6A=?C@<?@?<>E=DBAAC
...
@True_Junction|112|1|0-150=Helper_plasmid:19657-19808
TACGTCACTTCCCATTTTAAGAAAACTACAATTCCCAACACATACAAGTTACTCCGCCCTAAAACCTACGTCACCCGCCCCGTTCCCACGCCCCGCGCCACGTCACAAACTCCACCCCCTCATTATCATATTGGCTTCAATCCAAAATAA
+
EGB@ABBDEDDDBAADDEEEEDGFDEEEDEEFFFFFFFFFFFEEEFFEEFFFFFGEEEEEEFFGFGFGFCDEBDGDDEDFFFGECBFGFFFFEEEEBC:<?BDFDGFFDCDCAC?;=?CCBA8=D@@ACB=9C?EF>9A?BE47966H7?
...
@False_Junction|249|1|0-150=Bacterial_backbone:515-666
agtctagctacgcctagagtgctacgtatcatctattgcgcatatatagccgaatcagatagttatatgcgcgcgatgcagtcgtactgagctagcgtactgacgttactactgagtcgactgatagatgcgcgagctagctagctacga
+
AAAAA?A@A>??CDCDEEFFDECCCDDEEEEDEEEFFFGFDFEFEGGFGFFFFDEEDFHGFFFDEEEEEFHIEHGGFFIDGFHGFEDEEAA<>CFFDDCGIIBHF@HFEFC>;EGACGCCEHECAB<C<@DD9AI>=??DBIGD<5::93

Exemple of reads extracted from R1.fastq.gz with condition that allow reads to overlap a junction

...
@True_Junction|194|1|0-97=Bacterial_backbone:1144-1242|98-150=Phage_lambda_genome_J02459.1:41117-41170
CatcgtagctagctGgctcgcgcatctatcagtcgactcagtagtaacgtcagtacgctagctcagtacTactgcatcgcgcgcatataactatctgaCAGCATATTTGCTCTGGCCAATGGAGCAAAAGCGACGGGCAGGTAAAGACGT
+
A@@AABBB@ABCDDCDEEEDEEEEEEECEEEFFFFHGFFFEEFFGHGFFFFFEEEEEEEDDEEEEDEEGFGFFHGDEECCBDFFEFFFBHGB<?ECGFEEIGHHIIFB>HFDGC=<ACBHIAB@A>:C8EG=@83:<IAA?GDBFG><>
...
@False_Junction|107|1|0-4=Bacterial_backbone:1019-1024|5-150=Phage_lambda_genome_J02459.1:35573-35719
TCAGATCTCTCACCTACCATACAATGCCCCCCTGCAAAAAATAAATTCATATAAAAAACATACAGATAACCATCTGCGGTGATAAATTATCTCTGGCGGTGTTGACATAAATACCACTGGCGGTGATACTGAGCACATCAGCAGGttata
+
GECEFDDDBCBEEDDFFFFFFFDEFFGFGFEDEEEEEEEEDEEEEFFGFFFFGEEEFFFFFEEEECDEFHGGFFIIGFFHDEEBCDGGFFFHFEDDCHIGCCE@=:A@AE?DDDDB?=BHEA@?@<?GFAA?<>>CDEB9<@CGD:8FIE

@ Isis > IsisMain

Major modification of the main class.

Main() was removed to be replaced by top level instructions just bellow if __name__ == '__main__':

It has several avantage over the use of an independant main :

  • Variable declared in the section are global (same as self class variables) = less parameters to be given at function call
  • Pair end and single end processing were more clearly separed in 2 independant functions = IsisPair and IsisSingle
  • pyplot is imported only if the option GRAPH is True (reduce dependancies requirement)

 TODO

Make a doxygen complient documentation

2013 06 11

@ ReferenceGenome and ReferenceJunction

Fusion of the 2 classes in the same package and factorisation of the common code in a superclass named Reference. To be debugged = not functional for now

General

Doxygen doc is finished for all classes except SlicePicker.

2013 06 16

General

Final design diagram of the pipeline

TODO

  • Increase the speed of fastq writing by using multiprocessing features AND OR buffered file writting.
  • Improve the method to chose pairs overlapping junctions ie, modify min chimeric parameters