My program builds a tree based on input data. Before running the program, there is no way of knowing how many nodes should be created and where the position of the nodes (under which parent) should be.
Using JTree, we can add nodes easily if we, beforehand, are aware of the structure.
E.g.
//create the root node
DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root");
/create the child nodes
DefaultMutableTreeNode vegetableNode = new DefaultMutableTreeNode("Vegetables");
vegetableNode.add(new DefaultMutableTreeNode("Capsicum"));
vegetableNode.add(new DefaultMutableTreeNode("Carrot"));
vegetableNode.add(new DefaultMutableTreeNode("Tomato"));
vegetableNode.add(new DefaultMutableTreeNode("Potato"));
root.add(vegetableNode);
But my tree, once the root node is specified, is incrementally built. So I'd like my JTree to add a node under a specific parent at any time.
Please note that the tree will also be built inside a recursive method. Which means the main JTree object should be created outside this method.
The tree may have more than one layer, which means the path from the node to a leaf may require e.g. 10 jumps.
What is the best way of adding a node to a JTree at run-time which only knows about its parent?
A caveat here is when two different parents have the same name e.g. if node apple should go under a node called fruit but fruit is found in two different paths
root -> aaa -> bbb -> ccc -> fruit
root -> aaa -> fff -> ggg -> hhh -> fruit
You should look into providing your own tree model then.
Quoting the Oracle tutorial for JTree:
One of the ways you can lazily load children of a Tree is by utilizing the TreeWillExpandListener interface. For example, you can declare and load root, grandparent and parent of a Tree along with the application as shown in the following code:
Given the comments by the OP: the DefaultMutableTreeNode does not support "names". That would mean: you need to implement that yourself, in a super simply approach, probably like:
class MyTreeNode extends DefaultMutableTreeNode {
private final String name;
MyTreeNode(String name, ... whatever ) {
...
SOME_NODE_REGISTRY.put(name, this);
}
Then you need to provide that registry, probably as some sort of singleton map instance. In other words: you have to write code that A) enables you to store nodes by name to then B) identify/find nodes by name.
Related
I started to use the Jung library for my visualization of a graph. Main problem currently is that I don't know how to set labels/metadata for my vertices. Depending on a specific attribute of a vertex, I would like to color the vertices differently. The object of class Node contains an additional Integer-value, I would like to add as an additional attribute (by getGroup()) for the vertices. The following code only visualizes the getId()-String of each node.
Any recommendation?
This is my following code in the main class:
Graph<String,Double> g = new SparseGraph<String,Double>();
List<Link> linkList = new ArrayList<Link>();
List<Node> nodeList = new ArrayList<Node>();
linkList = f.getLinks();
nodeList = f.getNodes();
for(Node nodeElement:nodeList){
g.addVertex(nodeElement.getId());
}
for(Link linkElement:linkList){
g.addEdge(linkElement.getValue(), linkElement.getSource(), linkElement.getTarget());
}
VisualizationImageServer vs =
new VisualizationImageServer(
new SpringLayout(g), new Dimension(500, 500));
vs.getRenderContext().setVertexLabelTransformer(new ToStringLabeller() {
public String transform(Object v) {
return Integer.toString(((Node)v).getGroup());
}
});
JFrame frame = new JFrame("");
frame.getContentPane().add(vs);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
You didn't specify which version of JUNG you're using, but you've got the right general idea: call setVertexLabelTransformer() with a function that converts nodes to the string that you want to render.
That said, there are a few issues with your code as written and I'm not sure I understand how you're getting the reported behavior with the code as quoted above.
(0) I don't understand why you're adding the node ID as the vertex, rather than just the Node. Are the endpoints of your Links node IDs or Nodes?
In any event, if you don't add the Node, then it's not clear from your code as written how you expect the vertex Group to be available.
(1) The vertices of the graph are node IDs, not Nodes, but you're casting the vertex object passed to transform() to a Node. I would expect this to throw a ClassCastException.
(2) Even supposing that your vertices were actually Node objects,
I'm surprised that you're reporting that the vertex ID (rather than the Group) is what's showing up on the label, because the only thing that you're asking for in the vertex label is the Group; I wouldn't expect the ID to be showing up at all.
That said, if the vertices are Node objects, and you want multiple elements to show up, it's pretty easy; just provide a function that does what you want on the Node object.
* If that function is toString(), then you can use ToStringLabeller (and that should actually be the default, so you shouldn't even need to specify it); more on that below.
* If that function is (say) getLabel(), then this should work (in Java 8):
// either of these should work
setVertexLabelTransformer(Node::getLabel())
setVertexLabelTransformer(v -> v.getLabel())
or you can do the anonymous inner class thing if you're not using Java 8.
If you don't want your vertices to be Node objects, then you'll need to provide a way of mapping vertex objects (node IDs) to nodes, such as a Map<String, Node>, and then supply that map to the function that converts vertices to labels:
setVertexLabelTransformer(v -> labelToNode.get(v).getLabel())
Note: ToStringLabeller() shouldn't generally have its transform() method overridden; it just specifies that you want to use the toString() of the object itself as the label.
// These two are equivalent
setVertexLabelTransformer(v -> v.toString())
setVertexLabelTransformer(new ToStringLabeller())
(Needless to say, ToStringLabeller() predates Java 8. :) )
I'm learning about search algorithms BFS and DFS. I plan to implement both but before I do that, I need to implement my graph structure. Here's my idea:
A graph of connecting cities: Each city is represented by a Node.
Our graph will simply be an ArrayList of Nodes added as they're created, and each Node will have a list of it's neighbors, and a parent which will let us know where we came from (for path retrieval). I haven't coded anything up yet, I wanted to get some feedback on my ideas before spending the time writing up something that won't work. Here's some pseudocode-ish, code. One potential problem I can see is how we're going to deal with Nodes that we can get to from multiple places (multiple parents). If anyone has any suggestions on dealing with that, feel free to share.
public class Node{
String name;
Node parent;
ArrayList<Node> neighbors;
public addNeighbor(Node n);
public setParent(Node n);
public getNeighbors()
...
}
public static void main(String[] args){
ArrayList<Node> graph = new ArrayList<Node>();
//build node
Node node = new Node(String name);
//add neighbors
node.addNeighbor(neighbor1);
node.addNeighbor(neighbor2);
//set parent
node.setParent(parent1);
//add to graph
graph.add(node);
path = dfs(graph, startNode, goalNode);
System.out.print(path);
}
Edit: I know I could look online and find implementations of this pretty easily, but I'd prefer to come up with my own solutions.
Your implementation look good. It's the classic implentation of a graph structure (a node with a list of neighbors). Some points:
You can use backtracking to deal with multiples paths that reach the same node. If the dfs method have a recursive implementation, you need to avoid the recursive call if the Node has already a parent. But if the new path is better that the old one, then you discard the old parent, and set the new one.
Your implementation is a directional graph. In other words, you can build a graph that has a path from A to B, but has no path from B to A. I don't know if this is ok for you.
I recommend you encapsulate the building of the graph inside a wrapper, that build both paths automatically, whith a unique call to a method. That way, always you build bidirectional paths.
You can use a Set to store the neighbors. That way, there is no duplicates. Of course, you need to implements the "equals" method in the Node class.
I am working on a project that requires the use of a tree data structure. Having done some researches I found that Java JTree would be of great use to my project, however I stumbled upon a problem that I spent a week fixing but to no avail.
Here's the problem, in order to create a new node, a DefaultMutableTreeNode has to be instantiated and I'm not sure how that can be done in a loop. Normally when we want to create a new node in JTree, we would firstly declare the nodes in the following way:
DefaultMutableTreeNode parent = new DefaultMutableTreeNode("This is parent node.");
DefaultMutableTreeNode child = new DefaultMutableTreeNode("This is child node.");
Then, in order to add/link child node to parent node, we would do the following:
parent.add(child);
I have two arraylists containing the parent nodes and child nodes, they correspond to each other in a parent-child relationship, meaning that arraylistParent.get(x) will always be the parent of arraylistChild.get(x).
I was thinking that by using a for loop, I could do:
for (int x = 0; x < arraylistParent.size(); x++){
parent.add(new DefaultMutableTreeNode(arraylistChild.get(x)));
}
This could only work in a flat hierarchy tree, which obviously isn't the case for me. I will have different parent nodes in arrayListParent which I need to check before adding the child nodes, but once again not all child nodes have the same, single parent node. My arraylists probably contain something like this:
arraylistParent = [root, p1, p2, p2, p3, p1]
arraylistChild = [p1, p2, p5, p3, p4, p5]
and I want to generate the tree structure like this:
root
..p1
..p2
..p5
..p3
..p4
..p5
Obviously I can throw a few if loops inside to check whether parent.getUserObject() is the same as arraylistParent.get(x) but only those that match the string "This is parent node" will be checked and added.
If there's a different, non-existent parent found in the loop, a new parent needs to be created and this is the tricky part I don't know how to solve, as I have no idea how to have the loop automatically create a new instance of parent for the child node.
Let us assume your node-datums are Strings (that is, the contents of your ArrayLists are Strings). The explanation will work with any other Java object, though. We will call these contents 'nodes', as distinct from 'tree nodes'.
You can create a HashMap<String, DefautMutableTreeNode> m, so that m.get(node) will return the corresponding TreeNode.
Now, you have to iterate over the parents' arraylist. At each position, you will have a parent and a child. Look them up in the map. If the parent TreeNode does not exist, you will first have to create it. If the child TreeNode does not exist, the same will apply. You should make sure that the map is updated after creating any TreeNodes. Finally, you will mark the child as a child of the parent.
At the end of this algorithm, you should look through all the nodes in the child array. The one without any parents is the root. This is the root of your tree.
I did a search on similar topics, but the answers are too vague for my level of understanding and comprehension, and I don't think they're specific enough to my question.
Similar threads:
Tree (directed acyclic graph) implementation
Representing a DAG (directed acyclic graph)
Question:
I have formatted a text file which contains data of the following format...
Example dataset:
GO:0000109#is_a: GO:0000110#is_a: GO:0000111#is_a: GO:0000112#is_a: GO:0000113#is_a: GO:0070312#is_a: GO:0070522#is_a: GO:0070912#is_a: GO:0070913#is_a: GO:0071942#part_of: GO:0008622
GO:0000112#part_of: GO:0000442
GO:0000118#is_a: GO:0016581#is_a: GO:0034967#is_a: GO:0070210#is_a: GO:0070211#is_a: GO:0070822#is_a: GO:0070823#is_a: GO:0070824
GO:0000120#is_a: GO:0000500#is_a: GO:0005668#is_a: GO:0070860
GO:0000123#is_a: GO:0005671#is_a: GO:0043189#is_a: GO:0070461#is_a: GO:0070775#is_a: GO:0072487
GO:0000126#is_a: GO:0034732#is_a: GO:0034733
GO:0000127#part_of: GO:0034734#part_of: GO:0034735
GO:0000133#is_a: GO:0031560#is_a: GO:0031561#is_a: GO:0031562#is_a: GO:0031563#part_of: GO:0031500
GO:0000137#part_of: GO:0000136
I'm looking to construct a weighted directed DAG from this data (the above is just a snippet). The whole dataset of 106kb is here: Source
--------------------------------------------------
Taking into consideration line-by-line, the data of each line is explained as follows...
First line as an example:
GO:0000109#is_a: GO:0000110#is_a: GO:0000111#is_a: GO:0000112#is_a: GO:0000113#is_a: GO:0070312#is_a: GO:0070522#is_a: GO:0070912#is_a: GO:0070913#is_a: GO:0071942#part_of: GO:0008622
'#' is the delimeter/tokenizer for the line data.
The First term, GO:0000109 is the node name.
The subsequent terms of is_a: GO:xxxxxxx OR part_of: GO:xxxxxxx are the nodes which are connected to GO:0000109.
Some of the subsequent terms have connections too, as depicted in the dataset.
When it is is_a, the weight of the edge is 0.8.
When it is part_of, the weight of the edge is 0.6.
--------------------------------------------------
I have Google-d on how DAGs are, and I understand the concept. However, I still have no idea how to put it into code. I'm using Java.
From my understanding, a graph generally consists of nodes and arcs. Does this graph require an adjacency list to determine the direction of the connection? If so, I'm not sure how to combine the graph and adjacency list to communicate with each other.
After constructing the graph, my secondary goal is to find out the degree of each node from the root node. There is a root node in the dataset.
For illustration, I have drawn out a sample of the connection of the first line of data below:
Image Link
I hope you guys understand what I'm trying to achieve here. Thanks for looking through my problem. :)
Because it's easier to think about, I'd prefer to represent it as a tree. (Also makes it easier to traverse the map and keep intermediate degrees.)
You could have a Node class, which would have a Collection of child Node objects. If you must, you could also represent the child relationships as a Relationship object, which would have both a weight and a Node pointer, and you could store a Collection of Relationship objects.
Then you could do a walk on the tree starting from the root, and mark each visited node with its degree.
class Node{
String name;
List<Relationship> children;
}
class Relationship{
Node child;
double weight;
}
class Tree{
Node root;
}
Here, Tree should probably have a method like this:
public Node findNodeByName(String name);
And Node should probably have a method like this:
public void addChild(Node n, double weight);
Then, as you parse each line, you call Tree.findNodeByName() to find the matching node (and create one if none exists... but that shouldn't happen, if your data is good), and append the subsequent items on the line to that node.
As you've pointed out, DAGs cannot really be converted to trees, especially because some nodes have multiple parents. What you can do is insert the same node as the child of multiple parents, perhaps using a hash table to decide if a particular node has been traversed or not.
Reading the comments, you seem confused by how a Node can contain Relationships which each in turn contains a Node. This is quite a common strategy, it is in general called the Composite pattern.
The idea in the case of trees is that the tree can be thought of as consisting of multiple subtrees - if you were to disconnect a node and all its ancestors from the tree, the disconnected nodes would still make a tree, though a smaller one. Thus, a natural way to represent a tree is to have each Node contain other Nodes as children. This approach lets you do many things recursively, which in the case of trees is often, again, natural.
Letting a Node keep track of its children and no other parts of the tree also emulates the mathematical directed graph - each vertex is "aware" only of its edges and nothing else.
Example recursive tree implementation
For instance, to search for an element in a binary search tree, you would call the root's search method. The root then checks whether the sought element is equal, less or greater than itself. If it is equal, the search exits with an appropriate return value. If it is less or greater, the root would instead call search on the left or right child, respectively, and they would do exactly the same thing.
Analogously, to add a new Node to the tree, you would call the root's add method with the new node as a parameter. The root decides whether it should adopt the new node or pass it on to one of its children. In the latter case, it would select a child and call its add method with the new Node as a parameter.
I have a little confusion:
Is the function insertNodeInto used to inserts only a single node and not its sub nodes?
for example I have a code snippet as follows:
DefaultMutableTreeNode newNode = new DefaultMutableTreeNode("topMost");
newNode.add(new DefaultMutableTreeNode("A node"));
newNode.add(new DefaultMutableTreeNode("B node"));
model.insertNodeInto(newNode,rootNode,0);
So will the above code add all the 3 nodes to the tree or just the topMost node?
The node, with all its children, is inserted in the model, as a simple test would have shown.