19 September 2008

Center for the Study of Human Polymorphisms: Week 3

In my previous post I showed how I used apache velocity to generate some 'C' code for the Operon project based on BerkeleyDB. I also generated the Makefiles and some Lex and Yacc files to create a simple language to query each database. Today I've compiled and linked my first applications. Each application will use my simple language to query each database without having to write a new piece of code for each new kind of query.

For example, the database called 'snpIds' contains a consecutive number of structures defined as :

typedef struct snpIds_t
{
char* featureid;
char* rs_number;
}snpIds,*snpIdsPtr;


I can now query this database like this
snpiddump -q "OR( EQ({rs_number},\"rs10043098\"), EQ({rs_number},\"rs2377171\") ) " -f xml

(OK, the syntax looks ugly, but this design was the simplest way to avoid the shit/reduce conflicts in the yacc parser).The query part is broken into tokens by the lexer and interpreted by the yacc parser. The parser build a Parse Tree which can be drawn like this:

"rs2377171"
/
EQUALS
/ \
/ {rs_number}
--OR
\ {rs_number}
\ /
EQUALS
\
"rs10043098"

This tree is then evaluated versus each record in the database. When a record matches, it is printed out in xml|json|text. e.g.:
<?xml version="1.0" encoding="UTF-8"?>
<op:operon xmlns:op="http://operon.cng.fr">
<op:SnpIds>
<op:featureid>101051105133288</op:featureid>
<op:rs_number>rs10043098</op:rs_number>
</op:SnpIds>
<op:SnpIds>
<op:featureid>101161015120774</op:featureid>
<op:rs_number>rs2377171</op:rs_number>
</op:SnpIds>
</op:operon>

Again, most of the code was written using a velocity template [here].

Pierre

17 September 2008

Generating C code with apache-velicity

I'm currently working on Operon ( http://regulon.cng.fr/) a database developped by Mario Foglio at The National Center of Genotyping. The whole database/storage is developped around the Berkeley C API and I've been asked to write a clean 'C' API to access the data. Most data are stored with C structures and I wanted to quickly write the methods to:
* create a new instance of each structure
* free the resources allocated by each structure
* create a vector of those structures with the common methods (addElement, removeElement, getSize, clear, etc...)
* etc...

I wrote a description of a few structures in xml. Something like this:

<?xml version="1.0" encoding="UTF-8"?>
<op:operon
xmlns:h="http://www.w3.org/1999/xhtml"
xmlns:op="http://operon.cng.fr"
>
<op:table name="SnpIds">
<op:description>
SNPIDS Berkeley Hash db: stores all SNP ids. The key for this
database is the acn, and
duplicate acn keys are allowed.
</op:description>
<op:column name="fid" type="char*">
<op:description>fid: SNP feature id</op:description>
</op:column>
<op:column name="acn" type="char*">
<op:description>acn: SNP accession</op:description>
</op:column>
</op:table>


