Plot node size as legend using Networkx

Question:

While working with NetworkX, I managed to plot a graph that shows the node size corresponding to a node attribute. To produce a consistent plot, I want to show the node size in the legend.
Is there a pre-implemented way to add a legend with a defined number (e.g., four) of node sizes with the corresponding node attribute?

I imagine something similar to the appended legend.

https://i.stack.imgur.com/Mvffv.png

Asked By: brisuu

||

Answers:

I am unsure of a built-in way to do this, but networkx plotting algorithm uses scatter to set node size so you can create a set of ghost nodes using scatter that are used in the legend. (I am making up the term ghost because you don’t actually see them. There may be an officially accepted term, I don’t know.)

For some reason I am could not get these to work with scatter so I am using plot instead. (Note that the size of values in scatter follows area while plot follows width as discussed here so the the size of the ghost values used in plot are the square-root of the sizes generated by networkx.draw_networkx.

from math import sqrt
import networkx as nx
import matplotlib.pyplot as plt

# Create graph
G = nx.Graph()
N = 10 # number of nodes
for n in range(1,N + 1):
    G.add_node(n, size = n * 100, pos = [0, n]) # size of node based on its number

# Draw graph
node_sizes = nx.get_node_attributes(G, 'size')
nx.draw_networkx(G, node_color = 'b', node_size = [v for v in node_sizes.values()])

# Make legend
for n in [2, 4, 6, 8]:
    plt.plot([], [], 'bo', markersize = sqrt(n*100), label = f"{n}")
plt.legend(labelspacing = 5, loc='center left', bbox_to_anchor=(1, 0.5), frameon = False)

graph

Answered By: ramzeek

I have a bit of a hacky, alternative way of doing this, using scatter legend_items, basically making a scatter plot with your node sizes, copying the legend, then removing the scatter plot again. Probably neater way to to do this but it works.

import matplotlib.pyplot as plt
import networkx as nx
from scipy.stats import expon

# some random graph
G = nx.erdos_renyi_graph(10, 0.5)

# some attribute that will influence node size
attribute = [70*i for i in range(10)]

# helper method for getting legend
def get_legend(sizes, num=10):
    fig, ax = plt.subplots()
    sc = ax.scatter([0]*len(sizes), [0]*len(sizes), s=sizes, color='blue')
    store = sc.legend_elements("sizes", num=num)
    fig.clf()
    return store

fig, ax = plt.subplots()
nx.draw_networkx(G, node_size=attribute, ax=ax)
ax.legend(*get_legend(attribute, num=10), title="Variable A")

enter image description here

Answered By: Lourens
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.