Placing nodes vertically in Graphviz using pydot - python

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.

Related

Can graphviz constrain the graph to a certain width?

I'm using graphviz from python to plot japanese kanjis and their relationships. I'm exporting the output as a svg and using sfdp as a render engine.
The output is roughly square (3000x3000). I was wondering if there was any way to specify a constraint so that the output is more like a vertical rectangle (for instance 5000x1000) than a square.
It seems that the size parameters mostly work on the scale of the resulting image, and not on the positioning of the nodes themselves. But I have a lot of different connexe components so it should be easy to move them around.
Is what I'm trying to do impossible?
Thanks!
sfdp, because it uses a spring model, tends to produce square graphs. However, if you use dot you have the added attributes like rank and rankdir to shape your graph more to your wishes.
You can refer to Node, Edge and Graph Attributes to see which attributes sfdp supports.
Try playing with the ratio attribute:
...
If ratio is numeric, it is taken as the desired aspect ratio. Then, if the actual aspect ratio is less than the desired ratio, the drawing height is scaled up to achieve the desired ratio; if the actual ratio is greater than that desired ratio, the drawing width is scaled up.
So if the original graph was like this:
Adding the graph [ratio="1.5"] attribute will make it look like this:
UPD: also notice how the ratio attribute works in pair with size attribute, maybe the combination will be best for you. Detailed explanation in the ratio docs over the link I've posted.

Plot directional edges as non-overlapping lines

I have a networkx directional graph. I'd like to plot it so that nodes that interact (A->B, B->A) have two edges displayed and the colors correspond to the relative weights.
Currently I have a simple three-node graph. Naturally the flow is "order created" -> "order closed" but on not-so-rare occasions the flow can be reversed!
Since this is going on a dashboard, I need to avoid the "download it and use another software package" to visualize it. Ideally I'd just use igraph (love it in R), but it's not supported in my environment (Mode Analytics).
Is the best solution to just create a hack where I split every node to a pair: "node-sender" and "node-receiver"? At least that would have the bonus of seeing self-edges too. Or maybe switch to plotly's chord diagram?
Edit: What I'm looking for
Ideally I could just use something like the qgraph package in R.
edges <- data.frame(from = from_node, to = to_node, thickness = weights)
qgraph(edges, esize=10, gray=TRUE)

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.

order of networkx nodes - print graphviz layout vertically

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.

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:

Categories

Resources