The JUNG Developer's FAQ
 Last updated 2 December 2004
 Up to date for JUNG 1.5.1

============
GETTING HELP
============
Q. Where do I go to get questions answered?

A. Check either the JUNG Support forum
	https://sourceforge.net/forum/forum.php?forum_id=252062
or the JUNG-support mailing list


==============
THE BASICS
==============

Q. What is this "TestCase" that I see references to?

A. It's part of JUnit, the tool we use for unit testing out code. See http://junit.org


Q. How do I add two parallel edges to a SparseGraph?

A. Make sure the graph allows parallel edges (this means you can't use
 DirectedSparseGraph or UndirectedSparseGraph, unless you remove the 
 edge constraint Graph.NO_PARALLEL_EDGE from them) and make sure that the
 vertex implementation accepts them (don't use the Simple*SparseVertex 
 implementations).

	Graph g = new SparseGraph();
	Vertex v1 = g.addVertex( new SparseVertex());
	Vertex v2 = g.addVertex( new SparseVertex());
	g.addEdge( new UndirectedSparseEdge( v1, v2 ));
	g.addEdge( new UndirectedSparseEdge( v1, v2 ));
	
Q. How are the following related: the interfaces DirectedGraph and 
UndirectedGraph, the constraints Graph.DIRECTED_EDGE and Graph.UNDIRECTED_EDGE, 
and the classes DirectedSparseGraph and UndirectedSparseGraph?

A. DirectedGraph and UndirectedGraph are tagging interfaces, whose 
implementation contract states that any graph that implements these interfaces 
must have only directed or undirected edges (respectively).  In the 
implementations that we supply, these constraints are enforced by the predicates 
Graph.DIRECTED_EDGE and Graph.UNDIRECTED_EDGE.  This means, for example, that a 
graph can be small-d directed (i.e., have only directed edges) but not be an 
instance of DirectedGraph.  DirectedSparseGraph includes, by default, the 
constraint Graph.DIRECTED_EDGE.  (The last two sentences also apply to 
undirected graphs, with "undirected" substituted for "directed".)


Q. Why are there Directed, Undirected, and "neutral" versions of Edge, Graph, 
and Vertex?
	
A. Edges may be either Directed or Undirected.  This is an inherent property of
edges: they can either be directed, and have a defined head (destination) and
tail (source), or be undirected, and have neither.

Graphs may be Directed, Undirected, or neither.  This reflects the kinds of
edges that they accept.  If a given graph instance includes neither the 
Graph.DIRECTED_EDGE nor the Graph.UNDIRECTED_EDGE constraint, then they may 
accept either type of edge.  This is done so that algorithms that work one way 
on directed graphs, and another on undirected graphs, can find out what kind of 
input they have (or reject the input if it's not of the right type).

The different vertex implementations may be connected by directed edges, 
undirected edges, or both.  For reasons of computational efficiency (of both 
time and space), we've created several different implementations.  You can just 
use SparseVertex for everything, but it requires more space (and time) than the 
same methods on DirectedSparseVertex.   (Analogously, the Simple*Vertex 
implementations do not support parallel edges, and require correspondingly less 
space than their non-Simple counterparts.)  If this is confusing, you can create 
a TypedVertexGenerator factory, and use its create() method to make your 
vertices.

(Before JUNG's initial release, we experimented with making the graph solely 
responsible for creating vertices of the appropriate type (based on the graph's 
edge constraints).  The problem with this is that it prevents users from 
creating their own vertex types, which is can be a very powerful tool in Java.)

	
Q. I have a need for storing the ID of the vertex with the vertex and
accessing the id given vertex and accessng the vertex given id.

A. Both the StringLabeller and the Indexer mechanism allow one to go
back-and-forth from  ID to Vertex and vice versa. However, the Indexer
isn't robust in the face of graph changes (if the graph changes, the
index can too) and the StringLabeller works on Strings.

As a general solution, consider associating a BidiMap (from
Commons-Collections) with the Graph.

thus,
	BidiMap bMap = new DualHashBidiMap();
	graph.addUserDatum( BMAP_KEY, bMap, UserData.REMOVE );

then do things like
	bMap.put( VERTEX, ID );
	Vertex v = bMap.get( ID );
	Object id = bMap.get( vertex );


Q. How can I get a reliable ordering of vertices? In particular, if I
read in a GraphML file, how can I then iterate through them in the
order by ID? getAllVertices.iterator() doesn't go in any particular order.

