Python: how to visualize the Minimum Spanning Tree of a network? - python

I have a regular grid network made of NxN nodes. I am able to plot it, but I would also like to plot its minimum spanning tree, which is a "subgraph that contains all the vertices and is a tree".
This is how I create the network:
from __future__ import print_function, division
import numpy
from numpy import *
import networkx as nx
from networkx import *
import matplotlib.pyplot as plt
N=30
G=nx.grid_2d_graph(N,N)
pos = dict( (n, n) for n in G.nodes() )
labels = dict( ((i, j), i + (N-1-j) * N ) for i, j in G.nodes() )
nx.relabel_nodes(G,labels,False)
inds=labels.keys()
vals=labels.values()
inds.sort()
vals.sort()
pos2=dict(zip(vals,inds))
nx.draw_networkx(G, pos=pos2, with_labels=False, node_size = 15)
This is how I compute the Minimum Spanning Tree:
T=nx.minimum_spanning_tree(G)
This generates a graph just like G, with the difference that T has the same nodes as G and a selection of its edges. Therefore, I would like to plot T, and this is what I did:
plt.figure()
nx.draw_networkx(G, pos=pos2, with_labels=False, node_size = 15)
plt.show()
But I simply get the network plotted again. How can I amend the last lines to make sure my Minimum Spanning Tree is plotted?

plt.figure()
nx.draw_networkx(G, pos=pos2, with_labels=False, node_size = 15)
plt.show()
should be
plt.figure()
nx.draw_networkx(T, pos=pos2, with_labels=False, node_size = 15)
plt.show()

Related

Troubles with visualization of big graph in NetworkX

I have a undirected graph with 47 nodes and 90 weighted edges. I want to get the image of this graph, but I get something weird[1]: nodes are on top of each other. I want to fix it but I don't know how. Here is the code for drawing:
import networkx as nx
import matplotlib.pyplot as plt
import pylab
def show_graph(G):
pos = nx.spring_layout(G)
nx.draw(G, pos, node_color='#A0CBE2', edge_color='#BB0000', width=2, edge_cmap=plt.cm.Blues, with_labels=True)
plt.savefig("graph.png", dpi=1000)
# 2 way
# nx.draw(G, with_labels=True)
# plt.draw()
# plt.show()
f = open("europe.txt")
G = nx.Graph()
lines = f.readlines()
edges = list()
for line in lines:
tmp = line.split(', ')
tmp[2] = int(tmp[2])
edges.append(tmp)
G.add_weighted_edges_from(edges)
show_graph(G)
Image [1]: https://i.stack.imgur.com/B5Slx.png
The solution for me was:
import networkx as nx
import matplotlib.pyplot as plt
and the function
def show_graph(G):
plt.subplot(111)
nx.draw(G, pos=nx.planar_layout(G), node_color='r', edge_color='b', with_labels=True)
plt.show()
A planar layout made sense for my situation

Legend based on edge color in networkx

Is there a way to create a legend in networkx based on edge color (as opposed to by node color)?
This is my graph:
plt.figure(figsize = (15, 10))
G = nx.from_pandas_dataframe(df, 'From', 'To', ['Order', 'Colors'])
edge_labels = nx.get_edge_attributes(G, 'Order')
nx.draw_networkx(G, with_labels = False, node_color = 'black', alpha = 0.5, node_size = 3, linewidths = 1, edge_color = df['Colors'], edge_cmap =
plt.cm.Set2)
plt.show()
In this, ['Order'] is a descriptor of the edge and ['Color'] is a unique integer mapped to each value in ['Order'], which is working to create the edge colors based on the Set2 colormap.
I can get the edge labels with something like:
edge_labels = nx.get_edge_attributes(G, 'Order')
but how do I put this into a legend?
I'm happy to share the data and complete code if helpful!
One way you can do it is in the spirit of this SO answer which uses proxies for each member of a LineCollection in the legend.
You can get the LineCollection by using the step-by-step graph drawing functions, drawing the nodes and edges separately (e.g. draw_networkx_nodes doc.)
import matplotlib.pyplot as plt
import networkx as nx
from matplotlib.lines import Line2D
# make a test graph
n = 7 # nodes
m = 5 # edges
G = nx.gnm_random_graph(n, m)
# and define some color strings (you'll get this array from the dataframe)
_c = 'rgbcmky' * m # way too many colors, trim after
clrs = [c for c in _c[:m]]
plt.ion()
plt.figure(figsize = (9, 7), num=1); plt.clf()
# draw the graph in several steps
pos = nx.spring_layout(G)
h1 = nx.draw_networkx_nodes(G, pos=pos, node_color = 'black',
alpha = 0.9, node_size = 300, linewidths=6)
# we need the LineCollection of the edges to produce the legend (h2)
h2 = nx.draw_networkx_edges(G, pos=pos, width=6, edge_color=clrs)
# and just show the node labels to check the labels are right!
h3 = nx.draw_networkx_labels(G, pos=pos, font_size=20, font_color='c')
#https://stackoverflow.com/questions/19877666/add-legends-to-linecollection-plot - uses plotted data to define the color but here we already have colors defined, so just need a Line2D object.
def make_proxy(clr, mappable, **kwargs):
return Line2D([0, 1], [0, 1], color=clr, **kwargs)
# generate proxies with the above function
proxies = [make_proxy(clr, h2, lw=5) for clr in clrs]
# and some text for the legend -- you should use something from df.
labels = ["{}->{}".format(fr, to) for (fr, to) in G.edges()]
plt.legend(proxies, labels)
plt.show()
This produces something like:

