Inserimento voci enzimi (o proteine, o geni)
[modifica | modifica wikitesto]Siamo proprio all'inizio. Stiamo ancora decidendo, concretamente, cosa sia il caso di inserire. Geni? Proteine? Enzimi? In realtà credo che la soluzione sia quella di inserire tutti e tre all'interno di ogni singola voce. Però prima un pelo di didattica (immagino che tu non abbia ancora studiato 'ste cose).
Il gene è il pezzo di DNA che codifica per una proteina. Nel corpo umano esistono circa 25000/30000 geni, tutti individuati e registrati in db come HUGO o Entrez (alla sezione Entrez Gene). HUGO è già comunemente utilizzato dai template {{gene}} e {{proteina}}.
Le proteine sono le molecole che fanno la maggior parte delle cose che fanno le cellule. In realtà alcune hanno solo una funzione di impalcatura nella cellula, mentre molte altre invece fanno delle cose: si tratta degli enzimi. Esistono banche dati sia di proteine (Swiss-Prot o UniProt su tutte), sia di enzimi (KEGG, BRENDA e non solo). Come numero, abbiamo ovviamente più o meno 25000/30000 proteine umane (corrispettive dei 25000/30000 geni) e un po' meno enzimi umani (perchè non tutte le proteine sono anche enzimi). Per farla breve, però, c'è un primo grosso problema di ridondanza: in queste banche dati sono contenute sia proteine umane, che tutte le proteine similari presenti in tutti gli altri esseri viventi (che a noi proprio non interessano, a parte pochi casi). Tale problema può comunque essere risolto partendo da una banca dati che contenga solo info umane. Come HUGO.
Io credo, infatti, che enzimi e proteine umane siano decisamente enciclopedici (anche tutti e 35000), ma solo se le voci sono inserite con almeno il template {{proteina}} contenente un po' di informazioni di base (come puoi vedere ad esempio per l'enzima Glucochinasi). Quel template (come quello di en.wiki {{protein}}) contiene collegamenti sia alle info sul gene (prese da HUGO ed Entrez), sia a quelle sulla proteina (da UniProt, cioè SwissProt), sia sulla struttura 3D della proteina (PDB), sia sull'enzima (riportato il codice EC number, che è preso da KEGG), sia sulla localizzazione del gene (il locus, preso da Ensembl), sia infine sulle malattie correlate (OMIM).
Casino, vero? Fortunatamente le banche dati sono integrate tra loro. HUGO, ad esempio, contiene (quasi) tutte le info per riempire il template. Ad esempio prova a cliccare sul link GCK presente in glucochinasi, e vedi che la pagina che ti si apre contiene, nell'ordine:
- simbolo ufficiale (cioè il nome del gene): GCK;
- nome (e qui son dolori): glucokinase (hexokinase 4, maturity onset diabetes of the young 2) e non glucochinasi;
- posizione sul DNA umano;
- altri simboli usati, ma non ufficiali (sia i previous che gli aliases);
- codice di enzima (EC number);
- codice OMIM;
- codice Entrez Gene;
- codice Uniprot (cioè Swiss-Prot).
Manca solo il codice PDB (che peraltro non esiste per tutte le proteine). KEGG contiene anche tale codice, ma è un po' più complicato da usare. Potremmo anche fregarcene.
Il problema maggiore è la questione dei nomi da dare alle voci. Se per gli asteroidi erano internazionali, qui i nomi sono esclusivamente in inglese. E non esiste una trasposizione ufficiale in italiano (nè credo in nessun'altra lingua). Fanno fede i vari nomi dei geni e i codicilli di enzimi, proteine etc etc.
Dunque. O mettiamo come nome di ogni voce il codice del gene, oppure il nome della proteina in inglese. Entrambe le ipotesi hanno pochi pro e molti contro. La prima scelta credo sia la cosa migliore, perchè esclude la presenza di inglese nei titoli. La seconda, in ogni caso, ha il pregio di focalizzare l'attenzione sul vero tema della voce, che è la proteina e non il gene.
Credo che la situazione abbia bisogno di un po' di riflessione al Progetto:Bio. Spero che, nel frattempo, ti sia potuto fare un'idea... Per qualsiasi dubbio, chiedi pure... Nel caso decidessi di pubblicare il tuo script per gli asteroidi, poi, mandami pure il link. Grazie! --¡Giac83! (ma il copyviol è un'emergenza sempre) 22:01, 6 feb 2007 (CET)
- In questa pagina c'è tutto lo scaricabile del database HUGO. Nella sezione All Data ci sono i file txt (da 7,31 MB) e quello HTML (32,4 MB) che ci servono.
- In ogni caso, questo come idea di fondo, facciamo pure le cose con calma. Vorrei prima raccogliere un po' di pareri tra wikipediani esperti sul tema e che non sento da un po', prima di proporre la cosa alla comunità intera. Anche perchè la comunità ha già avuto le sue polemiche su 13000 nuovi asteroidi, quindi non vorrei che l'inserimento di così tante proteine possa creare problemi. D'altra parte, visto che un bot passerà per 25000/30000 voci o giù di lì, sto pensando se non sia il caso di ampliare lo stesso {{proteina}} con qualche altro parametro automatizzabile (tipo la bibliografia, attraverso il parametro Pubmed ID contenuto in HUGO). Grazie! --¡Giac83! (ma il copyviol è un'emergenza sempre) 22:27, 6 feb 2007 (CET)
Soluzione
[modifica | modifica wikitesto]Ecco come Pietrodn ha implementato la soluzione. In verità non è stato così semplice come l'ho descritto, a questa soluzione ci siamo arrivati poco alla volta. Un ringraziamento ai wikipediani del Progetto:Enzimi, che traducono instancabilmente ogni voce che il mio bot inserisce, e in particolare a Giac83 per i suoi consigli per l'inserimento massivo degli enzimi.
Ottenere i dati
[modifica | modifica wikitesto]Ho scaricato l'intero database in formato SQL da ftp://www.enzyme-database.org/pub/sql/enzyme-data.sql.gz e l'ho importato in MySQL in un database chiamato enzimi.
Successivamente, ho preso i nomi in italiano degli enzimi dalle pagine:
- Progetto:Enzimi/lista nomi accettati/1
- Progetto:Enzimi/lista nomi accettati/2
- Progetto:Enzimi/lista nomi accettati/3
- Progetto:Enzimi/lista nomi accettati/4
- Progetto:Enzimi/lista nomi accettati/5
Ho convertito la lista in una serie di istruzioni SQL tramite delle regex (che non mi sono segnato). Tali istruzioni inseriscono i nomi italiani degli enzimi nella tabella entries sotto una nuova colonna chiamata name_it. Ho quindi dato in pasto il file ottenuto a MySQL.
Inserimento: Enzimi
[modifica | modifica wikitesto]Adesso che abbiamo tutti i dati, bisogna inserirli. Il modo migliore è quello di usare Utente:BimBot, un bot che utilizza il framework pywikipedia.
Ho dunque fatto uno script, che prende in pasto il modello di voce e i dati degli enzimi e mette insieme la voce. Lo script non contiene il modello di voce: per questioni di flessibilità, questo risiede in un file separato, che viene poi letto dallo script. Il modello è stato creato a partire da quello del Progetto Enzimi.
La bibliografia è stata piuttosto difficile da fare. C'era una tabella con i riferimenti bibliografici, l'altra con gli enzimi e un'altra che li metteva insieme. Per ottenere i riferimenti bibliografici per un dato enzima, ho dovuto operare un JOIN. Inoltre, per i libri e le riviste scientifiche vanno usati due template e quindi due modelli differenti.
Lo script comprende una funzione per ripartire da un determinato enzima (e non da capo), e una che fa in modo che il bot operi in modalità automatica, senza chiedere conferma. Due opzioni utili per un inserimento massivo in più "puntate". Non si inseriscono gli enzimi tutti insieme perché le descrizioni sono in inglese, quindi i wikipediani del progetto enzimi devono tradurre ogni enzima inserito.
Inserimento: Categorie
[modifica | modifica wikitesto]Cos'è una categoria di enzimi? Ebbene, ogni enzima ha un proprio numero EC, che ha questo formato: x.x.x.x. Se tolgo l'ultimo numerino dal codice EC, ottengo la categoria a cui appartiene un qualsiasi enzima. Facile, no?
EC 1.2.3 è un esempio di voce per una categoria di enzimi. Ogni voce per una classe di enzimi deve anche contenere una tabella degli enzimi in essa contenuti.
Nel database, nella tabella class, sono presenti anche le categorie, con relative descrizioni. Querando il database in modo appropriato e imitando lo script per l'inserimento degli enzimi, non è difficile implementare anche questo inserimento.
importaenzimi.py
[modifica | modifica wikitesto]#!/usr/bin/env python
# -*- coding: utf-8 -*-
import re, wikipedia, codecs, _mysql
def main():
args = wikipedia.handleArgs()
serialBegin = 1 # Da dove deve cominciare? default=1
all = False
for currentArgument in args:
if currentArgument.startswith("-start:"):
serialBegin = int(currentArgument[7:]) # Se l'utente dice da dove deve cominciare, lo memorizza
if currentArgument.startswith("-always"):
all = True
#page = wikipedia.Page(wikipedia.getSite('it', 'wikipedia'), "Utente:BimBot/Sandbox") # Solo per test
db = _mysql.connect(host='localhost', user='EnzyBot', passwd='', db='enzimi')
db.query("SELECT COUNT(id) FROM entry") # Conta gli enzimi
num = int(db.store_result().fetch_row(how=1)[0]['COUNT(id)'])
templateFile = codecs.open("modello_enzimi.txt", "r", "utf-8")
modelloVoce = templateFile.read() # Legge il modello della voce
templateFile.close()
modelloBibliografia = { # Ci sono due template: uno per gli articoli e uno per i libri
'article': unicode("*{{Cita pubblicazione|autore=#author|titolo=#title|rivista=#journal|volume=#volume|anno=#year|pagine=#first_page–#last_page|id={{subst:#if:#pubmed_id|{{Entrez Pubmed|#pubmed_id}}}}}}", 'utf-8'),
'book': unicode("*{{Cita libro|autore=#author|titolo=#booktitle|capitolo=#title|lingua=#language|anno=#year|pagine=#first_page–#last_page|curatore=#editor|editore=#publisher|città=#address|edizione=#edition}}", 'utf-8'),
}
for i in range(serialBegin, num):
# Ottiene tutte le info sull'enzima corrente
db.query("SELECT * FROM entry JOIN html ON entry.ec_num = html.ec_num WHERE id LIKE " + str(i))
dict = db.store_result().fetch_row(how=2)[0]
# Ottiene le voci di bibliografia correlate all'enzima corrente
db.query("SELECT * FROM refs JOIN cite ON refs.cite_key=cite.cite_key WHERE ec_num LIKE '" + dict['entry.ec_num'] + "'")
vociBibliografia=db.store_result().fetch_row(how=1, maxrows=0)
if not dict['entry.name_it']:
# Se non esiste il nome italiano, usa quello inglese
dict['entry.name_it'] = dict['entry.accepted_name']
page = wikipedia.Page(wikipedia.getSite('it', 'wikipedia'), dict['entry.name_it'].decode('utf-8')) # Ottiene la pagina da modificare
wikipedia.output(">>>>> " + page.title() + " <<<<<")
if(page.exists()):
oldtxt = page.get()
else:
oldtxt = ''
newtxt = elaboraVoce(modelloVoce, dict, vociBibliografia, modelloBibliografia)
wikipedia.showDiff(oldtxt, newtxt)
if (not all) or page.exists():
# Se la pagina esiste, chiede in ogni caso la conferma prima di editare, anche se è in modalità automatica
choice = wikipedia.inputChoice(u"Modificare?", ['Yes', 'No', 'All'], ['y', 'N', 'a'], 'N')
else:
choice = 'y'
if choice in ['A', 'a']:
all = True
choice = 'y'
if choice in ['Y', 'y']:
page.put_async(newtxt, u'Nuovo enzima: ' + dict['entry.name_it'].decode('utf-8'))
def elaboraBibliografia(modelloBibliografia, vociBibliografia):
wikiBiblio = '' # Testo completo della bibliografia
for currentBiblio in vociBibliografia:
# Non gestisce questo tipo di voci bibliografiche; passa al prossimo
if currentBiblio['type'] != 'book' and currentBiblio['type'] != 'article':
continue
# Ottiene il modello giusto per questo tipo di voce di bibliografia
currentModel = modelloBibliografia[currentBiblio['type']]
elencoSostituzioni = { # Sostituisce le variabili nel modello
'#author': currentBiblio['author'],
'#title': currentBiblio['title'],
'#booktitle': currentBiblio['booktitle'],
'#language': currentBiblio['language'],
'#journal': currentBiblio['journal'],
'#volume': currentBiblio['volume'],
'#year': currentBiblio['year'],
'#edition': currentBiblio['edition'],
'#editor': currentBiblio['editor'],
'#publisher': currentBiblio['publisher'],
'#address': currentBiblio['address'],
'#first_page': currentBiblio['first_page'],
'#last_page': currentBiblio['last_page'],
'#pubmed_id': currentBiblio['pubmed_id'],
}
biblioRow = massiveReplace(elencoSostituzioni, currentModel)
biblioRow = re.sub('\n', '', biblioRow) # Toglie tutti i rientri a capo all'interno del singolo elemento
wikiBiblio = wikiBiblio + biblioRow + '\n' # Aggiunge l'elemento alla bibliografia
return wikiBiblio
def elaboraVoce(modelloVoce, dict, vociBibliografia, modelloBibliografia):
nome_classe = {
'1': 'ossidoreduttasi',
'2': 'transferasi',
'3': 'idrolasi',
'4': 'liasi',
'5': 'isomerasi',
'6': 'ligasi',
}[dict['entry.class']] # Ad ogni numero corrisponde una classe di enzimi
reazione = dict['html.reaction']
# Sostituisce l'uguale nelle reazioni chimiche con una fraccia Unicode
reazione = re.sub("=", u"{{Unicode|⇄}}", reazione)
# La categoria è il numero EC privato dell'ultima cifra
eccat = re.sub(r'(\d+\.\d+\.\d+)\.\d+', r'\1', dict['html.ec_num'])
# Genera la bibliografia
bibliografia = elaboraBibliografia(modelloBibliografia, vociBibliografia)
elencoSostituzioni = { # Sostituisce le variabili nel modello
'#nome_accettato': dict['entry.accepted_name'],
'#nome_it': dict['entry.name_it'].decode('utf-8'),
'#codice_ec': dict['html.ec_num'],
'#nome_sistematico': dict['html.sys_name'],
'#altri_nomi': dict['html.other_names'],
'#classe': nome_classe,
'#reazione': reazione,
'#descrizione': dict['html.comments'],
'#eccat': eccat,
'#bibliografia': bibliografia,
}
nuovoTesto = massiveReplace(elencoSostituzioni, modelloVoce)
# Sostituzioni HTML->wikimarkup
nuovoTesto = re.sub("< */? *(em|EM) *>", "''", nuovoTesto)
return nuovoTesto
def massiveReplace(dict, text):
# Dato un testo ed un dizionario di sostituzioni, usa le regex per il "find and replace"
for k in dict:
if dict[k] == None:
dict[k] = ''
text = text.replace(k, dict[k])
return text
if __name__ == "__main__":
try:
main()
finally:
wikipedia.stopme()
modelloenzimi.txt
[modifica | modifica wikitesto]{{Voce bot}} {{S|enzimi}} {{enzybox | nome = #nome_it | immagine = | didascalia = | ECnumber = #codice_ec | nome sistematico = #nome_sistematico | altri nomi = #altri_nomi }} La '''#nome_it''' è un [[enzima]] appartenente alla classe delle [[#classe]], che catalizza la seguente [[reazione chimica|reazione]]: :#reazione #descrizione == Bibliografia == #bibliografia [[Categoria:EC #eccat]] [[en:#nome_accettato]]
importacatenzimi.py
[modifica | modifica wikitesto]#!/usr/bin/env python
# -*- coding: utf-8 -*-
import re, wikipedia, codecs, _mysql
def main():
args = wikipedia.handleArgs()
serialBegin = 1 # Da dove deve cominciare? default=1
all = False
for currentArgument in args:
if currentArgument.startswith("-start:"):
serialBegin = int(currentArgument[7:]) # Se l'utente dice da dove deve cominciare, lo memorizza
if currentArgument.startswith("-always"):
all = True
modelloEnzimi = '|-\\n| EC #ec_num || [[#name_it]]'
#page = wikipedia.Page(wikipedia.getSite(), "Utente:BimBot/Sandbox") # Solo per test
db = _mysql.connect(host='localhost', user='EnzyBot', passwd='', db='enzimi')
db.query("SELECT COUNT(id) FROM entry") # Conta gli enzimi
num = int(db.store_result().fetch_row(how=1)[0]['COUNT(id)'])
templateFile = codecs.open("modellocatenzimi.txt", "r", "utf-8")
modelloVoce = templateFile.read() # Legge il modello della voce
templateFile.close()
for i in range(serialBegin, num):
# Ottiene tutte le info sulla classe corrente
db.query("SELECT * FROM class WHERE id LIKE " + str(i))
dict = db.store_result().fetch_row(how=1)[0]
dict['subclassdescription'] = ''
if dict['subsubclass'] != '0':
db.query("SELECT * FROM class WHERE class=" + dict['class'] + " AND subclass=" + dict['subclass'] + " AND subsubclass=0")
superdict = db.store_result().fetch_row(how=1)[0]
dict['subclassdescription'] = superdict['heading'] + ' '
# Ottiene gli enzimi di questa classe
catName = dict['class'] + '.' + dict['subclass'] + '.' + dict['subsubclass']
db.query("SELECT * FROM entry WHERE class=" + dict['class'] + " AND subclass=" + dict['subclass'] + " AND subsubclass=" + dict['subsubclass'] + " ORDER BY id")
enzimi=db.store_result().fetch_row(how=1, maxrows=0)
page = wikipedia.Page(wikipedia.getSite(), 'EC ' + catName) # Ottiene la pagina da modificare
wikipedia.output(">>>>> " + page.title() + " <<<<<")
if(page.exists()):
oldtxt = page.get()
else:
oldtxt = ''
newtxt = elaboraVoce(modelloVoce, dict, enzimi, modelloEnzimi)
wikipedia.showDiff(oldtxt, newtxt)
if (not all) or page.exists():
# Se la pagina esiste, chiede in ogni caso la conferma prima di editare, anche se è in modalità automatica
choice = wikipedia.inputChoice(u"Modificare?", ['Yes', 'No', 'All'], ['y', 'N', 'a'], 'N')
else:
choice = 'y'
if choice in ['A', 'a']:
all = True
choice = 'y'
if choice in ['Y', 'y']:
wikipedia.setAction(u'Nuova categoria enzimi: ' + catName)
page.put(newtxt)
def elaboraEnzimi(modelloEnzimi, enzimi):
wikiBiblio = '' # Testo completo della riga
for currentEnzy in enzimi:
name = ''
if currentEnzy['name_it'] == None:
name = currentEnzy['accepted_name']
else:
name = currentEnzy['name_it']
elencoSostituzioni = { # Sostituisce le variabili nel modello
'#ec_num': currentEnzy['ec_num'],
'#name_it': name,
}
enzyRow = massiveReplace(elencoSostituzioni, modelloEnzimi)
enzyRow = re.sub('\n', '', enzyRow) # Toglie tutti i rientri a capo all'interno del singolo elemento
wikiBiblio = wikiBiblio + enzyRow + '\n' # Aggiunge l'elemento alla tabella
return wikiBiblio
def elaboraVoce(modelloVoce, dict, enzimi, modelloEnzimi):
nome_classe = {
'1': 'ossidoreduttasi',
'2': 'transferasi',
'3': 'idrolasi',
'4': 'liasi',
'5': 'isomerasi',
'6': 'ligasi',
}[dict['class']] # Ad ogni numero corrisponde una classe di enzimi
note = ''
if dict['note'] != None:
note = dict['note']
# Genera la lista di enzimi
enzymes = elaboraEnzimi(modelloEnzimi, enzimi)
elencoSostituzioni = { # Sostituisce le variabili nel modello
'#class': dict['class'],
'#subclass': dict['subclass'],
'#subsubclass': dict['subsubclass'],
'#classname': nome_classe,
'#superdescription': dict['subclassdescription'],
'#heading': dict['heading'],
'#note': note,
'#enzymes': enzymes,
}
nuovoTesto = massiveReplace(elencoSostituzioni, modelloVoce)
# Sostituzioni HTML->wikimarkup
nuovoTesto = re.sub("< */? *(em|EM) *>", "''", nuovoTesto)
return nuovoTesto
def massiveReplace(dict, text):
# Dato un testo ed un dizionario di sostituzioni, usa le regex per il "find and replace"
for k in dict:
text = re.sub(k, dict[k], text)
return text
if __name__ == "__main__":
try:
main()
finally:
wikipedia.stopme()
modellocatenzimi.txt
[modifica | modifica wikitesto]{{WIPenzima}} La '''EC #class.#subclass.#subsubclass''' è una sotto-sottoclasse della [[classificazione EC]] relativa agli [[enzimi]]. Si tratta di una sottoclasse delle [[#classname]] che include enzimi #superdescription#heading. #note<ref>Fonte: [http://www.enzyme-database.org/class.php?c=#class&sc=#subclass&ssc=#subsubclass IUBMB]</ref> ==Enzimi appartenenti alla sotto-sottoclasse== {| class="wikitable sortable" ! numero EC !! nome accettato #enzymes |} ==Note== {{references}} [[Categoria:EC #class.#subclass.#subsubclass| ]]