Spróbujemy teraz wykorzystać w praktyce zdobyte dotychczas umiejętności. Jedną z ważniejszych cech Perla jest jego elastyczność i zgodnie z powiedzeniem dotyczącym tego języka każdy problem można w Perlu rozwiązać na co najmniej dwa sposoby. Dlatego też w niniejszej instrukcji przedstawiony zostanie jedynie pseudokod lub ogólny plan rozwiązania problemów programistycznych, którymi będziemy się zajmować tak, aby nie ograniczać inwencji twórczej programisty ☺
Poszukiwanie motywów w sekwencji
Brzmi znajomo, jednak tym razem zajmiemy się poszukiwaniem motywów, które pobierzemy z pliku oraz ustalimy ich ranking na podstawie ilości trafień w sekwencji DNA.
Oto w jaki sposób zabierzemy się do tego. W pierwszej kolejności powinniśmy wczytać odpowiednią sekwencję DNA z pliku. Pamiętajmy o obsłudze błędów, to znaczy skonstruujmy nasz program w taki sposób, aby zabezpieczyć się przed możliwymi pojawiającymi się błędami (np. brak pliku, który chcemy otworzyć). Oczywiście nie jest to konieczne dla funkcjonowania danego skryptu, jednak zadbanie o prawidłową obsługę błędów jest eleganckie i należy do dobrej praktyki programistycznej.
Dla większej łatwości operowania sekwencją odpowiednią tablicę zamieniamy w jeden ciąg.
Teraz możemy zabrać się za motywy, których będziemy poszukiwać w naszej sekwencji DNA. Podobnie jak powyżej wczytujemy motywy z odpowiedniego pliku i umieszczamy je w tablicy. Zwracam uwagę na konieczność pozbycia się znaków nowej linii, które występować będą na końcach poszczególnych motywów.
Tak przygotowaniu możemy zacząć właściwą część skryptu, która będzie poszukiwać motywów w sekwencji DNA i zliczać ilość trafień. W tym celu wykorzystamy pętlę foreach, za pomocą której pobierać będziemy motywy i przeszukiwać sekwencję DNA. Trafienia będziemy zliczać za pomocą pętli while, podobnie jak miało to miejsce w przykładzie dotyczącym obliczania ilości odpowiednich zasad w sekwencji DNA. Ostatnią operacją jakiej dokonamy w pętli foreach będzie zapisanie wyników zliczania trafień w odpowiedniej tablicy. Tutaj uwaga, elementy tej tablicy powinny odpowiadać kolejnym elementom w tablicy zawierającej motywy.
Ostatnim etapem będzie wydrukowanie wyników na ekranie. W tym celu znowu korzystamy z pętli foreach i drukujemy kolejne motywy z tablicy motywów oraz odpowiadające im trafienia z tablicy trafień.
Brzmi być może trochę skomplikowanie, ale w gruncie rzeczy jest to bardzo prosty program. Oto jego pseudokod:
#zainicjuj zmienne
$plik_dna = ‘dna.txt’;
$plik_motywy = ‘motywy.txt’
wczytaj sekwencję DNA z pliku $plik_dna do tablicy @DNA
zamień tablicę @DNA na łańcuch $DNA
#wczytaj motywy z pliku $plik_motywy do tablicy @motywy
while(<PLIKMOTYWY>) {
usuń znak nowej linii
zapisz w tablicy @motywy
}
# szukaj motywów w sekwencji DNA
Trochę praktyki…
Strona 1
foreach(@motywy) {
resetuj licznik
while(trafienia w $DNA) {
powiększ licznik o jeden
}
zapisz licznik w tablicy @wyniki
}
# drukujemy wyniki
foreach(@wyniki) {
drukuj odpowiedni motyw – element tablicy @motywy
drukuj odpowiadający mu wynik poszukiwań
}
exit;
Teraz tylko trzeba dobrać odpowiednie instrukcje kodu i sprawdzić działanie skryptu. Oczywiście program ten można skonstruować w inny sposób, to jest po prostu jedna z możliwości na napisanie której pozwalają nam poznane dotychczas informacje. Skrypt można by wzbogacić o kod, który pozwalałby na posortowanie wyników. Tylko uwaga!
Musimy pamiętać, że nasze motywy i wyniki znajdują się w osobnych tablicach, więc trzeba by dobrze przemyśleć całą operację sortowania.
Najprostsza grafika
Grafika to może trochę za mocno powiedziane. Spróbujemy teraz napisać skrypt, który przedstawiałby w formie graficznej wyniki naszych poszukiwań motywów. Wynik działania takiego skryptu mógłby wyglądać na przykład tak:
|------*---*--|
gdzie myślniki reprezentują fragmenty sekwencji przedstawione w jakiejś skali (trudno, żebyśmy mieli drukować na ekranie na przykład fragment DNA o długości 12 tysięcy par zasad), natomiast gwiazdki to położenie motywów.
Oczywiście to bardzo zgrubna prezentacja graficzna, jednak pozwala ona na szybkie zorientowanie się gdzie w interesującym nas fragmencie DNA znajduje się poszukiwany przez nas motyw. Oto przykładowy wynik wygenerowany przez skrypt:
Trochę praktyki…
Strona 2
W programie możemy wykorzystać część kodu napisanego w poprzednim przykładzie, ponieważ część zadań, jakie mają zostać wykonane jest dokładnie taka sama. Zatem po inicjalizacji zmiennych i wczytaniu danych z odpowiednich plików rozpoczynamy poszukiwanie motywów. Tym razem, zamiast zapisywania w tablicy samych ilości trafień dla odpowiednich motywów zapamiętujemy pozycje poszczególnych trafień dla każdego z motywów. Do tego celu korzystamy z funkcji pos(). Zatem kod:
while($dna =~ /$_/ig) {
push(@positions, pos($dna));
}
pozwala nam na przeszukanie sekwencji przechowywanej w zmiennej $dna i zapisanie w tablicy @positions pozycji znalezionych motywów.
Oto plan naszego programu. Rozpoczynamy od zainicjowania zmiennych i otwarcia pliku zawierającego sekwencję.
Tablicę zawierającą linie sekwencji zamieniamy na zmienną tekstową. Pamiętajmy o zdefiniowaniu zmiennej określającej skalę, w jakiej rysować będziemy nasze wyniki poszukiwań. Następnie wczytujemy z pliku motywy, pamiętając o usuwaniu znaku końca linii. Motywy zapamiętujemy w odpowiedniej tablicy. Teraz przystępujemy do poszukiwania motywów i rysowania wyników na ekranie. Do tego celu wykorzystujemy pętlę foreach, która wykonywana jest dla wszystkich elementów tablicy zawierającej motywy. Korzystając z pętli while i funkcji pos, zapisujemy w czasowej tablicy pozycje kolejnych trafień dla danego motywu.
Teraz zaczynamy tworzyć tablicę, na podstawie której wygenerujemy nasz rysunek. Stosujemy prosty trick, w którym kolejne elementy tablicy odpowiadać będą kolejnym myślnikom reprezentującym naszą sekwencję. Oczywiście najpierw przeliczamy długość sekwencji na jej długość w skali i cała tablicę rysunku wypełniamy myślnikami.
Przydatna może być funkcja int(), która zwraca część całkowita danej liczby. Następnie korzystając z pętli foreach, którą wykonujemy dla wszystkich elementów tablicy zawierającej pozycje trafień dla bieżącego motywu i przeliczamy tą pozycję w odpowiedniej skali. Uzyskany wynik jest dla nas wskazówką w którym miejscu tablicy rysunku należy umieścić znak gwiazdki, odpowiadający trafieniu. Teraz pozostaje już tylko zamiana tablicy rysunku na jedną zmienną i wyświetlenie jej na ekranie. Jako ostatni krok resetujemy tablice pozycji oraz rysunku.
A oto odpowiedni pseudokod programu:
#zainicjuj zmienne
$plik_dna = ‘dna.txt’;
$plik_motywy = ‘motywy.txt’
$skala
wczytaj sekwencję DNA z pliku $plik_dna do tablicy @DNA
zamień tablicę @DNA na łańcuch $DNA
#wczytaj motywy z pliku $plik_motywy do tablicy @motywy
while(<PLIKMOTYWY>) {
usuń znak nowej linii
zapisz w tablicy @motywy
}
# szukaj motywów i rysuj wynik
foreach(@motywy) {
while(trafienia w $DNA) {
zapisz pozycję trafienia w tablicy @pozycje
}
Trochę praktyki…
Strona 3
przelicz długość sekwencji na długość skali i zapisz w $caly
# twórz tablicę rysunku
for($licznik = 0; $licznik < $caly; ++$licznik) {
zapisz myślnik w elemencie $rysunek[$licznik]
}
# wstaw gwiazdki w miejsca trafień w sekwencji
foreach(@pozycje) {
wyraź pozycję w skali i zapisz w $pozycja
zapisz gwiazdkę w elemencie $rysunek[$pozycja]
}
# rysuj
zamień tablicę @rysunek na zmienną
drukuj zmienną rysunku na ekranie
# reset tablic
zresetuj tablicę @pozycje
zresetuj tablicę @rysunek
}
exit;
Po uzupełnieniu powyższego pseudokodu odpowiednimi instrukcjami i uruchomieniu programu powinniśmy otrzymać wynik zbliżony do wyniku przedstawionego na początku tego przykładu.
Sekwencja consensus
A teraz zadanie. Proszę napisać skrypt, który generować będzie sekwencję consensus na podstawie dwóch sekwencji zapisanych w odpowiednich plikach. Wynik powinien wyglądać na przykład tak:
------A--CG-----TG----C------ACGTG-----
Myślnik oznacza pozycję w sekwencji, dla której brak jest zgodności zasad, natomiast litery to sekwencje consensusowe.
Trochę praktyki…
Strona 4