I am attempting to autoscale a networkx graph based on the number of nodes and whether there are nodes that overlap in the horizontal direction or the vertical direction (ie. if all nodes were on the same line, they would intersect). To do this, I look at the position of each node and check whether the position plus the node size is between any other nodes coordinates plus the node size. To get the node positions, I am using networkx.nx_agraph.graphviz_layout
. The issue is that the positions and the node size are not of the same unit.
Networkx calls pyplot.scatter
underneath the hood (source: https://networkx.github.io/documentation/networkx-1.10/_modules/networkx/drawing/nx_pylab.html#draw_networkx_nodes
), which takes the node size as an area in pixels (source: https://stackoverflow.com/questions/14827650/pyplot-scatter-plot-marker-size
).
Networkx draws the graph with circle nodes, so based on this it would make sense that to convert the node size to inches, I would do node_size * 4 / (math.pi * DPI)
where DPI
is the DPI used by Matplotlib. In my code this does not seem to work. I have also tried taking the square root of the node size and dividing it by the DPI but that doesn't seem to work either.
Currently the issue is that I am not able to detect what nodes are overlapping.
In summary: If I am plotting a networkx graph with circle nodes, how can I convert the node size and/or the Pygraphviz positions to a common unit?
It could also be that my code is wrong, so here is a short reproducible example:
NODE_SIZE = 300
DPI = 100
mpl.rcParams['figure.dpi'] = DPI
G = nx.gnp_random_graph(50, 0)
pos = nx.nx_agraph.graphviz_layout(G)
tmp_pos = sorted(pos.items(), key=lambda x: x[1][0]) # Sort it by x value so you only have to check to the right of the node in the list of positions
node_size_inches = NODE_SIZE * 4 / (math.pi * DPI) # This is my attempt at getting the height/width of the nodes
i = 0
for key, xy in tmp_pos:
x = xy[0]
overlapping = []
# Since list is sorted by x, you only need to check nodes to the right
for k, xyt in tmp_pos[i+1:]:
xt = xyt[0]
# Check for overlapping nodes to the right
if x <= xt <= x + node_size_inches:
overlapping.append(k)
# Since list is sorted by x, if the previous condition fails, nothing after can be applicable
else:
break
if overlapping: print("{}:{}".format(key, overlapping))
i += 1
nx.draw(G, pos=pos, with_labels=True)