How to change colours of nodes and edges of bipartite graph in networkX?

I use this piece of code to draw a bipartite graph using networkX:
import networkx as nx
G = bipartite.from_biadjacency_matrix(a_matrix, create_using=None, edge_attribute='weight')
X, Y = bipartite.sets(G)
pos = dict()
pos.update((n, (0, i*10)) for i, n in enumerate(X))
pos.update((n, (0.5, i*10)) for i, n in enumerate(Y))
nx.draw(G, pos=pos)
Is there a way to randomly change colours of different sets of nodes and edges between them?
Generate some random numbers:
edge_color=np.random.random(num_edges)
node_color=np.random.random(num_nodes)
and set the edge color map:
edge_cmap=plt.get_cmap('Blues')
and node color map:
cmap=plt.get_cmap('Reds')
import numpy as np
import networkx as nx
import matplotlib.pyplot as plt
from networkx.algorithms import bipartite
import scipy.sparse as sparse
a_matrix = sparse.rand(10, 10, format='coo', density=0.8)
G = bipartite.from_biadjacency_matrix(a_matrix, create_using=None,
edge_attribute='weight')
X, Y = bipartite.sets(G)
pos = dict()
pos.update((n, (0, i*10)) for i, n in enumerate(X))
pos.update((n, (0.5, i*10)) for i, n in enumerate(Y))
num_edges = G.number_of_edges()
num_nodes = G.number_of_nodes()
nx.draw(G, pos=pos, with_labels=True,
edge_color=np.random.random(num_edges),
edge_cmap=plt.get_cmap('Blues'),
node_color=np.random.random(num_nodes),
cmap=plt.get_cmap('Reds'))
plt.show()
You could use subgraphs to color connected nodes:
C = nx.connected_component_subgraphs(G)
for g in C:
node_colors = [random.random()] * nx.number_of_nodes(g)
nx.draw(g, pos, node_size=40, node_color=node_colors, vmin=0.0, vmax=1.0, with_labels=False )

I can't see labels in NetworkX diagram

This is my code in Python 2.7.9:
import matplotlib.pyplot as plt
import networkx as nx
socialNetworl = nx.Graph()
socialNetworl.add_nodes_from([1,2,3,4,5,6])
socialNetworl.add_edges_from([(1,2),(1,3),(2,3),(2,5),(2,6)])
nx.draw(socialNetworl, node_size = 800, node_color="cyan")
plt.show()
But I can't see the node labels. Is there a line of code I forgot?
Just add with_labels=True to your code.
import matplotlib.pyplot as plt
import networkx as nx
socialNetworl = nx.Graph()
socialNetworl.add_nodes_from([1,2,3,4,5,6])
socialNetworl.add_edges_from([(1,2),(1,3),(2,3),(2,5),(2,6)])
nx.draw(socialNetworl, node_size = 800, node_color="cyan", with_labels = True)
plt.show()
If you want to change the labels, create a dict with the labels and pass labels=theLabelDict into nx.draw:
import matplotlib.pyplot as plt
import networkx as nx
socialNetworl = nx.Graph()
socialNetworl.add_nodes_from([1,2,3,4,5,6])
socialNetworl.add_edges_from([(1,2),(1,3),(2,3),(2,5),(2,6)])
labels = {1:'King Arthur', 2:'Lancelot', 3:'shopkeeper', 4:'dead parrot', 5:'Brian', 6:'Sir Robin'}
nx.draw(socialNetworl, node_size = 800, node_color="cyan", labels=labels, with_labels = True)
plt.show()
You can draw the node labels separately with nx.draw_networkx_labels (and control lots of other label options too). For example, after adding the nodes and edges, you could write:
pos=nx.spring_layout(socialNetworl)
nx.draw(socialNetworl, pos=pos, node_size = 800, node_color="cyan")
nx.draw_networkx_labels(socialNetworl, pos=pos);
plt.show()
Which draws:

