31 October 2006

JAVA custom Annotation & Concurrent Versions System

I manage my sources using CVS (Concurrent Versions System). When a user reported a bug in one of my java program, I faced the problem to get the version of the java class where the Exception was throwed..... I don't know if this was described but here is my solution using a custom java annotation. CVS can use a mechanism known as keyword substitution (or keyword expansion) to help identifying the files. Embedded strings of the form $keyword$ and $keyword:…$ in a file are replaced with strings of the form $keyword:value$ whenever you obtain a new revision of the file. Here I used Date,Source and Revision.

First I defined a new custom Annotation called @RCS returning the author, a date and a revision.

import java.lang.annotation.*;
/**
* describe a Revision Control System
* @author pierre
*
*/
@Retention(RetentionPolicy.RUNTIME) /* The annotation should be available for reflection at runtime.*/
@Target(ElementType.TYPE) /* place in : class, interface, enum */
public @interface RCS {
/** author of this source */
String author() default '[undefined]';
/** revision number of this source */
String revision() default '[undefined]';
/** date of revision of this source */
String date() default '[undefined]';
/** file name for this source */
String source() default '[undefined]';
}


and here are two files used for test. Both classes contains a @RCS annotation which can be find at runtime. Test2 jsut throws an Exception. Test1 catch this exception and display the stack trace. for each StackTraceElement it tries to find a @RCS annotation.


import java.lang.annotation.*;
@RCS( author='$Author: $',
date='$Date: $',
source='$Source: $',
revision='$Revision: $'
)

public class Test
{

Test()
{
Test2 t=new Test2();
t.doSomething();
}



public static void main(String args[])
{
try
{
Test t= new Test();
}
catch(Exception err)
{

System.err.println(err.getLocalizedMessage());
for(StackTraceElement e: err.getStackTrace())
{
System.err.println('Class :\t\t\t'+e. getClassName());
System.err.println('File :\t\t\t'+e. getFileName());
System.err.println('Line :\t\t\t'+e. getLineNumber());

if(e.getClassName()!=null)
{
try {
Class c= Class.forName( e.getClassName());
RCS rcsInfo=(RCS)c.getAnnotation(RCS.class);
System.err.println('Revision:\t\t'+(rcsInfo==null?'N/A':rcsInfo.revision()));
System.err.println('Date:\t\t\t'+(rcsInfo==null?'N/A':rcsInfo.date()));
System.err.println('Author:\t\t\t'+(rcsInfo==null?'N/A':rcsInfo.author()));
}
catch (Exception err2)
{
}
}
System.err.println();
}
}

}
}



@RCS(   author='$Author:  $',
date='$Date: $',
source='$Source: $',
revision='$Revision: $'
)

public class Test2
{
Test2()
{
}
void doSomething()
{
throw new RuntimeException('Test');
}

}


when the files where committed the CVS fields were substituted by their correct values. Here is the stack trace as it was printed:


pierre@linux:~/tmp/src> cvs commit
(...)
pierre@linux:~/tmp/src> javac Test.java
pierre@linux:~/tmp/src> java Test
Test
Class : Test2
File : Test2.java
Line : 13
Revision: $Revision: 1.2 $
Date: $Date: 2006/10/31 18:10:44 $
Author: $Author: pierre $


Class : Test
File : Test.java
Line : 15
Revision: $Revision: 1.5 $
Date: $Date: 2006/10/31 18:54:08 $
Author: $Author: pierre $


Class : Test
File : Test.java
Line : 24
Revision: $Revision: 1.5 $
Date: $Date: 2006/10/31 18:54:08 $
Author: $Author: pierre $



That's it.
Pierre

Pubmed "Abstract Plus" and Pubmed2connotea

I didn't mention it before, but I've upgraded the greasemonkey script pubmed2connotea for the new "Abstract Plus" format in pubmed. Pubmed2connotea/Pubmed2CiteULike is a Greasemonkey user script which alters the content web
page when browsing your bibliography on NCBI pubmed by inserting
a hyperlink. This new link adds a new bookmark into connotea with the current selected paper.

