Matrix object has no attribute nodes networkX python - python

I'm trying to represent some numbers as edges of a graph with connected components. For this, I've been using python's networkX module.
My graph is G, and has nodes and edges initialised as follows:
G = nx.Graph()
for (x,y) in my_set:
G.add_edge(x,y)
print G.nodes() #This prints all the nodes
print G.edges() #Prints all the edges as tuples
adj_matrix = nx.to_numpy_matrix(G)
Once I add the following line,
pos = nx.spring_layout(adj_matrix)
I get the abovementioned error.
If it might be useful, all the nodes are numbered in 9-15 digits. There are 412 nodes and 422 edges.
Detailed error:
File "pyjson.py", line 89, in <module>
mainevent()
File "pyjson.py", line 60, in mainevent
pos = nx.spring_layout(adj_matrix)
File "/usr/local/lib/python2.7/dist-packages/networkx/drawing/layout.py", line 244, in fruchterman_reingold_layout
A=nx.to_numpy_matrix(G,weight=weight)
File "/usr/local/lib/python2.7/dist-packages/networkx/convert_matrix.py", line 128, in to_numpy_matrix
nodelist = G.nodes()
AttributeError: 'matrix' object has no attribute 'nodes'
Edit: Solved below. Useful information: pos creates a dict with coordinates for each node. Doing nx.draw(G,pos) creates a pylab figure. But it doesn't display it, because pylab doesn't display automatically.

(some of this answer addresses some things in your comments. Can you add those to your question so that later users get some more context)
pos creates a dict with coordinates for each node. Doing nx.draw(G,pos) creates a pylab figure. But it doesn't display it, because pylab doesn't display automatically.
import networkx as nx
import pylab as py
G = nx.Graph()
for (x,y) in my_set:
G.add_edge(x,y)
print G.nodes() #This prints all the nodes
print G.edges() #Prints all the edges as tuples
pos = nx.spring_layout(G)
nx.draw(G,pos)
py.show() # or py.savefig('graph.pdf') if you want to create a pdf,
# similarly for png or other file types
The final py.show() will display it. py.savefig('filename.extension') will save as any of a number of filetypes based on what you use for extension.

spring_layout takes a network graph as it's first param and not a numpy array. What it returns are the positions of the nodes according to the Fruchterman-Reingold force-directed algorithm.
So you need to pass this to draw example:
import networkx as nx
%matplotlib inline
G=nx.lollipop_graph(14, 3)
nx.draw(G,nx.spring_layout(G))
yields:

Related

Color each Community of Nodes using Louvain Algorithm and NetworkX / Save the result into a new txt

I'm using the Louvain Algorithm below for community detection using graphs that I insert manually.
I have 2 problems here. The first one is about the color of the nodes. The color of each community of nodes, as you see below, is a bit dark or white and it is not clear as which are the exact communities.
So, which is the way to draw each community of nodes into brighter colors?
And my last question, any ideas to save the results into a new .txt after the community detection is done?
partition = community.best_partition(G)
values = [partition.get(node) for node in G.nodes()]
#drawing
size = float(len(set(partition.values())))
posi = nx.spring_layout(G)
count = 0
for com in set(partition.values()):
count = count + 1.
list_nodes = [nodes for nodes in partition.keys()
if partition[nodes] == com]
nx.draw_networkx_nodes(G, posi, list_nodes, node_size = 25, node_color=str(count/size))
#nx.draw_spring(G, cmap = plt.get_cmap('hsv'), node_color = values, node_size=30, with_labels=False)
nx.draw_networkx_edges(G, posi, alpha=0.5)
plt.show()
You can use the cmap parameter of draw_networkx_nodes, which allows you to specify any matplotlib.colormap. See here or here1 for example.
Minimal working colouring example:
import networkx as nx
import matplotlib.pylab as pl
graph = nx.karate_club_graph()
colors = []
for node in graph:
if graph.nodes[node]["club"] == "Mr. Hi":
colors.append(0)
else:
colors.append(1)
colors[0] = -1
colors[-1] = 2
nx.draw_networkx(graph, node_color=colors, vmin=min(colors), vmax=max(colors), cmap=pl.get_cmap("viridis"))
pl.axis("off")
pl.show()
For the saving of your graph, you can either choose a suitable graph format, such as GML. Then you first need to add the partition as node attribute to your graph:
for node in partition:
G.nodes[node]["cluster"] = partition[node]
# save file
nx.write_gml(G, "path_to_save_file")
# load file
saved_graph = nx.read_gml("path_to_save_file")
and afterwards save the graph together with the partition. Alternatively, you can only save the retrieved partition as json or (unsafe) via pickle.