Colorbar for edges in networkx

I am trying to get a colorbar for edges in a networkx graph. Here is a code snippet
import networkx as nx
import matplotlib.colors as colors
import matplotlib.cm as cmx
n = 12 # Number of clusters
w = 21 # Number of weeks
m = Basemap(
projection='merc',
ellps = 'WGS84',
llcrnrlon=-98.5,
llcrnrlat=25,
urcrnrlon=-60,
urcrnrlat=50,
lat_ts=0,
resolution='i',
suppress_ticks=True)
mx, my = m(list(ccentroids['lon']), list(ccentroids['lat']))
# The NetworkX part
# put map projection coordinates in pos dictionary
G = nx.DiGraph()
G.add_nodes_from(range(n))
for i in range(n):
for j in range(n):
if P_opt[i,j] > 0.5 and i != j:
G.add_edge(i,j, weight = P_opt[i,j])
pos = {i : (mx[i], my[i]) for i in range(n)}
# Add a color_map for the edges
jet = cm = plt.get_cmap('jet')
cNorm = colors.Normalize(vmin=0, vmax=np.max(P_opt))
scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=jet)
colorList = []
weights_list = []
for i in G.edges():
a, b = i
colorVal = scalarMap.to_rgba(G.edge[a][b]['weight'])
colorList.append(colorVal)
weights_list.append(G.edge[a][b]['weight'])
plt.clf()
fig = plt.figure()
ax = fig.add_subplot(111, axisbg='w', frame_on=False)
fig.set_size_inches(18.5, 10.5)
# draw the network
nodes = nx.draw_networkx_nodes(G, pos, node_size=100, node_color=q[:,t], cmap = plt.cm.jet,
font_size=8, with_labels=False, label='Cluster centroids')
edges = nx.draw_networkx_edges(G, pos, edge_color=colorList)
m.drawcountries()
m.bluemarble()
This gives me the following image:
Now I want to add a colorbar for the edges. I tried doing something like,
plt.sci(edges)
edges.set_array(np.array(weights_list))
plt.colorbar(shrink = 0.8)
This gives me an image like:
The colours of the arrows and edges seem to differ. How can I correct that? Thanks.
EDIT: I tried to use the following code by modifying the edge line:
edges = nx.draw_networkx_edges(G, pos, edge_color=colorList, edge_cmap = plt.cm.jet)
plt.colorbar(edges)
This gives me an error TypeError: You must first set_array for mappable
Changing the edge_color to be the weights_list I get the following picture:
It seems you are getting the colomap/colorbar for the nodes. Here is how to set a colormap and draw a colorbar for edge colors:
![import networkx as nx
import matplotlib.pyplot as plt
G = nx.star_graph(20)
pos = nx.spring_layout(G)
colors = range(20)
nodes = nx.draw_networkx_nodes(G,pos,node_color='k', with_labels=False)
edges = nx.draw_networkx_edges(G,pos,edge_color=colors,width=4,
edge_cmap=plt.cm.Blues)
plt.colorbar(edges)
plt.axis('off')
I know this is an old one, but I spent some time figuring this out, and maybe it is still useful for someone.
nx.draw_networkx_edges
returns
matplotlib.collection.LineCollection
if there are no arrows.
returns
list of matplotlib.patches.FancyArrowPatch
if there are arrows.
docs
For my specific case I could get a colorbar like in Aric's answer only if I set arrows to False:
edges = nx.draw_networkx_edges(G, edge_color=colors, arrows=False)
plt.colorbar(edges)

Categories