Collapsing nodes in Graphstream - java

Is there anyway I can collapse a certain number of nodes in a graph using graphstream? I have tried adding ui.hide attribute,but that is not what I want. Ideally I would want a + sign on the first node that is collapsed and then when I click on the + sign then the rest of the nodes should appear. Can anyone help me with this? TIA

Not exactly sure I got it right, but I guest you want to fold/unfold a tree, a bit like a package/file system view on a IDE (eclipse, netbean...).
If I am right then there are some tricks that can help you do that in GraphStream.
The ui.hide attribute, as you mentioned, used on nodes and edges.
The layout.frozen attribute that blocks the layout algorithm on the selected node and allows you to control its position. You may want to set the position of the "folded" right at the clicked node's position in order to give the "folding" visual feeling.
The ui.class attribute that allows you to assign CSS classes to nodes, and thus give a particular style to node folded/unfolded nodes (e.g. add a "plus" sign icon).
In order to get notified when a node is clicked you need to retrieve a ProxyPipe from the viewer and listen to modifications coming from that viewer. especially the ui.clicked attribute that is automatically assigned to nodes that get clicked.
ProxyPipe fromViewer = viewer.newViewerPipe();
fromViewer.addSink(new SinkAdapter(){
#Override
public void nodeAttributeAdded(String sourceId, long timeId, String nodeId, String attribute, Object value) {
if(attribute.equals("ui.clicked")){
// Being notified that a node was clicked...
}
}
});
Finally, you have to decide which node to collapse. I guess a simple iterator rooted at the clicked node is what you need.
// let n be the clicked node...
Iterator<Node> it = n.getBreadthFirstIterator(true);
while(it.hasNext()){
Node m = it.next();
for(Edge e : m.getLeavingEdgeSet()) {
e.setAttribute("ui.hide");
}
if(n != m) {
m.setAttribute("ui.hide");
}
}
Then the Layout algorithm will be troublesome regarding nodes positions and stabilisation limits but that not really important.
You'll find a working example in this gist where clicked nodes collapse their sub-trees :
https://gist.github.com/pigne/2d4c0cbe8583f8a8f6b03309becaff3f
Here is an example tree graph before collapsing sub-trees:
Same graph with node 13 and 15 collapsed after clicking:

Related

Select the TreeNode before (java swing, tree)

I am looking for a way to select the TreeNode before the actually selected node (if no Node is selected, the first Node AFTER the root should be selected) on Button click. I am basically having a Hashtable ht and a JTree filled with nodes (all Nodes allowing Children).
Once i click a node, i want to look up in the Hashtable for that Object and the system should write something like "You selected the 'Object.name'". Then the user should be able to click a JButton and select the node before the clicked node. Of course there should also be this line with an updated 'Object.name'. Maybe there is even a way to update the GUI of the tree, so that the other TreeNode is shown as selected.
I have been trying around for quite a while with the treePath-Methods of the selectionModel and the TreeNodes (e.g. saving them in Lists and trying to select the Element before), but nothing seems to work. I am also not finding anything useful on Google or StackOverflow. I was thinking that it might work somehow with the getPreviousSibling-Method from the DefaultMutableTreeNode?
Last thing I tried:
DefaultMutableTreeNode treeNode = new DefaultMutableTreeNode();
treeNode = (DefaultMutableTreeNode) getLastSelectedPathComponent();
setSelectionPath(new TreePath(((DefaultTreeModel) treeModel).getPathToRoot(treeNode.getPreviousSibling())));
Unfortunately I keep getting a NullPointerException:
in line 2 of this snippet (although I selected another TreeNode before, wich has a sibling before).
Can anyone please tell me what I did wrong or tell me what other way might work? :D If you need more information please have no regard in asking me.

How can I tell what nodes are highlighted on a displayed JTree?

I'm working on an app that displays a JTree. I want the user to be able to highlight certain nodes and then do things to those nodes after they press a button.
Highlighting already works - they can click on things, and then shift-click or control click to highlight other things. is there any way to detect which nodes are highlighted in this way?
Thanks!
If I'm understanding you correctly you want to find all the tree nodes that a user has selected. See JTree.getSelectionPaths(). The Javadoc states that it returns
An array of TreePath objects indicating the selected nodes, or null if nothing is currently selected
Each TreePath
represents an array of objects that uniquely identify the path to a node in a tree. The elements of the array are ordered with the root as the first element of the array
As #MadProgrammer states in the comment the last object in the array is the selected node.
You can create a TreeSelectionListener as follows and use e.paths from the TreeSelectionEvent:
jTree.addTreeSelectionListener(new TreeSelectionListener() {
#Override
public void valueChanged(TreeSelectionEvent e) {
// e.paths has the selected nodes in the TreeModel
}
});

Interactive multiway tree/graph applet with mouse listeners