Add and delete a random edge in networkx

I'm using NetworkX in python. Given any undirected and unweighted graph, I want to loop through all the nodes. With each node, I want to add a random edge and/or delete an existing random edge for that node with probability p. Is there a simple way to do this? Thanks a lot!
Create a new random edge in networkx
Let's set up a test graph:
import networkx as nx
import random
import matplotlib.pyplot as plt
graph = nx.Graph()
graph.add_edges_from([(1,3), (3,5), (2,4)])
nx.draw(graph, with_labels=True)
plt.show()
Now we can pick a random edge from a list of non-edge from the graph. It is not totally clear yet what is the probability you mentioned. Since you add a comment stating that you want to use random.choice I'll stick to that.
def random_edge(graph, del_orig=True):
'''
Create a new random edge and delete one of its current edge if del_orig is True.
:param graph: networkx graph
:param del_orig: bool
:return: networkx graph
'''
edges = list(graph.edges)
nonedges = list(nx.non_edges(graph))
# random edge choice
chosen_edge = random.choice(edges)
chosen_nonedge = random.choice([x for x in nonedges if chosen_edge[0] == x[0]])
if del_orig:
# delete chosen edge
graph.remove_edge(chosen_edge[0], chosen_edge[1])
# add new edge
graph.add_edge(chosen_nonedge[0], chosen_nonedge[1])
return graph
Usage exemple:
new_graph = random_edge(graph, del_orig=True)
nx.draw(new_graph, with_labels=True)
plt.show()
We can still add a probability distribution over the edges in random.choiceif you need to (using numpy.random.choice() for instance).
Given a node i, To add edges without duplication you need to know (1) what edges from i already exist and then compute (2) the set of candidate edges that don't exist from i. For removals, you already defined a method in the comment - which is based simply on (1).
Here is a function that will provide one round of randomised addition and removal, based on list comprehensions
def add_and_remove_edges(G, p_new_connection, p_remove_connection):
'''
for each node,
add a new connection to random other node, with prob p_new_connection,
remove a connection, with prob p_remove_connection
operates on G in-place
'''
new_edges = []
rem_edges = []
for node in G.nodes():
# find the other nodes this one is connected to
connected = [to for (fr, to) in G.edges(node)]
# and find the remainder of nodes, which are candidates for new edges
unconnected = [n for n in G.nodes() if not n in connected]
# probabilistically add a random edge
if len(unconnected): # only try if new edge is possible
if random.random() < p_new_connection:
new = random.choice(unconnected)
G.add_edge(node, new)
print "\tnew edge:\t {} -- {}".format(node, new)
new_edges.append( (node, new) )
# book-keeping, in case both add and remove done in same cycle
unconnected.remove(new)
connected.append(new)
# probabilistically remove a random edge
if len(connected): # only try if an edge exists to remove
if random.random() < p_remove_connection:
remove = random.choice(connected)
G.remove_edge(node, remove)
print "\tedge removed:\t {} -- {}".format(node, remove)
rem_edges.append( (node, remove) )
# book-keeping, in case lists are important later?
connected.remove(remove)
unconnected.append(remove)
return rem_edges, new_edges
To see this function in action:
import networkx as nx
import random
import matplotlib.pyplot as plt
p_new_connection = 0.1
p_remove_connection = 0.1
G = nx.karate_club_graph() # sample graph (undirected, unweighted)
# show original
plt.figure(1); plt.clf()
fig, ax = plt.subplots(2,1, num=1, sharex=True, sharey=True)
pos = nx.spring_layout(G)
nx.draw_networkx(G, pos=pos, ax=ax[0])
# now apply one round of changes
rem_edges, new_edges = add_and_remove_edges(G, p_new_connection, p_remove_connection)
# and draw new version and highlight changes
nx.draw_networkx(G, pos=pos, ax=ax[1])
nx.draw_networkx_edges(G, pos=pos, ax=ax[1], edgelist=new_edges,
edge_color='b', width=4)
# note: to highlight edges that were removed, add them back in;
# This is obviously just for display!
G.add_edges_from(rem_edges)
nx.draw_networkx_edges(G, pos=pos, ax=ax[1], edgelist=rem_edges,
edge_color='r', style='dashed', width=4)
G.remove_edges_from(rem_edges)
plt.show()
And you should see something like this.
Note that you could also do something similar with the adjacency matrix,
A = nx.adjacency_matrix(G).todense() (it's a numpy matrix so operations like A[i,:].nonzero() would be relevant). This might be more efficient if you have extremely large networks.

Node size dependent on the node degree on NetworkX

I imported my Facebook data onto my computer in the form of a .json file. The data is in the format:
{"nodes":[{"name":"Alan"},{"name":"Bob"}],"links":[{"source":0,"target:1"}]}
Then, I use this function:
def parse_graph(filename):
"""
Returns networkx graph object of facebook
social network in json format
"""
G = nx.Graph()
json_data=open(filename)
data = json.load(json_data)
# The nodes represent the names of the respective people
# See networkx documentation for information on add_* functions
G.add_nodes_from([n['name'] for n in data['nodes']])
G.add_edges_from([(data['nodes'][e['source']]['name'],data['nodes'][e['target']]['name']) for e in data['links']])
json_data.close()
return G
to enable this .json file to be used a graph on NetworkX. If I find the degree of the nodes, the only method I know how to use is:
degree = nx.degree(p)
Where p is the graph of all my friends. Now, I want to plot the graph such that the size of the node is the same as the degree of that node. How do I do this?
Using:
nx.draw(G,node_size=degree)
didn't work and I can't think of another method.
Update for those using networkx 2.x
The API has changed from v1.x to v2.x. networkx.degree no longer returns a dict but a DegreeView Object as per the documentation.
There is a guide for migrating from 1.x to 2.x here.
In this case it basically boils down to using dict(g.degree) instead of d = nx.degree(g).
The updated code looks like this:
import networkx as nx
import matplotlib.pyplot as plt
g = nx.Graph()
g.add_edges_from([(1,2), (2,3), (2,4), (3,4)])
d = dict(g.degree)
nx.draw(g, nodelist=d.keys(), node_size=[v * 100 for v in d.values()])
plt.show()
nx.degree(p) returns a dict while the node_size keywod argument needs a scalar or an array of sizes. You can use the dict nx.degree returns like this:
import networkx as nx
import matplotlib.pyplot as plt
g = nx.Graph()
g.add_edges_from([(1,2), (2,3), (2,4), (3,4)])
d = nx.degree(g)
nx.draw(g, nodelist=d.keys(), node_size=[v * 100 for v in d.values()])
plt.show()
#miles82 provided a great answer. However, if you've already added the nodes to your graph using something like G.add_nodes_from(nodes), then I found that d = nx.degree(G) may not return the degrees in the same order as your nodes.
Building off the previous answer, you can modify the solution slightly to ensure the degrees are in the correct order:
d = nx.degree(G)
d = [(d[node]+1) * 20 for node in G.nodes()]
Note the d[node]+1, which will be sure that nodes of degree zero are added to the chart.
other method if you still get 'DiDegreeView' object has no attribute 'keys'
1)you can first get the degree of each node as a list of tuples
2)build a node list from the first value of tuple and degree list from the second value of tuple.
3)finally draw the network with the node list you've created and degree list you've created
here's the code:
list_degree=list(G.degree()) #this will return a list of tuples each tuple is(node,deg)
nodes , degree = map(list, zip(*list_degree)) #build a node list and corresponding degree list
plt.figure(figsize=(20,10))
nx.draw(G, nodelist=nodes, node_size=[(v * 5)+1 for v in degree])
plt.show() #ploting the graph

