In networkx
, I have a directed draph G = networkx.DiGraph()
where each node has an attribute w
(always a positive integer, including zero). The graph is acyclic (it represents a poset), and the value increases as one goes from node to node, that is, generically G.nodes[n1]["w"] < G.nodes[n2]["w"]
if there is a path between n1
and n2
, but it is not a direct function of the position in the graph, i.e. two nodes with edges to the same node can have different values of w
, as long as they are bigger than that of their origin.
I need to draw this diagram as a tikz
figure in latex
. I want the figure to not only represent G
, but also that nodes with different values of w
are at different heights (and same values of w
at the same height.
A toy example I implemented is:
import networkx
import dot2tex
nodes = [
["A", {"w": 0}],
["B", {"w": 1}],
["C", {"w": 2}],
["D", {"w": 3}],
]
edges = [
["A", "B"],
["A", "C"],
["B", "D"],
["C", "D"],
]
G = networkx.DiGraph()
G.add_nodes_from(nodes)
G.add_edges_from(edges)
A = networkx.nx_agraph.to_agraph(G)
dot_string = A.string()
latex_string = dot2tex.dot2tex(
dot_string,
preproc=True,
docpreamble=r"\usepackage{amsmath,amssymb,amsthm,bm}",
format="tikz"
)
latex_string = dot2tex.dot2tex(
latex_string,
figonly=False,
docpreamble=r"\usepackage{amsmath,amssymb,amsthm,bm}",
autosize=True,
crop=True,
valignmode="dot",
format="tikz"
)
print(latex_string)
with open("test.tex", "w") as f:
f.write(latex_string)
This gives the picture on the left
However I need the node C
to be half way between B
and D
to reflect the fact that its argument w=2
satisfies 1<2<3
, as depicted more or less on the right. The actual diagrams I have can have order 50 nodes, so doing it by hand would take ages. Is there a simple way to do it automatically? The precise height is not really important, as long as it's clear that B
and C
have different w
.
As commented by @sroush, this is achieved by setting the minlen
attribute as the difference between each w
values for the dot
graph. The easiest is to do it directly at the level of the networkx.DiGraph
.
Simply adding the following bit lines in the code above will give the desired result
...
G = networkx.DiGraph()
G.add_nodes_from(nodes)
G.add_edges_from(edges)
for e in G.edges:
G.edges[e]["minlen"] = G.nodes[e[1]]["w"] - G.nodes[e[0]]["w"]
...