I use the following code to display a graph:
graph = new Graph(true);
vis = new Visualization();
vis.add(GRAPH, graph);
CustomLabelRenderer re = new CustomLabelRenderer();
re.setImageField(NODE_TYPE_IMAGE);
re.setImagePosition(Constants.TOP);
EdgeRenderer edgeRenderer = new EdgeRenderer(Constants.EDGE_TYPE_LINE, Constants.EDGE_ARROW_FORWARD);
edgeRenderer.setArrowType(Constants.EDGE_ARROW_FORWARD);
edgeRenderer.setArrowHeadSize(10, 10);
DefaultRendererFactory factory = new DefaultRendererFactory(re, edgeRenderer);
factory.add(new InGroupPredicate(EDGE_DECORATORS), new LabelRenderer(VisualItem.LABEL));
vis.setRendererFactory(factory);
As you can see instantiate the graph to use directed edges. Afterwards I set the EdgeRenderer to use arrow heads. However, I can't see any arrows on my edges, but just plain lines. What am I doing wrong?
That's how I add edges:
graph.addEdge(node1, node2);
You need to set the FILLCOLOR for edges:
filter.add(new ColorAction(edges, VisualItem.FILLCOLOR,
ColorLib.rgb(100,100,100));
I reproduce the problem with the RadialGraphView demo and I did not need any changes to the source code except for this line. (Though, I had to change the data file.)
Related
I have a use case as below. I need to construct a graph from a set of input as below -
SimpleDirectedGraph<String, DefaultEdge> g = new SimpleDirectedGraph<>(DefaultEdge.class);
g.addVertex("APP");
g.addVertex("CHROME");
g.addVertex("MOZILLA");
g.addVertex("LAPTOP");
g.addVertex("SERVER");
g.addVertex("CHROME_DEV");
g.addVertex("MOZILLA_DEV");
g.addVertex("APP_DEV");
Add edges for Server
g.addEdge("SERVER", "APP");
g.addEdge("SERVER", "CHROME");
g.addEdge("SERVER", "MOZILLA");
Add edges for Laptop
g.addEdge("LAPTOP", "APP_DEV");
g.addEdge("LAPTOP", "CHROME_DEV");
g.addEdge("LAPTOP", "MOZILLA_DEV");
Add Connecting edges between these 2 sets
g.addEdge("CHROME", "CHROME_DEV");
g.addEdge("MOZILLA", "MOZILLA_DEV");
Now i can construct a graph like this and the structure will looks something as below -
But my use starts here. Imagine i have removed the connecting edges from the graph above
g.removeEdge("CHROME", "CHROME_DEV");
g.removeEdge("MOZILLA", "MOZILLA_DEV");
Now my graph is essentially disjoint from each other. How do I find out it is disjoint graphs and how to get both the disjoint graphs. I will have to treat these two disjoint graphs separately here after.
What you are looking for is called 'connected components'. Have a look at the ConnectivityInspector.
To test whether your graph is connected:
Graph<String, DefaultEdge> g = new SimpleDirectedGraph<>(DefaultEdge.class);
ConnectivityInspector ci = new ConnectivityInspector(g);
//Test whether the graph is connected:
ci.isConnected();
You can get the vertices of each of the connected components using:
Set<String> vertexSets = ci.connectedSets();
For each of these sets, you can then create a graph induced on these vertices:
Set<String> vertexSets = ci.connectedSets();
for(Set<String> vertexSet : vertexSets){
Graph<String, DefaultEdge> subgraph = new AsSubGraph(g,vertexSet);
//Do something with the subgraph
}
More information on graph connectivity can be found here. For the purpose of your question you could also look into the difference between 'strongly' and 'weakly' connected components.
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.
I'm using JGraphX to draw a graph,using mxCircleLayout as basic representation, but I want to change some behavior. For example I want the EDGESTYLE_TOPTOBOTTOM, so before build mxGraphComponent I define a new edge style:
'
JGraphXAdapter graphAdapter = new JGraphXAdapter(this.stradario.getStradario());
graphAdapter.getModel().beginUpdate();
try {
Map<String, Object> edgeStyle = new HashMap<String, Object>();
edgeStyle = graphAdapter.getStylesheet().getDefaultEdgeStyle();
edgeStyle.put(mxConstants.STYLE_EDGE, mxConstants.EDGESTYLE_TOPTOBOTTOM);
mxStylesheet stylesheet = new mxStylesheet();
stylesheet.setDefaultEdgeStyle(edgeStyle);
graphAdapter.setStylesheet(stylesheet);
} finally {
graphAdapter.getModel().endUpdate();
}
mxCircleLayout layout = new mxCircleLayout(graphAdapter);
layout.execute(graphAdapter.getDefaultParent());
mxGraphComponent graphComponent = new mxGraphComponent(graphAdapter);
graphComponent.getViewport().setBackground(Color.white);
'
The graph was drawn as a circle layout, but edges are not in TOPTOBOTTOM style.
First draw
Then, if I draw a new edge, or I change an existing one, the edge is drawn with TOPTOBOTTON style.
Modified edge take the TOPTOBOTTOMSTYLE
I don't understand why the initial drawn is without TOPTOBOTTOM style and the modified edge was done with the new style.
The layout disables edge styles by default. Set the disableEdgeStyle member to false.
mxCircleLayout layout = new mxCircleLayout(graphAdapter);
layout.setDisableEdgeStyle(false);
layout.execute(graphAdapter.getDefaultParent());
I am trying out the GraphView Library for creating charts on Android. It looks quite decent, but I am wondering if there is a way to add some space between the tick labels and the graph itself. As you can see, there is basically none:
I use the following code to set up the graph (very similar to the example):
GraphView graph = (GraphView)view.findViewById(R.id.graph);
LineGraphSeries<DataPoint> series = new LineGraphSeries<DataPoint>(new DataPoint[] {
new DataPoint(0, 1),
new DataPoint(1, 5),
new DataPoint(2, 3)
});
graph.addSeries(series);
I tried using graph.getGridLabelRenderer().setPadding(), but that just added padding around the whole graph.
So, is there a way to put some padding around those labels?
yes it is possible in the current version in github (will be released in 4.0.1).
There is the method:
graph.getGridLabelRenderer().setLabelsSpace(x)
Follow this example to give your graph a custom label formatter. By doing so, you can at least add space padding to your y-axis labels (if not newline spacing to your x-axis labels).
// GraphView 4.x
graph.getGridLabelRenderer().setLabelFormatter(
new DefaultLabelFormatter() {
#Override
public String formatLabel(double value, boolean isValueX) {
if (isValueX) {
// show normal x values
return super.formatLabel(value, isValueX);
} else {
// show currency for y values
return super.formatLabel(value, isValueX) + " €";
}
}
}
);
I pulled this example from the GraphView documentation.
Otherwise, I found it interesting that someone chose this answer as the best response for a similar question.
Is there a way to create a table of contents using Java PDFBox library?
The table of contents should be clickable (jump to the right page)
Thanks.
There's no simple method for doing this, but here's an approach. I haven't figured out how to attach links directly to text, so my approach means you have to draw the annotations as rectangles and the text separately. It's a bit rough around the edges, but it works.
// there are other types of destinations, choose what is appropriate
PDPageXYZDestination dest = new PDPageXYZDestination();
// the indexing is odd here. if you are doing this on the first page of the pdf
// that page is -1, the next is 0, the next is 1 and so on. odd.
dest.setPageNumber(3);
dest.setLeft(0);
dest.setTop(0); // link to top of page, this is the XYZ part
PDActionGoTo action = new PDActionGoTo();
action.setDestination(dest);
PDAnnotationLink link = new PDAnnotationLink();
link.setAction(action);
link.setDestination(dest);
PDRectangle rect = new PDRectangle();
// just making these x,y coords up for sample
rect.setLowerLeftX(72);
rect.setLowerLeftY(600);
rect.setUpperRightX(144);
rect.setUpperRightY(620);
PDPage page = // however you are getting your table of contents page, eg new PDPage() or doc.getDocumentCatalog().getAllPages().get(0)
page.getAnnotations().add(link);
PDPageContentStream stream = new PDPageContentStream(doc, page, true, true);
stream.beginText();
stream.setTextTranslation(85, 600); // made these up, have to test to see if padding is correct
stream.drawString("Page 1");
stream.endText();
stream.close();
Phew! That's a lotta code. That should get you on your way. You can make the rectangle the same color as your document background if you want it to look like they are just clicking a link, but that requires more experimentation.