Draw more information on graph\nodes using PyGraphviz

I want to create a graph and draw it, so far so good, but the problem is that i want to draw more information on each node.
I saw i can save attributes to nodes\edges, but how do i draw the attributes?
i'm using PyGraphviz witch uses Graphviz.
An example would be
import pygraphviz as pgv
from pygraphviz import *
G=pgv.AGraph()
ndlist = [1,2,3]
for node in ndlist:
label = "Label #" + str(node)
G.add_node(node, label=label)
G.layout()
G.draw('example.png', format='png')
but make sure you explicitly add the attribute label for extra information to show as Martin mentioned https://stackoverflow.com/a/15456323/1601580.
You can only add supported attributes to nodes and edges. These attributes have specific meaning to GrpahViz.
To show extra information on edges or nodes, use the label attribute.
If you already have a graph with some attribute you want to label you can use this:
def draw_nx_with_pygraphviz_attribtes_as_labels(g, attribute_name, path2file=None):
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
# https://stackoverflow.com/questions/15345192/draw-more-information-on-graph-nodes-using-pygraphviz
if path2file is None:
path2file = './example.png'
path2file = Path(path2file).expanduser()
g = nx.nx_agraph.to_agraph(g)
# to label in pygrapviz make sure to have the AGraph obj have the label attribute set on the nodes
g = str(g)
g = g.replace(attribute_name, 'label') # it only
print(g)
g = pgv.AGraph(g)
g.layout()
g.draw(path2file)
# https://stackoverflow.com/questions/20597088/display-a-png-image-from-python-on-mint-15-linux
img = mpimg.imread(path2file)
plt.imshow(img)
plt.show()
# remove file https://stackoverflow.com/questions/6996603/how-to-delete-a-file-or-folder
path2file.unlink()
# -- tests
def test_draw():
# import pylab
import networkx as nx
g = nx.Graph()
g.add_node('Golf', size='small')
g.add_node('Hummer', size='huge')
g.add_node('Soccer', size='huge')
g.add_edge('Golf', 'Hummer')
draw_nx_with_pygraphviz_attribtes_as_labels(g, attribute_name='size')
if __name__ == '__main__':
test_draw()
result:
in particular note that the two huge's did not become a self loop and they are TWO different nodes (e.g. two sports can be huge but they are not the same sport/entity).
related but plotting with nx: Plotting networkx graph with node labels defaulting to node name

