I'm working on my personal family tree in Java/Eclipse, and happily bumped into prefuse as for graphic representation.
So far the result looks adaquate in regard to my database feed, but I'm still missing key points to make it easier to browse.
Point 1: verteces represent either a person or a union, and my graph is directed from older to younger members. This is reflected by the arrows on the edges. Yet I'd love to group the arrows in 1 direction only (I'm trying to group generations together if you like), but I can't start to find how to do that. For information, I'm using the NodeLinkTreeLayout as of now.
Point 2: aside from the graph itself, my app main window contains a second JPanel where I would like to modify / insert members. So I want to add an action to each node to call the procedures in the second JPanel. My research on how to access a java class from a node are inconclusive so far, it seems that all the examples from the starter prefuse pack are only based on graph interaction.
There it is. You might already have understood that I'm very new to prefuse and not a pro in Java. So any comment / directions / advice would really be appreciated. I will add a screecap and my graph code so you can see what could be done better.
Thank you for your time, and looking forward to reading your insights.
yorran
public class ShowGraph extends Display {
public static final String EDGES = "graph.edges";
public ShowGraph() {
super(new Visualization());
Graph mG = FamGraph.getGraph();
m_vis.addGraph("graph", mG);
m_vis.setInteractive("graphe.edges", null, false);
m_vis.setValue("graph.nodes", null, VisualItem.SHAPE, new Integer(Constants.SHAPE_ELLIPSE));
EdgeRenderer edgeR = new EdgeRenderer(Constants.EDGE_TYPE_CURVE, Constants.EDGE_ARROW_FORWARD);
LabelRenderer nodeR = new LabelRenderer("name");
nodeR.setRoundedCorner(8, 8);
nodeR.setHorizontalAlignment(Constants.LEFT);
DefaultRendererFactory drf = new DefaultRendererFactory();
drf.setDefaultRenderer(nodeR);
drf.setDefaultEdgeRenderer(edgeR);
m_vis.setRendererFactory(drf);
int[] palette = new int[] {
ColorLib.rgb(255, 180, 180), ColorLib.rgb(190, 190, 255)
};
DataColorAction nFill = new DataColorAction("graph.nodes", "label", Constants.NOMINAL, VisualItem.FILLCOLOR, palette);
ColorAction edges = new ColorAction("graph.edges", VisualItem.STROKECOLOR, ColorLib.gray(230));
ColorAction arrow = new ColorAction("graph.edges", VisualItem.FILLCOLOR, ColorLib.gray(230));
ColorAction text = new ColorAction("graph.nodes", VisualItem.TEXTCOLOR, ColorLib.gray(0));
ActionList color = new ActionList();
color.add(nFill);
color.add(edges);
color.add(arrow);
color.add(text);
ActionList layout = new ActionList(Activity.INFINITY);
//layout.add(new ForceDirectedLayout("graph", true));
layout.add(new NodeLinkTreeLayout("graph"));
layout.add(new RepaintAction());
m_vis.putAction("color", color);
m_vis.putAction("layout", layout);
setSize(1200, 900); //size controlled by parent jpanel - Comment out after tests
pan(360, 250);
setHighQuality(true);
addControlListener(new DragControl());
addControlListener(new PanControl());
addControlListener(new ZoomControl());
addControlListener(new ZoomToFitControl());
m_vis.run("color");
m_vis.run("layout");
}
public static void main(String[] args) {
Fulltree.fireUp();
ShowGraph mG = new ShowGraph();
JFrame frame = new JFrame("My family chart");
JPanel thePanel = new JPanel();
frame.getContentPane().add(thePanel);
thePanel.add(mG);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
So after a lot of reseach, I'm answering to my own questions in case someone meets the same issues :
as for point 1 : ForceDirectedGraph is a lot better than NodeLinkTreeLayout, especially when your graph starts counting many members. Family branches make a lot more sense than viewing generations aligned.
as for point 2 : node related actions are the way to go, through a ControlListener:
addControlListener(new ControlAdapter() {
public void itemClicked(VisualItem item, MouseEvent e) {
// anything you need here
// even filter right and left click for a sub menu
}
});
One more thing : if you add actions to your graph (search, predicates...), make sure to stop them if you need to rebuild your graph at some point. If you don't, your actions will generate errors you will spend hours (if not days) to debug.
Related
I'm trying to visualize a tree graph with the JUNG library.
The code I use is:
JPanel base = new JPanel();
Graph<String, String> grafo = OntologyGraph.getGraph(ontology);
Layout<String, String> layout = new TreeLayout<String, String>((Forest<String, String>) grafo);
VisualizationViewer<String, String> vv = new VisualizationViewer<String, String>(layout);
vv.getRenderContext().setVertexLabelTransformer(new ToStringLabeller<String>());
vv.getRenderContext().setEdgeLabelTransformer(new ToStringLabeller<String>());
vv.getRenderer().getVertexLabelRenderer().setPosition(Position.CNTR);
final DefaultModalGraphMouse<String, Number> graphMouse3 = new DefaultModalGraphMouse<>();
vv.setGraphMouse(graphMouse3);
graphMouse3.setMode(DefaultModalGraphMouse.Mode.PICKING);
base.add(vv);
return base;
It displays this
Now I want to change the circled verteces with a labelled JButton and to enlarge the space between them, but I can't find a tutorial on the web to achive this.
Changing the spacing between the nodes is easy enough; just use the TreeLayout constructor that accepts the distx and disty parameters.
Providing a JButton for each node is not something that JUNG natively supports, although you could do some hacking to enable it.
What problem are you trying to solve by using JButtons for nodes?
Here is some example code that you can use to open a JFrame with information about the node that was clicked (when you are in picking mode). If you want to have it respond to node clicks even when you are in the transforming mode, you'd have to change the graphmouseplugins a little to not remove the PickingGraphMousePlugin when in transforming mode.
vv.getRenderContext().getPickedVertexState().addItemListener(new ItemListener(){
#Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
JFrame frame = new JFrame("Vertex "+e.getItem()+" picked");
frame.getContentPane().add(new JButton("hello from "+e.getItem()));
frame.setSize(new Dimension(200,100));
frame.setLocation(200, 200);
frame.setVisible(true);
}
}
});
If you want the vertices to look more like rectangular buttons, the VertexLableAsShapeDemo may help. That demo uses JLabels to draw the vertices
I draw a simple graph (using Java swing interface).
The graph is OK, but the default / automatic vertices size is small for my purpose. How to set the vertex size (rectangle or ellipse)?
I can change some graph behavior using put() ( like put(mxConstants.STYLE_SHAPE, mxConstants.SHAPE_ELLIPSE)) but not the size of vertices.
The graph is OK, but the default / automatic vertices size is small for my purpose. How to set the vertex size (rectangle or ellipse)?
May I have misunderstood many about jgraphx?
The documentation is very difficult to understand, very cryptic (at least for me), can I have suggestions for books or links for better understand jgraphx for Java.
One more detail: the graph isn't built element by element, but it come from a graph built with jgraphT using jGraphXAdapter
JGraphXAdapter<Incrocio, Strada> graphAdapter =
new JGraphXAdapter<Incrocio, Strada>(listenableGraph);
Thank to Andrew for her patience.
English is not my language, and sometime I make a mistakes even in italian (my native language). Add that I'm new in Java. New even in this forum (an related rules, and this may not be the right place for my replay). I've not read your message previous with the due attention.
I put the code, whith a partial solution, I hope it's more clear.
package it.rex.view;
public class StradarioViewBis2 extends JFrame {
private JPanel contentPane;
// listenableGraph is a complete graph done with JgraphT
public StradarioViewBis2(ListenableGraph<Incrocio, Strada> listenableGraph) {
JGraphXAdapter<Incrocio, Strada> graphAdapter =
new JGraphXAdapter<Incrocio, Strada>(listenableGraph);
//graphAdapter.getStylesheet().getDefaultEdgeStyle().put(mxConstants.STYLE_NOLABEL, "1"); //remove label from edge
graphAdapter.getModel().beginUpdate();
try {
graphAdapter.clearSelection();
graphAdapter.selectAll();
Object[] cells = graphAdapter.getSelectionCells(); //here you have all cells
// Iterate into graph to change cells
for (Object c : cells) {
mxCell cell = (mxCell) c; //cast
mxGeometry geometry = cell.getGeometry();
if (cell.isVertex()) { //isVertex
// Here I can change vertex dimensions
geometry.setWidth(40);
geometry.setHeight(40);
}else{ //is not a vertex, so u can get source and target
// cell.setStyle("orthogonalEdgeStyle");
// cell.getChildAt(x); //Returns the child at the specified index. (target)
}
}
}
finally
{
graphAdapter.getModel().endUpdate();
}
mxIGraphLayout layout = new mxCircleLayout(graphAdapter); // questo sistema le posizione degli elementi
layout.execute(graphAdapter.getDefaultParent());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 550, 450);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
mxGraphComponent graphComponent = new mxGraphComponent(graphAdapter); // is JScrollPane extension
graphComponent.setPageVisible(true);
graphComponent.setBounds(30, 30, 300, 300);
contentPane.add(graphComponent);
//graphComponent.setEnabled(false);
graphComponent.getViewport().setBackground(Color.white);
;
}
}
After some tries, I've found that the vertex's size is back to initial dimension when I change the cell's label, not when I move the focus away from cell.
I think I need to change the default behavior of the graph, but i'm not yet discovered how.
This is the result, after editing label on top vetex:
enter image description here
We have a project for university which is a program to hold handouts and feedback for courseworks done.
What we've thought of is breaking the whole thing down into smaller pieces, for example:
You have a coursework which requires to write a program and a report on results etc.
So the user will create a new coursework by selecting the "code" and "report" options, since that's what is required. And then we need to create the respective tabs in the program so the user can input what is needed.
I have created all necessary forms and windows, It's just I'm not sure how to move on forward.
a) where should I put my code? should I have it on the "create" event?
b) how do I do this whole custom population thing?
Obviously, I'm not asking for the entire thing in code. I'm not even sure what to read and what to search for.
Following are some screenshots of the ui to help explain what I mean.
New project window
How the main window should be after creating a new projet. Notice the various tabs.
A form for report feedback
On your "Create" button click check for the checkbox.isSelected() and use the method below as:
if(reportCheckbox.isSelected()){
addonScreen(new reportFrame(),"Report Submission");
addonScreen(new reportFeedbackFrame(),"Report Feedback");
}
Use a desktop pane as a container...add your tabbed pane to it
public static JTabbedPane tabbedPane = new JTabbedPane();
jDesktopPane1.add(tabbedPane);
Use this method to add tabs to the layout at runtime
public static void addOnScreen(JInternalFrame inFrame, String title) {
//border for the internal frame
javax.swing.plaf.InternalFrameUI ifu = inFrame.getUI();
((javax.swing.plaf.basic.BasicInternalFrameUI) ifu).setNorthPane(null);
Border b1 = new LineBorder(new Color(114, 139, 173), 3, true) {
};
tabbedPane.setBounds(0, 0, jDesktopPane1.getWidth(), jDesktopPane1.getHeight());
inFrame.setLocation(0, 0);
inFrame.setSize(jDesktopPane1.getWidth(), jDesktopPane1.getHeight());
inFrame.setBorder(b1);
JPanel jp = new JPanel();
jp.setLayout(new GridLayout());
jp.setOpaque(true);
jp.add(inFrame);
tabbedPane.addTab(title, jp);
tabbedPane.setSelectedComponent(jp);
inFrame.requestFocusInWindow();
inFrame.setVisible(true);
tabbedPane.setVisible(true);
}
I created a graph using JUNG, and I want to add a combobox that give the user the possibility to change the used layout (Circle, KK, FR, etc.)
But I couldn't do that.
that's how I visualize my graph:
// The Layout<V, E> is parameterized by the vertex and edge types
this.layout = new CircleLayout<Ressource,Float>(this.graph);
layout.setSize(new Dimension(500, 500)); // sets the initial size of the
// layout space
// The BasicVisualizationServer<V,E> is parameterized by the vertex and
// edge types
this.vv = new BasicVisualizationServer<Ressource, Float>(layout);
vv.setPreferredSize(new Dimension(550, 550)); // Sets the viewing area
// size
// Adjust the edges thikness
Transformer<Float, Stroke> edgeStroke = new Transformer<Float, Stroke>() {
#Override
public Stroke transform(Float arg0) {
return new BasicStroke(arg0);
}
};
vv.getRenderContext().setEdgeStrokeTransformer(edgeStroke);
// Show vertex and edge labels
vv.getRenderContext().setVertexLabelTransformer(
new Transformer<Ressource, String>() {
public String transform(Ressource r) {
return (r.nom);
}
});
vv.getRenderContext().setEdgeLabelTransformer(new ToStringLabeller());
I tried to create a whole new BasicVisualizationServer object having each time a different Layout, but it didn't work, It sticks with the first layout (Circle in my case).
What is the best way to change layout ?
Thanks guys !
The source file for this demo (in your distribution) demonstrates how to do it: http://jung.sourceforge.net/doc/api/edu/uci/ics/jung/samples/ShowLayouts.html
I'm writing my very first program in Java that actually does UI, so please bear with me if the answer to this is obvious.
I'm using JGraph 5 (5.14) to visualize a graph created by JGrapht (0.8.3).
I can create the graph with JGrapht just fine, and I believe it gets converted to JGraph OK using org.jgrapht.ext.JGraphModelAdapter. The problem is, when the result is displayed in a window (I'm using a panel in a JApplet) all the vertices are displayed on top of another.
Someone else had this problem (JGraph Layout Does Not Work) and I tried the solution presented there, but then only two nodes are displayed. Basically, I just want the graph displayed in some way where the nodes are separate from each other.
Some code is worth a thousand words, so here is what I currently have, which only displays two nodes (there are 219 in the graph):
class ourGraphVisualizer extends JApplet
{
private static final Color DEFAULT_BG_COLOR = Color.decode("#FAFBFF");
private static final Dimension DEFAULT_SIZE = new Dimension(1280, 1024);
// this init overrides the JApplet.init(). Our class here extends JApplet so we can do the visualization
public void init(ListenableDirectedWeightedGraph<String, DefaultWeightedEdge> theGraph)
{
JGraphModelAdapter<String, DefaultWeightedEdge> jgAdapter;
JPanel panel = new JPanel();
panel.setPreferredSize(DEFAULT_SIZE);
JScrollPane scrollpane = new JScrollPane(panel);
scrollpane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
scrollpane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
this.getContentPane().add(scrollpane, BorderLayout.CENTER);
JFrame frame = new JFrame();
frame.add(this);
frame.setTitle("Call Graph, " + theGraph.vertexSet().size() + "nodes");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setPreferredSize(DEFAULT_SIZE);
jgAdapter = new JGraphModelAdapter<String, DefaultWeightedEdge>(theGraph);
JGraph jgraph = new JGraph(jgAdapter);
panel.add(jgraph);
resize(DEFAULT_SIZE);
// Let's see if we can lay it out
JGraphFacade jgf = new JGraphFacade(jgraph);
JGraphFastOrganicLayout layoutifier = new JGraphFastOrganicLayout();
layoutifier.run(jgf);
System.out.println("Layout complete");
final Map nestedMap = jgf.createNestedMap(true, true);
jgraph.getGraphLayoutCache().edit(nestedMap);
jgraph.getGraphLayoutCache().update();
jgraph.refresh();
frame.setVisible(true);
panel.setVisible(true);
scrollpane.setVisible(true);
}
Any constructive suggestions/help/inspiration will be greatly appreciated!
Thanks...
-Eric
If u want to avoid overlapping of your Vertex just try different graph Layout i havegiven some here this one for hierarchical layout and call run method of this
final JGraphHierarchicalLayout hir = new JGraphHierarchicalLayout();
final JGraphFacade graphFacade = new JGraphFacade(jgraph);
hir.run(graphFacade);
final Map nestedMap = graphFacade.createNestedMap(true, true);
jgraph.getGraphLayoutCache().edit(nestedMap);
It'll be a much better idea to create two JPanels and add your graphs individually to the JPanels and the JPanels to the the JFrame using an appropriate layout manager