Update the latest version at http://www.urbigene.com/pubmed2connotea/.



Pierre

Zotero

zotero is a free Firefox extension, easy-to-use research tool that helps you gather and organize resources (whether bibliography or the full text of articles), and then lets you to annotate, organize, and share the results of your research. It includes the best parts of older reference manager software (like EndNote)—the ability to store full reference information in author, title, and publication fields and to export that as formatted references—and the best parts of modern software such as del.icio.us , like the ability to sort, tag, and search in advanced ways.



In zotero, data are stored using the sqlite, so using an external sqlite engine, you can query or update the database without firefox/mozilla:

pierre@linux:~/> echo ".tables" |./sqlite3-3.3.8.bin -separator '   ' -header ~/.mozilla/firefox/xxxx.default/zotero/zotero.sqlite

charsets itemAttachments tags
collectionItems itemCreators transactionLog
collections itemData transactionSets
creatorTypes itemNotes transactions
creators itemSeeAlso translators
csl itemTags userFieldMask
fieldFormats itemTypeCreatorTypes userFields
fields itemTypeFields userItemTypeFields
fileTypeMimeTypes itemTypes userItemTypeMask
fileTypes items userItemTypes
fulltextItems savedSearchConditions version
fulltextWords savedSearches


pierre@linux:~/> echo "select * from items order by dateAdded;" |./sqlite3-3.3.8.bin-separator ' ' -header ~/.mozilla/firefox/xxxx.default/zotero/zotero.sqlite

itemID itemTypeID title dateAdded dateModified
8423 4 Haplotypes in the gene encoding protein kinase c-beta (PRKCB1) on chromosome 16 are associated with autism. 2006-10-30 18:47:16 2006-10-30 18:47:56
15625 1 2006-10-30 18:48:11 2006-10-31 10:50:53


About sqlite: There is a video about this engine on google-video.


23 October 2006

Things about Bioinformatics #1

Hum, too much work , I've not enough time to write some original post on this blog. So, as Deepak Singh did on business|bytes|genes|molecules, I'm also starting a series of post about thing I noticed:

dbSNP: From dbSNP: Users may now query genotypes for 1 or more snps by rs#, chromosome location, or gene Id. SNP properties and populations are specified prior to retrieval. Output includes HTML, XML, Text and HaploView format by population.
http://www.ncbi.nlm.nih.gov/projects/SNP/snp_gf.cgi

