How to get degrees with certain edge labels using python - python

I would like to find the node degree with edges of certain labels, when I use the the degree() method of networkx it gives me a dic with {:} but how to get the labels of those edges?. Any help including the info on what other graph analysis packages has this provision, is appreciated.

In igraph, you want g.es.select(_source=i). This gets all of the edges whose source vertex is i, at which point you can ask for the attributes of those edges:
>>> g = igraph.Graph.Full(3) #complete graph on three vertices
>>> g.es['label'] = ['a','b','c'] #sets the first edge to have 'label' value 'a', etc.
>>> g.es.select(_source=0)['label']
['a', 'b']

Nodes' degree by certain edges labels
Random graph functions
def rand_gen(m):
yield random.randint(0,m)
def get_edges(n):
tpl = []
for _ in range(n):
for x,y in zip(rand_gen(n), rand_gen(n)):
tpl.append((x,y, {random.choice(['a','b','c']): random.randint(0,10)}))
return tpl
Create graph
g = nx.Graph()
e = get_edges(10)
g.add_edges_from(e)
pos = nx.spring_layout(g)
nx.draw_networkx_nodes(g,pos)
nx.draw_networkx_labels(g,pos, font_color='w')
nx.draw_networkx_edges(g,pos)
nx.draw_networkx_edge_labels(g,pos, edge_labels={(x,y):l.keys()[0] for x,y,l in g.edges(data=True)})
plt.axis('off')
plt.show()
Select by label
nds = []
nds.extend([n1, n2] for n1,n2,l in g.edges(data=True) if l.keys()[0] == 'a')
nds = [x for y in nds for x in y]
Get the degree of unique labels
[nx.degree(g,x) for x in set(nds)]
[out]
[2, 3, 2, 2, 5]

Related

How to visualize communities from a list in igraph python

I have a community list as the following list_community.
How do I edit the code below to make the community visible?
from igraph import *
list_community = [['A', 'B', 'C', 'D'],['E','F','G'],['G', 'H','I','J']]
list_nodes = ['A', 'B', 'C', 'D','E','F','G','H','I','J']
tuple_edges = [('A','B'),('A','C'),('A','D'),('B','C'),('B','D'), ('C','D'),('C','E'),
('E','F'),('E','G'),('F','G'),('G','H'),
('G','I'), ('G','J'),('H','I'),('H','J'),('I','J'),]
# Make a graph
g_test = Graph()
g_test.add_vertices(list_nodes)
g_test.add_edges(tuple_edges)
# Plot
layout = g_test.layout("kk")
g.vs["name"] = list_nodes
visual_style = {}
visual_style["vertex_label"] = g.vs["name"]
visual_style["layout"] = layout
ig.plot(g_test, **visual_style)
I would like a plot that visualizes the community as shown below.
I can also do this by using a module other than igraph.
Thank you.
In igraph you can use the VertexCover to draw polygons around clusters (as also suggested by Szabolcs in his comment). You have to supply the option mark_groups when plotting the cover, possibly with some additional palette if you want. See some more detail in the documentation here.
In order to construct the VertexCover, you first have to make sure you get integer indices for each node in the graph you created. You can do that using g_test.vs.find.
clusters = [[g_test.vs.find(name=v).index for v in cl] for cl in list_community]
cover = ig.VertexCover(g_test, clusters)
After that, you can simply draw the cover like
ig.plot(cover,
mark_groups=True,
palette=ig.RainbowPalette(3))
resulting in the following picture
Here is a script that somewhat achieves what you're looking for. I had to handle the cases of single-, and two-nodes communities separately, but for greater than two nodes this draws a polygon within the nodes.
I had some trouble with matplotlib not accounting for overlapping edges and faces of polygons which meant the choice was between (1) not having the polygon surround the nodes or (2) having an extra outline just inside the edge of the polygon due to matplotlib overlapping the widened edge with the fill of the polygon. I left a comment on how to change the code from option (2) to option (1).
I also blatantly borrowed a convenience function from this post to handle correctly sorting the nodes in the polygon for appropriate filling by matplotlib's plt.fill().
Option 1:
Option 2:
Full code:
import networkx as nx
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
def sort_xy(x, y):
x0 = np.mean(x)
y0 = np.mean(y)
r = np.sqrt((x-x0)**2 + (y-y0)**2)
angles = np.where((y-y0) > 0, np.arccos((x-x0)/r), 2*np.pi-np.arccos((x-x0)/r))
mask = np.argsort(angles)
x_sorted = x[mask]
y_sorted = y[mask]
return x_sorted, y_sorted
G = nx.karate_club_graph()
pos = nx.spring_layout(G, seed=42)
fig, ax = plt.subplots(figsize=(8, 10))
nx.draw(G, pos=pos, with_labels=True)
communities = nx.community.louvain_communities(G)
alpha = 0.5
edge_padding = 10
colors = cm.get_cmap('viridis', len(communities))
for i, comm in enumerate(communities):
if len(comm) == 1:
cir = plt.Circle((pos[comm.pop()]), edge_padding / 100, alpha=alpha, color=colors(i))
ax.add_patch(cir)
elif len(comm) == 2:
comm_pos = {k: pos[k] for k in comm}
coords = [a for a in zip(*comm_pos.values())]
x, y = coords[0], coords[1]
plt.plot(x, y, linewidth=edge_padding, linestyle="-", alpha=alpha, color=colors(i))
else:
comm_pos = {k: pos[k] for k in comm}
coords = [a for a in zip(*comm_pos.values())]
x, y = sort_xy(np.array(coords[0]), np.array(coords[1]))
plt.fill(x, y, alpha=alpha, facecolor=colors(i),
edgecolor=colors(i), # set to None to remove edge padding
linewidth=edge_padding)