I have a graph in which the nodes have 0 or more successors and 0 or more predecessors.
I want to make a visualization (preferably through JAVA) such that:
There should be a search box. If I enter the id of the node the node should appear on the screen.
If I left click a node, it's children should appear below the node(in tree representation).
If I right click the node then it's parent should appear above the node.
If I double click any node then it should have same effect as searching the node(as in point 1)
I want to know what approach should I follow (any package etc.)? Is there some similar implementation whose code I may reuse?

How to make JTree selection model only allow sibling selection?

I have a jtree and I only want the user to be able to select sibling nodes. If the user selects nodes that aren't siblings, I want the previously selected nodes to be deselected.
The user should also be able to select sibling nodes that aren't contiguous. I was hoping to extend defaulttreeselectionmodel.
Is there a simple way to do this?
Seems like you'll have to play with TreeSelectionModel (which will store current selection state) and TreeSelectionListener. An example algorithm could be the following : when your selection change, if your TreeSelectionListener is not in active mode, it enters into that mode (this is useful as your listener will update selection in some cases, and you don't want crazy cycles, want you ?). Then, it checks selected nodes using TreeSelectionModel#getSelectionPaths(). If this array size is one, only one node is selected and all is OK. If its size si greater than 1, then you'll have to write some code to ensure those nodes are siblings (as an example by ensuring their TreePath are identical except the last part.

Prefuse Toolkit: dynamically adding nodes and edges

Does anyone have experience with the prefuse graph toolkit? Is it possible to change an already displayed graph, ie. add/remove nodes and/or edges, and have the display correctly adapt?
For instance, prefuse comes with an example that visualizes a network of friends:
http://prefuse.org/doc/manual/introduction/example/Example.java
What I would like to do is something along the lines of this:
// -- 7. add new nodes on the fly -------------------------------------
new Timer(2000, new ActionListener() {
private Node oldNode = graph.nodes().next(); // init with random node
public void actionPerformed(ActionEvent e) {
// insert new node //
Node newNode = graph.addNode();
// insert new edge //
graph.addEdge(oldNode, newNode);
// remember node for next call //
oldNode = newNode;
}
}).start();
But it doesn't seem to work. Any hints?
You should be aware the several layers of prefuse:
Data
Visualization
Display
To be short, the three layers can be linked this way:
Graph graph = new Graph(eg. yourXML_file);
Visualization viz = new Visualization();
viz.add(GRAPH, graph);
Display disp = new Display();
disp.setVisualization(viz);
Display is a graphic component that you add to a panel as usual.
Here you only modify the data layer.
Node newNode = graph.addNode();
graph.addEdge(oldNode, newNode);
You need now to update the visual layer:
viz.run("repaint");
The repaint action has to be defined.
ActionList repaint = new ActionList();
repaint.add(new RepaintAction());
viz.putAction("repaint", repaint);
I really advise you to read the prefuse doc.
And you can find a lot a resources on the official forum
At least, I can say you that prefuse is for the moment not really efficient for live graph update.
But it should not be enough, as you modified the graph structure, you have to regenerate it in the visualization (ie. recalculate the node placements etc...). There are two actions already defined in your sample code. Run them at the end of your actionPerformed.
viz.run("color");
viz.run("layout");
This method is not very efficient, because it adds a lot of computation each time you add a node, but there are not any others for the moment with prefuse.
As pointed out in my other post, the reason new nodes and edges are not visible in the original example is that the colors etc. for the nodes are not set correctly. One way to fix this is to explicitly call vis.run("color"); whenever a node or edge was added.
Alternatively, we can ensure that the color action is always running, by initializing the ActionList to which we add it (called "color" in the original example) slightly differently:
instead of
ActionList color = new ActionList();
we could write
ActionList color = new ActionList(Activity.INFINITY);
This keeps the action list running indefinitely, so that new nodes/edges will automatically be initialized for their visual appearance.
However, it is unclear to me whether this would actually be the preferred method - for things like a dynamic layout action (e.g. ForceDirectedLayout), such a declaration makes perfect sense, but for colors it seems to me that a constantly running coloring action is mostly overhead.
So, perhaps the previously posted solution of just running the "color" action explicitly (but only once) whenever the graph gets extended, might be the better choice...
Okay, after digging a bit through the prefuse sources, I now have a better understanding of how things work under the hood. I found out that actually the new nodes I create with the code above are not only added correctly to the graph, the visualization also takes note of it!
So, unlike Jerome suggests, it is not necessary to call vis.run("layout") explicitly.
The reason I thought the nodes were not added correctly was the fact that they are drawn with white background-, border- and text color - on white background that is. Not astonishing that they are a bit difficult to spot.
To fix that one has to call the color action after a new node is inserted, like this:
// insert new edge //
graph.addEdge(oldNode, newNode);
vis.run("color"); // <- this is new
(Note that this action is defined further up in the code of Example.jar under //-- 4.)
One last thing I am unsure about now is whether calling this action will make prefuse go over all graph nodes again and set their color - for very large graphs that would be undesired, of course.
You need to tell the control container ('d', in example.java) do get redrawn. Calling invalidate() should be enough (not sure, though).
Anyway, this might help you.

Categories

Resources