Showing posts sorted by relevance for query svg. Sort by date Show all posts
Showing posts sorted by relevance for query svg. Sort by date Show all posts

24 February 2006

UCSC Genome Browser + SVG

I wrote a PHP script to display tracks from the UCSC Genome Browser using SVG and the public mysql connection to their database. As Firefox now supports the SVG format, this drawing can be displayed in your web browser.




01ucsc2svgInkscape
Pictures can be exported as a SVG file and edited with a SVG tool such as Inkscape or Adobe Illustrator


02ucsc2svgInkscape
SVG is a vectorial format: Vector graphics editors allow to rotate, move, mirror, stretch, skew, generally perform affine transformations of objects, change z-order and combine the primitives into more complex objects.


Updated 2010-08-12: source code

<?php

/*

author:

- Pierre Lindenbaum PhD plindenbaum (at) yahoo (dot) fr http://www.integragen.com

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
``Software''), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.

The name of the authors when specified in the source files shall be
kept unmodified.

THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL 4XT.ORG BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.


$Id: $
$Author: $
$Revision: $
$Date: $
$Locker: $
$RCSfile: $
$Source: $
$State: $
$Name: $
$Log: $


*************************************************************************/

$sqllimitnumber="50";
$sqllimit=" limit ".$sqllimitnumber;
$fontsize="14";
$chrs= array(
"chr1","chr2","chr3","chr4","chr5","chr6","chr7","chr8","chr9","chr10",
"chr11","chr12","chr13","chr14","chr15","chr16","chr17","chr18","chr19","chr20",
"chr21","chr22","chrX","chrY"
);
$tables= array(
"knownGene"=>"full",
"all_mrna"=>"packed",
"refGene"=>"full",
"bacEndPairs"=>"full",
"fishClones"=>"full",
"stsMap"=>"full",
"snp"=>"packed"
);

$viewAs= array("full","packed","hide");

/**
*
* Item an item on the genome
*
*/
class Item
{
var $name;
var $track;
//constructor
function Item(&$track)
{
$this->track=$track;
}

//get 5' bound
function getStart()
{
return -1;
}

//get 3' bound
function getEnd()
{
return -1;
}

//returns wether 2 Item overlap
function overlap($other)
{
return (!($this->getEnd()<$other->getStart() || $other->getEnd()<$this->getStart()));
}

//returns wether 2 Item overlap on screen
function overlapOnScreen($other)
{
$start1= $this->base2pixel(min($this->getStart(),$this->getEnd()));
$end1= 1+$this->base2pixel(max($this->getStart(),$this->getEnd()));

$start2= $other->base2pixel(min($other->getStart(),$other->getEnd()));
$end2= 1+$other->base2pixel(max($other->getStart(),$other->getEnd()));

return (!($end1 < $start2 || $end2 < $start1));
}

//return a URL for this item
function getURL()
{
return "http://www.ncbi.nlm.nih.gov/gquery/gquery.fcgi?term=".htmlentities($this->name);
}

//convert a base position to the screen
function base2pixel($base)
{
$left= $this->track->browser->leftMarginWidth();
$screenw= $this->track->browser->genomeWidth();
return $left+$screenw* (($base - $this->track->browser->start)/($this->track->browser->end - $this->track->browser->start));
}


//force a pixel to be in the drawing area
function trimPixel($pix)
{
$pix= min($this->track->browser->getWidth(),$pix);
$pix= max($this->track->browser->leftMarginWidth(),$pix);
return $pix;
}

//return the height of this item on the screen
function getHeight()
{
return $this->track->browser->featureHeight;
}

//writes symbol for orientation
function writeStrand($out,$pixx1,$pixx2,$midy)
{
if($this->strand=="?") return;
//write orientation
for($i=$pixx1; $i<= $pixx2;$i+=10)
{
fwrite($out,"<svg:use x='".$i."' y='".$midy."' xlink:href='#".($this->strand=='-'?"minus":"plus")."'/>");
}
}

//write a svg:a link containg $svg
function writeAnchor($out,$svg)
{
fwrite($out,"<svg:a xlink:href='".$this->getURL()."' xlink:title='".htmlentities($this->name)."'>".
$svg."</svg:a>"
);
}
}

/**
*
* SimpleItem such as knownGene
*
*/
class SimpleItem extends Item
{
var $chromStart;
var $chromEnd;
var $strand;

//constructor
function SimpleItem(&$track)
{
parent::Item( $track);
$this->strand="?";
}

//get 5' bound
function getStart()
{
return $this->chromStart;
}

//get 3' bound
function getEnd()
{
return $this->chromEnd;
}

//write as SVG
function toSVG($out,$y,$isPacked=TRUE)
{
fwrite($out,"<svg:g>\n");

if($isPacked==FALSE)
{
$this->writeAnchor($out,"<svg:text x='".($this->track->browser->trackMarginWidth()+($this->track->browser->itemMarginWidth()/2.0))."' y='".($y+$this->getHeight()-$GLOBALS["fontsize"]/2.0)."' text-anchor='middle'>".htmlentities($this->name)."</svg:text>");
}


$pixx1= $this->trimPixel($this->base2pixel($this->chromStart));
$pixx2= $this->trimPixel($this->base2pixel($this->chromEnd));
$midy= ($y+$this->getHeight()/2.0);

//write orientation
$this->writeStrand($out,$pixx1,$pixx2,$midy);



$h2= $this->getHeight()/5.0;


$svg = "<svg:rect x='".$pixx1."' y='".($midy-$h2)."' width='".($pixx2-$pixx1)."' height='".($h2*2)."' style='stroke:red;fill:url(#metal);'/>";

if($isPacked)
{
$this->writeAnchor($out,$svg);
}
else
{
fwrite($out,$svg);
}

fwrite($out,"</svg:g>");
}
}


/**
*
* BEDItem such as knownGene
*
*/
class BEDItem extends Item
{
var $txStart;
var $txEnd;
var $cdsStart;
var $cdsEnd;
var $exonCount;
var $exonStarts;
var $exonEnds;

//constructor
function BEDItem(&$track)
{
parent::Item($track);
}

//5' bound
function getStart()
{
return $this->txStart;
}

//3' bound
function getEnd()
{
return $this->txEnd;
}

//write as SVG
function toSVG($out,$y,$isPacked=TRUE)
{
fwrite($out,"<svg:g>");
if($isPacked==FALSE)
{
$this->writeAnchor($out,"<svg:text x='".($this->track->browser->trackMarginWidth()+($this->track->browser->itemMarginWidth()/2.0))."' y='".($y+$this->getHeight()-$GLOBALS["fontsize"]/2.0)."' text-anchor='middle'>".htmlentities($this->name)."</svg:text>"
);
}

$pixx1= $this->trimPixel($this->base2pixel($this->txStart));
$pixx2= $this->trimPixel($this->base2pixel($this->txEnd));
$midy= ($y+$this->getHeight()/2.0);

$this->writeStrand($out,$pixx1,$pixx2,$midy);

//write gene
fwrite($out,"<svg:line x1='".$pixx1."' y1='".$midy."' x2='".$pixx2."' y2='".$midy."' stroke='black'/>");

$pixx1= $this->trimPixel($this->base2pixel($this->cdsStart));
$pixx2= $this->trimPixel($this->base2pixel($this->cdsEnd));

//write mRNA
$h2= $this->getHeight()/17.0;
fwrite($out,"<svg:rect x='".$pixx1."' y='".($midy-$h2)."' width='".($pixx2-$pixx1)."' height='".($h2*2)."' stroke='black' fill='blue'/>");


//write translation
$h2= $this->getHeight()/6.0;
for($i=0;$i< $this->exonCount;++$i)
{
$pixx1= $this->trimPixel($this->base2pixel($this->exonStarts[$i]));
$pixx2= $this->trimPixel($this->base2pixel($this->exonEnds[$i]));
$svg="<svg:rect x='".$pixx1."' y='".($midy-$h2)."' width='".($pixx2-$pixx1)."' height='".($h2*2)."' style='stroke:red;fill:url(#metal);'/>";
if($isPacked==FALSE)
{
fwrite($out,$svg);
}
else
{
$this->writeAnchor($out,$svg);
}
}

fwrite($out,"</svg:g>");
}


}


/**
*
* AlignItem such as all_mrna
*
*/
class AlignItem extends Item
{
var $tStart;
var $tEnd;
var $blockCount;
var $blockSizes;
var $tStarts;

//constructor
function AlignItem(&$track)
{
parent::Item($track);
}

//5' bound
function getStart()
{
return $this->tStart;
}

//3' bound
function getEnd()
{
return $this->tEnd;
}

//write as SVG
function toSVG($out,$y,$isPacked=TRUE)
{
fwrite($out,"<svg:g>");
if($isPacked==FALSE)
{
$this->writeAnchor($out,"<svg:text x='".($this->track->browser->trackMarginWidth()+($this->track->browser->itemMarginWidth()/2.0))."' y='".($y+$this->getHeight()-$GLOBALS["fontsize"]/2.0)."' text-anchor='middle'>".htmlentities($this->name)."</svg:text>"
);
}

$pixx1= $this->trimPixel($this->base2pixel($this->getStart()));
$pixx2= $this->trimPixel($this->base2pixel($this->getEnd()));
$midy= ($y+$this->getHeight()/2.0);

$this->writeStrand($out,$pixx1,$pixx2,$midy);

//write gene
fwrite($out,"<svg:line x1='".$pixx1."' y1='".$midy."' x2='".$pixx2."' y2='".$midy."' stroke='black'/>");

//write blocks
$h2= $this->getHeight()/6.0;
for($i=0;$i< $this->blockCount;++$i)
{
$pixx1= $this->trimPixel($this->base2pixel($this->tStarts[$i]));
$pixx2= $this->trimPixel($this->base2pixel($this->tStarts[$i]+$this->blockSizes[$i]));
$svg="<svg:rect x='".$pixx1."' y='".($midy-$h2)."' width='".($pixx2-$pixx1)."' height='".($h2*2)."' style='stroke:red;fill:url(#metal);'/>";
if($isPacked==FALSE)
{
fwrite($out,$svg);
}
else
{
$this->writeAnchor($out,$svg);
}
}

fwrite($out,"</svg:g>");
}

}