Update network graph plotting in same figure and change node color according to node degree

I'm trying to update graph plotting, every 5-7 second. so I tried matplotlib to refresh the plot figure. But by using this, the same graph plotted again and again.
for better understanding - I have two files one for node creation, which is changed by every 10 seconds using another program and another is edge creation, which is static. from this files trying to create one graph which is dynamic like this - https://drive.google.com/file/d/1snFITs4jvW5H8JSF-3pqFE2F1XjX88PD/view?usp=sharing
my network code is -
fig = plt.figure()
net = fig.add_subplot(111)
def update(it):
with open('node.csv', 'r') as nodecsv:
nodereader = csv.reader(nodecsv)
nodes = [n for n in nodereader][1:]
node_names = [n[0] for n in nodes]
with open('edge.csv', 'r') as edgecsv:
edgereader = csv.reader(edgecsv)
edges = [tuple(e) for e in edgereader][1:]
g = nx.Graph()
g.add_nodes_from(node_names)
g.add_edges_from(edges)
print(nx.info(g))
# * ******************** Node Color Part **************************** *
nx.draw(g,pos=pos,node_size=node_size,node_color=color, linewidths=2,**options)
ani = animation.FuncAnimation(fig, update, interval=1000)
plt.show()
and another thing is, I'm trying to apply node colour according to the node attribute that is working but also according to node degree means if node attribute colour is blue then apply degree separately in blue. If green then applies degree separately in green and so on.
My node colour code -
node_status = {}
for node in nodes:
node_status[node[0]] = node[1]
nx.set_node_attributes(g,node_status,'node_status')
color = []
for n in g.nodes():
#print(n,g.nodes[n]['node_status'])
if g.nodes[n]['node_status'] == 'A': color.append("blue")
if g.nodes[n]['node_status'] == 'B': color.append("yellow")
if g.nodes[n]['node_status'] == 'C': color.append("red")
if g.nodes[n]['node_status'] == 'D': color.append("green")
if g.nodes[n]['node_status'] == 'E': color.append("pink")
betCent = nx.betweenness_centrality(g, normalized=True, endpoints=True)
#node_color = [20000.0 * g.degree(v) for v in g]
node_size = [v * 10000 for v in betCent.values()]
Thanks in advance.

Networkx apparently scrambling color list python [duplicate]