Calendar: I've started to use google's calendar and I created a shared one about bioinformatics (mostly for test but I'll try to keep it up to date). Here is its address in XML and in iCal format. (See also: upcoming.org)

Connotea: Ben Lund has created a new (beta) tool for connotea called Notea: Notea is a Firefox Extension for storing and organizing local copies of online works. It optionally integrates with Connotea to allow easy sharing of bookmarks for your locally stored works.

Del.icio.us: from time to time, I synchronize my tagged bookmarks from connotea to del.icio.us (using xslt and curl) . Del.icio.us has a few functionalities that are missing to connotea: discovering sites using the network, suggesting links, tag bundles....

Comics: want to know more about North Korea ? Do read this comics : "Pyongyang: A Journey to North Korea."



Comics: 300, a film based on Frank Miller's graphic novel 300 about the the battle of thermopylae will be in theaters in 2007. The comparison between the book and the movie is astonishing !

The book:


The movie:


Pierre

05 October 2006

A Google Gadget for Bioinformatics.

As Pedro said on his blog: Google announced that their widgets (or gadgets) can now be used on third party webpages.. I've written ([here])a google gadget searching for pubmed or genbank using the NCBI EUtilies. Enjoy !





Add to Google



Pierre

Updated 2010-08-12: source code

<?xml version="1.0" encoding="UTF-8"?>
<Module>
<ModulePrefs
title="Search NCBI/__UP_db__"
directory_title="Search NCBI/__UP_db__"
description="Search Pubmed/Genbank at the National Center for Biotechnology Information (NCBI)"
author="Pierre Lindenbaum PhD"
author_email="plindenbaum+gadget4ncbi@yahoo.fr"
title_url="http://www.urbigene.com/googlegadget/index.html#gadget4ncbi"
author_affiliation="Integragen"
author_location="Evry,France"
height="200"
width="320"
scrolling="true"
singleton="true"
screenshot="http://www.urbigene.com/googlegadget/ncbi_screenshot.png"
thumbnail="http://www.urbigene.com/googlegadget/ncbi_thumbnail.png"
author_photo="http://www.urbigene.com/googlegadget/plindenbaum.png"
author_link="http://plindenbaum.blogspot.com"
author_aboutme="Bioinformatician at Integragen"
author_quote="A child of five would understand this. Send someone to fetch a child of five. "
>
<Locale lang="en"/>
<Locale lang="ja"/>
<Locale lang="fr"/>
<Locale lang="de"/>
<Locale lang="zn-cn"/>
<Locale lang="zh-tw"/>
</ModulePrefs>
<UserPref name="term"
display_name="Your Query"
datatype="string"
required="true"
default_value="Rotavirus"
/>
<UserPref name="db"
display_name="Database"
datatype="enum"
required="true"
default_value="pubmed">
<EnumValue value="pubmed" display_value="Pubmed"/>
<EnumValue value="nucleotide" display_value="Nucleotide"/>
<EnumValue value="protein" display_value="Protein"/>
</UserPref>
<UserPref name="retmax"
display_name="Number of items retrieved"
datatype="enum"
required="true"
default_value="10">
<EnumValue value="1" display_value="1"/>
<EnumValue value="2" display_value="2"/>
<EnumValue value="10" display_value="10"/>
<EnumValue value="15" display_value="15"/>
<EnumValue value="20" display_value="20"/>
<EnumValue value="25" display_value="25"/>
<EnumValue value="50" display_value="50"/>
<EnumValue value="100" display_value="100"/>
</UserPref>
<Content type="html"><![CDATA[
<style>
#content__MODULE_ID__ {
font-size: 9pt;
margin: 5px;
background-color: #FFFFBF;
}
dt {
font-size: 9pt;
}
dd {
font-size: 7pt;
}

</style>
<div id="content__MODULE_ID__"></div>
<script type="text/javascript">

var prefs__MODULE_ID__ = new _IG_Prefs(__MODULE_ID__);

function dom1__MODULE_ID__(node,tag)
{
if(node==null || tag==null) return null;
var n=node.firstChild;
while(n!=null)
{
if(n.nodeName==tag) return n;
n=n.nextSibling;
}
return null;
}

function dom2__MODULE_ID__(node)
{
if(node==null) return "undefined";
var c= node.firstChild;
if(c==null) return "undefined";
return c.nodeValue;
}

function pubmed__MODULE_ID__(response)
{
var nodes = response.getElementsByTagName("PubmedArticle");
var html="<div><dl>";
for (var i = 0; i < nodes.length ; i++)
{
var MedlineCitation= dom1__MODULE_ID__(nodes.item(i),"MedlineCitation");
var PMID= dom1__MODULE_ID__(MedlineCitation,"PMID");
var Article = dom1__MODULE_ID__(MedlineCitation,"Article");
var ArticleTitle = dom1__MODULE_ID__(Article,"ArticleTitle");
var Title = dom1__MODULE_ID__(dom1__MODULE_ID__(MedlineCitation,"MedlineJournalInfo"),"MedlineTA");
var AuthorList = dom1__MODULE_ID__(Article,"AuthorList");
var Author = dom1__MODULE_ID__(AuthorList,"Author");
var LastName = dom1__MODULE_ID__(Author,"LastName");

html+='<dt><a title=\"show this Article\" href=\"http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?db=pubmed&amp;cmd=Retrieve&amp;dopt=AbstractPlus&amp;list_uids='+dom2__MODULE_ID__(PMID)+
'\" target=\"pubmed'+dom2__MODULE_ID__(PMID)+
'\">'+dom2__MODULE_ID__(ArticleTitle)+'</a></dt>';
html+='<dd><i>'+dom2__MODULE_ID__(Title)+'</i>. <u>'+dom2__MODULE_ID__(LastName)+'</u> &amp; al.</dd>';
}

html+="</dl></div>";
_gel("content__MODULE_ID__").innerHTML = html;

}

function sequence__MODULE_ID__(response)
{
var nodes = response.getElementsByTagName("TSeq");
var html="<div><dl>";
for (var i = 0; i < nodes.length ; i++)
{
var c=nodes.item(i);
var TSeq_seqtype = dom1__MODULE_ID__(c,"TSeq_seqtype");
var TSeq_gi = dom1__MODULE_ID__(c,"TSeq_gi");
var TSeq_accver = dom1__MODULE_ID__(c,"TSeq_accver");
var TSeq_orgname = dom1__MODULE_ID__(c,"TSeq_orgname");
var TSeq_defline = dom1__MODULE_ID__(c,"TSeq_defline");
var TSeq_length = dom1__MODULE_ID__(c,"TSeq_length");

html+='<dt><a title=\"Show this Sequence\" href=\"http://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?db='+
TSeq_seqtype.getAttribute("value")+
'&amp;val='+dom2__MODULE_ID__(TSeq_gi)+
'\" target=\"seq'+dom2__MODULE_ID__(TSeq_gi)+
'\">'+dom2__MODULE_ID__(TSeq_defline)+'</a></dt>'+
'<dd><i>'+
dom2__MODULE_ID__(TSeq_accver)+
'</i>. <i>'+dom2__MODULE_ID__(TSeq_orgname)+'</i>. (length:'+dom2__MODULE_ID__(TSeq_length)+')</dd>';
}

html+="</dl></div>";


_gel("content__MODULE_ID__").innerHTML = html;
}


function dofetch__MODULE_ID__(response)
{
if (response == null ||
typeof(response) != "object" ||
response.firstChild == null)
{
_gel("content__MODULE_ID__").innerHTML = "<i>Invalid data for efetch</i>";
return;
}
if(prefs__MODULE_ID__.getString("db")=="pubmed")
{
pubmed__MODULE_ID__(response);
}
else
{
sequence__MODULE_ID__(response);
}
}

function doesearch__MODULE_ID__(response)
{

if (response == null ||
typeof(response) != "object" ||
response.firstChild == null)
{
_gel("content__MODULE_ID__").innerHTML = "<i>Invalid data for search</i>";
return;
}
var nodes = response.getElementsByTagName("QueryKey");
if(nodes==null || nodes.length!=1)
{
_gel("content__MODULE_ID__").innerHTML = "<i>Error with QueryKey</i>";
return;
}
var QueryKey=nodes.item(0).firstChild.nodeValue;
nodes = response.getElementsByTagName("WebEnv");
if(nodes==null || nodes.length!=1)
{
_gel("content__MODULE_ID__").innerHTML = "<i>Error with WebEnv</i>";
return;
}
var WebEnv=nodes.item(0).firstChild.nodeValue;
var url= "http://www.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db="+
prefs__MODULE_ID__.getString("db")+
"&WebEnv="+escape(WebEnv)+
"&query_key="+escape(QueryKey)+
"&tool=gadget4ncbi"+
"&retmode=xml"+
"&usehistory=y"+
"&retmax="+prefs__MODULE_ID__.getString("retmax");

if(prefs__MODULE_ID__.getString("db")!="pubmed")
{
url+="&rettype=fasta";
}

_IG_FetchXmlContent(url,dofetch__MODULE_ID__);
}

function dogadget__MODULE_ID__()
{
var url= "http://www.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db="+
prefs__MODULE_ID__.getString("db")+
"&term="+escape(prefs__MODULE_ID__.getString("term"))+
"&tool=gadget4ncbi"+
"&retmode=xml"+
"&usehistory=y"+
"&retmax="+prefs__MODULE_ID__.getString("retmax");
_IG_FetchXmlContent(url,doesearch__MODULE_ID__);
}

_IG_RegisterOnloadHandler(dogadget__MODULE_ID__);

</script>
]]></Content>
</Module>

