How to use lines with arrow in pydot - python

I have drawn a binary search tree using pydot with these commands
graph = pydot.Dot(graph_type='graph')
visit(n5, BFS)
graph.write_png('example1_graph.png')
Where function view traverses the tree and calls a simple routine to draw the edges:
def draw(parent_name, child_name):
# color for lines = red
edge = pydot.Edge(parent_name, child_name, color="#ff0000")
graph.add_edge(edge)
But the lines connecting the nodes are simple straight lines. Is there a way to change the simple lines into directed arrows?

To connect nodes with arrows, use a directed graph type. Change the first line of the code, and the lines connecting nodes will be arrows instead of lines.
graph = pydot.Dot(graph_type='digraph')

Related

how to apply GraphViz attrs to networkx / pygraphviz

I'm using networkx (v2.5) for a dependency-analysis problem, and visualizing the data via graphviz / pygraphviz (v1.7) on ubuntu 20.04. The contents of each node (label field) is a code block - so I'd like it LEFT justified. The problem is I can't seem to change the default (CENTER justified).
X/Y: - my specific need is to make a png from a networkx graph where the node text is left-justified - I believe Graphviz/pygraphviz is the best ~trivial way to do so - but any FOSS way to accomplish this would be fine.
I successfully generate a png as desired, via the following simplified code, but the text is all center-justified.
from networkx import DiGraph, nx_agraph
from networkx.drawing.nx_agraph import write_dot
# graph is created via networkx:
graph = DiGraph()
graph.add_edge("node1", "node2")
graph.nodes["node1"]["label"] = get_code_sniped("node1")
# ...
# and converted / output to dot & png via (internally) pygraphviz
write_dot(graph, "/tmp/foo.dot") # appears correctly output
a_graph = nx_agraph.to_agraph(graph)
a_graph.layout(prog="dot")
# attempt to add attrs per defs in
# https://www.graphviz.org/doc/info/attrs.html#d:labeljust
a_graph.graph_attr.update(labeljust="l") # <----- has no effect on output
a_graph.graph_attr.update(nojustify=True) # <-/
a_graph.draw("/tmp/foo.png") # <-- PNG outputs successfully,
# but all node text is CENTER justified
How can I modify the node text (specifically left-justifying it) in the PNG generated from my networkx graph?
it appears there is (undocumented, AFAICT) upstream/native graphviz behavior w.r.t. inheriting graph-level attributes.
setting a_graph.graph_attr.update(... is insufficient, as it is not inherited by child elements. In order to for instance set fontname, the following works:
for node in formattable_graph.iternodes():
node.attr["fontname"] = "Liberation Mono"
also, for text-justification, one can control this on a Per line basis by changing the line ending "\l" (Note: that is two bytes in python as it's not an actual escape char) and "\r" for left and right (respectively).
this will LEFT justify all lines
graph.nodes["node1"]["label"] = """my
node label
with newlines
""".replace("\n", "\l")

Use leidenalg and igraph to find cluster and then output gml file

import leidenalg as la
import igraph as ig
G = ig.Graph.Famous('Zachary')
partition = la.find_partition(G, la.ModularityVertexPartition)
ig.plot(partition,vertex_size = 30)
ig.save(G,'ttt.gml')
Everything works fine, however ig.save does not contain cluster information, just nodes and edges.
Need to add Cluster information to nodes in ttt.gml file
The graph itself doesn't contain any information of the partition. You should first add this information to the graph before saving it by doing G.vs['cluster'] = partition.membership.

Set node positions using Graphviz in Jupyter Python

I want to make a graph with random node positions but it seems that the "pos" attribute for nodes does nothing. Here is a minimal example:
import graphviz
import pylab
from graphviz import Digraph
g = Digraph('G', filename='ex.gv',format='pdf')
g.attr(size='7')
g.node('1',pos='1,2')
g.node('2',pos='2,3')
g.node('3',pos='0,0')
g.edge('1','2')
g.edge('1','3')
graphviz.Source(g)
Any ideas of how achieve that?
Thanks in advance.
Although not 100% clear in the docs, I think pos is not supported in the dot engine on input. The fdp or neato engines do support pos on input for setting the initial position, and if you end the coordinate specification with '!', the coordinates will not change and thus become the final node position.
Play with a live example at https://beta.observablehq.com/#magjac/placing-graphviz-nodes-in-fixed-positions
This standalone python script generates a pdf with the expected node positions:
#!/usr/bin/python
import graphviz
from graphviz import Digraph
g = Digraph('G', engine="neato", filename='ex.gv',format='pdf')
g.attr(size='7')
g.node('1',pos='1,2!')
g.node('2',pos='2,3!')
g.node('3',pos='0,0!')
g.edge('1','2')
g.edge('1','3')
g.render()
Since SO does not support pdf uploading, here's a png image generated with the same code except format='png':
Without the exclamation marks you get:
Without any pos attributes at all you get a similar (but not exactly the same) result:

Substitute node labels with emoji using networkX in Python

I am using networkX to draw a network plot from a distance matrix(emoji_sim, a DataFrame). Here is the code:
G = nx.from_numpy_matrix(np.array(emoji_sim))
nx.draw(G, edge_color='silver', node_color='lightsalmon', with_labels=True)
plt.show()
I know there is a way to relabel the nodes as:
G = nx.relabel_nodes(G, dict(zip(range(len(G.nodes())), range(1, len(G.nodes())+1))))
But I want to substitute the nodes label with images(possibly read from files or using Python Emoji package). Is there any way to do that? Thanks a lot!
To clarify, I am trying to substitute the actual circle with images.
The idea behind it is not very difficult but in order to get it to be displayed (at least on ubunto) it gave me some hard time as not all fonts support emoji. I shall display the straight forward way then some links that helped me in the end (maybe you will not need those).
From emoji cheat sheet from the emoji python package I picked up three to be shown as an example and here is the code.
G = nx.Graph()
G.add_nodes_from([0,1,2])
n0 = emoji.emojize(':thumbsup:',use_aliases=True)
n1 = emoji.emojize(':sob:',use_aliases=True)
n2 = emoji.emojize(':joy:',use_aliases=True)
labels ={0:n0,1:n1,2:n2}
nx.draw_networkx(G,labels=labels, node_color = 'w', linewidths=0, with_labels=True, font_family = 'Symbola' ,font_size = 35)
plt.show()
Difficulties encountered:
1- My machine is on ubunto 14.04, I could not display any emoji they always appeared as rectangles
Installed needed font Symbola using the following command (mentioned here):
sudo apt-get install ttf-ancient-fonts
2- Maplotlib (which networkx calls to draw) is not using the installed font.
From several useful discussions 1 2 3 4 5 6 I copied and pasted the .tff font file of Symbola in the default matplotib directory (where it fetches for fonts to use).
cp /usr/share/fonts/truetype/ttf-ancient-scripts/Symbola605.ttf /usr/share/matplotlib/mpl-data/fonts/ttf
Then I had to delete fontList.cache file for the new font to be loaded.
rm ~/.cache/matplotlib/fontList.cache
Note
You can have different views by changing the input to the draw_networkx e.g. not sending the linewidths will show circular border for each node, also if you want a specific background color for nodes change the color_node from white to a color that you want ... for more details check the documentation.

Converting networkx graph to flare json

I have a networkx graph
g
And I want to draw up this visualization
http://mbostock.github.io/d3/talk/20111018/tree.html
What that means is somehow I have to convert my graph into flare.json
https://bitbucket.org/john2x/d3test/src/2ce4dd511244/d3/examples/data/flare.json
To convert this graph into a tree.. I will give a seed node which serves as root of this json and then grow the tree by adding edges to this tree as its children upto say 3 hops..
How do i do this?
If you have a tree you can use the networkx tree_data() function to write the data in JSON tree format for that flare.json example.
The example shown there is:
>>> from networkx.readwrite import json_graph
>>> G = nx.DiGraph([(1,2)])
>>> data = json_graph.tree_data(G,root=1)
To build a tree from your graph either bfs_tree() or dfs_tree() would work.
Or maybe you already know how you want to build a tree from your graph.
There is an example of how to use the d3.js library with NetworkX at https://networkx.github.io/documentation/stable/auto_examples/index.html#javascript
That uses the d3.js force layout code.

Categories

Resources