Menu

Use the auto-layout algorithm in GVF

sam
2002-10-19
2002-12-18
  • sam

    sam - 2002-10-19

    Hi,

    I download GVF and run the demo. It is very cool.
    I am wondering if it is possible to use the auto-layout algorithm in GVF and display the graph in my application (Not in Royere)?

    If yes, can someone please tell me how to do it?
    Thank you.

     
    • yugen

      yugen - 2002-10-20

      All of the layout algorithms in Royere extend the royere.cwi.layout.Layout class, and the key method in the Layout class is computePositions().  This method takes a graph object and assigns coordinates to all of its nodes. 

      If you prefer to render the graphs in your own application, you would do this:

      (1) Convert your graph's node and edge objects to the Royere object model (i.e., instances of royere.cwi.structure.Node and royere.cwi.structure.Edge).  Then populate a royere.cwi.structure.Graph object with them via the Graph.add() method.

      (2) Choose a layout algorithm.  This will be a subclass of royere.cwi.layout.Layout.  (For example, royere.cwi.layout.ReingoldTilford.) However, you don't instantiate a layout object directly; layouts are constructed via LayoutFactory:

      String layoutName = "Reingold-Tilford";
      Layout rtLayout = LayoutFactory.createLayout(layoutName); 

      (3) Invoke the layout's computePositions() method to lay out the graph.

      (4) Now, for every node in the graph, ask the layout object for the node's coordinates.  (You can iterate through a graph's nodes via the Graph.getNodeTraversal() method.)  Every node's coordinates will be an instance of royere.cwi.layout.Coordinates.

      (5) Convert the Coordinates objects back to your object model.

      (6) You now have coordinates for every node in the graph, so you can draw the graph however you want to in your application.

      Does this answer your question?

       
    • sam

      sam - 2002-10-21

      Thanks for your detailed answer. Do you know what layout algorithm is/will support in GVF?

      I got these layout algorithm from ilog's jviews.
      # Hierarchical
      # Tree
      # Radial tree
      # Topological mesh
      # Circular (ring and star) and bus
      # Spring embedder, uniform length and grid

      thank you

       
    • yugen

      yugen - 2002-10-22

      > I got these layout algorithm from ilog's jviews.

      I assume you mean http://www.ilog.com/products/jviews/graphlayout/ .

      > Hierarchical
      See royere.cwi.layout.ReingoldTilford.

      > Tree
      See royere.cwi.layout.ReingoldTilford.

      > Radial tree
      See royere.cwi.layout.Radial.

      > Topological mesh
      N/A. You'd have to implement this one yourself.

      > Circular (ring and star) and bus
      See royere.cwi.layout.Ring.  No star or bus.

      > Spring embedder, uniform length and grid
      See royere.bath.layout.GEM -- this is a spring (force-directed) layout.

       
    • sam

      sam - 2002-10-22

      Thanks again.

       
    • sam

      sam - 2002-11-21

      Hi,

      I tried what you suggested, but I got NullPointerException
      java.lang.NullPointerException
          at royere.cwi.layout.ReingoldTilford.setYcoordinates(ReingoldTilford.java:497)
          at royere.cwi.layout.ReingoldTilford.setYcoordinates(ReingoldTilford.java:385)
          at royere.cwi.layout.ReingoldTilford.secondWalk(ReingoldTilford.java:240)
          at royere.cwi.layout.ReingoldTilford.computePositions(ReingoldTilford.java:296)
          at Test.main(Test.java:43)

      Here is my small test program:
      import royere.cwi.layout.Coordinates;
      import royere.cwi.layout.LayoutFactory;
      import royere.cwi.layout.ReingoldTilford;
      import royere.cwi.structure.Edge;
      import royere.cwi.structure.Graph;
      import royere.cwi.structure.Node;

      public class Test {

          public static void main(String[] args) {
              Graph g = new Graph();

              Node n1 = new Node();
              Node n2 = new Node();
              Node n3 = new Node();
              Node n4 = new Node();
              Node n5 = new Node();
              Node n6 = new Node();

              Edge e1 = new Edge(n1, n2);
              Edge e2 = new Edge(n2, n3);
              Edge e3 = new Edge(n3, n4);
              Edge e4 = new Edge(n4, n5);
              Edge e5 = new Edge(n5, n6);
         

              g.add(n1);
              g.add(n2);
              g.add(n3);
              g.add(n4);
              g.add(n5);
              g.add(n6);

              g.add(e1);
              g.add(e2);
              g.add(e3);
              g.add(e4);
              g.add(e5);
         

              ReingoldTilford layout = (ReingoldTilford) LayoutFactory.createLayout("ReingoldTilford");

              layout.computePositions(g);

              Coordinates c = layout.getCoordinates(n1, g);
              System.out.println("x=" + c.getX() + " y=" + c.getY());

              c = layout.getCoordinates(n2, g);
              System.out.println("x=" + c.getX() + " y=" + c.getY());

          }
      }

      Could you please tell me what do I miss? And the computePositions() method is protected. Can that change to public? I am forced to cast the Layout object returned from LayoutFactory to ReingoldTilford because of that.

       
      • M. Scott Marshall

        I can't test this directly because my test environment is currently broken but my initial guess is that what you're missing is the "directed" property for the graph:

        g.setProperty(Keys.ISDIRECTED, Boolean.TRUE);

        If you set this graph property *before* adding edges, then the lists of successors and predecessors for the affected nodes are updated whenever you add/remove an edge.

        Note that if you attempted the same layout by calling the LayoutManager, you would get a "PropertyMismatch" error in the error log. Your test file is bypassing the pipeline and some of the builtin safeguards.

        We are looking at changing some of the protected methods in a new release to make your type of application simpler to implement.

         
    • sam

      sam - 2002-11-21

      Thanks for your suggestion. I tried that, but it still gives me the same problem.

       
      • yugen

        yugen - 2002-11-21

        > I tried what you suggested, but I got NullPointerException
        > java.lang.NullPointerException
        >    at
        > royere.cwi.layout.ReingoldTilford.setYcoordinates(ReingoldTilford.java:497)

        I was able to reproduce your error.  Try inserting

            layout.setGraph(g);

        just before

            layout.computePositions(g);

        That solved the problem for me.

        > And the computePositions() method is
        > protected. Can that change to public?

        We will change it to public in the next release.

         
    • sam

      sam - 2002-11-22

      Thanks. I got that to work.

      But when I layout the following graph using ReingoldTilford, all 4 nodes are layout hortonizally.
          Node n1 = new Node();
              Node n2 = new Node();
              Node n3 = new Node();
              Node n4 = new Node();

              Edge e1 = new Edge(n1, n2);
              Edge e2 = new Edge(n1, n3);
              Edge e3 = new Edge(n1, n4);
             
              g.setProperty(Keys.ISDIRECTED, Boolean.TRUE);

              g.add(n1);
              g.add(n2);
              g.add(n3);
              g.add(n4);
         

              g.add(e1);
              g.add(e2);
              g.add(e3);

      When I print out the co-ordinate, I got this:

      x=0.0 y=0.0
      x=1.2000000000000002 y=0.0
      x=2.4000000000000004 y=0.0
      x=3.6000000000000005 y=0.0

      Why all 4 points are on the same line (y=0.0), I expect node 1 to be above node 2,3,4 (a hierachy structure).

      Is this a correct assumption? Do I miss something?
      Thank you.
      Sam
      ========================================
      the complete code:
          public static void main(String[] args) {
              Graph g = new Graph();

              Node n1 = new Node();
              Node n2 = new Node();
              Node n3 = new Node();
              Node n4 = new Node();

              Edge e1 = new Edge(n1, n2);
              Edge e2 = new Edge(n1, n3);
              Edge e3 = new Edge(n1, n4);
             
             
              g.setProperty(Keys.ISDIRECTED, Boolean.TRUE);

              g.add(n1);
              g.add(n2);
              g.add(n3);
              g.add(n4);
         

              g.add(e1);
              g.add(e2);
              g.add(e3);
             
              ReingoldTilford layout =
                  (ReingoldTilford) LayoutFactory.createLayout("ReingoldTilford");
                 
              layout.setGraph(g);
              layout.computePositions(g);

              Coordinates c = layout.getCoordinates(n1, g);
              System.out.println("x=" + c.getX() + " y=" + c.getY());

              c = layout.getCoordinates(n2, g);
              System.out.println("x=" + c.getX() + " y=" + c.getY());

              c = layout.getCoordinates(n3, g);
              System.out.println("x=" + c.getX() + " y=" + c.getY());

              c = layout.getCoordinates(n4, g);
              System.out.println("x=" + c.getX() + " y=" + c.getY());

         

          }

       
    • yugen

      yugen - 2002-11-22

      Reingold-Tilford uses the depth of each node (relative to the root) to determinte the node's Y coordinate.  In order to determine depth, the edges must be directed.  So you must explicitly set each edge's ISDIRECTED property to true:

      e1.setProperty(Keys.ISDIRECTED, Boolean.TRUE);
      e2.setProperty(Keys.ISDIRECTED, Boolean.TRUE);
      e3.setProperty(Keys.ISDIRECTED, Boolean.TRUE);

      It might be more user-friendly if the Graph.add(Edge) method automatically set this edge property for you, in those situations where the containing graph has been marked as directed.  However, this assumes that the user would never want to insert an undirected edge into a graph that has directed edges (creating a hybrid graph).  So, the responsibility is placed on whoever creates the Edge object to explicitly mark it as directed.

       
    • sam

      sam - 2002-11-22

      Thanks again.

      If I set the ISDIRECTED property to true, does that mean the To node (n1) and From node (n2) of an edge matters?
      Edge e1 = new Edge(n1, n2);

      Can I use different layout algorithms within the same graph?

      For example, I want to use GVF to layout UML elements.
      For Inheritance relationships, I want to use the Hirerachy layout, and for association relationships, I want to use the Ring layout. Is that possible?

      One think I can think of is to use a 2 steps approach.
      - walk thru the whole graph and find nodes with inheritance relationship only, build  Graph, Node, Edges objects for that
      - use GVF to layout that Graph ONLY using Hirerachy layout.
      - lock all the nodes.
      -add Node, Edges objects for nodes with association relationship,
      - use GVF to layout the graph again using Ring layout.

      Will this work? Does this make sense?

      Thanks.

       
      • yugen

        yugen - 2002-11-22

        > If I set the ISDIRECTED property to true, does
        > that mean the
        > To node (n1) and
        > From node (n2) of an edge matters?
        >  Edge e1 = new Edge(n1, n2);

        The order of the parameters matters, i.e., n1 is the source node and n2 is the target node.

        > Can I use different layout algorithms within the
        > same graph?
        >
        > For example, I want to use GVF to layout UML elements.
        >
        > For Inheritance relationships, I want to use the
        > Hirerachy layout, and
        > for association relationships, I want to use the
        > Ring layout.
        > Is that possible?

        Let's handle this question in a separate thread (see "Using multiple layout algorithms in one view" at
        http://sourceforge.net/forum/forum.php?thread_id=768684&forum_id=126557\).

         
    • Michael

      Michael - 2002-12-16

      Hello,
      I tried to extend the example that is given here, and tried to print out the coordinates-set of the edges in the example. But I always got
      NullPointerExceptions. So as a test, I added the following lines of code

      Coordinates[] edgeCoord = layout.getCoordinateSet(e1,g);
      System.out.println("edgeCoord: " + edgeCoord);

      And then I got as output
      edgeCoord: null

      So, for all the edges, I always get a null-object; and no coordinates-set for the edge.
      I've tried to look at the problem myself, but can't to find the origin of the problem, or a solution. Maybe you can help me?
      Thanks!

       
      • yugen

        yugen - 2002-12-17

        > Coordinates[] edgeCoord = layout.getCoordinateSet(e1,g);
        > System.out.println("edgeCoord: " + edgeCoord);
        >
        > And then I got as output
        > edgeCoord: null
        >
        > So, for all the edges, I always get a null-object;
        > and no coordinates-set for the edge.

        Presently, Royere layouts assign coordinates to nodes, not edges. 

        The getCoordinateSet() and setCoordinateSet() methods exist to support "polyline" edges.  A polyline edge consists of multiple line segments between the source and target nodes.  This is useful, for example, if you want to approximate an arc.

        A while ago I modified the code (specifically, the DCEdge constructor in DrawingControl.java) to make the simplifying assumption that an edge is always a single straight line segment from source to target.  This makes it easier to deal with edges that start inside one graph and terminate inside a different one.  (I can elaborate on this if you like, although it's a bit off-topic.)  Abandoning polyline edges was admittedly a non-backward-compatible change; however, none of the stock Royere layout algorithms use polyline edges, and I wasn't aware of any users who needed this feature.

        Do you need polyline edges?  If so, I can update DrawingControl.java to support them.  Of course, you would have to extend the appropriate Layout subclass and add the logic to assign the edge coordinates the way you want. 

         
        • Michael

          Michael - 2002-12-18

          Thanks for the quick response.
          For now, I don't need polyline edges. So it's not necessary to adapt DrawingControl.java.
          But I am still in a beginning phase of my project, so it is possible that in some time I notice that I would need them after all; and then I can contact you again,

          Michael...

           

Log in to post a comment.