order of networkx nodes - print graphviz layout vertically - python

I have a graphviz layout I've created. I've also tried to create graphs using differing drawing styles such as random, circular, shell, spectral, spring. I believe graphviz is the most accurate to my data. I created a file containing two columns of strings. These columns are the edges. (Each string has at least one corresponding partner, which is why GraphViz layout I think best represents these data) From that file I created a list of unique strings for the nodes. I then plotted the nodes and added the edges. A version of my script can be found here: (networkx - change node size based on list or dictionary value)
Here is the output using graphviz layout (instead of 100 the sizes were multiplied by 10, some numbers are as high as 15020, and other as small as 10):
Here is the output using random:
Can one conclude that all the edges that should be present are present in the graphviz example? Is it correct to say that smaller nodes "on top of" larger ones are conncted? Is it possible to make their edges viewable? Are there so many more edge visible in the random example due to the random placement of nodes in the graph, therefore edges can have a much higher 'length' to traverse?
If what I think is correct, and the graphviz is the best drawing option for my data, since there are many overlaps between the nodes and edges (and if those nodes "on top of" the larger node are indeed connected) what I would like to do is sort the plot in a "vertical" fashion. So, the largest nodes with most edges on top, going down to nodes with only 1 edge. I've tried to change the overall figure size, which did not make anything more discernable. For some reason, I got the original window with the plot and a secondary window with a grey blank background.
So, I'm starting to think some of my assumptions are correct. Here is the image as large as I can make it:

What is happening is that networkx puts the nodes over top of the edges. So the edges are drawn underneath the nodes.
I believe the easiest way to still see them is to set alpha=0.5 or something else less than 1 in the draw command to make the nodes partly transparent.

Related

Assigning surfaces to zones based on the 3D regions they enclose