/**
*
* class Track
* a track is a vector of Item
*
*/
class Track
{
var $name;
var $url;
var $browser;
var $items;
var $index2row;
var $nRows;

//constructor
function Track(&$browser,$name,$url)
{
$this->name = $name;
$this->url = $url;
$this->browser= $browser;
$this->items = array();
$this->index2row = null;
$this->nRows=-1;
}

//number of items
function getItemCount()
{
return count($this->items);
}

//add a new item in the track
function add($item)
{
$this->items[ $this->getItemCount() ] = $item;
$this->nRows=-1;
}

//return width on screen
function getWidth()
{
return $this->browser->getWidth();
}


//return height on screen
function getHeight()
{
if($this->isPacked())
{
return $this->nRows* $this->browser->featureHeight;
}
else
{
$h=0;
foreach($this->items as $K=>$V)
{
$h += $V->getHeight();
}
return $h;
}
}

//return wether is track has been packed
function isPacked()
{
return $this->nRows!=-1;
}

//pack this track
function packTrack()
{
$count= $this->getItemCount();
$this->index2row= array();
$this->nRows=1;
$this->index2row[0]=0;

for($i=1;$i< $count;$i++)
{
$itemi = $this->items[$i];
$choosenRow=0;
$done=FALSE;
while($done==FALSE)
{
$done=TRUE;
for($j=0;$j<$i;$j++)
{
if($this->index2row[$j]!=$choosenRow) continue;
$itemj = $this->items[$j];
if($itemi->overlapOnScreen($itemj)==TRUE)
{
$choosenRow++;
$done=FALSE;
break;
}
}
if($choosenRow>=$this->nRows)
{
$this->nRows++;
break;
}
}
$this->index2row[$i]=$choosenRow;
}
}


//write as SVG
function toSVG($out,$y)
{
$width = $this->getWidth();


fwrite($out,"<svg:g id=\"".$this->name."\">\n");
//track name
fwrite($out, "<svg:g>".
"<svg:a xlink:href='".$this->url."' xlink:title='".$this->name."'>".
"<svg:rect x='0' y='".$y."' width='".($this->browser->trackMarginWidth()).
"' height='".$this->getHeight()."' fill='rgb(240,240,255)'/>".
"</svg:a>".
"<svg:text x='0' y='0' text-anchor='middle' transform='translate(".(($this->browser->trackMarginWidth())/2.0).",".($y+$GLOBALS["fontsize"]/2.0+($this->getHeight())/2.0).") rotate(0)'>".$this->name."</svg:text>".
"</svg:g>\n"
);
fwrite($out,"<svg:rect x='".($this->browser->trackMarginWidth())."' y='".$y."' width='".($this->browser->itemMarginWidth()).
"' height='".$this->getHeight()."' fill='rgb(200,200,255)'/>\n");

if($this->isPacked()==TRUE)
{
$count= $this->getItemCount();
for($i=0;$i< $this->nRows;$i++)
{
for($j=0;$j<$count;$j++)
{
if($this->index2row[$j]!=$i) continue;
$this->items[$j]->toSVG($out,$y,TRUE);
}
$y+=$this->browser->featureHeight;
}

}
else
{
foreach($this->items as $K=>$V)
{
$V->toSVG($out,$y,FALSE);
$y+=$this->browser->featureHeight;
}
}
fwrite($out,"</svg:g>");
}
}

/**************
*
* Browser
* a browser is a vector of tracks
*
*/
class Browser
{
var $build;
var $chrom;
var $tracks;
var $start;
var $end;
var $featureHeight;

//constructor
function Browser($build,$chrom,$start,$end)
{
$this->build = $buid;
$this->chrom = $chrom;
$this->start = $start;
$this->end = $end;
$this->featureHeight=24;
$this->tracks=array();
}

//number of tracks
function getTrackCount()
{
return count( $this->tracks);
}

//add a new track
function add(&$track)
{
$this->tracks[ $this->getTrackCount() ]=& $track;
}

//width on screen
function getWidth()
{
return 800;
}

//height on screen
function getHeight()
{
$h=0;
foreach($this->tracks as $key=>$value)
{
$h+= $value->getHeight();
}
return $h;
}

//margin width for labels
function itemMarginWidth()
{
return $this->getWidth()/6.0;
}

//margin width for track
function trackMarginWidth()
{
return $this->getWidth()/6.0;
}

//left margin width = sum(item+track)
function leftMarginWidth()
{
return $this->trackMarginWidth()+$this->itemMarginWidth();
}

//drawing area
function genomeWidth()
{
return $this->getWidth()-$this->leftMarginWidth();
}

//pack the named track
function packTrack($name)
{
for($i=0;$i< count($this->tracks);$i++)
{
if($this->tracks[$i]->name==$name)
{
$this->tracks[$i]->packTrack();
}
}
}

//write as SVG
function toSVG($out)
{

if($out==NULL)
{
$out=fopen("php://output","w")or die ("stdout?");
}
$height=$this->getHeight();
$fh2 = ($this->featureHeight)/5.0;

fwrite($out, "<svg:svg xmlns:svg='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='".$this->getWidth()."' height='".$height."' stroke='black' stroke-width='0.5' font-size='".$GLOBALS["fontsize"]."'>".
"<svg:title>".$this->chrom.":".$this->start."-".$this->end."</svg:title>".
"<svg:desc>Genome Browser with SVG Pierre Lindenbaum plindenbaum (@) yahoo (dot) fr </svg:desc>".
"<svg:defs>".
"<svg:polyline id='plus' stroke='black' fill='none' points='".
"-".$fh2.",-".$fh2." ".
" 0,0 ".
"-".$fh2.",".$fh2."'/>".
"<svg:polyline id='minus' stroke='black' fill='none' points='".
"".$fh2.",-".$fh2." ".
" 0,0 ".
"".$fh2.",".$fh2."'/>".
"<svg:linearGradient x1='0%' y1='0%' x2='0%' y2='100%' id='metal'>\n".
"<svg:stop offset=\"5%\" stop-color=\"black\"/>\n".
"<svg:stop offset=\"50%\" stop-color=\"whitesmoke\"/>\n".
"<svg:stop offset=\"95%\" stop-color=\"black\"/>\n".
"</svg:linearGradient>\n".
"</svg:defs>"
);
fwrite($out,"<svg:rect x='0' y='0' ".
"width='".$this->getWidth()."' height='".$height."' stroke='blue' fill='white' ".
"/>"
);

//write vertical bar
fwrite($out,"<svg:g>");
for($i=1;$i<10;$i++)
{
$x= $this->leftMarginWidth()+($this->genomeWidth()/10.0)*$i;
fwrite($out,"<svg:line x1='".$x."' y1='0' x2='".$x."' y2='".$height."' stroke='blue' />");
}
fwrite($out,"</svg:g>");
$y=0;

foreach($this->tracks as $key=>$value)
{
$value->toSVG($out,$y);
$y+= $value->getHeight();
}
fwrite($out,"<svg:rect x='0' y='0' ".
"width='".$this->getWidth()."' height='".$height."' stroke='blue' fill='none' ".
"/>"
);
fwrite($out, "</svg:svg>");
}

}

/** return a POST parameter, convenient method that can be changed to __GET */
function getParameter($s)
{
return $_POST[$s];
}

/* performs a query in gene tracks */
function doGeneQuery($con,&$browser,$build,$trackname)
{
$prompt="select ".
"name,strand,txStart,txEnd,cdsStart,cdsEnd,exonCount,exonStarts,exonEnds".
" from ".
" ".$build.".".$trackname.
" where ".
" chrom=\"".mysql_escape_string($browser->chrom) ."\" and not(".
" txEnd < \"".mysql_escape_string($browser->start)."\" or \"".
mysql_escape_string($browser->end)."\" < txStart ".
") ".$GLOBALS["sqllimit"];
//echo "<!-- ".$prompt." -->";
$result = mysql_query($prompt,$con);
if(!$result)
{
echo "<!-- Bad query ".$prompt." -->";
}
else
{
$track= new Track($browser,$trackname,"http://www.genome.ucsc.edu/cgi-bin/hgTrackUi?g=".$trackname);
while($row=mysql_fetch_array($result))
{
$item= new BEDItem(&$track);
$item->name= $row[0];
$item->strand= $row[1];
$item->txStart = $row[2];
$item->txEnd = $row[3];
$item->cdsStart = $row[4];
$item->cdsEnd = $row[5];
$item->exonCount= $row[6];
$item->exonStarts= split(",",$row[7]);
$item->exonEnds= split(",",$row[8]);
$track->add( $item);
}
$browser->add(& $track);

}
}

