Un dels avantatges del Python com a llenguatge de programació és que podem fer prototipus complets, a molt alt nivell, sense sortir-nos del llenguatge i aprofitant la gran varietat de biblioteques de tercers lliures. En aquest post exposarem com ajuntarem una grapada de peces que en principi no tenen massa a veure per acabar tenir un rodó projecte de final de carrera.

Una branca molt interessant de la informàtica és la seva amalgama amb la biologia. La bioinformàtica presenta reptes en la manera de plantejar i resoldre problemes per que solen ser processos d'alta complexitat algorísmica i un volum de dades vàries vegades major que la memòria disponible. Si a més afegim que molts de cops l'especificació és poc clara i hem d'anar traduint conceptes biològics a línies de codi ens trobam en una situació on un llenguatge de molt alt nivell ens suposa un avantatge competitiu.

Al meu projecte de final de carrera consisteix en que l'usuari introdueix un conjunt d'espècies vegetals o virals mitjançant una estructura anomenada xarxa filogenètica. Aquest graf determina la semblança d'espècies i després de tota una grada de manipulacions podrem obtenir dades per l'estudi de malalties o el comportament de medicines. Tot això és molt abstracte i no sembla que tingui molt a veure amb Python, no? Si anam dividint els requeriments del nostre programa tenim:

  1. Una interfície per introduir les dades
  2. un sistema de manipulació de grafs
  3. una renderització de resultats
  4. una bateria de proves de rendiment
  5. eines de matemàtica estadística i de càlcul matricial

Així doncs, tenim varis mòduls a destacar:

  1. networkx, per manipulació de grafs
  2. bottle, microframework web
  3. rq, pel processament de cues sobre Redis (Redis-Queue)
  4. numpy, per càlculs matemàtics
  5. peewee, un senzill ORM
  6. matplotlib, per pintar taules i estadístiques
  7. redis-simple-cache com a cache senzilla per crides molt usades (memoize)
  8. profilehooks, uns decoradors per facilitar els benchmarks

Podreu trobat tot el codi del projecte per mirar-lo amb calma però m'agradaria destacar com interconnectàrem algunes de les peces.

El bottle ens serveix per muntar-nos una petita plana. Indicam les rutes sobre les vistes que volem tractar i tornam un diccionari amb el context:

from bottle import route
from bottle import redirect, view, post, request
from bottle import Response

@route("/about")
@view('templates/about')
def about():
     return {}

Però evidentment voldrem fer coses més complicades, com aquesta vista que ens indica l'estat d'una tasca a una cua RQ:

@route("/job/soft/<queue_key>/<job_id>")
def process_job_soft(queue_key, job_id):
     redis_connection = Redis()
     q = Queue.from_queue_key(queue_key, redis_connection)
     job = q.safe_fetch_job(job_id)
     if job.result:
         value =  json.dumps(list(job.result))
         return {'status': 'done',
                 'value': value, }
     else:
         return {'status': 'pending'}

Fins i tot podríem servir els estàtics:

from bottle import route, static_file

@route('/static/<filepath:path>')
def server_static(filepath):
    return static_file(filepath, root='./static')

Els benchmarks tardaven vàries hores en executar-se i volia poder tractar al dia següent els resultats. Per això desava els resultats mitjançant peewee:

from peewee import Model, SqliteDatabase
from peewee import IntegerField, FloatField, BooleanField

database_filename = "benchmarks.sqlite"
db = SqliteDatabase(database_filename)

class BenchmarkCase(Model):
    test = IntegerField()
    nodes = IntegerField()
    fulles = IntegerField()
    temps_soft = FloatField()
    es_treechild = BooleanField()
    n_families = IntegerField()

    class Meta:
        database = db

I així mentre podia escriure els scripts que me pintarien les gràfiques resultats. Primer obtenim les dades:

from peewee import SqliteDatabase
from benchmark_classes import BenchmarkCase

import numpy
from scipy import stats
import matplotlib.pyplot as plt

TEST_NUMBER = 1

database_filename = "benchmarks.sqlite"
database = SqliteDatabase(database_filename)
database.connect()
B = BenchmarkCase

qs = B.select().where(B.test == TEST_NUMBER)

grau = [q.nodes for q in qs]
temps = [q.temps_families for q in qs]

I després pintam el que necessitam:

data = [grau, temps]
xlabel = u"Grau d'hibridització"
title = u"Correlació entre el grau d'hibridització i t. per tree-child"

for x, y in zip(*data):
    plt.plot(x, y, 'ok')

plt.xlabel(xlabel)
plt.title(title)
plt.grid(True)
plt.ylabel(u"Temps en segons")
plt.savefig("hibriditzacio.pdf")
plt.close()

Resum i conclusions

Hem fet una passejada a un projecte que va ajuntar no sols eines de manipulacions de grafs sinó també una petita web i la manipulació d'una bateria de proves. Totes aquestes peces han vingut de biblioteques externes lliures que sense perdre l'expressivitat de Python resolen problemes d'àmbits molt distints. Estau més que convidats a contar-nos qualsevol mòdul estrany que vos hagi tret d'un bon tràngol!

blog comments powered by Disqus