forked from semsol/arc2
-
Notifications
You must be signed in to change notification settings - Fork 0
Plugins: Triples Visualizer
semsol edited this page Mar 14, 2011
·
2 revisions
The Triples Visualizer Plugin can generate graphviz files and images. It needs two configuration parameters and an ARC triples array as input:
/* ARC2 static class inclusion */
include_once('path/to/arc/ARC2.php');
/* configuration */
$config = array(
/* path to dot */
'graphviz_path' => '/usr/local/bin/dot',
/* tmp dir (default: '/tmp/') */
'graphviz_temp' => '/usr/local/tmp/',
/* pre-defined namespace prefixes (optional) */
'ns' => array('foaf' => 'http://xmlns.com/foaf/0.1/')
);
/* instantiation */
$viz = ARC2::getComponent('TriplesVisualizerPlugin', $config);
$triples = ...; /* e.g. from parse() or a "SELECT ?s ?p ?o" query */
/* display an svg image */
$svg = $viz->draw($triples, 'svg', 'base64');
echo '<embed type="image/svg+xml" src="data:image/svg+xml;base64,' . $svg . '"/>';
/* display a png image */
$png = $viz->draw($triples, 'png', 'base64');
echo '<img src="data:image/png;base64,' . $png . '"/>';
/* generate a dot file */
$dot_src = $viz->dot($triples);
Save to "plugins/ARC2_TriplesVisualizerPlugin.php"
<?php
/*
homepage: ARC or plugin homepage
license: http://arc.semsol.org/license
class: ARC2 Triples Visualizer Plugin
author: Luis A. Paulo
version: 2008-08-05
*/
ARC2::inc('Class');
class ARC2_TriplesVisualizerPlugin extends ARC2_Class {
function __construct ($a = '', &$caller) {
parent::__construct($a, $caller);
}
function ARC2_TriplesVisualizerPlugin ($a = '', &$caller) {
$this->__construct($a, $caller);
}
function __init () {
parent::__init();
$this->graphviz_path = $this->v('graphviz_path', '/usr/localbin/dot', $this->a);
$this->graphviz_temp = $this->v('graphviz_temp', '/tmp/', $this->a);
}
/**
* Display graph visualization on an <img> tag.
* returns null on error
* @param array $res
* @param array $infos
* @return string
* @access public
*/
function echo_PNG (&$res, &$infos) {
$format='png';
$output=self::draw($res,$infos,$format,'base64');
if ($this->getErrors()) {
return $output;
};
echo '<img src="data:image/'.$format.';base64,'.$output.'"/>';
}
/**
* Returns graph visualization result according to format and enconde params.
* returns null on error
* @param array $res
* @param array $infos
* @param array $format = 'dot'
* @param array $encode = 'raw'
* @return string
* @access public
*/
function draw($triples, $format = 'dot', $encode = 'raw') {
$dot=self::dot($triples, $format);
if (!in_array($encode, array('raw', 'base64', 'gzip'))) {
$this->addError('Unsupported encode "'.$encode.'"');
};
if (self::getErrors()) {
return $dot;
};
mt_srand((double)microtime()*1000000);
$filename=$this->graphviz_temp.md5(uniqid(mt_rand())).".dot";
$file_handle = fopen($filename, 'w');
if ($file_handle) {
fwrite($file_handle, $dot);
fclose($file_handle);
};
$dotinput = " -T" . $format . " " . $filename;
$lines = array();
exec($this->graphviz_path . " -T" . $format . " " . $filename . ' -o' . $filename . '.' . $format . ' 2>&1', $lines);
if (file_exists($filename . '.' . $format)) {
$output = file_get_contents($filename . '.' . $format);
}
unlink($filename);
unlink($filename . '.' . $format);
switch ($encode){
case 'base64':
//echo '<embed type="image/svg+xml" width="100%" height="100%" src="data:image/'.$format.'+xml;base64,'.$img.'"/>';
//echo '<img src="data:image/png;base64,'.base64_encode($output).'"/>';
return base64_encode($output);
break;
case 'gzip':
return gzencode($output);
break;
default:
return $output;
};
}
/**
* Construct dot source file based on a query result.
*
* @param array $res
* @param array $infos
* @param String $format = 'dot'
* @return string
* @access public
*/
function dot($triples, $format = 'dot') {
if (!in_array($format, array('dot', 'png', 'svg'))) {
return $this->addError('Unsupported format "'.$format.'"');
};
if (ARC2::getStructType($triples) != 'triples') {
return $this->addError('Input structure is not a triples array.');
};
$dot='digraph arc2 {'."\n";
$ns = $this->v('ns', array(), $this->a);
$nsc = 0;
$dot .= '_ns_box_';
// dot general graph parameters
$dot.='rankdir=LR;'.'ranksep=3;'.'nodesep=0.3;'."\n";
//$vars= & $res['variables'];
$nodes=array('uri'=>array()
,'bnode'=>array()
,'literal'=>array()
);
$edges=array('uri'=>array());
foreach ($triples as $i=>$t) {
$type= isset($t['s type']) ? $t['s type'] : $t['s_type'];
if (!($s=array_search($t['s'],$nodes[$type]))) {
$s='s'.$i;
switch ($type) {
case 'uri':
case 'bnode':
$nodes[$type][$s]= &$t['s'];
break;
default:
alert('Invalid type '.$type);
return '';
};
};
$type= isset($t['o type']) ? $t['o type'] : $t['o_type'];
if (!($o=array_search($t['o'],$nodes[$type]))) {
$o='o'.$i;
switch ($type) {
case 'uri':
case 'bnode':
$nodes[$type][$o]= &$t['o'];
break;
case 'literal':
$nodes[$type][$o]= &$t['o'];
break;
default:
alert('Invalid type '.$type);
return '';
};
};
/* p */
$type= 'uri';
switch ($type) {
case 'uri':
$edges[$type][]= array('label'=>&$t['p'],'s'=>$s,'o'=>$o);
break;
default:
alert('Invalid edge type '.$type);
return '';
};
};
// dot uri parameters
$dot.="node [shape=ellipse,fontsize=20,style=filled,fillcolor=limegreen];\n";
foreach ($nodes['uri'] as $i=>$nd) {
$label=self::guessNamespace($nd);
$prefix=array_search($label,$ns);
if ($prefix) {
$label=self::guessName($nd);
$label=($label)?$prefix.':'.$label:$nd;
} else {
$label=$nd;
};
$dot.=$i.'[label="'.$label.'"];'."\n";
};
// dot blanknode parameters
$dot.="node [fillcolor=greenyellow];\n";
foreach ($nodes['bnode'] as $i=>$nd) {
$dot.=$i.';'."\n";
};
// dot literal parameters
$dot.="node [shape=box,fontsize=20,style=filled,fillcolor=orange];\n";
foreach ($nodes['literal'] as $i=>$nd) {
$label = substr(strip_tags($nd), 0, 80);
$dot.=$i.'[label="'. $label .'"];'."\n";
};
// dot arrows (edge) parameters
$dot.="edge [samehead,fontsize=20];\n";
foreach ($edges['uri'] as $nd) {
$label = $nd['label'];
if (preg_match('/^(.*[\/#])([^\/\#]*)$/', $nd['label'], $m)) {
$ns_uri = $m[1];
$lname = $m[2];
if (!$prefix = array_search($ns_uri, $ns)) {
$ns['ns' . $nsc] = $ns_uri;
$prefix = 'ns' . $nsc;
$nsc++;
}
$label = $prefix . ':' . $lname;
}
$dot.=$nd['s'].' -> '.$nd['o'].'[label="'.$label.'"];'."\n";
};
$dot.='}'."\n";
/* ns box */
$sub_r = '';
if ($ns) {
$sub_r .= 'node [shape=record,fontsize=20,style=filled,color=black,fillcolor=gray];'."\n";
$first = 1;
foreach ($ns as $prefix => $uri) {
$sub_r .= ($first) ? 'struct [label="' : '|';
$sub_r .= $prefix . ': \<' . $uri . '\>';
$first = 0;
}
$sub_r .= '"];'."\n";
}
$dot = str_replace('_ns_box_', $sub_r, $dot);
return $dot;
}
/**
* Extracts the namespace prefix out of a URI.
*
* @param String $uri
* @return string
* @access public
*/
function guessNamespace ($uri) {
$l = self::getNamespaceEnd($uri);
return $l > 1 ? substr($uri ,0, $l) : "";
}
/**
* Delivers the name out of the URI (without the namespace prefix).
*
* @param String $uri
* @return string
* @access public
*/
function guessName ($uri) {
return substr($uri,self::getNamespaceEnd($uri));
}
/**
* Position of the namespace end
* Method looks for # : and /
* @param String $uri
* @access private
*/
function getNamespaceEnd ($uri) {
$l = strlen($uri)-1;
do {
$c = substr($uri, $l, 1);
if($c == '#' || $c == ':' || $c == '/')
break;
$l--;
} while ($l >= 0);
$l++;
return $l;
}
}
?>