A. This is true. The contract for the java Set iterator states that
the order in which the iterator visits the elements of the Set is
undefined. In particular, the order is not guaranteed to be the
insertion order (and usually isn't). See the previous answer for one
solution: you may then iterate the BidiMap's ID list.

Q. How can I append a second graph into a first?

A. NEW: GraphUtils.union(g1, g2).  (The previous answer is retained
below for archival purposes.)

It would be something like this:

	// adds all vertices of g2 into g1
	// connects g2 to g1 as if v1 and v2 were the same 

     void merge( graph g1, graph g2, vertex v1, vertex v2 ) {
	// copy the vertices in
	for ( Vertex v in g2.getVertices() ) {
	  if (v != v1 ) v.copy( g1 );

	  // copy the edges in
	  for ( Edge e in g2.getEdges() ) {
	    Vertex front = e.getEndpoints().first();
  	    Vertex back = e.getEndpoints() .back()
	  if( front == v1 ) {
	    g2.addEdge( new DirectedSparseEdge( v2, back);
	  } else if ( back == v1 ) {
	    g2.addEdge( new DirectedSparseEdge( front, v2);
	  } else {
	    e.copy( g2 );
	  }
	}



Q. Can I use JUNG without CERN Colt?

A. NEW: the most recent version of Colt has a license that allows 
commercial use.  If you want to remove Colt for some other reason,
you can, but this will disable the following elements: some of the 
classes in algorithms.importance, the KKLayout algorithm, the ExactFlowCommunity 
algorithm in algorithms.cluster, some of the code in 
algorithms.GraphMatrixOperations, io.MatrixFile, and some of the routines in the 
statistics package.  Everything else should work OK.


Q. Does JUNG support serialization?

A. We haven't implemented it, largely because none of the JUNG core
team understand serialization well enough to do it correctly. If you
do, please feel free to contribute code.

==================
CAPTURING GRAPHS
=================

Q. How can I save a graph to EPS, PNG, or JPG?

A. you can use a Java screen dump utility for EPS, PNG, and JPEG
http://drzaius.ics.uci.edu/blogs/danyelf/archives/000100.html

or, for JPEG, use either this code:

public void saveGraphAsJPEG(GraphDraw myGraph, String filename) {
  Dimension size = myGraph.getSize();
  BufferedImage myImage =
    new BufferedImage(size.width, size.height,
        BufferedImage.TYPE_INT_RGB);
  Graphics2D g2 = myImage.createGraphics();
  myGraph.paintComponent(g2);
  try {
    OutputStream out = new FileOutputStream(filename);
       JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
     encoder.encode(myImage);
     out.close();
   } catch (Exception e) {
     System.out.println(e);
  }
} 

or this (similar) code:

/**
* Convert the viewed graph to a JPEG image written in the specified file name.
* The size of the image is the size of the layout. The background color is this one
* of the visualization viewer. The default representation of the image is 8-bit RGB
* color components, corresponding to a Windows- or Solaris- style BGR color model,
* with the colors Blue, Green, and Red packed into integer pixels.
*/

  public void writeJPEGImage(VisualizationViewer vv, String filename) {
    int width = vv.getLayout().getCurrentSize().width;
    int height = vv.getLayout().getCurrentSize().height;
    Color bg = getBackground();

    BufferedImage bi = new BufferedImage(width,height,BufferedImage.TYPE_INT_BGR);
    Graphics2D graphics = bi.createGraphics();
    graphics.setColor(bg);
    graphics.fillRect(0,0, width, height);
    vv.paintComponent(graphics);

    try{
       ImageIO.write(bi,"jpeg",new File(filename));
    }catch(Exception e){e.printStackTrace();}
}


Q. How do I get XY locations for vertices without actually painting them?

A.  Use the Layout (that's what it's for) without the Renderer or the
GraphDraw. It looks like this:

	layout = new WhateverLayout( g );
	layout.initialize(new Dimension(600, 600));
	while (!layout.incrementsAreDone() ) {
	   // or run it for a fixed number of iterations
	   layout.advancePositions();
	}


Q. Where is (x,y) data stored for vertices? How can I save out the
locations of (x,y) coordinates of a graph to a file? How can I load
the coordinates to a current graph?

A. Under the GraphDraw systen, xy coordinates are maintained by the
Layout (call layout.getX( v )  and layout.getY( v ) ). They are,
however, stored on the vertex (for all AbstractLayout descendants) in
the UserData: call layout.getBaseKey() to get the key.

Unfortunately, there isn't a direct way to save out the vertices, but
you can do it manually. Similarly, there is not a current Layout that
reads from disk, but there's no reason it couldn't be built: simply
arrange for its getX and getY to return values from a disk file.



=================
DRAWING GRAPHS
===================

Q. Do the layout algorithms take vertex size into consideration?

A. No.



Q. How well does the code that applies Filters to GraphDraw work?

A. Poorly. We don't advocate using that as a way of generating dynamic graphs.


Q. Help! KKlayout calculates coordinates out of bounds!

A. Unfortunately, the algorithm is designed to pick a "roughly
correct" size, and sometimes gets it wrong. The NewGraphDraw has an
autoscale that's meant to help fix that; so is a patch submitted by
Masanori Harada.
	https://sourceforge.net/tracker/?group_id=73840&atid=539121
which you may find useful.




Q. On my graph I have several verticies with only 1 other vertex
connected to it. When I draw the graph all of my unconnected verticies
and low connected verticies are on the edges of the graph. Is there
some way to get them to display visibly in the middle of the graph and
not the edges?  

A. Unfortunately, both FRLayout and KKLayout tend to smear vertices
fairly far outwards. We haven't found a good solution to this yet.



Q. How do I use the SettableRenderer's EdgeThicknessFunctions,
VertexColorFunction, and similar?

A. A VertexColorFunction is an interface that takes a vertex and
returns a color. You can then create any object that implements that
interface. The SettableRenderer will then use this VertexColorFunction
to determine the color of each vertex by doing something like
	g.setColor( veretx_color_func.getColor( vertex ));
	
Here's some examples to help clarify. First, this VCF returns red for everything.

    // this returns red for everything
    public MyAllRedVertexColorFunction implements VertexColorFunction {
       public getColor( Vertex v ) {
          return Color.RED;
       }
    }
    
This VCF returns red for all vertices with the user datum "SELECTED",
blue for the input vertex, and black for everything else.

   public MyComplexVertexColorFunction implements VertexColorFunction {

      Vertex input = null;
      
      public MyComplexVertexColorFunction ( Vertex input ) {
        this.input = input;
      }
      
       public getColor( Vertex v ) {
         if ( v == input ) return Color.BLUE;
         if ( v.getUserDatum("SELECTED") != null) return Color.RED;
         return Color.BLACK;
       }     
      
   }
   
The important similiarity between these two is that they both return a
color, given a vertex in the graph.

More sample code is in ClusteringDemo, which paints different sorts of
edges depending on whether they are "in" or "out" of the selection.

NEW: Instead of SettableRenderer, try the new and improved PluggableRenderer;
for an extended example of how to use it, take a look at PluggableRendererDemo.


Q. I want to label nodes on a graph and use the (default) SettableRenderer.

A. Great! You should create a StringLabeller, which will assign a
label to each vertex. 

	StringLabeller sl = StringLabeller.getLabeller( g );
	int c  = 0;
	for( Iterator i = g.getVertices().iterator(); i.hasNext(); ) {
	    Vertex v = (Vertex) i.next();
	    sl.setVertex( v, "VERTEX " + c);
	    c++;
	}
	
Then create a SettableRenderer for your graph created with the StringLabeller

	// automatically uses the SettableRenderer as a default	
	GraphDraw gd = new GraphDraw( g );
	
	// SettableRenderer should automatically find the Labeller.
	// If you want to force it to use a different one, you'll need
	// to create a new SettableRenderer
	SettableRenderer sr = new SettableRenderer( sl );
	gd.setRenderer( sr );


Q. But I want to assign the labels in the UserData, or in the vertex's toString() method.

A. The SettableRenderer takes in a StringLabeller, which--in
turn--builds a graph-wide hashtable. As of recent versions, we've been
exploring other ways of doing it, including the ToStringLabeller
(which creates a virtual "label" for each node based on what the node
returns as "toString()") and GlobalStringLabeller (which globally maps
a list of labels, so that a label applies to all equivalent graphs, too.) 

You could write a StringLabeller yourself. It might look, say, something like this:


UserDataStringLabeller extends ToStringLabeller {

   public UserDataStringLabeller( Graph g, String key) {
     super( g );
     this.key = key;
   }

  public getLabel( Vertex v ) {
    return g.getUserDatum( v, key );
  }

}


Q. Got any clever ideas for drawing arrows or other annotations?
https://sourceforge.net/forum/forum.php?thread_id=1023095&forum_id=252062

Q. ... and I want to add and remove nodes from my graph!

A. See http://jung.sourceforge.net/applet/addnodedemo.html and the
code in samples.graph.addnodedemo


Q. How could I draw parallel edges?

A. See discussion at
https://sourceforge.net/forum/forum.php?thread_id=1079376&forum_id=252062




Q. How can I add a tooltip to each vertex or edge?

A. I haven't done it before. One is to override getTooltipText(
MouseEvent) for the GraphDraw which would figure out where the mouse
is, and thence which vertex or edge it is over. (Layouts can map a
mouse to an Edge or Vertex). Take a look at 
  http://java.sun.com/docs/books/tutorial/uiswing/components/tooltip.html

NEW: This is now built into GraphDraw as of JUNG 1.5.


Q. How can I implement rotate/pan/zoom for graphs?

A. This is MUCH easier with the "pipeline" functionality in the
NewGraphDraw system. See below, under "NewGraphDraw Specfic"

NEW: Pan and zoom (but not rotate) are now (JUNG 1.5) built into the old graph 
draw system as well.  Take a look at the contrib directory for the details.


Q. How come the exact same graph turns out completely different each
time it is drawn? This happens with all the layout managers. Are there
randomness to it and is there a way to remove it?

A. In the current visualization system, vertex x and y locations are
 initialized with random functions. This happens in the functio
 initializeLocation, which takes a Coordinates object, a Vertex, and
 the size of the current screen. It is responsible for placing the vertex.

Because the various embedders are (mostly) deterministic, if you start
with a fixed layout, you'll get the same layout.

You may override it by doing something like

	class MyFRLayout extends FRLayout {

	// overlaps all vertices at location x = 23,
	// y = random to start with.
	// probably not a good idea.
	protected void initializeLocation(
	    Vertex v,
 	    Coordinates coord,
	    Dimension d) {
	  double x = 23;
  	  double y = Math.random() * d.getHeight();
	  coord.setX(x);
	  coord.setY(y);
	}
	}
	
Note that the NewGraphDraw mechanisms have explicit initiailization
layouts (known as "StaticLayouts").


Q. Is there a SpringLayout.incrementsAreDone() function?

A. A possible "isdone" function is to add up all the stress (=actual
length/desired length) on all the edges in the SpringLayout, and then
watch for it to not change more than a specific amount for several
iterations. We haven't provided one, however. Altenately, in the
"samples.newGraphDraw" package, you can find systems for running a
finite number of iterations and then stopping.


Q. Does SpringLayout converge?

A. Not necessarily, unfortunately. It can pretty much keep running
forever. KKLayout and FRLayout both guarantee convergence.


Q. Do the current layout algorithms use edge weight in any meaningful way?

A. Not yet. Feel free to contribute code that does! Note that you'll
 probably want to do that for undirected graphs only;
a directed graph has the odd property that weights can be different in
 opposite directions.

================
DYNAMIC GRAPHS
=================

Q. I get a ConcurrentModificationException when using GraphDraw. What does it mean?

A. CME's come from changing graphs in the GraphDraw system. This is
incompletely supported in GraphDraw, but more thoroughly supported in NewGraphDraw.


================
NEWGRAPHDRAW SPECIFIC
================

Q. Ok, why is there both GraphDraw and NewGraphDraw?

A. GraphDraw was written as a quick adaptation of some code I have
sitting around. While it works fairly well, it isn't elegant, and in
particular it doesn't force synchronization (so that it may be
calculating while it is drawing, which makes for ugly artifacts) and
doesn't handle changes to the underlying graph. NewGraphDraw is meant
to provide stable solutions for these issues.


Q. When will NewGraphDraw be released?

A. I'm not completely confident in it yet--only minor tweaks will be
made before it's final release, but I don't expect that until
August. Contact me (offkey@sourceforge) if you want to help out.

Q. What support forum threads have worked on NewGraphDraw?

A. 
"Rotate/Pan/Zoom and Hiding Vertices"
https://sourceforge.net/forum/forum.php?thread_id=1064205&forum_id=252062


Q. When initializing an iterable layout with a static layout, is there
 a "good" static layout to choose? I have tried using a Random layout
 to initialize the SpringLayout, but all the vertices move towards the
 center before spreading back out towards the outer edges. This is
 rather time consuming. Suggestions are greatly appreciated.

A. Unfortunately, the answer is "it depends on the graph". Some
combinations of layout algorithms and graphs just don't work very
well. Some layout algorithms are very good at what they do, but are
(as you noted) time-consuming, especially for large
graphs. SpringLayout is a rather slow choice, actually: have you
considererd running a KKLayout, which starts with a phase of swapping
vertices before it wiggles them about?

For initialization, right now we only provide CircleLayout and RandomLayout.

Consider also changing from one layout algorithm to another midway
 through: consider
 samples.preview_new_graphdraw.iterablelayouts.WrappedIterableLayout,
 which allows you to run (say) KKLayout until it is done, followed by
 a little bit of SpringLayout.


Q. How can I implement rotate/pan/zoom for graphs?

A. Put the rotation into the pipeline! Specifically, a
LayoutTransformer modifies an EmittedLayout. Each time that the
EmittedLayout is regen
erated (due to a screen-resizing, or the
animation advancing), the Transformer changes it before showing it on screen.

So I would think that the best way to let the user "offset" vertices
is to store the offsets in a Transformer that will automatically
offset them as the program runs. Here's some sample code that will pan
the whole graph over by (x,y); in addition, it will offset individual
vertices by an additional (x, 0):

  OffsetLayoutTransformer extends LayoutTransformer {

    public void setOffset( double x, double y ) {
      this.xOffset = x;
      this.yOffset = y;
    }

    public void setOffsetSpecificVertex( Double x, Vertex v ) {
      this.vertexOffset.put( v, x );
    }

    public EmittedLayout transform( EmittedLayout el ) {
      for (vertex v in vertices) {
      v.offset( x, y );
      if( vertexoffset.containskey( v ))
        v.offset( vertexoffset.get( v ), 0);
      }
    }
  }


===================
Can I use JUNG with...
=====================

Q. ... Prefuse ( http://prefuse.sourceforge.net/ )

A. Yes. Limited support is avaialable through the jung-prefuse toolkit.


Q.  ... SWT ?

A. Not yet. While we have had a code contribution of an SWT-ified
GraphDraw, it froze up in some odd ways. If you are interested in
trying to work with it, or are an SWT expert, we would be grateful for
your help.



Q. ...ColdFusion?

A. We've seen it work before.
https://sourceforge.net/forum/forum.php?thread_id=1093601&forum_id=252062
Make sure to include the various packages: you can't create a graph
without commons-collections, for example.


==============
OTHER
============

Q. How do I figure out where a mouse was clicked?

A. See
http://jung.sourceforge.net/doc/api/edu/uci/ics/jung/visualization/GraphMouseListener.html
and the GraphDraw method addGraphMouseListener.
x

Q. How do I compile a project with JUNG?

A. If you're working from the command line, you'll probaly want a line that looks like
	javac -cp .;java\lib\jung.jar;java\lib\commons-collections.jar;java\lib\colt.jar test.java
	java -cp .;java\lib\jung.jar;java\lib\commons-collections.jar;java\lib\colt.jar Test
but you will probably be happier with a basic introduction to Java first 
	http://java.sun.com/docs/books/tutorial/
and the classpath documentation
	http://java.sun.com/j2se/1.3/docs/tooldocs/win32/classpath.html
and a decent IDE (integrated development environment)
	http://www.eclipse.org

Q. Where do the sample datasets live?

A. If your distribution didn't come with them, then download them from
the separate datasets.zip file on the release.  (As of JUNG 1.5, the build
process has been modified to include the datasets in the jung-#.#.#.zip file.) 


Q. Where is the source code?

A. The JUNG.ZIP download has the source code; JUNG.JAR has only the class files.


Q. GraphML seems not to load GraphML "data" attributes.

A. Yes, that's correct. As of 1.4.3, Our GraphML is still buggy. We're
looking for corrected code contributions.


Q. What is a ConstraintViolationException, and how do I tell
which constraint failed?

A. A ConstraintViolationException is a subclass of IllegalArgumentException
that is thrown when you try to add an edge or vertex to a graph that won't
allow you to add that edge/vertex.  This can happen, for example, if you try
to add a DirectedEdge to an UndirectedGraph.  It can also happen if you have 
added a vertex/edge constraint (for example, "must include a Color user datum") 
that a vertex/edge doesn't satisfy.

The stack trace of a ConstraintViolationException will look something like this:

edu.uci.ics.jung.exceptions.ConstraintViolationException: Predicate
org.apache.commons.collections.functors.NotPredicate rejected
E56(V81,V80): org.apache.commons.collections.functors.NotPredicate@1de3f2d
	at edu.uci.ics.jung.graph.impl.AbstractArchetypeGraph.validate(AbstractArchetypeGraph.java:191)
	at edu.uci.ics.jung.graph.impl.AbstractSparseGraph.addEdge(AbstractSparseGraph.java:136)
	at [somewhere in your code]
	
At this point, you have a couple of options:

(1) If the constraint is a simple one (i.e., it does not operate on other
constraints/predicates), look at your code where you're adding this edge/vertex 
and try to figure out what constraint is being violated.  This is usually fairly 
obvious from the constraint type and the error message.

(2) If the constraint is not simple (as in the example above; NotPredicate takes 
a Predicate as an argument), catch the ConstraintViolationException, call 
getViolatedConstraint() on it, and use PredicateUtils.evaluateNestedPredicates() 
on the constraint to find out the results of evaluating each constituent 
predicate.