Package home | Report new bug | New search | Development Roadmap Status: Open | Feedback | All | Closed Since Version 1.3.0

Request #15943 adding subgraph to subgraph?
Submitted: 2009-02-25 20:21 UTC
From: krzysztofciba Assigned: jausions
Status: Closed Package: Image_GraphViz
PHP Version: 5.2.3 OS: all
Roadmaps: (Not assigned)    
Subscription  


 [2009-02-25 20:21 UTC] krzysztofciba (Krzysztof Ciba)
Description: ------------ Your script for creating graphs is excellent, but... How can I add subgraph inside another subgraph? I mean this is supported in GraphViz, e.g. please try to render this: digraph G { subgraph cluster_A { node0 -> node1; subgraph cluster_B { node2 -> node3; } } } I can't see how this can be made using Image_GraphViz... Test script: --------------- Expected result: ---------------- Actual result: --------------

Comments

 [2009-04-01 17:14 UTC] krzysztofciba (Krzysztof Ciba)
What about this one crapy implementation: <pre> class graphviz { var $graph = array( "name" => "G", "__attr__" => array(), "__nodes__" => array(), "__edges__" => array(), "__clusters__" => array() ); var $fmt = "svg"; var $dotCommand = "/usr/bin/dot"; var $neatoCommand = "/usr/bin/neato"; /** * @brief c'tor * @param $name graph name * @param $fmt output format */ public function __construct( $name=null, $fmt=null ) { if ( $name != null && is_string($name) ) { $this->graph["name"] = $name; } if ( $fmt != null && is_string($fmt) ) { $this->fmt = $fmt; } } /** * @brief cluster finder * @param $clusterName name of cluster to find * @param $where reference to array */ public function &findCluster( $clusterName, &$where=null) { if ( $where == null ) { $where =& $this->graph; } if ( isset( $where["__clusters__"][$clusterName] ) ) { return $where["__clusters__"][$clusterName]; } else { foreach ( $where["__clusters__"] as $key => &$cluster ) { return $this->findCluster( $clusterName, &$cluster ); } } return null; } /** * @brief add subcluster to graph * @param $id new cluster id * @parm $attr array with attributes * @param $toCluster parent subcluster */ public function addCluster( $id, $attr=null, $toCluster=null ) { if ( $toCluster == null ) { if ( ! isset( $this->graph["__clusters__"][$id] ) ) { $this->graph["__clusters__"][$id] = array( "__attrs__" => array(), "__nodes__" => array(), "__edges__" => array(), "__clusters__" => array() ) ; if ( $attr != null && is_array() ) { $this->graph["__clusters__"][$id]["__attrs__"] = $attr; } } } else { $where =& $this->findCluster( $toCluster ); if ( $where != null ) { $where["__clusters__"][$id] = array( "__attrs__" => array(), "__nodes__" => array(), "__edges__" => array(), "__clusters__" => array() ) ; if ( $attr != null && is_array() ) { $where["__clusters__"][$id]["__attrs__"] = $attr; } } } } /** * @brief add node to graph * @param $id node id * @param $attr array with node attributes * @param $cluster parent cluster */ public function addNode( $id, $attr=null, $cluster=null ) { if ( $attr == null ) $attr = array(); if ( $cluster != null ) { $where =& $this->findCluster( $cluster ); if ( $where != null ) { $where["__nodes__"][$id] = $attr; } else { $this->addCluster($cluster); $this->graph["__clusters__"][$cluster]["__nodes__"][$id] = $attr; } } else { $this->graph["__nodes__"][$id] = $attr; } } /** * @brief connect to nodes * @param $from begin node * @param $to end node * @param $attr edge attributes */ public function addEdge( $from, $to, $attr=null ) { $id = $from . "-->" . $to; if ( !isset( $this->graph["__edges__"][$id]) ) { $this->graph["__edges__"][$id] = array( "__from__" => $from, "__to__" => $to, "__attrs__" => array() ); if ( is_array( $attr ) ) { $this->graph["__edges__"][$id]["__attrs__"] = $attr; } } else { if ( is_array($attr) ) { $this->graph["__edges__"][$id]["__attrs__"] = array_merge($attr, $this->graph["__edges__"][$id]["__attrs__"] ); } } } /** * @brief transform internal subclusters representation to dot language * @param where location to parse * @return string with GraphViz markup */ private function __parseClusters( $where = null ) { $out = ""; if ( $where == null ) { $where = $this->graph; } foreach ( $where["__clusters__"] as $clusterName => $cluster ) { $out .= "subgraph cluster_".$clusterName. " {\n"; // attributes foreach ( $cluster["__attrs__"] as $attr => $attrValue ) { $attributeList[] = $attr.'="'.$attrValue.'"'; } if (!empty($attributeList) ) { $out .= implode(';', $attributeList).";\n"; } // nodes foreach ( $cluster["__nodes__"] as $nodeName => $attr ) { foreach ( $attr as $attrName => $attrValue ) { $nodeAttr[] = $attrName . "=\"" . $attrValue . "\""; } $out .= $nodeName; if ( !empty($nodeAttr) ) { $out .= " [ " . implode(',', $nodeAttr) . " ]"; } $out .= ";\n"; } $out .= $this->__parseClusters( $cluster ); $out .= "}\n"; } return $out; } /** * @brief transform internal graph representation to dot language * @return string GraphViz markup */ public function parse() { if ( isset($this->graph["name"]) && is_string($this->graph["name"]) ) { $parsedGraph = "digraph " . $this->graph["name"] . " {\n"; } else { $parsedGraph = "digraph G {\n"; } if (isset($this->graph["__attrs__"])) { foreach ($this->graph["__attrs__"] as $key => $value) { $attributeList[] = $key . '="' . $value . '"'; } if ( !empty($attributeList) ) { $parsedGraph .= "graph [ ".implode(",", $attributeList) . " ];\n"; } } // subclusters $parsedGraph .= $this->__parseClusters(); // nodes foreach ( $this->graph["__nodes__"] as $nodeName => $attr ) { foreach ( $attr as $attrName => $attrValue ) { $nodeAttrList[] = $attrName . "=\"" . $attrValue . "\""; } $parsedGraph .= $nodeName; if ( !empty($nodeAttr) ) { $parsedGraph .= " [ " . implode(",", $nodeAttrList) . " ]"; } $parsedGraph .= ";\n"; } // edges foreach ( $this->graph["__edges__"] as $id => $edge ) { $from = $edge["__from__"]; $to = $edge["__to__"]; $egdeAttributes = $edge["__attrs__"]; foreach ( $edgeAttributes as $attrName => $attrValue ) { $edgeAttrList[] = $attrName."=\"".$attrValue."\""; } $parsedGraph .= $from . " -> " . $to; if ( !empty($edgeAttrList) ) { $parsedGraph .= " [ " . implode(",", $edgeAttrList) . " ]"; } $parsedGraph .= ";\n"; } // end of graph $parsedGraph .= "}\n"; return $parsedGraph; } } class test_graphviz { public function __construct() { $this->gr = new graphviz( "a", "svg" ); $this->gr->addCluster( "main", array(), null ); $this->gr->addCluster( "sub", array(), "main" ); $this->gr->addNode( "node_in_graph" ); $this->gr->addNode( "node_in_main", array(), "main" ); $this->gr->addNode( "node_in_sub", array(), "sub" ); $this->gr->addEdge( "node_in_main", "node_in_graph" ); $this->gr->addEdge( "node_in_main", "node_in_sub" ); $this->gr->addEdge( "node_in_sub", "node_in_graph" ); echo "<pre>---dot---\n"; echo $this->gr->parse(); echo "</pre><br>"; } } if ( isset($_GET["test"] ) ) { $t = new test_graphviz(); } ?> </pre> --- Result: ---dot--- digraph a { subgraph cluster_main { node_in_main; subgraph cluster_sub { node_in_sub; } } node_in_graph; node_in_main -> node_in_graph; node_in_main -> node_in_sub; node_in_sub -> node_in_graph; }
 [2009-07-03 19:01 UTC] krzysztofciba (Krzysztof Ciba)
Any news on that? I mean I've posted solution almost 6 month ago, which could fix the problem... I'm using it w/o any problem. Is Image_GraphViz module death?
 [2009-12-08 21:31 UTC] jausions (Philippe Jausions)
-Status: Open +Status: Analyzed -Assigned To: +Assigned To: jausions
 [2009-12-14 03:22 UTC] jausions (Philippe Jausions)
-Status: Analyzed +Status: Closed
This bug has been fixed in SVN. If this was a documentation problem, the fix will appear on pear.php.net by the end of next Sunday (CET). If this was a problem with the pear.php.net website, the change should be live shortly. Otherwise, the fix will appear in the package's next release. Thank you for the report and for helping us make PEAR better.