I have a java component on which I draw 100 by 40 rectangles to represent nodes of a graph. When a new node is added, I would like to be able to position it in a useful position. Currently, I simply choose the next available space on the x-axis. However, this means when I load a graph, I get a large chain of nodes spanning off the view to the right - not ideal!
A better solution may involve adding a node at the point closest to the center-point of the user's view. I'm sure there are many solutions to this problem I am unable to think of a reasonable way to achieve this.
I have three methods that are relevant to this problem:
positionNode(Node) // which tries to find suitable x,y to place a node
setPos(x,y) // which moves a node to the respective position
findElementAt(x,y) // which returns a node's model if such a node exists at (x,y)
A potential solution may somehow involve spiraling around the center point but I am unable to imagine a good solution for performing this.
Graph rendering is a hard problem which is the subject of a lot of research.
If you want to make the nodes into a sort of a bundle, rather than a line of nodes, the main disadvantage will be that lines coming out of the nodes will get overlapped by the other children.
You can make a square bundle or a round bundle. To make a square bundle, take the square root of the number of nodes and add one. For example, if you have 17 nodes, the sides of the square is 4 + 1 = 5. So you have a 5 x 5 square. Position each node in a cell of the square.
To make a round bundle draw concentric circles. So first node is at center. Then calculate an imaginary circle around that node. Divide the circle into segments by degrees according to how much space you need. Then locate each additional node in the center of each segment.
Note that you might want to overlap nodes. Depending on how your interface works, overlapping might allow you to fit more nodes in.
Sounds like an opportunity for force based layout:
http://en.wikipedia.org/wiki/Force-based_algorithms_(graph_drawing)
When you say graph I assume nodes are connected with each other so drawing them so their lines minimally criss cross to make it easier to visualize what the graph is telling you seems important. Forced based layout can help arrange the graph so it isn't under "stress" with lots of lines intersecting each other.
Related
I am working on a visualization tool for an excel document containing a relatively large amount of business requirements (70 data elements).
The purpose is to show some of the internal structures of the data which is not immediately obvious when staring at the excel file. The structure looks something like this:
root-->(
(component 1)--->(
sub-component a)--->(data element 1, data element 2, ..., data element 30),
(component 2)--->(
sub-component a)--->(data element 1, data element 2, ..., data element 30),
(component 3)--->(
sub-component a)--->(data element 2, data element 2, ..., data element 30)
)
What I'm noticing is that:
Graphs are great at showing structure, but suck at showing data.
Tables are great at showing data, but suck at showing structure.
At this point I can no longer use the default autolayout of GraphStream. Due to the large number of data elements attached to a single sub component, the autolayout cannot position those elements in such a way that they don't overlap and become impossible to read. What happens is a sort of flower effect, where the data elements are are like overlapping petals around their parent.
If I disable the autolayout, I have to position the nodes myself. Graphstream says the following:
You fix the coordinates as you wish. The units you use will be called “Graph Units”. However, as you will see later, the viewer supports two other units: pixels and percents.
http://graphstream-project.org/doc/Tutorials/Graph-Visualisation/1.0/
Alright, as it turns out, either this is a difficult problem or I am slow. I have been unable to position nodes is a readable way.
Things I've tried:
Positioning children relative to their parent: Iterate through the nodes with for loops (in retrospect it may be worth implementing this recursively to support n levels), starting with root. Determine the number of children of root divided by 2 (3/2 = 1 with integer division) call this middle. Set component 1 X position to i - middle. Set the y position to root y position - 1. In this way I can create a 'tree' structure where the parent sits centered on top of its children.
Other people's children are what's wrong with this world...
Unfortunately this doesn't work out well in practice. Any single component is ok but if there are other parents on the same level their children overlap with every other parent's children. This happens because the children are being positioned relative to their parent, and have no idea that, in fact, the position they want to go in is already being taken up by someone else's kids.
So now I don't know what to do. I can't position nodes taking into account nodes that don't exist yet. I have a few idea fragments, but they all seem convoluted.
So before I venture into hell code, I made this question because I feel like I can't possibly be the first person to have to draw a readable graph, and there probably are established ways to do this.
For reference these are the idea fragments:
Make individual graph elements responsible for their own position and have them position themselves relative to their children or lack there of.
Look into manipulating the camera in combination with some positioning solution. Limit the number of nodes that can be visible at a given time (kill other people's children if there's too many). Use zoom and panning based on which component is clicked.
Recursion. Is a word I know. Kidding aside, I have used recursion before and I feel graphs, especially graphs like mine without cyclic structures in them, practically beg for recursive solution. I actually have, in a different project used a recursive approach to draw graphs, but I ended up in the same situation. How can I be aware of the recursive paths drawing other parent's children? I should still probably brainstorm some recursive approaches.
Create a new data structure that represents relative real estate in the viewport. Segment into regions, nodes take up the relative regions, 2 nodes cannot take up the same relative region. Figure out what to do when some one try's to sit on someone else's kid. I came up with this while writing this post actually.
That's all I got, what do you guys think? Is there some well known algorithm for node positioning that already solves my issue? Which of my idea fragments sound most promising?
I'm using a triangulation library to compute the Constrained Delaunay Triangulation of a set of rectangles within some large boundary. The algorithm returns all the edges, but also adds edges inside of the rectangles that define the constraints. I want to be able to find if an edge lies inside of a rectangle in O(1) time.
Here's a more general description of the problem I want to solve. Given a set of nonoverlapping rectangles (the borders of the rectangles may touch) and an edge e with endpoints (x1,y1) and (x2, y2), find in O(1) time if e lies within any of the rectangles (including the border).
Also let me know of any data structures I can use for speedups! I'm also implementing this in java so I have easy access to hash sets, maps and all those nice data structures.
Since the rectangles are completely enclosed, the inside of each rectangle will simply be the CDT of the rectangle itself -- which is to say, two triangles, meeting along a diagonal of the rectangle. So you can just insert all rectangles' diagonals (remember, two possible diagonals per rectangle) into a hashtable, and check which edges exactly match those endpoints.
It is possible to break up the area that all of the rectangles cover into a N by M grid of boxes. By labeling each box with the rectangle it is in or the rectangles it overlaps. It is possible to obtain O(1) queries, with O(N*M) pre-processing.
However, in order for it to work, the grid has to created based on an algorithm that allows for calculating which box a point lies in in O(1). It also requires that the number of rectangles a box overlaps be very small (ideally no more than 2 or 3) as otherwise the average query time could be O(log N) or worst. This means that the number of boxes can get very large.
I want to draw a dendrogram from objects which I have already clustered and saved in a (leave)tree. My Cluster object in Java can be represented by these pictures. Each leaves contains an object and each node contains the distance between its children.
Now, I want to draw a dendrogram stepwise, so first object 1 and 2 should be drawn, then object 3 should be added to those. Then 5 and 6 together etc.. to the end where everything is connected. I already have all the tools to draw this easily, but I cannot find an efficient way in walking through the tree correctly.
This should be the result so far in the example (EDIT: There's a mistake, the distance from 5 to 6 now looks smaller than the distance from 3 to 1&2, but that isn't the case in my example!):
Does anyone have some tips for this recursive algorithm?
you're rendering depth first - you may find you need to keep track of depth to get the layout to work right - also note you have to draw non-terminal notes as well ("*" gets drawn before 3)
basically
draw(node)
{
if(hasleft) draw(left)
if(hasright) draw(right)
drawme()
}
this does assume a binary tree, but that is what you've drawn - and this is going to get a lot more complicated because of layout issues - you really want to consider drawing breadth first from the top down, it makes layout a lot less painful
I need a way to define if a contour represents a line or a closed shape. In Java, I have an object Shape which contains all the points which defines it again as separate objects. The object Point represents the coordinates of the point. I tried parsing the shapes with a recursion but for larger shapes, more then 150 points, the performance is very poor. I am attaching a picture of the shapes I want to parse to help better understand the question.
I am putting a image for better visualisation of the problem.
This is just showing all the shapes I got. I want to display just the two closed ones.
Thanks in advance.
Vassil Kossev
First idea: Use a suitable contour tracing algorithm to get an ordered contour. If your contour is closed you will get back to the first point eventually.
Second idea: Use a flood filling algorithm: if you get out of the bounding box of your object it is open, otherwise it is closed.
Third idea: use morphology. Remove lone pixels. Find all endpoints and branchpoints. Remove all branchpoints. Connected components with no endpoints are closed contours ("circles"), connected components with two endpoints are open contours ("lines"). Re-project connected components with no endpoints to the original image and keep only connected components that have common part with them. I think this could be implemented real-time, and the easiest to implement.
If you have contour lines of 1 pixel width, then you can count the number of neighbors for each point *. If every point of a given contour has 2 neighbors, then the contour is closed. If there are 2 points with only 1 neighbor each, then the contour is open.
If your contours are thicker, then you can apply a skeletonization algorithm to make them exactly 1 pixel thin. An interesting case is when you have side branches on a contour, but in this case there must be branching points with 3 neighbors, so similar situations can be handled easily.
* Counting neighbors is easy: use the original image! Choose one point of the contour randomly, check the neighboring 8 pixels, and count those which are part of the contour. Then repeat the neighbor-checking for these, and so on, until all pixels of the contour have been checked.
If the points are stored in order, you might be able to compare the first and last points. If they're spatially equal, the contour is closed.
I have implemented a simple Dijkstra's algorithm for finding the shortest path on an .osm map with Java.
The pathfinding in a graph which is created from an .osm file works pretty well. But in case the user's current location and/or destination is not a node of this graph (just raw coordinates) how do we 'link' those coordinates to the graph to make pathfinding work?
The simple straightforward solution "find the nearest to the current location node and draw a straight line" doesn't seem to be realistic. What if we have a situation like on the attached picture? (UPD)
The problem here is that before we start any 'smart' pathfinding algorithms (like Dijkstra's) we 'link' the current position to the graph, but it is just dumb formula (a hypotenuse from Pythagorean theorem) of finding the nearest node in terms of geographical coordinates and this formula is not 'pathinding' - it can not take obstacles and types of nodes into account.
To paraphrase it - how do we find the shortest path between A and B if B is a node in a graph, and A is not a node?
Have you heard of any other solutions to this problem?
The process you're describing is "map matching," and it uses a spatial index to find the nearest node.
One common approach is to construct a quadtree that contains all your nodes, then identify the quad that contains your point, then calculate the distance from your point to all nodes in the quad (recognizing that longitudinal degrees are shorter than latitudinal degrees). If there are no nodes in the quad then you progressively expand your search. There are several caveats with quadtrees, but this should at least get you started.
Practically speaking, I would just ignore the problem and use your suggested algorithm "straight line to nearest node". It is the user's responsibility to be as close as possible to a routable entity. If the first guess you suggested was missleading, user can change the starting position accordingly.
The user who really starts his journey in no man's land hopefully knows the covered area much more than your algorithm. Trust him.
BTW, this is the algorithm that OpenRouteService and Google Maps are using.
If still not convinced, I suggest to use the "shortest straight line that does not cross an obstacle". If this is still not enough, define a virtual grid of say 5mx5m and its diagonals. Than span a shortest path algorithm until you reach a graph-vertex.
You could treat the current location as a node, and connect that node to a few of the nearest nodes in a straight line. GPS applications would consider this straight line as being 'off road', so the cost of this line is very big compared to the other lines between nodes.
However, I didn't see your attached picture, so not sure this is a good solution for you.
If you have constraints in your path, you should consider using a linear programming formulation of the same shortest path problem.
http://en.wikipedia.org/wiki/Shortest_path_problem
Your objective would be to minimize the sum of the distance of each "way" taken between the starting and ending "nodes" defined in your .osm file. Any obstacles would be formulated as constraints. To implement with Java, see the link below.
http://javailp.sourceforge.net/
Really nice question!
Quad tree is a solution, as you can also index lines/edges into it, not only nodes.
But the problems with this 'naive' approach is that these solutions are memory intensive. E.g. if you already have a very big graph for shortest path calculation then you need the same or more memory for the quad tree (or I was doing something very stupid).
One solution is as follows:
use an array which is a grid over the used area. I mean you can devide your area into tiles, and per tile you have an array entry with the list of nodes.
so per array entry you'll have a list of nodes in that tile. For an edge you can just add both nodes to the entry. Take care when there are edges crossing a tile without having its node in this tile. The BresenhamLine algorithm will help here.
querying: converte the input ala (lat,lon) into a tile number. now get all points from the array entry. Calculate the nearest neighbor of the nodes AND edges to your point A using euclidean geometry (which should be fine as long as they are not too far away which is the case for nearest neighbor).
Is this description clear?
Update
This is now implemented in graphhopper!
To get a more memory efficient solution you have to simply exclude identical nodes for one entry (tile).
A bit more complicated technic to reduce mem-usage: if a graph traversal respects the tile bounds you can imagine that the graph is then devided into several sub-graphs for that tile (ie. a graph traversal wouldn't reach the other sub-graph within the tile-bounds). Now you don't need all nodes but only the nodes which lay in a different sub-graph! This will reduce the memory usage, but while querying you need to traverse not only one edge further (like in the current graphhopper implementation)! Because you need to traverse the full tile - i.e. as so long as the tile bounds are not exceeded.