I managed to produce the graph correctly, but with some more testing noted inconsistent result for the following two different line of codes:
colors = [h.edge[i][j]['color'] for (i,j) in h.edges_iter()]
widths = [h.edge[i][j]['width'] for (i,j) in h.edges_iter()]
nx.draw_circular(h, edge_color=colors, width=widths)
This approach results in consistent output, while the following produces wrong color/size per the orders of edges:
colors = list(nx.get_edge_attributes(h,'color').values())
widths = list(nx.get_edge_attributes(h,'width').values())
nx.draw_circular(h, edge_color=colors, width=widths)
However, it looks to me the above two lines both rely on the function call to return the attributes per the order of edges. Why the different results?
It looks a bit clumsy to me to access attributes with h[][][]; is it possible to access it by dot convention, e.g. edge.color for edge in h.edges().
Or did I miss anything?
The order of the edges passed to the drawing functions are important. If you don't specify (using the edges keyword) you'll get the default order of G.edges(). It is safest to explicitly give the parameter like this:
import networkx as nx
G = nx.Graph()
G.add_edge(1,2,color='r',weight=2)
G.add_edge(2,3,color='b',weight=4)
G.add_edge(3,4,color='g',weight=6)
pos = nx.circular_layout(G)
edges = G.edges()
colors = [G[u][v]['color'] for u,v in edges]
weights = [G[u][v]['weight'] for u,v in edges]
nx.draw(G, pos, edges=edges, edge_color=colors, width=weights)
This results in an output like this:
Dictionaries are the underlying data structure used for NetworkX graphs, and as of Python 3.7+ they maintain insertion order.
This means that we can safely use nx.get_edge_attributes to retrieve edge attributes since we are guaranteed to have the same edge order in every run of Graph.edges() (which is internally called by get_edge_attributes).
So when plotting, we can directly set attributes such as edge_color and width from the result returned by get_edge_attributes. Here's an example:
G = nx.Graph()
G.add_edge(0,1,color='r',weight=2)
G.add_edge(1,2,color='g',weight=4)
G.add_edge(2,3,color='b',weight=6)
G.add_edge(3,4,color='y',weight=3)
G.add_edge(4,0,color='m',weight=1)
colors = nx.get_edge_attributes(G,'color').values()
weights = nx.get_edge_attributes(G,'weight').values()
pos = nx.circular_layout(G)
nx.draw(G, pos,
edge_color=colors,
width=list(weights),
with_labels=True,
node_color='lightgreen')
if you want to avoid adding edge colors and alphas / width manually, you may also find this function helpful:
def rgb_to_hex(rgb):
return '#%02x%02x%02x' % rgb
adjacency_matrix = np.array([[0, 0, 0.5], [1, 0, 1], [1, 0.5, 0]]))
n_graphs = 5
fig, axs = plt.subplots(1, len(n_graphs), figsize=(19,2.5))
for graph in range(n_graphs):
pos = {0: (1, 0.9), 1: (0.9, 1), 2: (1.1, 1)}
# draw DAG graph from adjacency matrix
gr = nx.from_numpy_matrix(adjacency_matrix, create_using=nx.DiGraph)
weights = nx.get_edge_attributes(gr, "weight")
# adding nodes
all_rows = range(0, adjacency_matrix.shape[0])
for n in all_rows:
gr.add_node(n)
# getting edges
edges = gr.edges()
# weight and color of edges
scaling_factor = 4 # to emphasise differences
alphas = [weights[edge] * scaling_factor for edge in edges]
colors = [rgb_to_hex(tuple(np.repeat(int(255 * (1-
weights[edge])),3))) for edge in edges]
# draw graph
nx.draw(gr,
pos,
ax=axs[graph],
edgecolors='black',
node_color='white',
node_size=2000,
labels={0: "A", 1: "B", 2: "C"},
font_weight='bold',
linewidths=2,
with_labels=True,
connectionstyle="arc3,rad=0.15",
edge_color=colors,
width=alphas)
plt.tight_layout()

Plot size of each node according to dictionary

So far I have the following code:
source = ['0','0','0','0','0','0','0']
destination = ['1','2','3','4','5','6','7']
FB_network_graph = pd.DataFrame({ 'from':source, 'to':destination})
G=nx.from_pandas_edgelist(FB_network_graph, 'from', 'to')
plt.figure(figsize = (100,100))
nx.draw(G, with_labels=True)
I want to plot a graph whereby node '0' has a size of 7 and node '1'-'7' has a size of 1.
It looks like you want to adjust the node_size according to the degree. For that you can define a dictionary from the result of G.degree and set the size according to the corresponding node degree by looking up the dictionary:
scale = 300
d = dict(G.degree)
nx.draw(G, node_color='lightblue',
with_labels=True,
nodelist=d,
node_size=[d[k]*scale for k in d])
Alternatively you could just define your custom dictionary, to set the corresponding node sizes in node_size. For this specific case with something like:
d = {str(k):1 for k in range(1,8)}
d['0'] = 7