26 September 2006

MYSQL UDF, trees of data, hierarchy

In a previous post I described how to write a mysql user defined function (UDF) in C to create a translate-dna-to-protein function for mysql. Now, I've been playing with hierachies and I wrote a few UDFs to explore a tree of data; I guess this could have been done with a mysql stored procedure but I'm currently using an old server (and I need a deeper knowledge of mysql5 :-) ). The source code is available [here].
The tree itself is written as a sorted static const array of data so you cannot modify it via a mysql command but you'll have to recompile the code.

typedef struct Taxonomy
{
/** the ncbi-id */
taxon_type_t tax_id;
/** id of the parent */
taxon_type_t parent_id;
/** scientific name */
char name[TAXON_NAME_SIZE];
}Taxon,*const TaxonPtr;


It may also not be suitable for large trees. In my example, I've been using a subset of the NCBI taxonomy:

static const Taxon all_taxons[]={
{1, -1, "root"},
{2759, 131567, "Eukaryota"},
{6072, 33208, "Eumetazoa"},
{7711, 33511, "Chordata"},
{7742, 89593, "Vertebrata"},
{7776, 7742, "Gnathostomata"},
{8287, 117571, "Sarcopterygii"},
{9347, 32525, "Eutheria"},
{9443, 314146, "Primates"},
...)
};