/* performs a generic query */
function doSimpleQuery($con,&$browser,$build,$trackname,$N,$T,$C,$S,$E)
{
$prompt="select ".
"$N,".($T==NULL?"\"?\"":$T).",$S,$E ".
" from ".
" ".$build.".".$trackname.
" where ".
" $C=\"".mysql_escape_string($browser->chrom) ."\" and not(".
" $E < \"".mysql_escape_string($browser->start)."\" or \"".
mysql_escape_string($browser->end)."\" < $S ".
") ".$GLOBALS["sqllimit"];
//echo "<!-- ".$prompt." -->";
$result = mysql_query($prompt,$con);
if(!$result)
{
echo "<!-- Bad query ".$prompt." -->";
}
else
{
//echo "<!-- query ".$prompt." -->";
$track= new Track($browser,$trackname,"http://www.genome.ucsc.edu/cgi-bin/hgTrackUi?g=".$trackname);
while($row=mysql_fetch_array($result))
{
$item= new SimpleItem(&$track);
$item->name= $row[0];
$item->strand= ($T==NULL?"?":$row[1]);
$item->chromStart = $row[2];
$item->chromEnd = $row[3];
$track->add( $item);
}
$browser->add(& $track);
}
}

/* performs a alignment query */
function doAlignQuery($con,&$browser,$build,$trackname,$N,$T,$C,$S,$E,$BC,$BS,$BL)
{
$prompt="select ".
"$N,".($T==NULL?"\"?\"":$T).",$S,$E,$BC,$BS,$BL".
" from ".
" ".$build.".".$trackname.
" where ".
" $C=\"".mysql_escape_string($browser->chrom) ."\" and not(".
" $E < \"".mysql_escape_string($browser->start)."\" or \"".
mysql_escape_string($browser->end)."\" < $E ".
") ".$GLOBALS["sqllimit"];
//echo "<!-- ".$prompt." -->";
$result = mysql_query($prompt,$con);
if(!$result)
{
echo "<!-- Bad query ".$prompt." -->";
}
else
{
$track= new Track($browser,$trackname,"http://www.genome.ucsc.edu/cgi-bin/hgTrackUi?g=".$trackname);
while($row=mysql_fetch_array($result))
{
$item= new AlignItem(&$track);
$item->name= $row[0];
$item->strand= $row[1];
$item->tStart = $row[2];
$item->tEnd = $row[3];
$item->blockCount= $row[4];
$item->tStarts= split(",",$row[5]);
$item->blockSizes= split(",",$row[6]);
$track->add( $item);
}
$browser->add(& $track);

}
}

$svgonly= getParameter("svgonly");
//$build= getParameter("build"); you can un-comment this
if(!isset($build)) $build="hg17";
if(isset($build)) $build=trim($build);
$chrom= getParameter("chrom");
if(isset($chrom)) $chrom=trim($chrom);
$start= getParameter("start");
if(isset($start)) $start=intval($start);
$end= getParameter("end");
if(isset($end)) $end=intval($end);

if(
isset($chrom) &&
isset($start) &&
isset($end) &&
$start<$end
)
{
$title=$chrom.":".$start."-".$end;
}
else
{
$title=NULL;
}

if($title==NULL || isset($svgonly)==FALSE)
{
header("Content-type: application/xhtml+xml");
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<link rel="alternate" type="application/rss+xml" href="../rss/rss.txt"/>
<meta name="dc.description" content="UCSC Genome Browser with SVG"/>
<meta name="dc.keywords" content="UCSC; Genome Browser; goldenpath; SVG; PHP;mozilla; firefox; genomics; bioinformatics; integragen"/>
<meta name="dc.author" content="Pierre Lindenbaum"/>
<title><?php echo ($title==NULL?"UCSC Genome Browser with SVG":$title); ?></title>
</head>
<body>
<h1>Displaying Data from the UCSC Genome Browser With SVG</h1>
<h4>Pierre Lindenbaum PhD, 2006</h4>
<div align="center" style="font-size:9pt; background-color:#DDDDDD;border-color:black; border-width:1px; ; border-style:solid;"><br/>
<?php
if(isset($sqllimitnumber))
{
echo "<br/>For security reason, the number of items per track is limited to <b style='color:red;'>$sqllimitnumber</b>.<br/><br/>";
}
?>
<form method="POST">
<input type="hidden" name="build" value="hg17" />
Assembly:<span style='border-color:gray; border-width:1px; ; border-style:dashed;background-color:white;'><?php echo $build; ?></span>
<label for="chrom">Chromosome:</label><select name="chrom" id="chrom">
<?php

echo "<input type=\"hidden\" name=\"_rand\" value=\"".time()."\"/>";


foreach($chrs as $K)
{
echo "<option value=\"".$K."\"";
if(isset($chrom) && $K==$chrom) echo " selected=\"true\" style='background-color:#EE00EE'";
echo ">".$K."</option>";
}
?>
</select>
<label for="start">Start:</label><input type="text" id="start" name="start" value="<?php echo (isset($start)?$start:910000); ?>"/>
<label for="end">End:</label><input type="text" id="end" name="end" value="<?php echo (isset($end)?$end:930000); ?>"/>
<?php
echo "<br/><table><tr>";
foreach($tables as $T=>$D)
{
$v=getParameter($T);
if(isset($v) && in_array($v,$viewAs))
{
$D=$v;
$tables[$T]=$D;
}
echo "<th><label for='$T'>$T</label></th><td><select id='$T' name='$T'>";
foreach($viewAs as $V)
{
echo "<option value='$V'";
if($V==$D) echo " selected=\"true\" style='background-color:#EE00EE' ";
echo ">".$V."</option>";
}
echo "</select></td>\n";
}
echo "</tr></table>";
?>
<input type="submit" name="Submit" value='Display as XHTML'/>
<input type="submit" name="svgonly" value='Save As SVG' />
<br/><br/></form>
</div>
<p/>
<div align="center" style="font-size:9pt; background-color:#DDDDFF;border-color:#DDDDDD; border-width:1px; ; border-style:solid;"><br/>
<?php
}
else
{
header("Content-disposition: attachment; filename=\"".$chrom."_".$start."_".$end."\"");
header("Content-type: image/svg+xml");

?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<?php
}

if(
isset($chrom) &&
isset($start) &&
isset($end) &&
$start<$end
)
{
if(isset($svgonly)==FALSE)
{
echo "<a style='font-size:200%;' href='http://www.genome.ucsc.edu/cgi-bin/hgTracks?clade=vertebrate&amp;org=Human&amp;db=$build&amp;position=$chrom%3A$start-$end&amp;pix=1000'>($build)$title</a><br/>";
}
$con = mysql_connect("genome-mysql.cse.ucsc.edu", "genome");
if(!$con)
{
die("Cannot connect :=".mysql_error($con));
}
else
{
$browser= new Browser($build,$chrom,$start,$end);

if($tables["knownGene"]!="hide")
{
doGeneQuery($con,&$browser,$build,"knownGene");
if($tables["knownGene"]=="packed") $browser->packTrack("knownGene");
}
if($tables["refGene"]!="hide")
{
doGeneQuery($con,&$browser,$build,"refGene");
if($tables["refGene"]=="packed") $browser->packTrack("refGene");
}

if($tables["all_mrna"]!="hide")
{
doAlignQuery($con,&$browser,$build,"all_mrna","qName","strand","tName","tStart","tEnd","blockCount","tStarts","blockSizes");
if($tables["all_mrna"]=="packed") $browser->packTrack("all_mrna");
}

if($tables["bacEndPairs"]!="hide")
{
doSimpleQuery($con,&$browser,$build,"bacEndPairs","name","strand","chrom","chromStart","chromEnd");
if($tables["bacEndPairs"]=="packed") $browser->packTrack("bacEndPairs");
}

if($tables["fishClones"]!="hide")
{
doSimpleQuery($con,&$browser,$build,"fishClones","name",NULL,"chrom","chromStart","chromEnd");
if($tables["fishClones"]=="packed") $browser->packTrack("fishClones");
}

if($tables["stsMap"]!="hide")
{
doSimpleQuery($con,&$browser,$build,"stsMap","name",NULL,"chrom","chromStart","chromEnd");
if($tables["stsMap"]=="packed") $browser->packTrack("stsMap");
}
if($tables["snp"]!="hide")
{
doSimpleQuery($con,&$browser,$build,"snp125","name","strand","chrom","chromStart","chromEnd");
if($tables["snp"]=="packed") $browser->packTrack("snp");
}

$browser->toSVG(NULL);

mysql_close($con);
}


}

