23

I have a graph of nodes with specific attributes and I want to draw the graph by networkx in Python with several attributes as labels of nodes outside the node.

Can someone help me how can I write my code to achieve this aim?

There is a loop in my code which generate "interface_?" attribute for each input from firewall list (fwList)

for y in fwList:
    g.add_node(n, type='Firewall')
    print 'Firewall ' + str(n) + ' :' 
    for x in fwList[n]:
        g.node[n]['interface_'+str(i)] = x
        print 'Interface '+str(i)+' = '+g.node[n]['interface_'+str(i)]
        i+=1
    i=1
    n+=1

Then, later on I draw nodes and edges like:

pos=nx.spring_layout(g)
nx.draw_networkx_edges(g, pos)
nx.draw_networkx_nodes(g,pos,nodelist=[1,2,3],node_shape='d',node_color='red')

and will extended it to some new nodes with other shape and color later.

For labeling a single attribute I tried below code, but it didn't work

labels=dict((n,d['interface_1']) for n,d in g.nodes(data=True))

And for putting the text out of the node I have no idea...

0

4 Answers 4

15

In addition to Aric's answer, the pos dictionary contains x, y coordinates in the values. So you can manipulate it, an example might be:

pos_higher = {}
y_off = 1  # offset on the y axis

for k, v in pos.items():
    pos_higher[k] = (v[0], v[1]+y_off)

Then draw the labels with the new position:

nx.draw_networkx_labels(G, pos_higher, labels)

where G is your graph object and labels a list of strings.

Sign up to request clarification or add additional context in comments.

1 Comment

If I have two graphs, how to change node labels only for one? What should be pos?
14

You have access to the node positions in the 'pos' dictionary. So you can use matplotlib to put text wherever you like. e.g.

In [1]: import networkx as nx

In [2]: G=nx.path_graph(3)

In [3]: pos=nx.spring_layout(G)

In [4]: nx.draw(G,pos)

In [5]: x,y=pos[1]

In [6]: import matplotlib.pyplot as plt

In [7]: plt.text(x,y+0.1,s='some text', bbox=dict(facecolor='red', alpha=0.5),horizontalalignment='center')
Out[7]: <matplotlib.text.Text at 0x4f1e490>

enter image description here

Comments

6

I like to create a nudge function that shifts the layout by an offset.

import networkx as nx
import matplotlib.pyplot as plt

def nudge(pos, x_shift, y_shift):
    return {n:(x + x_shift, y + y_shift) for n,(x,y) in pos.items()}

G = nx.Graph()
G.add_edge('a','b')
G.add_edge('b','c')
G.add_edge('a','c')

pos = nx.spring_layout(G)
pos_nodes = nudge(pos, 0, 0.1)                              # shift the layout

fig, ax = plt.subplots(1,2,figsize=(12,6))
nx.draw_networkx(G, pos=pos, ax=ax[0])                      # default labeling
nx.draw_networkx(G, pos=pos, with_labels=False, ax=ax[1])   # default nodes and edges
nx.draw_networkx_labels(G, pos=pos_nodes, ax=ax[1])         # nudged labels
ax[1].set_ylim(tuple(i*1.1 for i in ax[1].get_ylim()))      # expand plot to fit labels
plt.show()

Two graph representations, side by side, of three nodes in a triangle. The one on the left has labels placed directly on the nodes per the networkx defaults, and the one on the right has labels shifted slightly up

Comments

4

NetworkX's documentation on draw_networkx_labels also shows that you can use the horizontalalignment and verticalalignment parameters to get an easy, out-of-the-box solution without manually nudging the labels.

From the docs:

  • horizontalalignment ({‘center’, ‘right’, ‘left’}) – Horizontal alignment (default=’center’)

  • verticalalignment ({‘center’, ‘top’, ‘bottom’, ‘baseline’, ‘center_baseline’}) – Vertical alignment (default=’center’)

Even more conveniently, you can use this with higher-level NetworkX functions, like nx.draw() or one of the nx.draw_spectral (or its variants) because these higher function arguments accept keyword arguments which is in turn passed into its lower-level functions.

So the following code is a minimally-viable code that does what you asked for, which is to push / nudge the labels outside of the node:

G = nx.DiGraph(name='Email Social Network')
nx.draw(G, arrowsize=3, verticalalignment='bottom')
# or:
nx.draw(G, arrowsize=3, verticalalignment='top')
plt.show()

The result of that verticalalignment is visualized below: enter image description here

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.