but one could imagine something like this...

{1,-1,"root"},
{2,1,"world"},
{3,2,"europe"},
{4,3,"france"},
...


or...

{1,-1,"rdf:Property"},
{2,1,"foaf:knows"},
{3,2,"rel:friendOf"},
{4,2,"rel:childOf"},
...


the source taxonudf.c was successfuly compiled on my computer using the following command-line.

gcc -fPIC -shared -DDBUG_OFF -O3 -I/usr/include/mysql -lmysqlclient -o /usr/lib/taxonudf.o taxonudf.c


taxon_name returns the scientific name of an organism from a ncbi-tax-id.

mysql> create function taxon_name
returns string soname "taxonudf.o";
Query OK, 0 rows affected (0,00 sec)

mysql> select taxon_name(9606);
+------------------+
| taxon_name(9606) |
+------------------+
| Homo sapiens |
+------------------+
1 row in set (0,43 sec)


tax_id returns the ncbi-tax-id from from its name.

mysql> create function taxon_id
returns integer soname "taxonudf.o";
Query OK, 0 rows affected (0,00 sec)

mysql> select taxon_id("Homo sapiens");
+--------------------------+
| taxon_id("Homo sapiens") |
+--------------------------+
| 9606 |
+--------------------------+
1 row in set (0,00 sec)


taxon_childof returns wether a node in the hierarchy is a descendant of another node.

mysql> create function taxon_childof
returns integer soname "taxonudf.o";
Query OK, 0 rows affected (0,00 sec)

mysql> select taxon_childof(taxon_id("Homo"),taxon_id("Homo Sapiens"))
as "is Homo child of Homo.Sapiens ?";
+---------------------------------+
| is Homo child of Homo.Sapiens ? |
+---------------------------------+
| 0 |
+---------------------------------+
1 row in set (0,00 sec)


mysql> select taxon_childof(taxon_id("Homo Sapiens"),taxon_id("Homo"))
as "Is Homo.Sapiens descendant of Homo ?";
+--------------------------------------+
| Is Homo.Sapiens descendant of Homo ? |
+--------------------------------------+
| 1 |
+--------------------------------------+
1 row in set (0,00 sec)



taxon_com is an aggregate function which finds the common ancestral node in a set of node.

mysql> create aggregate function taxon_com
returns integer soname "taxonudf.o";
Query OK, 0 rows affected (0,00 sec)

mysql> create temporary table t1(cluster varchar(20),taxon int);
Query OK, 0 rows affected (0,07 sec)

mysql> insert into t1(cluster,taxon) values("A",251093),
("A",9781), ("A",37348),("B",9605),("B",9606),("B",63221),
("C",32523),("C",33154),("C",7776),("C",9443);
Query OK, 10 rows affected (0,03 sec)
Records: 10 Duplicates: 0 Warnings: 0

