Thibaut Démare
LITIS - Université du Havre
NeX Days' 2015 - Agadir, Morocco
28 - 30 April 2015
Basic steps to install GraphStream
eclipsefolder is created. Move it somewhere safe.
git clone -b NeX2015 git://github.com/graphstream/gs-talk.git
Demosfolder.
File > Import > General > Existing projects into workspace.
Demosfolder), Eclipse should recognize the project.
gs-algo-1.3.zip,
gs-core-1.3.zip,
gs-ui-1.3.zip.
gs-algo-1.3.jar,
gs-core-1.3.jar,
gs-ui-1.3.jarto the
lib/folder of the project.
gs-talk-simtools), then
properties, then
Java build path(left panel), then
libraries(right panel), then clic the
Add jarsbutton, and select our 3 jar files in the
gs-talk-simtools/libfolder.
mvn compile
src > org > graphstream > demo > tutorial1 > Tutorial1.java
import org.graphstream.graph.*;
import org.graphstream.graph.implementations.*;
public class Tutorial1 {
public static void main(String args[]) {
Graph graph = new SingleGraph("Tutorial 1");
graph.display();
graph.addNode("A");
graph.addNode("B");
graph.addEdge("AB", "A", "B");
graph.addNode("C");
graph.addEdge("BC", "B", "C", true); // Directed edge.
graph.addEdge("CA", "C", "A");
}
}
mvn exec:java -Dexec.mainClass="org.graphstream.demo.tutorial1.Tutorial1"
We can improve the display with some CSS:
...
graph.display();
graph.addAttribute("ui.quality");
graph.addAttribute("ui.antialias");
graph.addAttribute("ui.stylesheet",
"edge { fill-color: grey; }");
graph.addNode("A");
...
Node n = graph.addNode("A");
Node n = graph.getNode("A");
graph.removeNode("A");
Edge ab = graph.getEdge("AB");
Edge bc = graph.getEdge("BC");
Edge ca = graph.getEdge("CA");
ab.setAttribute("ui.label", "AB");
bc.setAttribute("ui.label", "BC");
ca.setAttribute("ui.label", "CA");
setAttribute()and a variable number of arguments:
ab.setAttribute("aNumber", 10);
bc.setAttribute("anObject", new Double(10));
ca.setAttribute("anArrayOfThings", 1, 2, 3);
You can access attributes in several ways:
int value1 = ((Number) ab.getAttribute("aNumber")).intValue();
double value2 = bc.getAttribute("anObject");
Object[] value3 = ca.getAttribute("anArrayOfThings");
Special methods are here to simplify things:
double value4 = ab.getNumber("aNumber");
double value5 = bc.getNumber("anObject");
Travelling through all nodes of the graph is easy:
for(Node n: graph) {
System.out.println(n.getId());
}
The same for edges:
for(Edge e: graph.getEachEdge()) {
System.out.println(e.getId());
}
You can also do it with iterators:
Iterator<? extends Node> nodes = graph.getNodeIterator();
while(nodes.hasNext()) {
System.out.println(nodes.next().getId());
}
The same for edges:
Iterator<? extends Edge> edges = graph.getEdgeIterator();
while(edges.hasNext()) {
System.out.println(edges.next().getId());
}
Or even with indices:
int n = graph.getNodeCount();
for(int i=0; i<n; i++) {
System.out.println(graph.getNode(i).getId());
}
The same for edges:
int n = graph.getEdgeCount();
for(int i=0; i<n; i++) {
System.out.println(graph.getEdge(i).getId());
}
Be careful: indices remain the same as long as the graph is unchanged. But as soon as an addition or removal occurs, indices are no longer tied to their old node or edge.
You can also travel the graph using nodes:
import static org.graphstream.algorithm.Toolkit.*;
...
Node node = randomNode(graph);
for(Edge e : node.getEachEdge()) {
System.out.printf("neighbor %s via %s%n",
e.getOpposite(node).getId(),
e.getId() );
}
Toolkitis a collection of often used methods and small algorithms.
You can iterate on directed edges:
Node node = getRandomNode(graph);
Iterator<? extends Edge> edges = node.getLeavingEdgeIterator();
Or:
Iterator<? extends Edge> edges = node.getEnteringEdgeIterator();
And get the node degree, entering or leaving:
System.out.println(“Node degree %d (entering %d, leaving %d)%n”,
node.getDegree(),
node.getInDegree(),
node.getOutDegree());
Source.addSink(Sink)method.
addElementSink(ElementSink). Elements are nodes and edges.
addAttributeSink(AttributeSink).
Sinkis only an empty interface inheriting
ElementSinkand
AttributeSink.
An element sink must follow the interface:
public interface ElementSink {
void nodeAdded( ... );
void nodeRemoved( ... );
void edgeAdded( ... );
void edgeRemoved( ... );
void graphCleared( ... );
void stepBegins( ... );
}
An attribute sink must follow the interface:
public interface AttributeSink {
void graphAttributeAdded( ... );
void graphAttributeChanged( ... );
void graphAttributeRemoved( ... );
void nodeAttributeAdded( ... );
void nodeAttributeChanged( ... );
void nodeAttributeRemoved( ... );
void edgeAttributeAdded( ... );
void edgeAttributeChanged( ... );
void edgeAttributeRemoved( ... );
}
A source is an interface that only defines methods to handle a set of sinks.
public interface Source {
void addSink(Sink sink);
void removeSink(Sink sink);
void addAttributeSink(AttributeSink sink);
void removeAttributeSink(AttributeSink sink);
void addElementSink(ElementSink sink);
void removeElementSink(ElementSink sink);
void clearElementSinks();
void clearAttributeSinks();
void clearSinks();
}
A DGS file looks like this. You can find it in the data > tutorial2.dgs
DGS003
"Tutorial 2" 0 0
an "A"
an "B"
an "C"
ae "AB" "A" "B"
ae "BC" "B" "C"
ae "CA" "C" "A"
ce "AB" label="AB"
ce "BC" label="BC"
ce "CA" label="CA"
anadd a node and
aean edge.
ae "AB" "A" > "B"adds a directed edge.
cn,
ceand
cgchange or add one or more attributes on a node, edge or graph.
dnand
deallow to remove nodes, edges.
step.
st <number>.
The ability to remove nodes and edges make the format dynamic.
Add this to the previous DGS file:
st 2
an "D"
an "E"
ae "BD" "B" "D"
ae "CE" "C" "E"
ae "DE" "D" "E"
de "AB"
dn "A"
st 3
And save it.
graph.read("tutorial2.dgs");
Graphinterface allowing to read static graphs from all the supported file formats.
We can read the DGS file event by event using an input source:
public class Tutorial2 {
public static void main(String args[]) {
Graph graph = new SingleGraph("Tutorial2");
graph.display();
graph.addAttribute("ui.antialias");
try {
FileSource source = FileSourceFactory.sourceFor(
"tutorial2.dgs");
source.addSink(graph);
source.begin("tutorial2.dgs");
while(source.nextEvents());
source.end();
} catch(Exception e) { e.printStackTrace(); }
}
}
while(source.nextEvents());that does the job.
begin()and
end()methods before and after reading to cleanly open and close the file.
while(source.nextEvents()) {
Thread.sleep(1000);
}
We can also run it step by step so that events between two step appear together
while(source.nextStep()) {
Thread.sleep(1000);
}
xand
yattributes:
an "A" x=0 y=1
an "B" x=1 y=-1
an "C" x=-1 y=-1
And:
an "D" x=1 y=1
an "E" x=-1 y=1
You have to tell the viewer it should not place nodes for you:
graph.display(false);
You can now run the program anew.
Get the Slides and Materials online:
NeX2015)