Ćwiczenie 3: Analiza sekwencji nukleotydowych. Tworzenie programów do analizy sekwencji DNA 1 Cel Zapoznanie się z podstawowymi funkcjami pakietu Biopython, parsowanie sekwencji z plików w formacie fasta i GenBank, tworzenie prostych programów do analizy danych biologicznych. 2 Wprowadzenie Można przyjąć, że głównym obiektem zainteresowania w bioinformatyce jest sekwencja. W związku z tym od niej rozpoczniemy przegląd możliwości jakie daje nam Biopython. Spróbujmy przypisać zmiennej moja_sek następującą sekwencję: „AGTACACTGGT”. Najpierw importujemy z modułu Bio.Seq obiekt Seq: >>> from Bio.Seq import Seq Następnie przypisujemy wyżej wspomnianą sekwencję korzystając z obiektu Seq: >>>moja_sek = Seq("AGTACACTGGT") Teraz możemy ją wywołać: >>>moja_sek Seq(’AGTACACTGGT’, Alphabet()) >>> print moja_sek AGTACACTGGT >>> moja_sek.alphabet Alphabet() Moja_sek jest obiektem o nieustalonym alfabecie, gdyż nie podaliśmy, czy ma to być DNA czy białko. Poza tym, że Seq posiada alfabet, różni się on od zwykłego ciągu znaków w Pythonie. Dla ciągu znaków nie byłoby możliwości uzyskania zasad komplementarnych: >>> moja_sek.complement() Seq(’TCATGTGACCA’, Alphabet()) czy też zasad komplementarnych w odwróconej sekwencji: >>>moja_sek.reverse_complement() Seq(’ACCAGTGTACT’, Alphabet()) Duża część zadań bioinformatycznych związana jest z obróbką rekordów sekwencji, które zapisywane są w postaci wielu różnych formatów plików. Rekordy te zawierają cenne i interesujące informacje biologiczne, ale zanim będą mogły być opracowywane za pomocą języka programowania (takiego jak Python), konieczne jest poddanie ich tzw. parsingowi. Obecnie zapoznamy się z modułem Bio.SeqIO. Dla przykładu wczytamy plik w formacie fasta o nazwie termit (4 sekwencje będące wynikiem przeszukiwania bazy danych NCBI Nucleotide dla kwerendy „Serritermitidae”). W tym celu wpisujemy następujący kod: >>>from Bio import SeqIO 1 >>> for rekord_sek in SeqIO.parse("termit.fasta", "fasta"): print rekord_sek.id print repr(rekord_sek.seq) print len(rekord_sek) W rezultacie powinniśmy otrzymać następujący wynik: gi|48476610|gb|AY553161.1| Seq('CACCCAGAAGTATATATTTTGATTCTACCAGGATTTGGTATAATTTCTCACATC...ATC', SingleLetterAlphabet()) 816 gi|8886830|gb|AF220598.1| Seq('ATGGCAACATGAATAAACCTTAATCTCCAAGACGGAGCATCCCCAATCATAGAA...GAG', SingleLetterAlphabet()) 667 gi|8886805|gb|AF220565.1| Seq('AATGGCTCATTAAATCAGTTATGGTTCCTTAGATGGTGGACAGTTACTTGGATA...AGG', SingleLetterAlphabet()) 1718 gi|12965151|gb|AF262577.1|AF262577 Seq('TATTTCCCGATTTTGGAGGAGTTAACAATTGGTGTGTTGTTTATTGTTTTATAA...GAT', SingleLetterAlphabet()) 818 Zauważmy, że format FASTA nie specyfikuje alfabetu, dlatego Bio.SeqIO wybrał domyślną opcję SingleLetterAlphabet(), raczej niż specyficzny kod dla DNA. Spróbujmy teraz wczytać ten sam plik w formacie GenBank. Jedyna różnica jaka pojawia się w tym wypadku dotyczy rozszerzenia pliku (.gb) oraz formatu („genbank”, zamiast „fasta” ): >>>for rekord_sek in SeqIO.parse("termit.gb", "genbank"): print rekord_sek.id print repr(rekord_sek.seq) print len(rekord_sek) Powinniśmy otrzymać następujący wynik: AY553161.1 Seq('CACCCAGAAGTATATATTTTGATTCTACCAGGATTTGGTATAATTTCTCACATC...ATC', IUPACAmbiguousDNA()) 816 AF220598.1 Seq('ATGGCAACATGAATAAACCTTAATCTCCAAGACGGAGCATCCCCAATCATAGAA...GAG', IUPACAmbiguousDNA()) 667 AF220565.1 Seq('AATGGCTCATTAAATCAGTTATGGTTCCTTAGATGGTGGACAGTTACTTGGATA...AGG', IUPACAmbiguousDNA()) 1718 AF262577.1 Seq('TATTTCCCGATTTTGGAGGAGTTAACAATTGGTGTGTTGTTTATTGTTTTATAA...GAT', IUPACAmbiguousDNA()) 818 Zauważmy, że tym razem (IUPACAmbiguousDNA()) . Bio.SeqIO był w stanie wybrać sensowny alfabet 3.1 Sekwencje i alfabety Obiekt alfabet jest w zasadzie głównym elementem obiektu Seq, który odróżnia go od zwykłego ciągu znaków (string). Obecnie dostępne alfabety w Biopythonie są zawarte w module Bio.Alphabet. Przy analizie sekwencji DNA, RNA i białek, będziemy korzystać z alfabetów IUPAC (Międzynarodowa Unia Chemii Czystej i Stosowanej). Bio.Alphabet.IUPAC dostarcza podstawowe typy alfabetów dla białek, DNA i RNA, ale dodatkowo umożliwia też ich modyfikację i 2 dostosowywanie do własnych potrzeb. Np. dla białek istnieje podstawowa klasa IUPACProtein, ale jest też specjalna klasa ExtendedIUPACProtein obejmująca elementy „U” (lub „Sec” dla selenocysteiny) i „O” (lub „Pyr” dla pirolizyny), a także niejednoznaczne symbole „B” (lub „Asx” dla asparaginy lub kwasu asparaginowego), „Z” (lub „Glx” dla glutaminy lub kwasu glutaminowego”), „J” (lub „Xle” dla leucyny lub izoleucyny) oraz „X” (lub „Xxx” dla nieznanego aminokwasu). Dla DNA można wybrać alfabet IUPACUnabiguousDNA, który uwzględnia tylko podstawowe zasady, IUPACAmbiguousDNA (który uwzględnia wszystkie zasady niejednoznaczne) oraz ExtendedIUPACDNA, który zezwala na stosowanie liter dla zmodyfikowanych zasad. Podobnie dla RNA mamy alfabety IUPACAmbiguousRNA i IUPACUnambiguousRNA. Korzyści płynące z obecności klasy typu alfabet są dwojakiego rodzaju. Po pierwsze pozwala to na uwzględnienie rodzaju informacji (sekwencji) zawartej w postaci obiektu Seq. Po drugie, umożliwia ograniczenie typu informacji i służyć może jako narzędzie sprawdzające typ sekwencji. Sekwencję niejednoznaczną z domyślnym ogólnym alfabetem tworzymy w następujący sposób: >>> from Bio.Seq import Seq >>> moja_sek = Seq("AGTACACTGGT") >>> moja_sek Seq('AGTACACTGGT', Alphabet()) >>> moja_sek.alphabet Alphabet() Zawsze powinniśmy podać rodzaj stosowanego alfabetu tam, gdzie to możliwe: >>> from Bio.Alphabet import IUPAC >>> moja_sek = Seq("AGTACACTGGT", IUPAC.unambiguous_dna) >>> moja_sek Seq('AGTACACTGGT', IUPACUnambiguousDNA()) >>> moja_sek.alphabet IUPACUnambiguousDNA() Jeżeli byłby to łańcuch aminokwasowy, mielibyśmy: >>> from Bio.Alphabet import IUPAC >>> moje_bialko = Seq("AGTACACTGGT", IUPAC.protein) >>> moje_bialko Seq('AGTACACTGGT', IUPACProtein()) >>> moje_bialko.alphabet IUPACProtein() W wielu przypadkach możemy postępować z obiektem Seq, tak jak byłby to zwykły ciąg znaków. Możemy np. określić jego długość itp.: >>>from Bio.Seq import Seq >>>from Bio.Alphabet import IUPAC >>>moja_sek = Seq("GATCGATGGGCCTATATAGGATCGAAAATCGC", IUPAC.unambiguous_dna) >>>for indeks, litera in enumerate(moja_sek): print indeks, litera print len(litera) Otrzymamy wówczas zestawienie wszystkich indeksów, zasad oraz długości ciągów zasad. Można też odwoływać, się do poszczególnych elementów sekwencji poprzez ich indeksy: >>> print moja_sek[0] G >>> print moja_sek[2] T 3 >>> print moja_sek[-1] C Ostatnia komenda przywołuje ostatnią zasadę. Podobnie jak w przypadku ciągu znaków w Pythonie, można zliczać ile razy występuje dany element: >>> "AAAA".count("AA") 2 >>> Seq("AAAA").count("AA") 2 Jednak w niektórych przypadkach potrzebne może nam być określenie liczby zachodzących na siebie elementów. Przy pojedynczym znaku nie ma to znaczenia: >>> len(moja_sek) 32 >>> moja_sek.count("G") 9 >>> 100 * float(moja_sek.count("G") + moja_sek.count("C")) / len(moja_sek) 46.875 Ostatnia komenda w powyższym kodzie wylicza procent zasad G i C w sekwencji. Zamiast tego, można wykorzystać wbudowaną funkcję zliczającą procent zasad G i C: >>> from Bio.SeqUtils import GC >>> moja_sek = Seq("GATCGATGGGCCTATATAGGATCGAAAATCGC", IUPAC.unambiguous_dna) >>> GC(moja_sek) 46.875 Zauważmy, że funkcja Bio.SeqUtils.GC() obsługuje także sekwencje pisane raz małymi, raz dużymi literami oraz zawierające symbol S, dla oznaczenia G lub C. 3.2 Zadania 1. Napisz skrypt o nazwie pobieranie.py, który będzie parsował sekwencję o ścieżce dostępu (np. C:\Users\Public\....) i formacie (fasta, genbank) podanym przez użytkownika. Przykładowy efekt działania skryptu powinien być następujący: Podaj nazwe pliku lub sciezke:C:\Users\daniel\Desktop\sekwencja.fasta Podaj format pliku:fasta gi|2765658|emb|Z78533.1|CIZ78533 Seq('CGTAACAAGGTTTCCGTAGGTGAACCTGCGGAAGGATCATTGATGAGACCGTGG...CGC', SingleLetterAlphabet()) 740 gi|2765657|emb|Z78532.1|CCZ78532 Seq('CGTAACAAGGTTTCCGTAGGTGAACCTGCGGAAGGATCATTGTTGAGACAACAG...GGC', SingleLetterAlphabet()) 753 gi|2765656|emb|Z78531.1|CFZ78531 Seq('CGTAACAAGGTTTCCGTAGGTGAACCTGCGGAAGGATCATTGTTGAGACAGCAG...TAA', SingleLetterAlphabet()) …. 2. Napisz skrypt o nazwie odwrocona.py, który będzie podawał sekwencję komplementarną i odwróconą sekwencję komplementarną do sekwencji zadanej przez użytkownika. Przykładowy efekt działania skryptu powinien być następujący: 4 Podaj sekwencje DNA: TTTTTGGGGCAAATGCAAATGTCAA Sewencja komplementarna to: AAAAACCCCGTTTACGTTTACAGTT Sekwencja komplementarna odwrocona to: TTGACATTTGCATTTGCCCCAAAAA 3. Rozszerz powyższy skrypt o następujące elementy: zadeklarowanie przez użytkownika rodzaju alfabetu, podanie przez skrypt nazwy wybranego alfabetu, długości sekwencji, pierwszej i ostatniej litery tej sekwencji, a także wyliczenie procentu zasad AT (zakładamy, że mamy do czynienia z sekwencją nukleotydową). Przykładowy efekt powinien być następujący: Podaj sekwencje DNA: GGGTACAGTTCAAGTGTAACA Podaj rodzaj alfabetu: IUPAC.unambiguous_dna Sekwencja komplementarna to: CCCATGTCAAGTTCACATTGT Sekwencja komplementarna odwrocona to: TGTTACACTTGAACTGTACCC Rodzaj wybranego alfabetu to: IUPACUnambiguousDNA() Dlugosc sekwencji: 21 , Pierwsza litera to: G Ostatnia litera to: A , Procent zasad AT: 57.1428571429 4.1 Wycinanie fragmentów sekwencji Spróbujemy teraz wyciąć fragment sekwencji: >>>from Bio.Seq import Seq >>>moja_sek = Seq("GATCGATGGGCCTATATAGGATCGAAAATCGC", IUPAC.unambiguous_dna) >>> moja_sek[4:12] Seq(’GATGGGCC’, IUPACUnambiguousDNA()) Pierwszym elementem powyższej sekwencji jest 0. Przy wycinaniu pierwszy element jest włączany do nowej sekwencji, a ostatni pomijany. Np. w powyższym przykładzie 4. element zostaje, a 12 jest pomijany. Ponadto, nowo utworzona sekwencja jest znowu obiektem Seq zachowującym alfabet pierwotnej sekwencji. Podobnie jak w Pythonie, można użyć do wycinania sekwencji opcje start, stop i stride (wielkość kroku wybrana domyślnie jako 1). Możemy np. uzyskać pozycje 1., 2. i 3. kodonu sekwencji: >>> moja_sek[0::3] Seq(’GCTGTAGTAAG’, IUPACUnambiguousDNA()) >>> moja_sek[1::3] Seq(’AGGCATGCATC’, IUPACUnambiguousDNA()) >>> moja_sek[2::3] Seq(’TAGCTAAGAC’, IUPACUnambiguousDNA()) Poza tym można odwrócić sekwencję stosując ujemny krok (stride=-1): >>> moja_sek[::-1] Seq(’CGCTAAAAGCTAGGATATATCCGGGTAGCTAG’, IUPACUnambiguousDNA()) 4.2 Zamiana obiektów Seq na ciągi znaków Jeżeli chcemy zamienić obiekt Seq na zwykły ciąg znaków (string) stosujemy funkcję str: >>> str(moja_sek) ’GATCGATGGGCCTATATAGGATCGAAAATCGC’ Można w tym celu wykorzystać także funkcję print: >>> print moja_sek GATCGATGGGCCTATATAGGATCGAAAATCGC 5 Obiekt Seq można także stosować bezpośrednio ze znakiem %s przy formatowaniu ciągu znaków w Pythonie lub z operatorem interpolacji %: >>> fasta_format_string = ">Nazwa\n%s\n" % moja_sek >>> print fasta_format_string >Nazwa GATCGATGGGCCTATATAGGATCGAAAATCGC Powyższy kod generuje prosty rekord w formacie FASTA. 4.3 Zadania 1. Utwórz skrypt o nazwie wycinek.py, który będzie wycinał fragment o podanych przez użytkownika współrzędnych (indeks początkowy i końcowy) z sekwencji także podanej przez użytkownika. Zastosuj przy tym alfabet IUPAC.unambiguous_dna. Przykładowy efekt powinien być następujący: Podaj sekwencje DNA: CCAAATGTTACTTAGCT Podaj indeks poczatkowy: 4 Podaj indeks koncowy: 12 Wyciety fragment to: ATGTTACT 2. Utwórz nowy skrypt krok.py, który dla zadanej przy użytkownika sekwencji będzie podwał co trzecią zasadę począwszy od 1,2 i 3 litery sekwencji, a na końcu odwróci tą sekwencję. Skorzystaj przy tym z alfabetu IUPAC.unambiguous_dna. Przykładowy rezultat powinien wyglądać następująco: Podaj sekwencje DNA: GGGTACGGTAAACGT Kolejne zasady poczawszy od 0 przy kroku rownym 3: GTGAC Kolejne zasady poczawszy od 1 przy kroku rownym 3: GAGAG Kolejne zasady poczawszy od 2 przy kroku rownym 3: GCTAT Sekwencja odwrocona: TGCAAATGGCATGGG 5.1 Łączenie i dodawanie sekwencji Obiekty Seq mogą być ze sobą łączone tak, jak łączy się w Pythonie zwykłe ciągi znaków. Nie można jednak łączyć ze sobą sekwencji o niekompatybilnych alfabetach (np. sekwencja białkowa i nukleotydowa). Gdyby jednak bardzo nam na tym zależało, to najpierw należy przypisać obu sekwencjom alfabet ogólny (generic alphabet). Poniższy przykład dotyczy dodania sekwencji DNA z alfabetem ogólnym do sekwencji DNA z alfabetem jednoznacznym IUPAC, co daje w rezultacie sekwencję z alfabetem niejednoznacznym: >>> from Bio.Seq import Seq >>> from Bio.Alphabet import generic_nucleotide >>> from Bio.Alphabet import IUPAC >>> nuk_sek = Seq("GATCGATGC", generic_nucleotide) >>> dna_sek = Seq("ACGT", IUPAC.unambiguous_dna) >>> nuk_sek Seq(’GATCGATGC’, NucleotideAlphabet()) >>> dna_sek Seq(’ACGT’, IUPACUnambiguousDNA()) >>> nuk_sek + dna_sek Seq(’GATCGATGCACGT’, NucleotideAlphabet()) 6 5.2 Zmiana wielkości znaków Python posiada bardzo użyteczną funkcję zmiany wielkości znaków w ciągu znaków. To samo można wykonać w Biopythonie dla obiektu Seq, przy czym brany jest pod uwagę rodzaj alfabetu: >>> from Bio.Seq import Seq >>> from Bio.Alphabet import generic_dna >>> dna_sek = Seq("acgtACGT", generic_dna) >>> dna_sek Seq(’acgtACGT’, DNAAlphabet()) >>> dna_sek.upper() Seq(’ACGTACGT’, DNAAlphabet()) >>> dna_sek.lower() Seq(’acgtacgt’, DNAAlphabet()) Opcja ta jest użyteczna przy przeszukiwaniu sekwencji bez względu na wielkość znaków: >>> "GTAC" in dna_sek False >>> "GTAC" in dna_sek.upper() True Należy zwrócić uwagę, że alfabety IUPAC funkcjonują tylko dla sekwencji pisanych dużymi literami: >>> from Bio.Seq import Seq >>> from Bio.Alphabet import IUPAC >>> dna_sek = Seq("ACGT", IUPAC.unambiguous_dna) >>> dna_sek Seq(’ACGT’, IUPACUnambiguousDNA()) >>> dna_sek.lower() Seq(’acgt’, DNAAlphabet()) 5.3 Uzyskiwanie sekwencji komplementarnych i komplementarnych odwróconych Możliwe jest uzyskiwanie sekwencji komplementarnych lub komplementarnych odwróconych dla obiektu Seq: >>> from Bio.Seq import Seq >>> from Bio.Alphabet import IUPAC >>> moja_sek = Seq("GATCGATGGGCCTATATAGGATCGAAAATCGC", IUPAC.unambiguous_dna) >>> moja_sek Seq(’GATCGATGGGCCTATATAGGATCGAAAATCGC’, IUPACUnambiguousDNA()) >>> moja_sek.complement() Seq(’CTAGCTACCCGGATATATCCTAGCTTTTAGCG’, IUPACUnambiguousDNA()) >>> moja_sek.reverse_complement() Seq(’GCGATTTTCGATCCTATATAGGCCCATCGATC’, IUPACUnambiguousDNA()) Jak już wspomnieliśmy, najprostszą metodą odwrócenia sekwencji jest jej wycięcie przy kroku równym -1: >>> moja_sek[::-1] Seq(’CGCTAAAAGCTAGGATATATCCGGGTAGCTAG’, IUPACUnambiguousDNA()) We wszystkich powyższych operacjach zachowywana jest informacja o alfabecie. Ma to zastosowanie na wypadek, gdybyśmy np. niechcący spróbowali uzyskać sekwencję komplementarną do aminokwasowej: 7 >>> from Bio.Seq import Seq >>> from Bio.Alphabet import IUPAC >>> sek_bialkowa = Seq("EVRNAK", IUPAC.protein) >>> sek_bialkowa.complement() ... ValueError: Proteins do not have complements! 5.4 Zadania 1. Napisz skrypt (dowolna nazwa), który będzie łączył dwie sekwencje nukleotydowe podane przez użytkownika skryptu (skorzystaj z alfabetu generic_nucleotide), poda połączoną sekwencję, zmieni wielkość liter tej sekwencji na małe, pozwoli stwierdzić, czy w ramach tej sekwencji występuje zadana przez użytkownika krótsza sekwencja, a na końcu poda sekwencję komplementarną i komplementarną odwróconą. Przykładowy wynik działania takiego skryptu: Podaj pierwsza sekwencje: gtttgattcgt Podaj druga sekwencje: aaacccgtaagc Sekwencja polaczona: gtttgattcgtaaacccgtaagc Sekwencja pisana malymi literami: gtttgattcgtaaacccgtaagc Podaj fragment do wyszukiwania (male litery): aaa True Sekwencja komplementarna: caaactaagcatttgggcattcg i komplementarna odwrocona: gcttacgggtttacgaatcaaac 6.1 Transkrypcja Przejdziemy teraz do transkrypcji. Na początku należy zauważyć, że w naturze transkrypcja odbywa się w oparciu o nić komplementarną do kodującej, podczas gdy w bioinformatyce pracujemy bezpośrednio na nici kodującej. Wynika to z faktu, że w ten sposób można łatwo przepisać DNA na RNA zamieniając T na U. Zanim dokonamy transkrypcji utwórzmy obiekty Seq dla nici kodującej i komplementarnej: >>> from Bio.Seq import Seq >>> from Bio.Alphabet import IUPAC >>> kodujacy_dna = Seq("ATGGCCATTGTAATGGGCCGCTGAAAGGGTGCCCGATAG", IUPAC.unambiguous_dna) >>> kodujacy_dna Seq(’ATGGCCATTGTAATGGGCCGCTGAAAGGGTGCCCGATAG’, IUPACUnambiguousDNA()) >>> matrycowy_dna = kodujacy_dna.reverse_complement() >>> matrycowy_dna Seq(’CTATCGGGCACCCTTTCAGCGGCCCATTACAATGGCCAT’, IUPACUnambiguousDNA()) Teraz przepiszemy nić kodującą DNA na mRNA korzystając z wbudowanej metody transcribe: >>> kodujacy_dna Seq(’ATGGCCATTGTAATGGGCCGCTGAAAGGGTGCCCGATAG’, IUPACUnambiguousDNA()) >>> informacyjny_rna = kodujacy_dna.transcribe() >>> informacyjny_rna Seq(’AUGGCCAUUGUAAUGGGCCGCUGAAAGGGUGCCCGAUAG’, IUPACUnambiguousRNA()) Jak widać w powyższym przykładzie, wszystko co czyni metoda transcribe polega na zamianie T na U i dostosowaniu alfabetu. Gdybyśmy jednak chcieli dokonać prawdziwej transkrypcji na nici matrycowej, to można to wykonać w dwóch następujących etapach: 8 >>> matrycowy_dna.reverse_complement().transcribe() Seq(’AUGGCCAUUGUAAUGGGCCGCUGAAAGGGUGCCCGAUAG’, IUPACUnambiguousRNA()) Obiekt Seq umożliwia także odwrotną transkrypcję z mRNA na kodującą nić DNA, co znowu polega na zamianie U na T i dostosowaniu alfabetu: >>> from Bio.Seq import Seq >>> from Bio.Alphabet import IUPAC >>> informacyjny_rna = Seq("AUGGCCAUUGUAAUGGGCCGCUGAAAGGGUGCCCGAUAG", IUPAC.unambiguous_rna) >>> informacyjny_rna Seq(’AUGGCCAUUGUAAUGGGCCGCUGAAAGGGUGCCCGAUAG’, IUPACUnambiguousRNA()) >>> informacyjny_rna.back_transcribe() Seq(’ATGGCCATTGTAATGGGCCGCTGAAAGGGTGCCCGATAG’, IUPACUnambiguousDNA()) 6.2 Translacja Pozostając przy tym samym przykładzie, co przy transkrypcji spróbujemy teraz przepisać mRNA na białko: >>> from Bio.Seq import Seq >>> from Bio.Alphabet import IUPAC >>> informacyjny_rna = Seq("AUGGCCAUUGUAAUGGGCCGCUGAAAGGGUGCCCGAUAG", IUPAC.unambiguous_rna) >>> informacyjny_rna Seq(’AUGGCCAUUGUAAUGGGCCGCUGAAAGGGUGCCCGAUAG’, IUPACUnambiguousRNA()) >>> informacyjny_rna.translate() Seq(’MAIVMGR*KGAR*’, HasStopCodon(IUPACProtein(), ’*’)) Można także dokonać translacji bezpośrednio z kodującej nici DNA: >>> from Bio.Seq import Seq >>> from Bio.Alphabet import IUPAC >>> kodujacy_dna = Seq("ATGGCCATTGTAATGGGCCGCTGAAAGGGTGCCCGATAG", IUPAC.unambiguous_dna) >>> kodujacy_dna Seq(’ATGGCCATTGTAATGGGCCGCTGAAAGGGTGCCCGATAG’, IUPACUnambiguousDNA()) >>> kodujacy_dna.translate() Seq(’MAIVMGR*KGAR*’, HasStopCodon(IUPACProtein(), ’*’)) Zauważmy, że w powyższej sekwencji oprócz końcowego kodonu stop, występuje kodon stop wewnątrz sekwencji (oznaczony gwiazdką). Przykład ten ilustruje konsekwencje stosowania różnych rodzajów kodu genetycznego przy tłumaczeniu sekwencji nukleotydowej na białko. Rodzaje kodu genetycznego stosowane w Biopythonie są zgodne ze standardem NCBI. Załóżmy, że mamy do czynienia z sekwencją mitochondrialną. Musimy wybrać odpowiedni kod genetyczny: >>> kodujacy_dna.translate(table="Vertebrate Mitochondrial") Seq(’MAIVMGRWKGAR*’, HasStopCodon(IUPACProtein(), ’*’)) Rodzaj kodu genetycznego można podać też stosując jego numer wg NCBI. Poza tym, numer ten podawany jest często w plikach sekwencji GenBank: >>> kodujacy_dna.translate(table=2) Seq(’MAIVMGRWKGAR*’, HasStopCodon(IUPACProtein(), ’*’)) Teraz możemy dokonać translacji do momentu wystąpienia pierwszego kodonu stop, czyli tak jak 9 dzieje się to w naturze: >>> kodujacy_dna.translate() Seq(’MAIVMGR*KGAR*’, HasStopCodon(IUPACProtein(), ’*’)) >>> kodujacy_dna.translate(to_stop=True) Seq(’MAIVMGR’, IUPACProtein()) >>> kodujacy_dna.translate(table=2) Seq(’MAIVMGRWKGAR*’, HasStopCodon(IUPACProtein(), ’*’)) >>> kodujacy_dna.translate(table=2, to_stop=True) Seq(’MAIVMGRWKGAR’, IUPACProtein()) Zauważmy, że przy korzystaniu z argumentu to_stop kodon stop nie ulega translacji i znak kodonu stop nie pojawia się w sekwencji. Można także samemu określić symbol kodonu stop, jeśli nie podoba nam się domyślna gwiazdka: >>> kodujacy_dna.translate(table=2, stop_symbol="@") Seq(’MAIVMGRWKGAR@’, HasStopCodon(IUPACProtein(), ’@’)) Załóżmy teraz, że mamy do czynienia z regionem kodującym CDS (mRNA po splicingu), składającym się z samych kodonów, zaczynającym się od kodonu start i kończącym się kodonem stop, bez wewnętrznych kodonów stop. Zazwyczaj domyślna opcja translacji z zastosowanym argumentem to_stop da oczekiwany wynik, ale w niektórych przypadkach mamy do czynienia z niestandardowym kodem genetycznym, jak w przypadku bakterii. >>>from Bio.Alphabet import generic_dna >>>gen=Seq("GTGAAAAAGATGCAATCTATCGTACTCGCACTTTCCCTGGTTCTGGTCGCTCCCATGGCA GCACAGGCTGCGGAAATTACGTTAGTCCCGTCAGTAAAATTACAGATAGGCGATCGTGATAATCGTGGCT ATTACTGGGATGGAGGTCACTGGCGCGACCACGGCTGGTGGAAACAACATTATGAATGGCGAGGCAATC GCTGGCACCTACACGGACCGCCGCCACCGCCGCGCCACCATAAGAAAGCTCCTCATGATCATCACGGC GGTCATGGTCCAGGCAAACATCACCGCTAA", generic_dna) >>> gen.translate(table="Bacterial") Seq(’VKKMQSIVLALSLVLVAPMAAQAAEITLVPSVKLQIGDRDNRGYYWDGGHWRDH...HR*’, HasStopCodon(ExtendedIUPACProtein(), ’*’) >>> gen.translate(table="Bacterial", to_stop=True) Seq(’VKKMQSIVLALSLVLVAPMAAQAAEITLVPSVKLQIGDRDNRGYYWDGGHWRDH...HHR’, ExtendedIUPACProtein()) W kodzie genetycznym bakterii GTG jest kodonem startowym i podczas, gdy normalnie koduje walinę, w tym wypadku koduje metioninę. Efekt taki uzyskamy, jeśli zaznaczymy, że mamy do czynienia z kompletnym CDS: >>> gen.translate(table="Bacterial", cds=True) Seq(’MKKMQSIVLALSLVLVAPMAAQAAEITLVPSVKLQIGDRDNRGYYWDGGHWRDH...HHR’, ExtendedIUPACProtein()) Oprócz tego, że poprawnie została dokonana translacja, stosując argument cds=True, mamy pewność, że podany fragment sekwencji jest rzeczywiście regionem kodującym. Jeśli tak nie jest, zostaniemy o tym powiadomieni. 6.3 Tabele translacji Przy translacji sekwencji nukleotydowych wykorzystywane są tabele translacji zgodne ze standardem NCBI. Obecnie skupimy się na dwóch rodzajach kodu genetycznego: standardowym i mitochondrialnym kręgowców: 10 >>> from Bio.Data import CodonTable >>> standard_table = CodonTable.unambiguous_dna_by_name["Standard"] >>> mito_table = CodonTable.unambiguous_dna_by_name["Vertebrate Mitochondrial"] Zamiast podawać pełne nazwy, można podać numery typów kodu genetycznego: >>> from Bio.Data import CodonTable >>> standard_table = CodonTable.unambiguous_dna_by_id[1] >>> mito_table = CodonTable.unambiguous_dna_by_id[2] Można porównać tabele kodu genetycznego drukując je: >>>print standard_table Table 1 Standard, SGC0 ….... >>> print mito_table Table 2 Vertebrate Mitochondrial, SGC1 ….. Powyższe zestawienia są użyteczne, np. jeśli sami chcemy analizować sekwencje pod kątem występowania genów: >>> mito_table.stop_codons [’TAA’, ’TAG’, ’AGA’, ’AGG’] >>> mito_table.start_codons [’ATT’, ’ATC’, ’ATA’, ’ATG’, ’GTG’] >>> mito_table.forward_table["ACG"] ’T’ 6.4 Zadania 1. Napisz skrypt translacja.py, dokonujący transkrypcji, a następnie translacji sekwencji pierwszego rekordu w pliku sekwencja.fasta, tak, aby użytkownik mógł wybrać rodzaj tabeli translacji. Translacja ma przebiegać do momentu wystąpienia pierwszego kodonu stop. Skrypt ma podawać długość sekwencji mRNA oraz białka. Wykorzystaj następujący fragment kodu w celu przypisania zmiennej dna sekwencji z pierwszego rekordu ww. pliku, wstawiając za „ścieżka dostępu” właściwą ścieżkę: >>>from Bio import SeqIO >>>rekord_iterator = SeqIO.parse("ścieżka dostępu", "fasta") >>>pierwszy_rekord = rekord_iterator.next() >>>dna=pierwszy_rekord.seq Efekt działania skryptu powinien być następujący: mRNA: CACCCAGAAGUAUAUAUUUUGAUUCUACCAGGAUUUGGUAUAAUUUCUCACAUCAUCUGCCACGAGA GAGGUAAAAAGGAAGCCUUCGGAAACUUAGGAAUAAUUUUCGCCAUACUAGCAAUUGGCCUACUAGG …...... 11 Dlugosc mRNA: 816 zasad Podaj numer tabeli translacji: 1 bialko: HPEVYILILPGFGIISHIICHERGKKEAFGNLGIIFAILAIGLLGFVV Dlugosc bialka: 48 aminokwasow Porównaj wynik działania skryptu dla tabeli translacji =1 i 2. Czy rezultat jest taki sam? 2. Napisz podobny skrypt o nazwie odwrotna_transkrypcja.py, który będzie dokonywał transkrypcji sekwencji DNA wczytanej z pliku sekwencja.fasta, a następnie dokonywał odwrotnej transkrypcji powstałego mRNA. Przykładowy efekt działania skryptu: mRNA: CACCCAGAAGUAUAUAUUUUGAUUCUACCAGGAUUUGGUAUAAUUUCUCACAUCAUCUGCCACGAGA GAGGUAAAAAGGAAGCCUUCGGAAACUUAGGAAUAAUUUUCGCCAUACUAGCAAUUGGCCUACUAGG ....... Dlugosc mRNA: 816 zasad Wynik odrotnej transkrypcji: CACCCAGAAGTATATATTTTGATTCTACCAGGATTTGGTATAATTTCTCACATCATCTGCCACGAGAGAGGT AAAAAGGAAGCCTTCGGAAACTTAGGAATAATTTTCGCCATACTAGCAATTGGCCTACTAGGATTTGTGGT. ...... Dlugosc DNA: 816 zasad 7.1 Porównywanie obiektów Seq Ogólnie rzecz biorąc, porównywanie sekwencji jest bardzo złożonym problemem i nie ma łatwego sposobu stwierdzenia, czy dwie sekwencje są jednakowe. Podstawowym problemem jest to, że znaczenie litery w sekwencji zależy od jej rodzaju – czy jest to DNA, RNA czy białko. Biopython wykorzystuje obiekty alfabetu jako część każdego obiektu Seq, w celu próby uchwycenia tej informacji. Tak więc porównywanie dwóch obiektów Seq oznacza porównanie ich sekwencji jak i alfabetów. Np. można sądzić, że dwie sekwencje DNA (obiekty Seq): Seq("ACGT", IUPAC.unambiguous dna) i Seq("ACGT", IUPAC.ambiguous dna) są jednakowe, chociaż posiadają różne alfabety. W zależności od rodzaju sekwencji może to być ważna informacja. Problem może się jeszcze bardziej skomplikować. Załóżmy, że dwa obiekty Seq: Seq("ACGT", IUPAC.unambiguous dna) i Seq("ACGT") (tj. domyślny alfabet ogólny) powinny być jednakowe. Wtedy, logicznie rzecz biorąc obiekty Seq("ACGT", IUPAC.protein) and Seq("ACGT") też powinny być jednakowe. W logice jeśli A=B i B=C, to A=C. Tak więc idąc tym tropem powinniśmy uznać, że Seq("ACGT", IUPAC.unambiguous dna) i Seq("ACGT", IUPAC.protein) są jednakowe, co większość ludzi uzna za błąd. Ten problem ma również swoje implikacje przy stosowaniu obiektów Seq jako kluczy słowników Pythona. Więc co robi Biopython? Test równości jest opcją domyślną obiektów Pythona – sprawdza on w pamięci czy ma do czynienia z tymi samymi obiektami. Jest to bardzo restrykcyjny test: >>> from Bio.Seq import Seq >>> from Bio.Alphabet import IUPAC >>> sek1 = Seq("ACGT", IUPAC.unambiguous_dna) >>> sek2 = Seq("ACGT", IUPAC.unambiguous_dna) >>> sek1 == sek2 False >>> sek1 == sek1 True W tym samym celu można wykorzystać funkcję id Pythona: 12 >>> id(sek1) == id(sek2) False >>> id(sek1) == id(sek1) True W codziennym użytkowaniu najczęściej mamy do czynienia z tym samym alfabetem, lub co najmniej z tym samym typem sekwencji (DNA, RNA lub białko). W związku z tym, w celu sprawdzenia, czy sekwencje są jednakowe, porównujemy je jako ciągi znaków (strings): >>> str(sek1) == str(sek2) True >>> str(sek1) == str(sek1) True 7.2 Obiekty MutableSeq Tak jak w przypadku zwykłego ciągu znaków w Pythonie, obiekt Seq może być tylko odczytywany, czyli w terminologii Pythona jest nieodmienny. Oprócz tego, że chcemy, aby obiekt Seq funkcjonował jako ciąg znaków, ta funkcja domyślna jest także pożyteczna z innego powodu – w wielu zastosowaniach biologicznych zależy nam na tym, aby analizowana sekwencja nie uległa modyfikacji: >>> from Bio.Seq import Seq >>> from Bio.Alphabet import IUPAC >>> moja_sek = Seq("GCCATTGTAATGGGCCGCTGAAAGGGTGCCCGA", IUPAC.unambiguous_dna) >>> moja_sek[5] = "G" Traceback (most recent call last): File "<stdin>", line 1, in ? AttributeError: ’Seq’ instance has no attribute ’__setitem__’ Jednak istnieje możliwość przekształcenia tej sekwencji w taką, w której można dokonywać zmian (obiekt MutableSeq): >>> zmienna_sek = moja_sek.tomutable() >>> zmienna_sek MutableSeq(’GCCATTGTAATGGGCCGCTGAAAGGGTGCCCGA’, IUPACUnambiguousDNA()) Można też stworzyć obiekt MutableSeq bezpośrednio z ciągu znaków: >>> from Bio.Seq import MutableSeq >>> from Bio.Alphabet import IUPAC >>> zmienna_sek = MutableSeq("GCCATTGTAATGGGCCGCTGAAAGGGTGCCCGA", IUPAC.unambiguous_dna) Każdy z tych sposobów da w wyniku sekwencję, która może być modyfikowana: >>> zmienna_sek MutableSeq(’GCCATTGTAATGGGCCGCTGAAAGGGTGCCCGA’, IUPACUnambiguousDNA()) >>> zmienna_sek[5] = "T" >>> zmienna_sek MutableSeq(’GCCATTGTAATGGGCCGCTGAAAGGGTGCCCGA’, IUPACUnambiguousDNA()) >>> zmienna_sek.remove("T") >>> zmienna_sek MutableSeq(’GCCATGTAATGGGCCGCTGAAAGGGTGCCCGA’, IUPACUnambiguousDNA()) >>> zmienna_sek.reverse() >>> zmienna_sek MutableSeq(’AGCCCGTGGGAAAGTCGCCGGGTAATGTACCG’, IUPACUnambiguousDNA()) 13 Zauważmy, że w przeciwieństwie do obiektu Seq, metody obiektu MutableSeq, takie jak reverse.complement() i reverse() od razu zmieniają modyfikowaną sekwencję. Ponadto ważną różnicą pomiędzy obiektami stałymi i zmiennymi w Pythonie jest to, że MutableSeq nie może być używany jako klucz słownika w przeciwieństwie do ciągu znaków lub obiektu Seq. Po zakończeniu edycji sekwencji można z powrotem zapisać ją jako nieedytowalny obiekt Seq: >>> nowa_sek = zmienna_sek.toseq() >>> nowa_sek Seq(’AGCCCGTGGGAAAGTCGCCGGGTAATGTACCG’, IUPACUnambiguousDNA()) Istnieje też możliwość uzyskania ciągu znaków (string) z obiektu MutableSeq, tak jak ze zwykłego obiektu Seq. 7.3 Obiekty UnknownSeq Obiekty UnknownSeq stanowią podklasę podstawowego obiektu Seq, która służy do przetwarzania sekwencji, dla których znamy długość, ale nie znamy wszystkich elementów ją tworzących. Można oczywiście wykorzystać w tym celu zwykły obiekt Seq, ale przechowywanie w pamięci komputera ciągu miliona znaków „N” (nieznana zasada) jest znacznie mniej praktyczne niż zapisanie „N” i liczby całkowitej, mówiącej o liczbie nieznanych zasad. >>> from Bio.Seq import UnknownSeq >>> nieznana = UnknownSeq(20) >>> nieznana UnknownSeq(20, alphabet = Alphabet(), character = ’?’) >>> print nieznana ???????????????????? >>> len(nieznana) 20 Istnieje też możliwość specyfikacji alfabetu dla podanej sekwencji, tak aby zamiast znaków „?” pojawiły się „N” dla kwasów nukleinowych lub „X” dla białek: >>> from Bio.Seq import UnknownSeq >>> from Bio.Alphabet import IUPAC >>> nieznany_dna = UnknownSeq(20, alphabet=IUPAC.ambiguous_dna) >>> nieznany_dna UnknownSeq(20, alphabet = IUPACAmbiguousDNA(), character = ’N’) >>> print nieznany_dna NNNNNNNNNNNNNNNNNNNN Obiekt UnknownSeq może podlegać wszystkim tym modyfikacjom, co zwykły obiekt Seq, z tym że wyniki tych modyfikacji zajmują znacznie mniej miejsca w pamięci komputera: >>> nieznany_dna UnknownSeq(20, alphabet = IUPACAmbiguousDNA(), character = ’N’) >>> nieznany_dna.complement() UnknownSeq(20, alphabet = IUPACAmbiguousDNA(), character = ’N’) >>> nieznany_dna.reverse_complement() UnknownSeq(20, alphabet = IUPACAmbiguousDNA(), character = ’N’) >>> nieznany_dna.transcribe() UnknownSeq(20, alphabet = IUPACAmbiguousRNA(), character = ’N’) >>> nieznane_bialko = nieznany_dna.translate() >>> nieznane_bialko UnknownSeq(6, alphabet = ProteinAlphabet(), character = ’X’) >>> print nieznane_bialko 14 XXXXXX >>> len(nieznane_bialko) 6 7.4 Zadania 1. Napisz skrypt o nazwie porownywanie.py, który pozwoli na porównanie dwóch sekwencji podanych przez użytkownika. Użytkownik podaje też rodzaj alfabetu dla każdej z dwóch porównywanych sekwencji. Przykładowy rezultat działania: Podaj pierwsza sekwencje do porownania: AAAGGGTTTAAA Podaj alfabet dla pierwszej sekwencji: IUPAC.unambiguous_dna Podaj druga sekwencje do porownania: AAAGGGTTTAAA Podaj alfabet dla drugiej sekwencji: IUPAC.unambiguous_dna Wynik porownania: True 2. Dla sekwencji: „TTTATTCACAATAGGAGGATTAACGGGAGTAGTTCTCGCAAACTCCTC AATCGACATTATCCTACACGATACCTACTACG” utwórz obiekt MutableSeq, korzystając z alfabetu IUPAC.unambiguous_dna. Następnie dokonaj następujących operacji na tej sekwencji: podmień zasady na 5, 10, 15 i 20 miejscu na „C”, usuń pierwszą napotkaną zasadę A, odwróć tak zmodyfikowaną sekwencję, a na koniec przekształć ją z powrotem na obiekt Seq. 3. Napisz skrypt o dowolnej nazwie tworzący obiekt UnknownSeq o parametrach zadanych przez użytkownika (długość nieznanej sekwencji, typ alfabetu, symbol nieznanej zasady), a następnie dokonujący transkrypcji i translacji tej sekwencji oraz podający długość wynikowych produktów. Przykładowy rezultat: Podaj dlugosc nieznanej sekwencji: 25 Podaj typ alfabetu: IUPAC.ambiguous_dna Podaj symbol zasady: N Nieznana sekwencja: NNNNNNNNNNNNNNNNNNNNNNNNN mRNA: NNNNNNNNNNNNNNNNNNNNNNNNN Dlugosc mRNA: 25 bialko: XXXXXXXX Dlugosc bialka: 8 8 Bezpośrednia praca z ciągami znaków Na koniec warto zaznaczyć, że zamiast pracować na obiektach Seq, UnknownSeq czy MutableSeq istnieje możliwość pracy bezpośrednio na ciągach znaków (string). Importujemy wtedy z Bio.Seq same funkcje: >>> from Bio.Seq import reverse_complement, transcribe, back_transcribe, translate >>> moj_lancuch = "GCTGTTATGGGTCGTTGGAAGGGTGGTCGTGCTGCTGGTTAG" >>> reverse_complement(moj_lancuch) ’CTAACCAGCAGCACGACCACCCTTCCAACGACCCATAACAGC’ >>> transcribe(moj_lancuch) ’GCUGUUAUGGGUCGUUGGAAGGGUGGUCGUGCUGCUGGUUAG’ >>> back_transcribe(moj_lancuch) ’GCTGTTATGGGTCGTTGGAAGGGTGGTCGTGCTGCTGGTTAG’ >>> translate(moj_lancuch) ’AVMGRWKGGRAAG*’ 9 Literatura: Jeff Chang, Brad Chapman, Iddo Friedberg, Thomas Hamelryck, Michiel de Hoon, Peter Cock, 15 Tiago Antao, Eric Talevich, Bartek Wilczyński. Biopython. Tutorial and Cookbook. 2010. ss. 7-31. 16