Version française

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 = 
# 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
Since it's a bit tedious, you can use the following API instead (#use "ubigraph_api.ml";;):
(* 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] )

end
And 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 

Last modification: Friday 11 December 2009
Mail box
Powered by the ENS Lyon