if($title==NULL || isset($svgonly)==FALSE)
{
if($title==NULL) {
?>

<div align="left">This <a href="http://www.php.net">PHP</a> script display tracks from the <a href="http://www.genome.ucsc.edu/">UCSC Genome Browser</a> using <a href="http://www.w3.org/Graphics/SVG/">SVG</a> and the <a href="http://genome.ucsc.edu/FAQ/FAQdownloads#download29">public mysql connection to their database</a>. As <a
href="http://www.mozilla.org">Firefox</a> <a href="http://developer.mozilla.org/en/docs/SVG_in_Firefox_1.5"> now supports the SVG</a> format, this drawing can be displayed in your
web browser.</div>

<br/>
<p style="font-size:200%;"><u>Must</u> be viewed with <u><b>Firefox 1.5 or higher</b></u> : <a href="http://www.spreadfirefox.com/?q=affiliates&amp;id=0&amp;t=45"><img alt="Get Firefox!" title="Get Firefox!" src="http://sfx-images.mozilla.org/affiliates/Buttons/80x15/blue_1.gif" border="0"/></a></p>
<br/>
Pictures can be exported as a SVG file and edited with a SVG tool such as <a href="http://www.inkscape.org/" target="inkscape" >Inkscape</a> or <a target="illustrator" href="http://www.adobe.com/svg/tools.html">Adobe Illustrator</a>
<img src="01ucsc2svgInkscape.jpeg" alt="01ucsc2svgInkscape.jpeg"/><br/>
<br/>
SVG is a <a href="http://en.wikipedia.org/wiki/Vector_graphics">vectorial format</a>: <cite>Vector graphics editors allow to rotate, move, mirror, stretch, skew, generally perform affine transformations of objects, change z-order and combine the primitives into more complex objects.</cite><br/>
<img src="02ucsc2svgInkscape.jpeg" alt="02ucsc2svgInkscape.jpeg"/>
<br/>
<?php

echo "<div align='left'><h3>The PHP Code</h3><pre style='background-color:lightgray'>";
echo htmlspecialchars(file_get_contents("ucsc.php"));
echo "</pre></div>";


}
?>
</div>

<h3>How to cite this code?</h3>
<p>Displaying data from the UCSC GenomeBrowser using SVG: Pierre Lindenbaum 2006. Integragen</p>
<p><a href="http://www.genome.ucsc.edu/">UCSC GenomeBrowser</a>: The UCSC Genome Browser Database: update 2006. Nucleic Acids Res. 2006 Jan 1;34(Database issue):D590-8. PMID: <a href="http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?cmd=Retrieve&amp;db=pubmed&amp;dopt=Abstract&amp;list_uids=16381938">16381938</a></p>
<h3>Links</h3>
<ul>
<li><a href="http://www.genome.ucsc.edu/">UCSC GenomeBrowser</a>: The UCSC Genome Browser Database: update 2006. Nucleic Acids Res. 2006 Jan 1;34(Database issue):D590-8. PMID: <a href="http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?cmd=Retrieve&amp;db=pubmed&amp;dopt=Abstract&amp;list_uids=16381938">16381938</a></li>
<li><a href="http://www.integragen.com">Integragen</a></li>
<li><a href="http://www.urbigene.com">Home</a></li>
<li><a href="http://plindenbaum.blogspot.com">blog</a></li>
</ul>

<hr/>
<adress>
<a href="http://plindenbaum.blogspot.com">Pierre Lindenbaum PhD</a><br/>
lindenb ( at ) integragen (dot) com<br/>
<a href="http://www.integragen.com">Integragen</a><br/>
4, rue Pierre Fontaine
91000 EVRY.
</adress>
<div align="center"><a href="http://www.integragen.com"><img src="http://www.integragen.com/img//title.png"
border="1" /></a></div>


<script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
</script>
<script type="text/javascript">
_uacct = "UA-XXXXX-2";
urchinTracker();
</script>

</body>
</html>
<?php
}

27 May 2008

NCBI Blast+ XSLT => XHTML + SVG

This post was inspired by the article Processing and duplicons on human chromosomes sent by Paulo Nuin yesterday and the short discussion that followed on FriendFeed. Paulo described in this article how the processing tool was used to display an output of ncbi-blast.

Here I show how a XSLT stylesheet can be used to transform a Blast into a XHTML+SVG page.

The stylesheet described here is available [here]



Here is how it works, at the beginning we've got a blast output in XML (here the query was a murine histone vs the human genome)

<?xml version="1.0"?>
<!DOCTYPE BlastOutput PUBLIC "-//NCBI//NCBI BlastOutput/EN" "NCBI_BlastOutput.dtd">
<BlastOutput>
<BlastOutput_program>blastn</BlastOutput_program>
<BlastOutput_version>blastn 2.2.5 [Nov-16-2002]</BlastOutput_version>
<BlastOutput_reference>~Reference: Altschul, Stephen F., Thomas L. Madden, Alejandro A. Schaffer, ~Jin
ghui Zhang, Zheng Zhang, Webb Miller, and David J. Lipman (1997), ~&quot;Gapped BLAST and PSI-BLAST: a new
generation of protein database search~programs&quot;, Nucleic Acids Res. 25:3389-3402.</BlastOutput_r
eference>
<BlastOutput_db>HumanGenome</BlastOutput_db>
<BlastOutput_query-ID>lcl|QUERY</BlastOutput_query-ID>
<BlastOutput_query-def>gi|34556456|gb|AY158922.2| Mus musculus histone protein Hist2h2ab gene, complet
e cds</BlastOutput_query-def>
<BlastOutput_query-len>1680</BlastOutput_query-len>
<BlastOutput_param>
<Parameters>
<Parameters_expect>10</Parameters_expect>
<Parameters_sc-match>1</Parameters_sc-match>
<Parameters_sc-mismatch>-3</Parameters_sc-mismatch>
<Parameters_gap-open>5</Parameters_gap-open>
<Parameters_gap-extend>2</Parameters_gap-extend>
<Parameters_filter>D</Parameters_filter>
</Parameters>
</BlastOutput_param>
<BlastOutput_iterations>
<Iteration>
<Iteration_iter-num>1</Iteration_iter-num>
<Iteration_hits>
<Hit>
<Hit_num>1</Hit_num>
<Hit_id>gnl|BL_ORD_ID|32</Hit_id>
<Hit_def>chr6</Hit_def>
<Hit_accession>32</Hit_accession>
<Hit_len>170975699</Hit_len>
<Hit_hsps>
<Hsp>
<Hsp_num>1</Hsp_num>
<Hsp_bit-score>444.541</Hsp_bit-score>
<Hsp_score>224</Hsp_score>
<Hsp_evalue>7.76885e-122</Hsp_evalue>
<Hsp_query-from>209</Hsp_query-from>
<Hsp_query-to>580</Hsp_query-to>
<Hsp_hit-from>27883967</Hsp_hit-from>
<Hsp_hit-to>27884338</Hsp_hit-to>
<Hsp_query-frame>1</Hsp_query-frame>
<Hsp_hit-frame>1</Hsp_hit-frame>
<Hsp_identity>335</Hsp_identity>
<Hsp_positive>335</Hsp_positive>
<Hsp_align-len>372</Hsp_align-len>
<Hsp_qseq>ATGTCTGGCCGTGGCAAACAGGGAGGCAAGGCCCGCGCCAAGGCCAAGTCGCGGTCTTCCCGGGCCGGGCTACAGTTCCC
GGTGGGGCGTGTGCACCGGCTGCTGCGCAAGGGCAACTACGCGGAGCGCGTGGGTGCCGGCGCGCCGGTATACATGGCGGCGGTGCTGGAGTACCTAACGGCCGAGATCC
TGGAGCTGGCGGGCAACGCGGCCCGCGACAACAAGAAGACGCGCATCATCCCGCGCCACCTGCAGCTGGCCATCCGCAACGACGAGGAGCTCAACAAGCTGCTGGGCAAA
GTGACGATCGCACAGGGCGGCGTCCTGCCCAACATCCAGGCCGTGCTGCTGCCCAAGAAGACCGAGAGCCAC</Hsp_qseq>
<Hsp_hseq>ATGTCTGGGCGTGGCAAGCAGGGAGGCAAAGCTCGCGCCAAGGCCAAGACCCGCTCTTCTCGGGCCGGGCTTCAGTTTCC
CGTAGGCCGAGTGCATCGCCTGCTCCGCAAAGGCAACTATGCGGAGCGGGTCGGTGCTGGAGCGCCGGTGTACCTGGCGGCGGTGCTGGAGTACCTGACCGCCGAGATCC
TGGAGCTGGCTGGCAACGCGGCCCGCGACAACAAGAAGACTCGCATCATCCCGCGTCACCTCCAGCTGGCCATCCGCAACGATGAGGAGCTCAACAAGCTTCTGGGCAAA
GTCACCATCGCACAGGGTGGCGTCCTGCCCAACATCCAGGCCGTGCTACTGCCCAAGAAGACCGAGAGCCAC</Hsp_hseq>
<Hsp_midline>|||||||| |||||||| ||||||||||| || ||||||||||||||| | || ||||| ||||||||||| |||||
|| || || || ||||| || ||||| ||||| |||||||| |||||||| || ||||| || |||||||| ||| |||||||||||||||||||||| || |||||||
||||||||||||| ||||||||||||||||||||||||||||| |||||||||||||| ||||| |||||||||||||||||||| ||||||||||||||||| ||||||
||||| || ||||||||||| ||||||||||||||||||||||||||||| ||||||||||||||||||||||||</Hsp_midline>
</Hsp>
<Hsp>
<Hsp_num>2</Hsp_num>
<Hsp_bit-score>420.753</Hsp_bit-score>
<Hsp_score>212</Hsp_score>
<Hsp_evalue>1.1255e-114</Hsp_evalue>
<Hsp_query-from>580</Hsp_query-from>
<Hsp_query-to>209</Hsp_query-to>
<Hsp_hit-from>27890126</Hsp_hit-from>
<Hsp_hit-to>27890497</Hsp_hit-to>
<Hsp_query-frame>1</Hsp_query-frame>
<Hsp_hit-frame>-1</Hsp_hit-frame>
<Hsp_identity>332</Hsp_identity>
<Hsp_positive>332</Hsp_positive>
<Hsp_align-len>372</Hsp_align-len>
<Hsp_qseq>GTGGCTCTCGGTCTTCTTGGGCAGCAGCACGGCCTGGATGTTGGGCAGGACGCCGCCCTGTGCGATCGTCACTTTGCCCA
GCAGCTTGTTGAGCTCCTCGTCGTTGCGGATGGCCAGCTGCAGGTGGCGCGGGATGATGCGCGTCTTCTTGTTGTCGCGGGCCGCGTTGCCCGCCAGCTCCAGGATCTCG
GCCGTTAGGTACTCCAGCACCGCCGCCATGTATACCGGCGCGCCGGCACCCACGCGCTCCGCGTAGTTGCCCTTGCGCAGCAGCCGGTGCACACGCCCCACCGGGAACTG
TAGCCCGGCCCGGGAAGACCGCGACTTGGCCTTGGCGCGGGCCTTGCCTCCCTGTTTGCCACGGCCAGACAT</Hsp_qseq>
<Hsp_hseq>GTGGCTCTCAGTTTTCTTTGGCAGCAGCACGGCCTGGATGTTGGGCAGGACGCCACCCTGTGCGATGGTGACTTTGCCCA
GAAGCTTGTTGAGCTCCTCATCGTTGCGGATGGCCAGCTGGAGGTGACGCGGGATGATGCGAGTCTTCTTGTTGTCGCGGGCCGCGTTGCCAGCCAGCTCCAGGATCTCG
GCGGTCAGGTACTCCAGCACCGCCGCCAGGTACACCGGCGCTCCAGCACCGACCCGCTCCGCATAGTTGCCTTTGCGGAGCAGGCGATGCACTCGGCCTACGGGAAACTG
AAGCCCGGCCCGAGAAGAGCGGGTCTTGGCCTTGGCGCGAGCTTTGCCTCCCTGCTTACCACGCCCAGACAT</Hsp_hseq>
<Hsp_midline>||||||||| || ||||| ||||||||||||||||||||||||||||||||||| ||||||||||| || |||||||
|||| ||||||||||||||||| |||||||||||||||||||| ||||| |||||||||||||| ||||||||||||||||||||||||||||| |||||||||||||||
||||| || |||||||||||||||||||||| ||| |||||||| || ||||| || |||||||| |||||||| ||||| ||||| || ||||| || || || || ||
||| ||||||||||| ||||| || | ||||||||||||||| || ||||||||||| || ||||| ||||||||</Hsp_midline>
</Hsp>