mysql> select cluster,taxon as "ncbi-id",taxon_name(taxon) as "Name",taxon_childof(taxon,taxon_id("Primates")) as "Is_Primate" from t1;
+---------+---------+-------------------------------+------------+
| cluster | ncbi-id | Name | Is_Primate |
+---------+---------+-------------------------------+------------+
| A | 251093 | Elephas antiquus | 0 |
| A | 9781 | Elephantidae gen. sp. | 0 |
| A | 37348 | Mammuthus | 0 |
| B | 9605 | Homo | 1 |
| B | 9606 | Homo sapiens | 1 |
| B | 63221 | Homo sapiens neanderthalensis | 1 |
| C | 32523 | Tetrapoda | 0 |
| C | 33154 | Fungi/Metazoa group | 0 |
| C | 7776 | Gnathostomata | 0 |
| C | 9443 | Primates | 1 |
+---------+---------+-------------------------------+------------+
10 rows in set (0,00 sec)

mysql> select cluster,taxon_com(taxon) as ncbi_id
from t1 group by cluster;
+---------+---------+
| cluster | ncbi_id |
+---------+---------+
| A | 9780 |
| B | 9605 |
| C | 33154 |
+---------+---------+
3 rows in set (0.00 sec)


That's all folks

03 September 2006

Scott McCloud at SciFoo 2006

I've just discovered on Flickr that Scott McCloud was present at SciFoo 2006.

scifoo


McLoud is the author of Understanding comics, one of the best book about comics I've ever read.

scifoo


In this book, McLoud introduced a map of visual iconography that took the shape of a triangle.

The lower left corner was visual resemblance (e.g., photography and realistic painting). The lower right included the products of what he called iconic abstraction (e.g., cartooning). And at the top were the denizens of the picture plane ("pure" abstraction) which ceased to make reference to any visual phenomena other than themselves. The move from realism to cartoons along the bottom edge was a move away from resemblance that still retained "meaning," so words, the next logical step in the progression, were included at far right, thereby enclosing anything in comics' visual vocabulary between the three points.

See also: http://www.scottmccloud.com/inventions/triangle/triangle.html


29 August 2006

My own little scifoo camp 2006.

Back from holidays at Montresor where, as the leader of Nature Network BrieComte Robert, I organized my own little private rainy scifoo camp.

My own private scifoo camp


The reason you didn't see me at SciFoo 2006

The reason you didn't see me at SciFoo 2006
The reason you didn't see me at SciFoo 2006


11 August 2006

The Life Sciences Semantic Web is Full of Creeps!

An article published in " Briefings in Bioinformatics Advance Access".

The Life Sciences Semantic Web is Full of Creeps!


Benjamin M. Good and Mark D. Wilkinson
Abstract:The Semantic Web for the Life Sciences (SWLS), when realized, will dramatically improve our ability to conduct bioinformatics analyses using the vast and growing stores of web-accessible resources. This ability will be achieved through the widespread acceptance and application of standards for naming, representing, describing and accessing biological information. The W3C-led Semantic Web initiative has established most, if not all, of the standards and technologies needed to achieve a unified, global SWLS. Unfortunately, the bioinformatics community has, thus far, appeared reluctant to fully adopt them. Rather, we are seeing what could be described as ‘semantic creep’--timid, piecemeal and ad hoc adoption of parts of standards by groups that should be stridently taking a leadership role for the community. We suggest that, at this point, the primary hindrances to the creation of the SWLS may be social rather than technological in nature, and that, like the original Web, the establishment of the SWLS will depend primarily on the will and participation of its consumers.

Mark Wilkinson is one of the creators of BioMoby. Bio Moby is a system for interoperability between biological data hosts and analytical services. Benjamin Good is a PhD student in the British Columbia Strategic Training Program in Bioinformatics. Both of them have a profile on connotea (users bgood, mwilkinson), group:Wilkinson Laboratory).

Although I'm convinced that the semantic web/RDF/XML model is the format of choice for any application (please ! use it for your output format !), I admit I never had the time and the technical knowledge about web services to really understand how BioMoby works , why I should use it and why I should use a LSID instead of an good old URI... :-)

hey, I'm going to ask them an offprint :-)