networkx - change color/width according to edge attributes - inconsistent result

I managed to produce the graph correctly, but with some more testing noted inconsistent result for the following two different line of codes:
colors = [h.edge[i][j]['color'] for (i,j) in h.edges_iter()]
widths = [h.edge[i][j]['width'] for (i,j) in h.edges_iter()]
nx.draw_circular(h, edge_color=colors, width=widths)
This approach results in consistent output, while the following produces wrong color/size per the orders of edges:
colors = list(nx.get_edge_attributes(h,'color').values())
widths = list(nx.get_edge_attributes(h,'width').values())
nx.draw_circular(h, edge_color=colors, width=widths)
However, it looks to me the above two lines both rely on the function call to return the attributes per the order of edges. Why the different results?
It looks a bit clumsy to me to access attributes with h[][][]; is it possible to access it by dot convention, e.g. edge.color for edge in h.edges().
Or did I miss anything?
The order of the edges passed to the drawing functions are important. If you don't specify (using the edges keyword) you'll get the default order of G.edges(). It is safest to explicitly give the parameter like this:
import networkx as nx
G = nx.Graph()
G.add_edge(1,2,color='r',weight=2)
G.add_edge(2,3,color='b',weight=4)
G.add_edge(3,4,color='g',weight=6)
pos = nx.circular_layout(G)
edges = G.edges()
colors = [G[u][v]['color'] for u,v in edges]
weights = [G[u][v]['weight'] for u,v in edges]
nx.draw(G, pos, edges=edges, edge_color=colors, width=weights)
This results in an output like this:
Dictionaries are the underlying data structure used for NetworkX graphs, and as of Python 3.7+ they maintain insertion order.
This means that we can safely use nx.get_edge_attributes to retrieve edge attributes since we are guaranteed to have the same edge order in every run of Graph.edges() (which is internally called by get_edge_attributes).
So when plotting, we can directly set attributes such as edge_color and width from the result returned by get_edge_attributes. Here's an example:
G = nx.Graph()
G.add_edge(0,1,color='r',weight=2)
G.add_edge(1,2,color='g',weight=4)
G.add_edge(2,3,color='b',weight=6)
G.add_edge(3,4,color='y',weight=3)
G.add_edge(4,0,color='m',weight=1)
colors = nx.get_edge_attributes(G,'color').values()
weights = nx.get_edge_attributes(G,'weight').values()
pos = nx.circular_layout(G)
nx.draw(G, pos,
edge_color=colors,
width=list(weights),
with_labels=True,
node_color='lightgreen')
if you want to avoid adding edge colors and alphas / width manually, you may also find this function helpful:
def rgb_to_hex(rgb):
return '#%02x%02x%02x' % rgb
adjacency_matrix = np.array([[0, 0, 0.5], [1, 0, 1], [1, 0.5, 0]]))
n_graphs = 5
fig, axs = plt.subplots(1, len(n_graphs), figsize=(19,2.5))
for graph in range(n_graphs):
pos = {0: (1, 0.9), 1: (0.9, 1), 2: (1.1, 1)}
# draw DAG graph from adjacency matrix
gr = nx.from_numpy_matrix(adjacency_matrix, create_using=nx.DiGraph)
weights = nx.get_edge_attributes(gr, "weight")
# adding nodes
all_rows = range(0, adjacency_matrix.shape[0])
for n in all_rows:
gr.add_node(n)
# getting edges
edges = gr.edges()
# weight and color of edges
scaling_factor = 4 # to emphasise differences
alphas = [weights[edge] * scaling_factor for edge in edges]
colors = [rgb_to_hex(tuple(np.repeat(int(255 * (1-
weights[edge])),3))) for edge in edges]
# draw graph
nx.draw(gr,
pos,
ax=axs[graph],
edgecolors='black',
node_color='white',
node_size=2000,
labels={0: "A", 1: "B", 2: "C"},
font_weight='bold',
linewidths=2,
with_labels=True,
connectionstyle="arc3,rad=0.15",
edge_color=colors,
width=alphas)
plt.tight_layout()

Categories