Ubigraph
During my Ph.D. thesis, I came across Ubigraph which is a great software for visualizing graphs. Since my program was written in OCaml, I used ocaml-xmlrpc bindings to communicate to the server (package libxmlrpc-light-ocaml-dev for debian).
Using Ubigraph from OCaml top-level
Here, the problem is getting the right libraries in the right order. It took me a little while to figure a order which works. (#use "ubigraph_toplevel.ml";;);
#load "unix.cma";; #load "netsys/netsys.cma";; #load "equeue/equeue.cma";; #load "xml-light/xml-light.cma";; #load "pcre/pcre.cma";; #load "netstring/netstring.cma";; #load "netclient/netclient.cma";; #load "rpc/rpc.cma";; #load "netplex/netplex.cma";; #load "netcgi2/netcgi.cma";; #load "nethttpd-for-netcgi2/nethttpd-for-netcgi2.cma";; #load "xmlrpc-light/xmlrpc-light.cma";; #directory "/usr/lib/ocaml/3.10.1/xmlrpc-light";;Now we can play with Ubigraph:
# let rpc = new XmlRpc.client "http://localhost:2078/RPC2";; val rpc : XmlRpc.client =Since it's a bit tedious, you can use the following API instead (#use "ubigraph_api.ml";;):# rpc#call "ubigraph.new_vertex" [] ;; - : XmlRpc.value = `Int 117666857 # rpc#call "ubigraph.new_vertex_w_id" [`Int 1] ;; - : XmlRpc.value = `Int 0 # rpc#call "ubigraph.new_vertex_w_id" [`Int 2] ;; - : XmlRpc.value = `Int 0 # rpc#call "ubigraph.new_edge" [`Int 1; `Int 2] ;; - : XmlRpc.value = `Int 120689713
(* API for Ubigraph *) exception Ubigraph_fail class graph = object(self) val rpc = new XmlRpc.client "http://localhost:20738/RPC2" val only_warnings = true val get = function | `Int i when i <> -1 -> i | _ -> raise Ubigraph_fail val check = function | `Int i when i <> -1 -> true | _ -> false method launch proc args = let ret = rpc#call proc args in try get ret with Ubigraph_fail -> let errmsg = List.fold_left (fun s arg -> s^XmlRpc.dump arg^"; " ) ("Ubigraph returned bad valuet: " ^ XmlRpc.dump ret ^ " for function "^proc^" with args ") args in if only_warnings then ( Format.eprintf "Warning: %s@." errmsg ; -1) else failwith errmsg (*/* Basic API methods */ *) method clear () = ignore(self#launch "ubigraph.clear" []) method new_vertex () = self#launch "ubigraph.new_vertex" [] method new_edge x y = self#launch "ubigraph.new_edge" [`Int x; `Int y] method remove_vertex id = ignore(self#launch "ubigraph.remove_vertex" [`Int id] ) method remove_edge id = ignore(self#launch "ubigraph.remove_edge" [`Int id] ) (*/* Vertex/edge creation when user wants to use their own id's */ *) method new_vertex_w_id id = ignore(self#launch "ubigraph.new_vertex_w_id" [`Int id]) method new_edge_w_id id x y = ignore(self#launch "ubigraph.new_edge_w_id" [`Int id; `Int x; `Int y] ) (*/* Set a vertex attribute */ *) method set_vertex_attribute id att value = ignore(self#launch "ubigraph.set_vertex_attribute" [`Int id; `String att; `String value] ) (*/* Vertex styles */ *) method change_vertex_style id s = ignore(self#launch "ubigraph.change_vertex_style" [`Int id; `Int s] ) method new_vertex_style parent_style = self#launch "ubigraph.new_vertex_style" [`Int parent_style] method set_vertex_style_attribute s att value = ignore(self#launch "ubigraph.set_vertex_style_attribute" [`Int s; `String att; `String value] ) (*/* Set an edge attribute */ *) method set_edge_attribute id att value = ignore(self#launch "ubigraph.set_edge_attribute" [`Int id; `String att; `String value] ) (*/* Edges styles */ *) method change_edge_style id s = ignore(self#launch "ubigraph.change_edge_style" [`Int id; `Int s] ) method new_edge_style parent_style = self#launch "ubigraph.new_edge_style" [`Int parent_style] method set_edge_style_attribute s att value = ignore(self#launch "ubigraph.set_edge_style_attribute" [`Int s; `String att; `String value] ) endAnd here is a example using the API. (#use "ubigraph_api_testing.ml";;).
(* API Testing *) let _ = let g = new graph in g#clear (); for i = 0 to 9 do g#new_vertex_w_id i done ; let x = g#new_vertex() in for i = 0 to 9 do g#new_edge_w_id i i ((i+1) mod 10); let e = g#new_edge x i in g#set_edge_attribute e "color" "#ff0000" done ; Unix.sleep 1; for i = 0 to 9 do g#remove_edge i ; g#set_vertex_attribute i "label" ("node "^string_of_int i); done; Unix.sleep 1; g#set_vertex_attribute 0 "color" "#ff0000"
Using Ubigraph from OCaml compiled code
Here, the problem is finding the right options to compile and link your code.
To compile to an object code, use:
ocamlopt -c -I +xmlrpc-light ubigraph_api.ml
To link your final code, with a main file test.ml using the Ubigraph API:
ocamlopt unix.cmxa -I +netsys netsys.cmxa -I +equeue equeue.cmxa -I +pcre \ pcre.cmxa -I +netstring netstring.cmxa -I +netclient netclient.cmxa -I \ +xml-light xml-light.cmxa -I +xmlrpc-light xmlrpc-light.cmxa ubigraph_api.cmx \ test.cmx -o test
If you are using ocamlbuild as I do, use the following _tags and myocamlbuild.ml files:
#_tag file "ubigraph_api.ml": use_unix, use_xmlrpc-light <*.{byte,native}>: use_unix, use_xmlrpc-light, use_xml-light, use_netsys, use_equeue, use_pcre, use_netstring, use_netclient,
(* myocamlbuild file *) open Ocamlbuild_plugin open Command (* Configuration section *) let static = true dispatch begin function | After_rules -> (* For Ubigraph *) ocaml_lib ~extern:true ~dir:"+netsys" "netsys"; ocaml_lib ~extern:true ~dir:"+equeue" "equeue"; ocaml_lib ~extern:true ~dir:"+pcre" "pcre"; (* Neturl, Netencoding *) ocaml_lib ~extern:true ~dir:"+netstring" "netstring"; (* Http_client *) ocaml_lib ~extern:true ~dir:"+netclient" "netclient"; (* Xml *) ocaml_lib ~extern:true ~dir:"+xml-light" "xml-light"; (* Main dependance *) ocaml_lib ~extern:true ~dir:"+xmlrpc-light" "xmlrpc-light"; | _ -> () end