To generate my C code I've first tried to use xslt but I later found it too ugly.
I then looked for something that could have looked like a standalone version of the java server page (jsp). I didn't find one ( it would have been nice to re-use the custom-tags).
I then tried apache-velocity ( http://velocity.apache.org/), a java processor, and this is the technology I used.

OK, this kind of C structures can be described as a java interface:
public interface CField
{
public String getName();
public String getType();
(...)
}

public interface CStructure
{
public Colllection<CField> getFields();
public String getName();
(...)
}


Those objects are created by parsing the XML description of the structures and are then associated with a string in the 'context' of velocity. (source code [here]).
CStructure mystructure;
(...)
velocityContext.put("struct",mystrucure);
The velocity engine is then called, it uses the object reflection to resolve the velocity statements. For example the following template:
 typedef struct $struct.typedef
{
#foreach($field in ${struct.fields})
/**
* ${field.name}
* ${field.description}
*/
${field.type} ${field.name};
#end
} ${struct.name}, *${struct.name}Ptr;
will generate the C header for this structure.
The velocity templates generating the *.c and the *.h are available [here] and [here] (Warning this is a work in progress)

But that is not all: I also wanted to query each berkeley database without having to re-write a new code for each new kind of query. So I've used velocity to generate a Flex/lex and Bison/yacc files. Those tools then generate a simple parser to build a concrete syntax tree and then searching each database.
YNodePtr search = mydatabaseParseQuery("AND(LT([chromEnd],10000),GT([chromStart],100))");
myDatabaseArray array= myDatabaseSearch(search);

The velocity templates for flex and bison are available [here] and [here] (again, warning , this is a work in progress)

That's it

Pierre

16 September 2008

What is in a list of snp ?

Here is a common question: "Here is a list of snp genotyped with a high p-value. Is there anything interesting in this snp list ? is there a common link between those snp ?".
Today, to answer this question, I've played with NCBI ELink. ELink checks for the existence of an external or Related Articles link from a list of one or more primary IDs; retrieves IDs and relevancy scores for links to Entrez databases or Related Articles; creates a hyperlink to the primary LinkOut provider for a specific ID and database, or lists LinkOut URLs and attributes for multiple IDs..
The java tool I created, AboutRsList, takes as input a list of rs. For each rs it calls ELink and get the links of this snp to pubmed, omim, ncbi-gene.... The information (title...) about each snp is then retrieved using ncbi/EFetch. Then the program creates a set of clusters of snps where each cluster has no link with another one. Each cluster is then saved as a SVG figure using graphviz dot.

Here is an example of cluster, showing all the links between a set of rs### , papers and genesThe circles are the rs##, the ellipse are the papers in pubmed, the polygons are the genes


I put the sources here: http://code.google.com/p/lindenb/source/browse/trunk/proj/tinytools/src/org/lindenb/tinytools/AboutIdentifiers.java
And an executable jar is available here: http://code.google.com/p/lindenb/downloads/list.

Enjoy

Pierre

05 September 2008

Center for the Study of Human Polymorphisms: Week 1

I've started my first week at the center Center for the Study of Human Polymorphisms and today we had our first meeting with Mario Foglio and some other to define what will be my job in the following monthes. As I said, I will collaborate with the National Center of Genotyping on Operon, a feasible bioinformatics platform to centralize scientific software and biomedical data with internal results. It was curious because I found that nobody there uses most of the tools used/discussed with the biogang (rss feeds, social bookmarking, etc... ) and I hope I will present some slides about this later.

I will have to re-factoring the current 'C' code of operon (written over BerkeleyDB) to build a new clean C API that will be used some other persons.

What is cool is that this is an open source project and we will host it on google (http://code.google.com/p/polymorphism/).
I've also created a mailing list on google.groups: http://groups.google.com/group/operon-dev, shown my collaborators how to share a calendar on google-calendar (to find what are the possible dates for organizing a meeting) and we have already started to share some documents using google-docs. Thank you google.

The 'C' language was chosen because it is a low-level language and it seems that the developers at the CNG prefer it. I hope I will create some wrappers around this API with some other language. I already know it is possible with java using the Java Native Interface (JNI, see my previous post about this). SWIG (http://www.swig.org/), a tool generating some wrappers in various languages (python, perl...), might also be of hel. Using a Java wrapper will allow us to deploy any application in a java web server such as tomcat.

I've not much played with 'C' since 1998 ( I then played with C++ for 4 years before switching to java) but I (hope) still have some good skills and I know I now have better good programming practice.

That's it for tonight.

Pierre

02 September 2008

Ubiquity: Arf-arf ! smooch ! Achoo! Wee Woo !

Ok, after a few others (Pawel, Thomas Lemberger, Egon, )I've succumbed to Mozilla Ubiquity, an experimental Firefox extension that (they say) gives you a powerful way to interact with the Web. The following useless script comics inserts a speech balloon using the font samples from http://www.dafont.com/

CmdUtils.CreateCommand({
name: "comics",
author: { name: "Pierre Lindenbaum", email: "plindenbaum@yahoo.fr"},
description: "Comics",
takes: {"Your text": noun_arb_text},
help: "Insert a speech balloon with a comic font ",

preview: function( pblock, theShout ) {
var msg = "Inserts a speech balloon : (<i>"+ theShout.summary+"</i>)";
pblock.innerHTML = CmdUtils.renderTemplate( msg );
},

execute: function(theShout) {
CmdUtils.setSelection(
"<img src=\'http://img.dafont.com/preview.php?text=" +
escape(theShout.text)+
"&ttf=badaboom_bb0&size=49&psize=m&y=58'/>"
);
}
})


It worked fine with GMail !



Update: The script is available here.

Pierre

01 September 2008

I'm not looking for a job anymore: Welcome at the CEPH


Today was my first day as a bioinformatician at the Center for the Study of Human Polymorphisms (CEPH http://www.cephb.fr/en/cephdb) and I want to thank my former colleagues Christine K and Philippe Gesnouin (philguess on twitter/FF ) who helped me to find this position. It's a short term contract (one year).

The CEPH is localized in Paris near the St-Louis Hospital and the "Place de la République" it maintains a database of genotypes for genetic markers that have been typed on the CEPH reference family resource for linkage mapping (Genomics 6: 575-577, 1990; Science 265: 2049-2054, 1994). The CEPH works works in conjunction with the National Center of Genotyping (CNG/Evry) where I also worked height years ago and both centers are managed by Dr Mark Lathrop. One of my first objective is to develop a set of tools around OPERON with the help of his author, Mario Foglio.

As far as I've understand operon today (I may be wrong), it is a C program handling a large set of genotypes (among other things...) using BerkeleyDB as a storage engine (I blogged about BerkeleyDB a few posts ago). It seems that using this strategy, the genotypes can be quickly accessed using something like fseek(table,sizeof(genotype_t)*(sample_count*marker_index+sample_index),SEEK_SET).

As a java programmer, I wish I could write a wrapper around the Operon C API, that would be useful to embed this model in a web container (servlet, jsp) or to write a Swing interface. My first ideas to achieve this are:
* using JNI (Java Native Interface, allows to call C from java) to write a java wrapper around the C API
* reading the data in the berkeleyDB files using the BerkeleyDB Java API.
* ...

That's it for tonight.

Pierre

30 August 2008

My Old Thesis Presentation

I found the my thesis presentation (in french, 2000) in the old iBook I left in my cellar.



It is really outdated now :-) ....

I wonder how I would write this presentation now... this makes me think about this presentation pointed out by Berci Mesko on twitter: I would make this presentation obligatory for all the speakers of the world.
Death by PowerPoint
View SlideShare presentation or Upload your own. (tags: powerpoint ppt)


Pierre

Mesh Fequencies & Pubmed Articles

In a recent post on his blog, David Rothman was asked for a 3rd Party PubMed/MEDLINE Tool: What I’d like to do is to be able to enter the PMIDs of several citations and have the tool search MEDLINE via PubMed for the assigned MeSH terms, and return a single list of the terms used by any of the entered citations with a measurement of frequency. For example, if I input PMIDs 16234728, 15674923, and 17443536, the tool would return results telling me that 100% or 3 of 3 use the term “Catheters, Indwelling”, 2 of 3 use “Time Factors,” 1 of the 3 uses “Urination Disorders,” and so on. Although this example uses 3 PMIDs, I’d like to be able to input at least 10, just based on personal experience.

It took less than half an hour to write this tool using java. The source code is available here and an executable jar file is available here.

The input is a standard pubmed query :

java -jar pubmedfrequencies.jar -term "Lindenbaum P[Author]" -n 20 > ~/page.html
or a list of pmid
java -jar pubmedfrequencies.jar -pmid 8985320,16027742,15047801,18053270,9682060 > ~/page.html


The output is a simple html table:











Mesh89853201602774215047801180532709682060
HumansXXX
AnimalsXX
Autistic DisorderXX
(...)
RNA-Binding ProteinsXX
RotavirusXX
SoftwareX
Two-Hybrid System TechniquesX
Zinc FingersX


well... that was not Big Science....

Note: Rajarshi Guha also suggested another solution: http://www.chembiogrid.org/cheminfo/rest/mesh/16234728,15674923,17443536

Pierre


Addendum:After the first comments, I've added a gui support and a count of the mesh terms in the result.

25 July 2008

Feeling like a newbie: Parsing NCBI-TinySeq with RUBY

I've been recently interested in the new popular language Ruby and its web framework Rails for two reasons:
First,this picture:


Second, Matt Wood's blog about bioinformatics and ruby.

So here is my very first experience with ruby. The book I used was

Very good for learning but a little bit outdated. And I shoudl have started with a book about ruby only.

I've downloaded rails as described here. I got two problems:
  • a ssl library was not installed. I fixed the problem thank to this post
  • a problem with the zlib library, fixed by installing the ruby-zlib


My 'hello world' was "download a sequence from ncbi in TinySeq/XML format, parse the XML and create a new instance of 'a sequence' class". I've been suprised to find that ruby doesn't contain a decent API for parsing XML with DOM or SAX. The default API is called REXML and I found it ugly (or I may be too new to ruby to understand why it may be good). On friendfeed Adam Kraut suggested me to consider libxml-ruby (http://libxml.rubyforge.org/) or Hpricot (an xhtml parser). However I gave REXML a try by using its event-based API (but it is *not* a SAX API (namespaces are not supported) ).

OK, here is how I coded this (it took me hours to find the correct statements :-) ).
First we define a class handling an Organism which is just an id and a name (taxId and taxName)
class Organism
#constructor
def initialize(id,name)
@id=id
@name=name
end
end


We also tell ruby to generate the getters to access those two properties
attr_accessor :id, :name


Next, we define a TinySeq class:
class TinySeq
#class members
@seqtype=nil
@gi=nil
@accver=nil
@sid=nil
@local=nil
@organism=nil
@defline=nil
@length=nil
end


In this TinySeq class I defined a nested class Handler: a XML stream handler using the REXML::StreamListener API. This looks like a SAX Handler but it doesn't handle the namespaces.
A TinySeq XML looks like this
<?xml version="1.0"?>
<!DOCTYPE TSeqSet PUBLIC "-//NCBI//NCBI TSeq/EN" "http://www.ncbi.nlm.nih.gov/dtd/NCBI_TSeq.dtd">
<TSeqSet>
<TSeq>
<TSeq_seqtype value="nucleotide"/>
<TSeq_gi>5</TSeq_gi>
<TSeq_accver>X60065.1</TSeq_accver>
<TSeq_taxid>9913</TSeq_taxid>
<TSeq_orgname>Bos taurus</TSeq_orgname>
<TSeq_defline>B.bovis beta-2-gpI mRNA for beta-2-glycoprotein I</TSeq_defline>
<TSeq_length>1136</TSeq_length>
<TSeq_sequence>CCAGCGCTCGTCT.....CAAGAAAAAAA</TSeq_sequence>
</TSeq>
</TSeqSet>


here is the code I used to handle the XML events:
class Handler
include REXML::StreamListener
....

the class is initialized with an empty TinySeq instance
def initialize(tinyseq)
@tinyseq = tinyseq
#current tag
@tag = nil
#current text
@textcontent = nil
#did we see an error ?
@error=false
@taxid=nil
@taxname=nil
end

I wish I could have just declared some getters for the class TinySeq but this nested class TinySeq::Handler needed to set the properties of this tinyseq. It seems not to work like java where the nested classes have an access to the private properties of the parent class) that is why I asked ruby to create both setters and getters in TinySeq.
attr_accessor :seqtype, :gi, :accver, :sid, :local, :organism, :defline, :length


Next we define what the handler should do when it opens a tag
def tag_start(name, attrs)
@tag=nil
if !( name=="TSeq_sequence" || name=="TSeqSet" || name=="TSeq" || name=="TSeq_seqtype"|| name=="Error" )
@tag=name
@textcontent=""
elsif name=="TSeq_seqtype"
@tinyseq.seqtype = attrs["value"]
elsif name=="Error"
@error=true
end
end

... when it finds a text within a tag
def text(text)
unless @tag.nil?
@textcontent+=text
end
end

... when it closes a tag (it fills the properties of the tinyseq)
def tag_end(name)
unless @tag.nil?
case @tag
when "TSeq_gi"
@tinyseq.gi = @textcontent
when "TSeq_accver"
@tinyseq.accver = @textcontent
when "TSeq_sid"
@tinyseq.sid = @textcontent
when "TSeq_local"
@tinyseq.local = @textcontent
when "TSeq_defline"
@tinyseq.defline = @textcontent
when "TSeq_taxid"
@taxid = @textcontent
when "TSeq_orgname"
@orgname = @textcontent
when "TSeq_length"
@tinyseq.length = @textcontent
else
$stderr.puts "Error #{name} #{@tag}\n"
end
end

if name=="TSeq" && !error
@tinyseq.organism= Organism.new(@taxid,@orgname)
end
@tag=nil
@textcontent=""
end


Then we create a static... sorry... a "class method" fetch for TinySeq returning a TinySeq object from a ncbi gi identifier.
def TinySeq.fetch(gi)
#build the efetch uri
#the API works whatever db is protein or nucleotide
url = "http://www.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=protein&id="+ CGI::escape(gi.to_s)+"&rettype=fasta&retmode=xml";
#create a new Streaming handler
handler= TinySeq::Handler.new TinySeq.new
#parse the document
REXML::Document.parse_stream(Net::HTTP.get_response(URI.parse(url)).body, handler)
if handler.error
return nil
end
return handler.tinyseq
end


Finally, here is a good old 'main argc/argv' reading a list of gi on the command line, fetching a TinySeq object, putting this instance in an array and printing the content of the array.
seqarray=[]
ARGV.each{|gi|
seq=TinySeq.fetch(gi)
if seq.nil?
$stderr.print "#{gi} is a bad gi\n"
else
seqarray << seq
end
}
seqarray.each{|seq| print seq.to_s+"\n"}


... testing....
pierre@linux:~> ruby tinyseq.rb 5 6 7
(5|X60065.1) "B.bovis beta-2-gpI mRNA for beta-2-glycoprotein I" size:1136 (9913) Bos taurus
(6|CAA42669.1) "beta-2-glycoprotein I [Bos taurus]" size:342 (9913) Bos taurus
(7|X51700.1) "Bos taurus mRNA for bone Gla protein" size:437 (9913) Bos taurus



That's it. I would be curious to know about a simpler and more elegant solution.

Pierre



The complete source code:


require "cgi"
require 'net/http'
require 'rexml/document'
require 'rexml/streamlistener'

#an organism: a taxon ncbi id and a name
class Organism
#generate the getters; getId() and getName()
attr_accessor :id, :name
#constructor
def initialize(id,name)
@id=id
@name=name
end

#toString method
def to_s
return "("+@id+") "+@name
end
end

#a ncbi TinySeq
class TinySeq

#class members
@seqtype=nil
@gi=nil
@accver=nil
@sid=nil
@local=nil
@organism=nil
@defline=nil
@length=nil

#generate the getters and the setters
#How can I just use attr_reader instead attr_accessor of and the nested class TinySeq::Handler have an access to those properties ?
attr_accessor :seqtype, :gi, :accver, :sid, :local, :organism, :defline, :length

#toString function
def to_s
return "(#{@gi}|#{@accver}) \"#{@defline}\" size:#{@length} #{@organism}"
end

#internal class
class Handler
include REXML::StreamListener
attr_reader :error, :tinyseq

#initialize with a tinyseq
def initialize(tinyseq)
@tinyseq = tinyseq
#current tag
@tag = nil
#current text
@textcontent = nil
#did we see an error
@error=false
@taxid=nil
@taxname=nil
end

def tag_start(name, attrs)
@tag=nil
if !( name=="TSeq_sequence" || name=="TSeqSet" || name=="TSeq" || name=="TSeq_seqtype"|| name=="Error" )
@tag=name
@textcontent=""
elsif name=="TSeq_seqtype"
@tinyseq.seqtype = attrs["value"]
elsif name=="Error"
@error=true
end
end

def tag_end(name)
unless @tag.nil?
case @tag
when "TSeq_gi"
@tinyseq.gi = @textcontent
when "TSeq_accver"
@tinyseq.accver = @textcontent
when "TSeq_sid"
@tinyseq.sid = @textcontent
when "TSeq_local"
@tinyseq.local = @textcontent
when "TSeq_defline"
@tinyseq.defline = @textcontent
when "TSeq_taxid"
@taxid = @textcontent
when "TSeq_orgname"
@orgname = @textcontent
when "TSeq_length"
@tinyseq.length = @textcontent
else
$stderr.puts "Error #{name} #{@tag}\n"
end
end

if name=="TSeq" && !error
@tinyseq.organism= Organism.new(@taxid,@orgname)
end
@tag=nil
@textcontent=""

end

def text(text)
unless @tag.nil?
@textcontent+=text
end
end

end


#class method (eq java static)
def TinySeq.fetch(gi)


#build the efetch uri
#the API works whatever db is protein or nucleotide
url = "http://www.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=protein&id="+ CGI::escape(gi.to_s)+"&rettype=fasta&retmode=xml";
#create a new Streaming handler
handler= TinySeq::Handler.new TinySeq.new
#parse the document
REXML::Document.parse_stream(Net::HTTP.get_response(URI.parse(url)).body, handler)
if handler.error
return nil
end
return handler.tinyseq
end
end

seqarray=[]
ARGV.each{|gi|
seq=TinySeq.fetch(gi)
if seq.nil?
$stderr.print "#{gi} is a bad gi\n"
else
seqarray << seq
end
}
seqarray.each{|seq| print seq.to_s+"\n"}

21 July 2008

SciFOAF 2.0

If you're following me on twitter or on friendfeed you may know that I've re-written a new version of SciFOAF.

Here is the documentation:



What is SciFOAF


SciFOAF is the second version of a tool I created to build a FOAF/RDF file from your publications in ncbi/pubmed. The FOAF project defines a semantic format based on RDF/XML to define persons or groups, their relationships, as well as their basic properties such as name, e-mail address, subjects of interest, publications, and so on... This FOAF profile can be used to describe your work, your laboratory, your contacts.
The first version was introduced in 2006 here as a java webstart interface and had many problems:

  • the RDF file could not be loaded/saved

  • only a few properties could be edited

  • authors'name definition may vary from one journal to another as some journal may use the initial of an author while another may use the complete first name.

  • the interaction was just a kind of multiple-choice questionnaire


The new version now uses the Jena API, the rdf repository can be loaded and saved.

Requirements



Downloading SciFOAF


A *.jar file should be available for download at http://lindenb.googlecode.com/files/scifoaf.jar.

Running SciFOAF


Setup the CLASSPATH
export JENA_LIB=your_path_to/Jena/lib
export CLASSPATH=${JENA_LIB}/antlr-2.7.5.jar:${JENA_LIB}/arq-extra.jar:${JENA_LIB}/arq.jar:${JENA_LIB}/commons-logging-1.1.1.jar:${JENA_LIB}/concurrent.jar:${JENA_LIB}/icu4j_3_4.jar:${JENA_LIB}/iri.jar:${JENA_LIB}/jena.jar:${JENA_LIB}/jenatest.jar:${JENA_LIB}/json.jar:${JENA_LIB}/junit.jar:${JENA_LIB}/log4j-1.2.12.jar:${JENA_LIB}/lucene-core-2.3.1.jar:${JENA_LIB}/stax-api-1.0.jar:${JENA_LIB}/wstx-asl-3.0.0.jar:${JENA_LIB}/xercesImpl.jar:${JENA_LIB}/xml-apis.jar:YOUR_PATH_TO/scifoaf.jar

Run SciFOAF
java org.lindenb.scifoaf.SciFOAF

the first time your run SciFOAF, You're prompted to give yourself an URI. The best choice would be to give the URL where your foaf file will be stored or the URL of your personnal homepage or blog. On startup a file called foaf.rdf will be created in your home directory. Alternatively you can specify a file on the command line.
When the application is closed, the FOAF model will be saved back to the file.

The Main Pane


The first window contains a sequence of tab Each tab fits to a given rdf Class:

  • foaf:Person

  • geo:Place

  • bibo:Article

  • ...


For each tab, a button "New ...." creates a new instance of the given Class.

Building your profile


Add a foaf:Image


Add the URL of the picture, for example: http://upload.wikimedia.org/wikipedia/commons/4/42/Charles_Darwin_aged_51.jpg.

Add an bibo:Article


enter the PMID of the artcle

Add a geo:Place


SciFOAF, uses the geonames.org API.

Add a foaf:Person


You can the link this person to his publication, his foaf:based_near, the persons he knows..
SciFOAF 2.0

Etc...


Create foaf:Group, event:Event, doap:Project....

Exporting to KML


(Experimental) In menu "File' select 'Export to KML'. SciFOAF will export a KML file containing the geolocalized foaf:Persons.
A test is available here and is visible in maps.google.com at http://maps.google.com/maps?q=http://yokofakun.....

Exporting to XHTML+SVG


(Experimental) In menu "File' select 'Export to XHTML'. Here, I've roughly copied the tool I wrote for exploring the Nature Network using SVG/javscript/JSON/XTML. Many things remain to do.
Nature Network

Loading a Batch of Articles


In the main panel, for bibo:Article a button can be used to load a batch of articles.
On ncbi/pubmed, perform a query, choose
Display: and then . Copy the list of PMID and paste it in the "Load Batch" dialog, press OK. After a moment, all the articles are uploaded in the RDF model.

Example


A RDF File describing a few persons in the Biogang is available here.

Source Code


The source code is available on http://code.google.com/p/lindenb/.
The ant file is in
lindenb/proj/scifoaf/build.xml
.


Pierre