Have to point two dimensional graph(x,y) co ordinates networkx python

I am getting information from a spatial database the values are like line string(spatial) format and i need to add this info to networkx graph later need to draw a graph in a matplot lib
I have written this code
cursor.execute("SELECT AsText(roadstring) FROM road1")
for row in cursor.fetchall():
a=row[0][12:-2]
a=str(a)
a=a.split(",")
for i in a:
i=i.split(" ")
i[0]=float(i[0])
i[1]=float(i[1])
weig=abs(i[0]-i[1])
G.add_node((i[0],i[1]))
I unable to get how to add two dimensional edges for roads (x1,y1) to (x2,y2) even i need to add weight to these edges for distance between them
Any suggestions??
The line string of every road are like these 643715.202,2499149.0506 643752.61523545,2499089.86084203 643773.6038,2499056.6558 643773.73878609,2499056.44011079 643793.20162482,2499025.34111554 643813.55943268,2498992.81212045 643826.6563,2498971.8852
I am getting this error I have matplotlib installed I tried by copying your code
Traceback (most recent call last): File "D:\python\gis\new.py", line
2, in
from matplotlib import pyplot as plt File "C:\Python27\lib\site-packages\matplotlib__init__.py", line 133, in
from matplotlib.rcsetup import (defaultParams, File "C:\Python27\lib\site-packages\matplotlib\rcsetup.py", line 19, in
from matplotlib.colors import is_color_like File "C:\Python27\lib\site-packages\matplotlib\colors.py", line 54, in
import matplotlib.cbook as cbook File "C:\Python27\lib\site-packages\matplotlib\cbook.py", line 15, in
import new File "D:\python\gis\new.py", line 2, in
from matplotlib import pyplot as plt File "C:\Python27\lib\site-packages\matplotlib\pyplot.py", line 20, in
from matplotlib import _pylab_helpers, interactive ImportError: cannot import name interactive
I'm not completely sure what you want to accomplish, but here's how I interpret
it.
You have roads defined as coordinates along the road and you want to draw these
coordinates as nodes and the road between them as edges. You also want the edge
weight to be the distance between the two nodes.
This can quite easily be accomplished by saving the previous node and using the Pythagorean theorem to calculate the distance. This is
how I did it:
import networkx as nx
from matplotlib import pyplot as plt
import math
G = nx.Graph()
row = '643715.202,2499149.0506 643752.61523545,2499089.86084203 ' +\
'643773.6038,2499056.6558 643773.73878609,2499056.44011079 ' +\
'643793.20162482,2499025.34111554 643813.55943268,2498992.81212045 ' +\
'643826.6563,2498971.8852'
a=row.split(" ")
# Saving the previous node to be able to calculate the distance
prev_point = None
# Save the positions in a dictionary to be able to draw
# the nodes at the correct positions
pos = {}
for i in a:
cur_point = tuple([float(x) for x in i.split(',')])
assert len(cur_point) == 2
if prev_point is not None:
# Calculate the distance between the nodes with the Pythagorean
# theorem
b = cur_point[1] - prev_point[1]
c = cur_point[0] - prev_point[0]
a = math.sqrt(b ** 2 + c ** 2)
G.add_edge(cur_point, prev_point, weight=a)
G.add_node(cur_point)
pos[cur_point] = cur_point
prev_point = cur_point
nx.draw(G, pos=pos)
plt.savefig('roads.png')
In this example I assume that a space separates the node positions and each
position's x and y coordinate is comma separated, but this can easily be changed. The above code will output something like this:
This will put the nodes at their "correct" positions, although it can cause some issues if there are big differences in road length. In the above example you can see that two nodes are more or less on top of each other. But that's a different question.

Categories

Resources