1

I'm trying to use networkx to draw circles at particular positions. Each of the circle I want to draw has a set of coordinates, and a radius.

I can set the coordinates easily:

import networkx as nx
import matplotlib.pyplot as plt

positions = [(0, 0), (36.439507534009273, 0.0),
             (36.439507534009273, -36.439507534009273),
             (36.439507534009273, -72.879015068018546),
             (0.0, -72.879015068018546),
             (2.231276313201516e-15, -109.31852260202781),
             (4.4625526264030319e-15, -145.75803013603709),
             (36.43950753400928, -145.75803013603709),
             (36.43950753400928, -182.19753767004639)]

G = nx.Graph()

pos = dict()

for i, couple in enumerate(positions):
    G.add_node(i)
    print(couple)
    pos[i] = couple


print(G.number_of_nodes())

fig = plt.figure(1)

nodes = nx.draw_networkx_nodes(G, pos)

nx.draw_networkx_edges(G, pos)

plt.axis('equal')
plt.savefig('drawing.png', bbox_inches='tight', dpi=400)
plt.clf()

But I can't set the radius properly. The positions in my example are in millimetres, and the radii of my circles will be as well.

enter image description here

I can set the "size of the nodes" with node_size, but I don't think I can correlate node_size to my radii. For example, the default for node_size is 300, and I don't know what it corresponds to.

If I have a circle at position let's say (20, 20), and the radius is 20, I should have a circle ranging from 0 to 40 (in x).

How can I achieve that with networkx ?

JPFrancoia
  • 4,866
  • 10
  • 43
  • 73
  • 1
    the sizes are approx areas -- see https://stackoverflow.com/q/14827650. (The networkx draw functions use matplotlib) – Bonlenfum Mar 12 '18 at 13:26
  • Ok thanks, that should do. Defining the node size like that makes it unusable for my use case I guess :/ – JPFrancoia Mar 12 '18 at 13:56
  • yes, I see. I thought about it, and although you could define a marker to have an appropriate size in points, you will likely run into trouble because the rendering is zoom-dependent, i.e., the marker size stays the same even if the axes are 100x further out. I made a suggestion using axes patch artists - but not totally sure it is appropriate for you – Bonlenfum Mar 12 '18 at 15:02

1 Answers1

0

One way you could approach this, depending on the number of nodes you're expecting to draw, would be to use matplotlib patches for each node.

Borrowing from https://stackoverflow.com/a/21267406,

import networkx as nx
import matplotlib.pyplot as plt
from matplotlib.patches import Circle

# define graph as you did already 
positions = [(0, 0), (36.439507534009273, 0.0),
             (36.439507534009273, -36.439507534009273),
             (36.439507534009273, -72.879015068018546),
             (0.0, -72.879015068018546),
             (2.231276313201516e-15, -109.31852260202781),
             (4.4625526264030319e-15, -145.75803013603709),
             (36.43950753400928, -145.75803013603709),
             (36.43950753400928, -182.19753767004639)]

G = nx.Graph()
pos = dict()
for i, couple in enumerate(positions):
        G.add_node(i)
        print(couple)
        pos[i] = couple


# now make up radius for each node -- default will be 10...
for node in G.nodes():
    G.node[node]['rad'] = 10

# ...but show a bit of variety too
G.node[2]['rad'] = 20
G.node[4]['rad'] = 40
G.node[8]['rad'] = 80

# vector of node radii
rad = [rad for (n, rad) in nx.get_node_attributes(G, 'rad').items()]

# draw nodes manually, with MPL patches.
fig, ax = plt.subplots(1, 1)

for node in G.nodes():
    ax.add_artist(Circle(xy=pos[node], radius=G.node[node]['rad'], 
    facecolor='orange', alpha=0.2, edgecolor='black'))

ax.set_aspect('equal') # important if you want to see *circles*
plt.axis([-150, 200, -300, 25]) # set zoom to view whole image. (patches don't seem to invoke the auto-range setting, unlike scatter does.)

# let's verify they have correct extent
ax.axhline(-10, c='k', ls=':')
ax.axhline(+10, c='k', ls=':')

Circle patches to show dimension of graph

Bonlenfum
  • 19,101
  • 2
  • 53
  • 56
  • Yes I could do that, or calculate the node size based on the approximate area and the radius I want. But for what I want to do (mouse hovering, etc), I'm simply going to use matplotlib. A shame, because connecting nodes is easy with networkx. – JPFrancoia Mar 12 '18 at 15:16
  • don't overlook the fact that nx.draw_networkx_* functions (e.g. `draw_networkx_edges`) just manipulate matplotlib axes, so this solution is compatible with rendering edges, node labels, etc by nx. BUT for UI like mouse hovering, maybe it is worth looking at d3? (an interesting-looking library here: http://mpld3.github.io/, I've not invested enough to use in earnest yet) – Bonlenfum Mar 12 '18 at 16:15