(...)

</Hit_hsps>
</Hit>
</Iteration_hits>
<Iteration_stat>
<Statistics>
<Statistics_db-num>1</Statistics_db-num>
<Statistics_db-len>245522847</Statistics_db-len>
<Statistics_hsp-len>0</Statistics_hsp-len>
<Statistics_eff-space>5.13463e+12</Statistics_eff-space>
<Statistics_kappa>0.710605</Statistics_kappa>
<Statistics_lambda>1.37407</Statistics_lambda>
<Statistics_entropy>1.30725</Statistics_entropy>
</Statistics>
</Iteration_stat>
</Iteration>
</BlastOutput_iterations>
</BlastOutput>


And the XSLT stylesheet:
1 <?xml version="1.0" encoding="UTF-8"?>
2 <xsl:stylesheet
3 version="1.0"
4 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
5 xmlns:svg="http://www.w3.org/2000/svg"
6 xmlns:xlink="http://www.w3.org/1999/xlink"
7 xmlns:h="http://www.w3.org/1999/xhtml"
8 >


17 <!-- ========================================================================= -->
18 <xsl:output method='xml' indent='yes' omit-xml-declaration="no"/>
19 <!-- we preserve the spaces in that element -->
20 <xsl:preserve-space elements="svg:style h:style" />
21
22 <!-- ========================================================================= -->
23 <!-- the width of the SVG -->
24 <xsl:variable name="svg-width">800</xsl:variable>
25 <!-- height of a HSP -->
26 <xsl:variable name="hsp-height">10</xsl:variable>
27 <!-- total number of Hits in first blast iteration -->
28 <xsl:variable name="hit-count"><xsl:value-of select="count(BlastOutput/BlastOutput_iterations/Iteration[1]/Iteration_hits/Hit)"/></xsl:variable>
29 <!-- total number of HSP in first blast iteration -->
30 <xsl:variable name="hsp-count"><xsl:value-of select="count(BlastOutput/BlastOutput_iterations/Iteration[1]/Iteration_hits/Hit/Hit_hsps/Hsp)"/></xsl:variable>
31 <!-- query length (bases or amino acids ) -->
32 <xsl:variable name="query-length"><xsl:value-of select="BlastOutput/BlastOutput_query-len"/></xsl:variable>
33 <!-- margin between two hits -->
34 <xsl:variable name="space-between-hits"><xsl:value-of select="3* $hsp-height"/></xsl:variable>
35 <!-- height of all hits -->
36 <xsl:variable name="hits-height"><xsl:value-of select="$hsp-count * $hsp-height + ($hit-count + 1) * $space-between-hits"/></xsl:variable>
37 <!-- size of the top header -->
38 <xsl:variable name="header-height">50</xsl:variable>
39
40 <!-- ========================================================================= -->
41
42 <!-- matching the root node -->
43 <xsl:template match="/">
44 <!-- start XHTML -->
45 <h:html>
46 <h:head>
47 <h:style type="text/css">
48 body {
49 font-size:10px;
50 font-family:Helvetica;
51 background-color:rgb(150,150,150);
52 color:white;
53 }
54 </h:style>
55 <h:title><xsl:value-of select="BlastOutput/BlastOutput_query-def"/></h:title>
56 </h:head>
57 <h:body>
58 <h:h1>Blast Results</h:h1>
59 <h:div>
60 <h:h3>Parameters</h:h3>
61 <h:table>
62 <h:tr><h:th>Database</h:th><h:td><xsl:value-of select="BlastOutput/BlastOutput_db"/></h:td></h:tr>
63 <h:tr><h:th>Query ID</h:th><h:td><xsl:value-of select="BlastOutput/BlastOutput_query-ID"/></h:td></h:tr>
64 <h:tr><h:th>Query Def.</h:th><h:td><h:b><xsl:value-of select="BlastOutput/BlastOutput_query-def"/></h:b></h:td></h:tr>
65 <h:tr><h:th>Query Length</h:th><h:td><h:b><xsl:value-of select="BlastOutput/BlastOutput_query-len"/></h:b></h:td></h:tr>
66 <h:tr><h:th>Version</h:th><h:td><xsl:value-of select="BlastOutput/BlastOutput_version"/></h:td></h:tr>
67 <h:tr><h:th>Reference</h:th><h:td><h:a href="http://www.ncbi.nlm.nih.gov/pubmed/9254694"><xsl:value-of select="BlastOutput/BlastOutput_reference"/></h:a></h:td></h:tr>
68 </h:table>
69 </h:div>
70 <h:hr/>
71 <h:div style="text-align:center">
72
73 <!-- starts SVG figure -->
74 <xsl:element name="svg:svg">
75 <xsl:attribute name="version">1.0</xsl:attribute>
76 <xsl:attribute name="width"><xsl:value-of select="$svg-width"/></xsl:attribute>
77 <xsl:attribute name="height"><xsl:value-of select="$hits-height + $header-height "/></xsl:attribute>
78 <svg:title><xsl:value-of select="BlastOutput/BlastOutput_query-def"/></svg:title>
79 <svg:defs>
80 <svg:style type="text/css">
81 text.t1 {
82 fill:black;
83 font-size:<xsl:value-of select="$hsp-height - 2"/>px;
84 font-family:Helvetica;
85 }
86 text.t2 {
87 fill:blue;
88 font-size:<xsl:value-of select="$space-between-hits - 2"/>px;
89 font-family:Helvetica;
90 text-anchor:middle;
91 }
92 text.title {
93 fill:white;
94 stroke:black;
95 font-size:12px;
96 font-family:Helvetica;
97 text-anchor:middle;
98 alignment-baseline:middle;
99 }
100 line.grid {
101 stroke:lightgray;
102 stroke-width:1.5px;
103 }
104
105 rect.hit {
106 fill:none;
107 stroke:darkgray;
108 stroke-width:1px;
109 }
110 </svg:style>
111
112 <svg:linearGradient x1="0%" y1="0%" x2="0%" y2="100%" id="score1">
113 <svg:stop offset="5%" stop-color="red" />
114 <svg:stop offset="50%" stop-color="whitesmoke" />
115 <svg:stop offset="95%" stop-color="red" />
116 </svg:linearGradient>
117 <svg:linearGradient x1="0%" y1="0%" x2="0%" y2="100%" id="score2">
118 <svg:stop offset="5%" stop-color="orange" />
119 <svg:stop offset="50%" stop-color="whitesmoke" />
120 <svg:stop offset="95%" stop-color="orange" />
121 </svg:linearGradient>
122 <svg:linearGradient x1="0%" y1="0%" x2="0%" y2="100%" id="score3">
123 <svg:stop offset="5%" stop-color="green" />
124 <svg:stop offset="50%" stop-color="whitesmoke" />
125 <svg:stop offset="95%" stop-color="green" />
126 </svg:linearGradient>
127 <svg:linearGradient x1="0%" y1="0%" x2="0%" y2="100%" id="score4">
128 <svg:stop offset="5%" stop-color="blue" />
129 <svg:stop offset="50%" stop-color="whitesmoke" />
130 <svg:stop offset="95%" stop-color="blue" />
131 </svg:linearGradient>
132 <svg:linearGradient x1="0%" y1="0%" x2="0%" y2="100%" id="score5">
133 <svg:stop offset="5%" stop-color="black" />
134 <svg:stop offset="50%" stop-color="whitesmoke" />
135 <svg:stop offset="95%" stop-color="black" />
136 </svg:linearGradient>
137 </svg:defs>
138
139 <xsl:element name="svg:rect">
140 <xsl:attribute name="x">0</xsl:attribute>
141 <xsl:attribute name="y">0</xsl:attribute>
142 <xsl:attribute name="width"><xsl:value-of select="$svg-width - 1"/></xsl:attribute>
143 <xsl:attribute name="height"><xsl:value-of select="$hits-height + $header-height "/></xsl:attribute>
144 <xsl:attribute name="fill">whitesmoke</xsl:attribute>
145 <xsl:attribute name="stroke">blue</xsl:attribute>
146 </xsl:element>
147
148
149 <xsl:apply-templates select="BlastOutput"/>
150 </xsl:element>
151 <!-- end SVG figure -->
152
153 </h:div>
154 <h:hr/>
155 <xsl:apply-templates select="BlastOutput/BlastOutput_param/Parameters"/>
156 <h:hr/>
157 <h:p><h:b>SVG</h:b> figure generated with <h:a href="http://code.google.com/p/lindenb/source/browse/trunk/src/xsl/blast2svg.xsl">blast2svg</h:a>. <h:a href="http://plindenbaum.blogspot.com">Pierre Lindenbaum PhD</h:a> <h:i>( plindenbaum at yahoo dot fr )</h:i></h:p>
158
159 </h:body>
160 </h:html>
161 </xsl:template>
162 <!-- ========================================================================= -->
163 <!-- display parameters in a HTML table -->
164 <xsl:template match="Parameters">
165 <h:div>
166 <h:h3>Parameters</h:h3>
167 <h:table>
168 <h:tr><h:th>Expect</h:th><h:td><xsl:value-of select="Parameters_expect"/></h:td></h:tr>
169 <h:tr><h:th>Sc-match</h:th><h:td><xsl:value-of select="Parameters_sc-match"/></h:td></h:tr>
170 <h:tr><h:th>Sc-mismatch</h:th><h:td><xsl:value-of select="Parameters_sc-mismatch"/></h:td></h:tr>
171 <h:tr><h:th>Gap-open</h:th><h:td><xsl:value-of select="Parameters_gap-open"/></h:td></h:tr>
172 <h:tr><h:th>Gap-extend</h:th><h:td><xsl:value-of select="Parameters_gap-extend"/></h:td></h:tr>
173 <h:tr><h:th>Filter</h:th><h:td><xsl:value-of select="Parameters_filter"/></h:td></h:tr>
174 </h:table>
175 </h:div>
176 </xsl:template>
177
178
179 <!-- ========================================================================= -->
180 <xsl:template match="BlastOutput">
181 <!-- paint header -->
182 <svg:g>
183 <xsl:element name="svg:rect">
184 <xsl:attribute name="x">0</xsl:attribute>
185 <xsl:attribute name="y">0</xsl:attribute>
186 <xsl:attribute name="width"><xsl:value-of select="$svg-width - 1"/></xsl:attribute>
187 <xsl:attribute name="height"><xsl:value-of select="$header-height - 2"/></xsl:attribute>
188 <xsl:attribute name="fill">url(#score5)</xsl:attribute>
189 <xsl:attribute name="stroke">black</xsl:attribute>
190 </xsl:element>
191
192 <xsl:element name="svg:text">
193 <xsl:attribute name="x"><xsl:value-of select="$svg-width div 2"/></xsl:attribute>
194 <xsl:attribute name="y"><xsl:value-of select="$header-height div 2"/></xsl:attribute>
195 <xsl:attribute name="class">title</xsl:attribute>
196 <xsl:value-of select="BlastOutput_query-def"/> (len=<xsl:value-of select="BlastOutput_query-len"/> )
197 </xsl:element>
198 </svg:g>
199 <xsl:apply-templates select="BlastOutput_iterations/Iteration[1]/Iteration_hits"/>
200 </xsl:template>
201
202 <!-- ========================================================================= -->
203
204 <xsl:template match="Iteration_hits">
205 <xsl:apply-templates select="Hit"/>
206 </xsl:template>
207
208 <!-- ========================================================================= -->
209
210 <xsl:template match="Hit">
211 <!-- count number of preceding hits -->
212 <xsl:variable name="preceding-hits"><xsl:value-of select="count(preceding-sibling::Hit)"/></xsl:variable>
213 <!-- count number of preceding hsp -->
214 <xsl:variable name="preceding-hsp"><xsl:value-of select="count(preceding-sibling::Hit/Hit_hsps/Hsp)"/></xsl:variable>
215 <!-- calculate hieght of this part -->
216 <xsl:variable name="height"><xsl:value-of select="count(Hit_hsps/Hsp)*$hsp-height"/></xsl:variable>
217 <!-- translate this part verticaly -->
218 <xsl:element name="svg:g">
219 <xsl:attribute name="transform">translate(0,<xsl:value-of select="$header-height + $preceding-hsp * $hsp-height + ($preceding-hits + 1) * $space-between-hits "/>)</xsl:attribute>
220 <xsl:attribute name="id">hit-<xsl:value-of select="generate-id(.)"/></xsl:attribute>
221 <xsl:element name="svg:text">
222 <xsl:attribute name="x"><xsl:value-of select="$svg-width div 2"/></xsl:attribute>
223 <xsl:attribute name="y"><xsl:value-of select="-2"/></xsl:attribute>
224 <xsl:attribute name="class">t2</xsl:attribute>
225 <xsl:value-of select="Hit_def"/>
226 </xsl:element>
227 <xsl:element name="svg:rect">
228 <xsl:attribute name="x">0</xsl:attribute>
229 <xsl:attribute name="y">0</xsl:attribute>
230 <xsl:attribute name="width"><xsl:value-of select="$svg-width"/></xsl:attribute>
231 <xsl:attribute name="height"><xsl:value-of select="$height"/></xsl:attribute>
232 <xsl:attribute name="class">hit</xsl:attribute>
233 </xsl:element>
234
235 <xsl:call-template name="grid">
236 <xsl:with-param name="x" select="0"/>
237 <xsl:with-param name="d" select="20"/>
238 <xsl:with-param name="W" select="$svg-width"/>
239 <xsl:with-param name="H" select="$height"/>
240 </xsl:call-template>
241
242 <xsl:apply-templates select="Hit_hsps"/>
243
244
245
246 </xsl:element>
247 </xsl:template>
248
249 <!-- ========================================================================= -->
250 <!-- draw vertical lines , recursive template -->
251 <xsl:template name="grid">
252 <xsl:param name="x" select="0" />
253 <xsl:param name="d" select="20" />
254 <xsl:param name="W" select="0" />
255 <xsl:param name="H" select="0" />
256 <svg:line class="grid" x1="{$x}" x2="{$x}" y1="0" y2="{$H}"/>
257 <xsl:if test="$d + $x &lt; $W">
258 <xsl:call-template name="grid">
259 <xsl:with-param name="x" select="$d + $x"/>
260 <xsl:with-param name="d" select="$d"/>
261 <xsl:with-param name="W" select="$W"/>
262 <xsl:with-param name="H" select="$H"/>
263 </xsl:call-template>
264 </xsl:if>
265 </xsl:template>
266
267 <!-- ========================================================================= -->
268
269 <xsl:template match="Hit_hsps">
270 <xsl:apply-templates select="Hsp"/>
271 </xsl:template>
272
273
274 <!-- ========================================================================= -->
275 <xsl:template match="Hsp">
276 <!-- number of previous hsp in the same Hit -->
277 <xsl:variable name="preceding-hsp"><xsl:value-of select="count(preceding-sibling::Hsp)"/></xsl:variable>
278 <!-- get the 5' position of the hsp in the query -->
279 <xsl:variable name="hsp-left"><xsl:choose>
280 <xsl:when test="Hsp_query-from &lt; Hsp_query-to"><xsl:value-of select="Hsp_query-from"/></xsl:when>
281 <xsl:otherwise><xsl:value-of select="Hsp_query-to"/></xsl:otherwise>
282 </xsl:choose></xsl:variable>
283 <!-- get the 3' position of the hsp in the query -->
284 <xsl:variable name="hsp-right"><xsl:choose>
285 <xsl:when test="Hsp_query-from &lt; Hsp_query-to"><xsl:value-of select="Hsp_query-to"/></xsl:when>
286 <xsl:otherwise><xsl:value-of select="Hsp_query-from"/></xsl:otherwise>
287 </xsl:choose></xsl:variable>
288 <!-- 5' position on screen -->
289 <xsl:variable name="x1"><xsl:value-of select="($hsp-left div $query-length ) * $svg-width"/></xsl:variable>
290 <!-- 3' position on screen -->
291 <xsl:variable name="x2"><xsl:value-of select="($hsp-right div $query-length ) * $svg-width"/></xsl:variable>
292 <!-- label -->
293 <xsl:variable name="label"><xsl:value-of select="Hsp_hit-from"/> - <xsl:value-of select="Hsp_hit-to"/> (<xsl:choose>
294 <xsl:when test="Hsp_query-from &lt; Hsp_query-to">+</xsl:when>
295 <xsl:otherwise>-</xsl:otherwise></xsl:choose>) e=<xsl:value-of select="Hsp_evalue"/></xsl:variable>
296
297 <!-- translate this Hsp verticaly in its Hit -->
298 <xsl:element name="svg:g">
299 <xsl:attribute name="transform">translate(0,<xsl:value-of select="$preceding-hsp * $hsp-height"/>)</xsl:attribute>
300 <xsl:attribute name="id">hsp-<xsl:value-of select="generate-id(.)"/></xsl:attribute>
301 <xsl:attribute name="title"><xsl:value-of select="Hsp_evalue"/></xsl:attribute>
302
303 <!-- paint the Hsp Rectangle -->
304 <xsl:element name="svg:rect">
305 <xsl:attribute name="x"><xsl:value-of select="$x1"/></xsl:attribute>
306 <xsl:attribute name="y">2</xsl:attribute>
307 <xsl:attribute name="width"><xsl:value-of select="$x2 - $x1"/></xsl:attribute>
308 <xsl:attribute name="height"><xsl:value-of select="$hsp-height - 4"/></xsl:attribute>
309 <!-- choose a color according to the e-value -->
310 <xsl:attribute name="fill"><xsl:choose>
311 <xsl:when test="Hsp_evalue &lt; 1E-100">url(#score1)</xsl:when>
312 <xsl:when test="Hsp_evalue &lt; 1E-10">url(#score2)</xsl:when>
313 <xsl:when test="Hsp_evalue &lt; 0.1">url(#score3)</xsl:when>
314 <xsl:when test="Hsp_evalue &lt; 0">url(#score4)</xsl:when>
315 <xsl:otherwise>url(#score5)</xsl:otherwise>
316 </xsl:choose></xsl:attribute>
317 </xsl:element>
318
319 <!-- paint the label according to the position of the Hsp on screen -->
320 <xsl:choose>
321 <xsl:when test="$x2 &lt; (0.75 * $svg-width)">
322 <xsl:element name="svg:text">
323 <xsl:attribute name="class">t1</xsl:attribute>
324 <xsl:attribute name="x"><xsl:value-of select="$x2 + 10 "/></xsl:attribute>
325 <xsl:attribute name="y"><xsl:value-of select="$hsp-height -1"/></xsl:attribute>
326 <xsl:attribute name="text-anchor">start</xsl:attribute>
327 <xsl:value-of select="$label"/>
328 </xsl:element>
329 </xsl:when>
330 <xsl:when test="$x1 &gt; (0.25 * $svg-width)">
331 <xsl:element name="svg:text">
332 <xsl:attribute name="class">t1</xsl:attribute>
333 <xsl:attribute name="x"><xsl:value-of select="$x1 - 10 "/></xsl:attribute>
334 <xsl:attribute name="y"><xsl:value-of select="$hsp-height -1"/></xsl:attribute>
335 <xsl:attribute name="text-anchor">end</xsl:attribute>
336 <xsl:value-of select="$label"/>
337 </xsl:element>
338 </xsl:when>
339 <xsl:otherwise>
340 <xsl:element name="svg:text">
341 <xsl:attribute name="class">t1</xsl:attribute>
342 <xsl:attribute name="x"><xsl:value-of select="($x2 - $x1) div 2 "/></xsl:attribute>
343 <xsl:attribute name="y"><xsl:value-of select="$hsp-height -1"/></xsl:attribute>
344 <xsl:attribute name="text-anchor">middle</xsl:attribute>
345 <xsl:value-of select="$label"/>
346 </xsl:element>
347 </xsl:otherwise>
348 </xsl:choose>
349
350 </xsl:element>
351 </xsl:template>
352 <!-- ========================================================================= -->
353
354
355 </xsl:stylesheet>

Some random notes:
Line 22-38: I define a few variables such as the number of Hsp or the number of Hits
Line 43: matching the root., we start the XHTML document here
line 73: we start the SVG document here. It is embedded in the XHTML document
line 80-110: CSS can be used for SVG
line 112-137: we define a few gradients to colorize the Hsp. TODO: finding a better method to colorize according to its e-value/score
line 199: for the first iteration, the <Hit> templates are called
line 211: we need to count the number of preceding hits/hsp to know how much we should translate vertically this group of object
line 242: we loop over each hsp in this hit
line 276-292: again, we need to know the number of preceding hits/hsp to translate this hsp vertically. We also calculate the 5' and the 3' position of the Hit in the query.
line 304-307: here, we paint the hsp-rectangle
line 320-348: lousy method, we paint a label for this hsp, trying to find the best place (left/right/middle) to print the label.

The blast file was processed with xsltproc:
xsltproc --novalid blast2svg.xsl blast.xml > ~/blast.xhtml


A sample output is displayed below
blast2svg



Pierre

09 January 2006

Firefox, XUL, SVG, XSLT & Genbank

This WE I played with XUL and Firefox 1.5. This last version of firefox allows to write SVG (a XML-based vectorial drawing format) within the html code (see http://developer.mozilla.org/en/docs/SVG_In_HTML_Introduction) I wondered if it was possible to display the features of a genbank sequence as SVG into a XUL window.

The result is displayed below:



I still had problems with the XUL layout and I was not able to display more than one tabpanel (the others were frozen). But creating such image on the fly could be great way to display interaction genomic maps. As an example, the UCSC genome browser (aka golden path) might use this system to display its tracks and make it interactive.

Updated 2010-08-12

<?xml version="1.0" ?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:h="http://www.w3.org/TR/REC-html40"
>
<!--
author : Pierre Lindenbaum PhD
blog: http://plindenbaum.blogspot.com
mail: plindenbaum [ A T ] yahoo.fr
date: 2006
desc: transform a genbank/XML file into html+svg
-->
<xsl:param name="screen-width">100</xsl:param>
<xsl:param name="seq-height">12</xsl:param>
<xsl:output
method="xml"
version="1.0"
encoding="UTF-8"
indent="yes"
/>


<xsl:template match="/">
<xul:window
id="findfile-window"
title="Find Files"
orient="horizontal"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<xsl:apply-templates/>
</xul:window>
</xsl:template>

<xsl:template match="GBSet">
<xul:tabbox flex="1">
<xul:tabs >
<xsl:for-each select="GBSeq">
<xsl:element name="xul:tab">
<xsl:attribute name="id"><xsl:value-of select="generate-id(.)"/></xsl:attribute>
<xsl:attribute name="label"><xsl:value-of select="GBSeq_locus"/></xsl:attribute>
</xsl:element>
</xsl:for-each>
</xul:tabs>
<xul:tabpanels flex="1">

<xsl:for-each select="GBSeq">
<xul:tabpanel flex="1" id="searchpanel">
<xul:vbox flex="1">
<xul:hbox flex="1">
<xsl:apply-templates select="GBSeq_references"/>
</xul:hbox>
<xul:hbox flex="1">
<xul:iframe id="pubmed-iframe" src="about:blank" flex="1" style="overflow : auto; width : 30px; height : 300px; border:1px solid blue;"/>
<xul:box flex="1" style="overflow : auto; width : 30px; height : 300px; border:1px solid blue;">

<xsl:element name="svg:svg">
<xsl:attribute name="xul:flex">1</xsl:attribute>
<xsl:attribute name="width"><xsl:value-of select="2*$screen-width"/>+500</xsl:attribute>
<xsl:attribute name="height"><xsl:value-of select="count(GBSeq_feature-table/GBFeature)*20+5"/></xsl:attribute>
<xsl:attribute name="stroke">black</xsl:attribute>
<svg:g>
<svg:defs>
<svg:linearGradient x1="0%" y1="0%" x2="0%" y2="100%" id="metal">
<svg:stop offset="5%" stop-color="black" />
<svg:stop offset="50%" stop-color="whitesmoke" />
<svg:stop offset="95%" stop-color="black" />
</svg:linearGradient>
<svg:filter id="MyFilter" filterUnits="userSpaceOnUse" x="0%" y="0%" width="100%" height="100%">
<svg:feGaussianBlur in="SourceAlpha" stdDeviation="4" result="blur"/>
<svg:feOffset in="blur" dx="4" dy="4" result="offsetBlur"/>
<svg:feSpecularLighting in="blur" surfaceScale="5" specularConstant=".75"
specularExponent="20" lighting-color="lightgray"
result="specOut">
<svg:fePointLight x="-5000" y="-10000" z="20000"/>
</svg:feSpecularLighting>
<svg:feComposite in="specOut" in2="SourceAlpha" operator="in" result="specOut"/>
<svg:feComposite in="SourceGraphic" in2="specOut" operator="arithmetic"
k1="0" k2="1" k3="1" k4="0" result="litPaint"/>
<svg:feMerge>
<svg:feMergeNode in="offsetBlur"/>
<svg:feMergeNode in="litPaint"/>
</svg:feMerge>
</svg:filter>

</svg:defs>
<svg:g fill="red">
<xsl:call-template name="rect">
<xsl:with-param name="sequence-size" select="GBSeq_length" />
<xsl:with-param name="label" select="GBSeq_definition" />
<xsl:with-param name="x0" select="0" />
<xsl:with-param name="x1" select="GBSeq_length" />
</xsl:call-template>
<xsl:apply-templates select="GBSeq_feature-table" />
</svg:g>
</svg:g>
</xsl:element>

</xul:box>
</xul:hbox>
</xul:vbox>
</xul:tabpanel>
</xsl:for-each>

</xul:tabpanels>
</xul:tabbox>
</xsl:template>



<xsl:template match="GBSeq_references">
<xsl:element name="xul:tree">
<xsl:attribute name="flex">1</xsl:attribute>
<xsl:attribute name="enableColumnDrag">true</xsl:attribute>
<xsl:attribute name="onselect">var iframe= document.getElementById(&apos;pubmed-iframe&apos;);
if(iframe==null) { alert(&apos;cannot find iframe!&apos;); return;}
switch(this.currentIndex+1)
{
<xsl:for-each select="GBReference">
case <xsl:value-of select="position()"/>:
iframe.setAttribute(&apos;src&apos;,&apos;http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?cmd=Retrieve&amp;db=pubmed&amp;dopt=Abstract&amp;query_hl=1&amp;list_uids=<xsl:value-of select="GBReference_pubmed"/>&apos;);
break;
</xsl:for-each>
default: iframe.setAttribute(&apos;src&apos;,&apos;about:blank&apos;);
break;
}
</xsl:attribute>
<xul:treecols>
<xul:treecol id="1" label="PMID" flex="1"/>
<xul:treecol id="3" label="Title" flex="1"/>
<xul:treecol id="4" label="Reference" flex="1"/>
<xul:treecol id="5" label="Authors" flex="1"/>
<xul:treecol id="6" label="Remarks" flex="2"/>
</xul:treecols>
<xul:treechildren >
<xsl:for-each select="GBReference">
<xul:treeitem>
<xul:treerow flex="1">
<xsl:element name="xul:treecell">
<xsl:attribute name="label">
<xsl:value-of select="GBReference_pubmed"/>
</xsl:attribute>
</xsl:element>


<xsl:element name="xul:treecell">
<xsl:attribute name="label">
<xsl:value-of select="GBReference_title"/>
</xsl:attribute>
</xsl:element>

<xsl:element name="xul:treecell">
<xsl:attribute name="label">
<xsl:value-of select="GBReference_journal"/>
</xsl:attribute>
</xsl:element>


<xsl:element name="xul:treecell">
<xsl:attribute name="label">
<xsl:for-each select="GBReference_authors/GBAuthor">
<xsl:value-of select="."/><xsl:text> </xsl:text>
</xsl:for-each>
</xsl:attribute>
</xsl:element>


<xsl:element name="xul:treecell">
<xsl:attribute name="label">
<xsl:value-of select="GBReference_remark"/>
</xsl:attribute>
</xsl:element>


</xul:treerow>
</xul:treeitem>
</xsl:for-each>
</xul:treechildren>
</xsl:element>
</xsl:template>

<xsl:template match="GBSeq_feature-table">
<xsl:apply-templates match="GBFeature" />
</xsl:template>


<xsl:template match="GBFeature">
<xsl:apply-templates select="GBFeature_intervals" />
</xsl:template>

<xsl:template match="GBFeature_intervals">
<xsl:apply-templates select="GBInterval" />
</xsl:template>

<xsl:template match="GBInterval">
<xsl:if test="GBInterval_from">
<xsl:call-template name="rect">
<xsl:with-param name="x0" select="GBInterval_from" />
<xsl:with-param name="x1" select="GBInterval_to" />
<xsl:with-param name="y" select="30+(count(../../preceding-sibling::*))*20" />
<xsl:with-param name="sequence-size" select="../../../../GBSeq_length" />
<xsl:with-param name="label" select="../../GBFeature_key" />
</xsl:call-template>
</xsl:if>

<xsl:if test="GBInterval_point">
<xsl:call-template name="rect">
<xsl:with-param name="x0" select="GBInterval_point" />
<xsl:with-param name="x1" select="GBInterval_point" />
<xsl:with-param name="y" select="30+(count(../../preceding-sibling::*))*20" />
<xsl:with-param name="sequence-size" select="../../../../GBSeq_length" />
<xsl:with-param name="label" select="../../GBFeature_key" />
</xsl:call-template>
</xsl:if>

</xsl:template>





<xsl:template name="rect">
<xsl:param name="x0" select="0" />
<xsl:param name="y" select="0" />
<xsl:param name="x1" select="0" />
<xsl:param name="label" />
<xsl:param name="height" select="10" />
<xsl:param name="sequence-size" />
<xsl:param name="i0" select="($x0 div $sequence-size)* $screen-width" />
<xsl:param name="width" select="(($x1 div $sequence-size)* $screen-width)-$i0" />
<xsl:param name="y2" select="$y+12" />
<xsl:if test="$i0 &gt;= 0">
<xsl:element name="svg:rect">
<xsl:attribute name="x"><xsl:value-of select="$i0"/></xsl:attribute>
<xsl:attribute name="y"><xsl:value-of select="$y"/></xsl:attribute>
<xsl:attribute name="width"><xsl:value-of select="1+$width"/></xsl:attribute>
<xsl:attribute name="height"><xsl:value-of select="$height"/></xsl:attribute>
<xsl:attribute name="fill">url(#metal)</xsl:attribute>
<xsl:attribute name="stroke">black</xsl:attribute>
<xsl:attribute name="filter">url(#MyFilter)</xsl:attribute>
</xsl:element>
</xsl:if>

<xsl:element name="svg:text">
<xsl:attribute name="stroke">blue</xsl:attribute>
<xsl:attribute name="x"><xsl:value-of select="$screen-width+10"/></xsl:attribute>
<xsl:attribute name="y"><xsl:value-of select="$y2"/></xsl:attribute>
<xsl:value-of select="$x0"/> -&gt;<xsl:value-of select="$x1"/> : <xsl:value-of select="$label"/>
</xsl:element>
</xsl:template>


</xsl:stylesheet>


02 September 2010

Playing with the ming API , a C library for SWF/Flash.My notebook.

Ming is a C library generating some simple Flash/SWF movies. In this post I will describe how I used the Ming API by try to converting to SWF the SVG that was generated in a previous post
Genetic Algorithm with Darwin's Face: Dynamic SVG


The original SVG file

The original SVG file looks like this:
<?xml version="1.0"?>
<svg:svg xmlns:svg="http://www.w3.org/2000/svg" version="1.1" width="160" height="222" style="stroke: none;" viewBox="0 0 160 222">
<svg:g id="face">
<svg:polygon points="110,193 11,320 -67,164" style="fill: rgb(129, 82, 122); opacity: 0.68;"/>
<svg:polygon points="109,30 224,181 -4,-1" style="fill: rgb(213, 113, 17); opacity: 0.52;"/>
<svg:polygon points="128,105 101,0 209,-75" style="fill: rgb(200, 91, 58); opacity: 0.04;"/>
<svg:polygon points="115,183 169,232 193,-29" style="fill: rgb(185, 133, 125); opacity: 0.9;"/>
<svg:polygon points="68,186 47,39 57,30" style="fill: rgb(249, 68, 34); opacity: 0.62;"/>
<svg:polygon points="80,185 108,123 158,131" style="fill: rgb(62, 181, 169); opacity: 0.56;"/>
<svg:polygon points="110,61 211,-86 115,217" style="fill: rgb(10, 46, 216); opacity: 0.86;"/>
<svg:polygon points="115,183 169,232 192,-27" style="fill: rgb(188, 127, 122); opacity: 0.9;"/>
<svg:polygon points="78,197 205,135 85,178" style="fill: rgb(53, 145, 210); opacity: 0.6;"/>
<svg:polygon points="108,64 211,-81 111,220" style="fill: rgb(10, 46, 216); opacity: 0.46;"/>
<svg:polygon points="110,59 210,-88 116,215" style="fill: rgb(10, 46, 216); opacity: 0.86;"/>
<svg:polygon points="53,138 60,45 46,60" style="fill: rgb(13, 98, 29); opacity: 0.8;"/>
(...)


A generic C program using the ming API would look like this:
/* initialize ming */
Ming_init();
/* create a movie */
movie=newSWFMovie();
/* set number of frames */
SWFMovie_setNumberOfFrames(movie, NUM_FRAME);
/* loop over the frames */
for(i=0;i<NUM_FRAME;++i)
{
/* create rectange */
rect = newSWFShape();
SWFShape_movePenTo(rect,x,y);
SWFShape_drawLineTo(rect,x+width,y);
SWFShape_drawLineTo(rect,x+width,y+height);
SWFShape_drawLineTo(rect,x,y+height);
SWFShape_drawLineTo(rect,x,y);
/* add figure in the movie */
SWFMovie_add(swf, rect);
(...)
/* add frame */
SWFMovie_nextFrame(movie);
}
/* save movie to file */
WFMovie_save(movie,"file.swf");
/* dispose movie */
destroySWFMovie(movie);
I created a simple C code transforming my SVG to SWF using the ming API. The file contains 5 frames where I slightly moved some shapes. The code was posted on github at: http://github.com/lindenb/ccsandbox/blob/master/src/svg2swf.c.
Compile & run:
export LD_LIBRARY_PATH=${ming.lib.dir}
gcc -L ${ming.lib.dir} -I ${ming.include.dir} `xml2-config --cflags ` svg2swf.c -lming `xml2-config --libs `
./a.out -o darwin.swf darw.svg




That's it
Pierre