Given a set of surfaces in three-dimensional space, I am attempting to assign each surface to a zone referring to the smallest 3D region the set encloses, or no zone if this is not applicable. I also want to determine if a surface is an interface between two zones. So, for example, if we had 11 surfaces representing two cubes stacked on top of each other, the surfaces in the top cube would be in the same zone and the surfaces in the bottom would be in a different zone (with the interface surface being in both zones).
As an example, I want to take in a set of surfaces such as this and turn it in to this. Each color here represents a zone, with gray being no zone associated (as in the flap at the bottom).
I have done some searching around trying to find if someone has already come up with an algorithm to do this, but I have not found anything (most seem to identify regions rather than link surfaces to the region they enclose). As such I am trying to come up with my own algorithm and am wondering if there are any other alternatives or if my method would work.
I am assuming all surfaces are connected.
My idea is the following:
Select a random surface whose sides each touch exactly one other surface, and add this to zone 1.
Add each connected surface to zone 1 provided each of its sides touch exactly one other surface.
For those connected surfaces that touch more than one surface on at least one of its sides, add it to the "maybe" list.
For each new surface in zone 1, repeat steps 2-3.
Once a surface has been added to the "maybe" list twice, add it to zone 1 and remove from the "maybe" list. Mark this surface as a zone interface.
Add the zone interface to zone 2.
Select one random surface from the "maybe" list and assign it to zone 2 and clear the "maybe" list.
Repeat steps 2-7 (updating the zone number of course) until there are no surfaces that are unassigned.
This seems to work for simple scenarios (e.g., two cubes stacked on top of one another), but I am not sure if there are any tricky conditions I need to watch out for, or if it falls apart once there are more than two zones that share a side.
Any improvement on my rough algorithm/alternate ideas for implementation would be appreciated. Thanks!
EDIT: Here are some more details in response to some comments.
A zone by my definition is simply a group of surfaces that completely bound a 3D region with no gaps. So if I had two cubes, A and B, that do not touch, I would have two zones: one consisting of all the surfaces of cube A and the other of all the surfaces for cube B. If I had a cube that was missing one side, there would be no zone associated with those surfaces.
My end goal is to make an automated process for grouping surfaces in a modeling tool I am creating. The specifics are classified, but essentially I am dealing with models where certain properties are common only between surfaces in the same "zone" as described above. I want to make an automated process that creates these zones so that the user can apply these properties to all surfaces in the zone at once instead of doing it manually.
Essentially the problem boils down to finding the smallest 3D regions that are completely enclosed by an arbitrary set of surfaces, and keeping track of which surfaces belong to which regions. I hope this makes my question more clear.
What you are interested in, then, would be discovering closed surface (volume) mesh topology from a set of input polygons; in other words - polytopes. This is common to pretty much every 3d modeling package. I would guess that Blender has code that does that. There are different ways of doing this, commonly however, some version of half-edge graph is used. See wiki link here: Doubly Linked half edge graph. The idea is to walk your input polies, and build these graphs. Once done, you can easily query each graph to see if there are holes (edges missing, etc).
I attached a picture explaining how to use a half-edge structure to get what you want: Say you are given a soup of five rectangles (they make up a cube with out a top. U process your first rectangle say ABCD, this creates your first graph, say G1. Now you process second polygon, say FEHG, none of these vertices you have seen yet, so you create second graph, G2. Now say you process polygon CDGH. You have seen these vertices before, so instead of creating a new graph, you merge(connect) existing graphs that share these nodes. Proceed until you process all polygons. You get graph in picture.
Now, to query the graph to get your information. Once you walk the graph, you will see that there are exactly four vertices (nodes) that are missing edges. Those verts correspond to the missing top of the box (the edges are red in the illustration). Hence you know that this graph is not a closed manifold. If you had another box, that did not share nodes with this one, you would have another graph. So each graph, once you done processing your polygons, is a "zone" for you.
Note, if you have two say intersecting shapes, you can track those too using these graphs, but its much more complicated. Basically when processing a new polygon, you would not only have to see if any of its verts belong to already processed graphs, but also see if this polygon intersects any of the previously processed polygons, if so, split this polygon and add all this to the intersected graph.

networkx - python - distance between nodes nx.draw_graphviz()

I'm using networkx to make some graphs. I like the output of the fdp layout with Graphviz.
However, I can't seem to get the nodes to space apart far enough to vizualize.
I've tried using scale, K and nodesep in the nx.draw() command, however a lot of the nodes are still jumbled and can't be seen because of overlap. I decreased the node size from 300 (default) to 200, still not too good. Any smaller and the colors I've added are not easily recognizable.
There are approx. 2400 nodes. Does anyone know how to space nodes with nx.draw_graphviz(g, prog="fdp")? Ideally I would like to order the nodes from largest cluster to smallest in a vertical fashion, but can't seem to find a layout.
I tried using prog="dot" and using rankdir="TB", but the nodes are still printed left to right in a jumbled order and are very hard to make out. I either need to increase the spacing of the nodes, or make the image much larger, and I've also tried playing around with the parameters to Matplotlib and the image is the same size every time. All thoughts are appreciated.

Is there a way to control line angle when producing graphs with pyDot

I wrote a python class to display and animate binary search trees. Yet the graphs produced by the pyDot edge and node commands don't seem to allow me to control the angle or direction of the arrows connecting each element of my tree.
There are lots of controls for shape of the nodes but there does not seem to be any control for angle of the lines. I was hoping to find some kind of minimum angle parameter to add to my edges as they are added to the graph?
This is a sample of my code where I draw nodes using the edge command:
def draw(parent_name, child_name):
# color for lines = red
edge = pydot.Edge(parent_name, child_name, color="#ff0000")
graph.add_edge(edge)
The end result is that my graphs for binary search trees don't look like the traditional tree structures when several nodes have only one child.
Here is a link to my project where you can see the otherwise working results:
http://www.embeddedcomponents.com/blogs/2013/12/visualizing-software-tree-structures/
from pydot documentation:
create will write the graph to a temporary dot file and process
it with the program given by 'prog' (which defaults to 'twopi'),
reading the Postscript output and returning it as a string is the
operation is successful.
it is not possible to directly control edges angels using the dot language, but adding invisible edges can give you the result you want, see an example here that generates the following graph:

Group vertices in clusters using NetworkX

I am trying to represent graphically some graphs, and I need to group in clusters some nodes that have a common characteristics.
I am using NetworkX, and I need to do something similar with the graph from this tutorial, from the slide 44, left figure.
I want to draw some delimiting line around each cluster. My current code is like that:
vec = self.colors
colors = (linspace(0, 1, len(set(vec))) * 20 + 10)
nx.draw_circular(g, node_color=array([colors[x] for x in vec]))
show()
I wish to find an example and see how can I use networkx to cluster the graph.
I'm not positive what your question is. I think you're asking "how do I get networkx to put some nodes close together"
Before I launch into the answer, the drawing documentation for networkx is here: http://networkx.lanl.gov/reference/drawing.html
So that figure you're asking about has 4 different communities that are clustered based on having lots of edges within each community and not many outside.
If you don't want to put much effort into it, spring_layout is often good for putting tightly knit communities together. The basic algorithm of spring_layout acts as if the edges are springs (and nodes repel). So lots of edges keeps nodes close together. Note that it initializes the positions randomly, so each time you'll get a different output.
The easiest way to do this is just
nx.draw_spring(G)
But maybe you want more. If you want to, you can fix every single node's position. Define a dict, usually named pos.
pos = {}
for node in G.nodes_iter():
pos[node] = (xcoord, ycoord).
where xcoord and ycoord are the coordinates you want the node to be at.
Then just do
draw_networkx(G, pos = pos)
That's often a lot of effort. So sometimes you just tell it a few of them have to be in particular places, and let networkx do the rest
Define fixedpos for a few nodes and then run
spring_layout
telling it what nodes are fixed and giving it fixedpos as the initial positions. Then it will hold those fixed and fit everything else around.
Here is some code which generates a network that has 4 completely connected parts and a few other edges between them. (actually it generates a complete network and then deletes all but a few edges between these parts). Then it draws it with a simple spring layout. Then it fixes 4 of them to be at the corners of a square and places the other nodes around those fixed positions.
import networkx as nx
import random
import pylab as py
from math import floor
G = nx.complete_graph(20)
for edge in G.edges():
if floor(edge[0]/5.)!=floor(edge[1]/5.):
if random.random()<0.95:
G.remove_edge(edge[0],edge[1])
nx.draw_spring(G)
py.show()
fixedpos = {1:(0,0), 6:(1,1), 11:(1,0), 16:(0,1)}
pos = nx.spring_layout(G, fixed = fixedpos.keys(), pos = fixedpos)
nx.draw_networkx(G, pos=pos)
py.show()
You can also specify weights to the edges, pass the weights to spring_layout and larger weights will tell it to keep the corresponding nodes closer together. So once you've identified your communities, increase weights within the communities/clusters if necessary to keep them close together.
Note that you can also specify what color to make each node, so it is straightforward to specify the color for each community/cluster.
If you then want to draw curves around each of those clusters, you'll have to do that through matplotlib.

Placing nodes vertically in Graphviz using pydot

I am using Graphviz in Python via pydot. The diagram I am making has many clusters of directed graphs. pydot is putting them next to each other horizontally resulting in an image that is very wide. How can I tell it to output images of a maximum width so that I can scroll vertically instead?
There are several things you can do.
You can set the maximum size of your graph, using 'size' (e.g., size = "4, 8" (inches)). This fixes the size of your final layout. Unlike most other node,edge, and graph parameters in the dot language, 'size' has no default. Also, the default orientation is 'portrait', which i believe is what you want (for a graph that is taller vs. wider), but you might want to set this parameter explicitly in case it was set to 'landscape' earlier.
'Size' can be used with the 'ratio' parameter (the layout aspect ratio) to manipulate the configuration. 'Ratio' takes a float (e.g., ratio = "2.0") or 'auto' or 'fill'. (The latter tells graphviz to fill use the entire graph region alloted by 'size'.
The parameters that have the greatest effect on graph configuration are 'nodesep' and 'ranksep'. These are the minimum horizontal distance between adjacent nodes of equal 'rank', and the minimum vertical distance between adjacent ranks of nodes. The default values are 0.25 and 0.75 inches, respectively. To get the configuration you want, you will want to simultaneously increase nodesep and decrease ranksep. Gradual iteration should allow you to quickly converge on a set of values for these two parameters that gives you the configuration you want.
Initialize your graph like this:
graph = pydot.Dot(graph_type='digraph', rankdir='LR')
This will set the graph direction from left to right. In general, use the graphviz documentation to find the right attribute in order to achieve what you want.
I'm not sure if you're able to do this with your data, but if you change the order that the nodes are inserted into the graph it can really affect the generated graph. If you don't want to supply any ordering information to Graphviz and want Graphviz to attempt solving optimal placement of nodes to minimize contention, use Graphviz's neato instead. It uses a spring model to figure out where nodes should be placed.
It looks like you should be able to use neato inside pydot like:
my_graph.write('my_graph.png', prog='neato', format='png')
See pydot's documenation here.

Categories

Resources