Adding specific weights to edges through dictionary - python

I have two dictionaries of nodes with edges like below:
all_nodes_edges = {20101: (20102, 20201), 20102: (20101, 20103), 20103: (20102, 20104)}
nodes_with_weights = {20101: 20201, 20119: 20219, 20201: (20301, 20101)}
I've created the graph and default weights for all the edges in the graph with the below code:
g = nx.Graph(all_nodes_edges)
nx.set_edge_attributes(g, 1, 'weight')
I'm trying to use the nodes_with_weights dict to create weights of 2 on specific edges. How do I achieve this?. Do I have to loop through the dictionary or can I just use a specific nx function?
Sorry kinda new to graphs.

I finally figured it out!
for u,v,a in g.edges(data=True):
if u and v in nodes_with_weights:
a = 2

Related

Remove weights from networkx graph

I have a weighted Networkx graph G. I first want to make some operation on G with weights (which is why I just don't read the input and set weights=None) and then remove them from G afterwards. What is the most straightforward way to make it unweighted?
I could just do:
G = nx.from_scipy_sparse_array(nx.to_scipy_sparse_array(G,weight=None))
Or loop through the G.adj dictionary and set weights=0, but both of these options feels too complicated. Something like:
G = G.drop_weights()
It is possible to access the data structure of the networkx graphs directly and remove any unwanted attributes.
At the end, what you can do is define a function that loops over the dictionaries and remove the "weight" attribute.
def drop_weights(G):
'''Drop the weights from a networkx weighted graph.'''
for node, edges in nx.to_dict_of_dicts(G).items():
for edge, attrs in edges.items():
attrs.pop('weight', None)
and an example of usage:
import networkx as nx
def drop_weights(G):
'''Drop the weights from a networkx weighted graph.'''
for node, edges in nx.to_dict_of_dicts(G).items():
for edge, attrs in edges.items():
attrs.pop('weight', None)
G = nx.Graph()
G.add_weighted_edges_from([(1,2,0.125), (1,3,0.75), (2,4,1.2), (3,4,0.375)])
print(nx.is_weighted(G)) # True
F = nx.Graph(G)
print(nx.is_weighted(F)) # True
# OP's suggestion
F = nx.from_scipy_sparse_array(nx.to_scipy_sparse_array(G,weight=None))
print(nx.is_weighted(F)) # True
# Correct solution
drop_weights(F)
print(nx.is_weighted(F)) # False
Note that even reconstructing the graph without the weights through nx.to_scipy_sparse_array is not enough because the graph is constructed with weights, only these are set to 1.

Is there a way to run pagerank algorithm on NetworkX's MultiGraph?

I'm working on a graph with multiple edges between the same nodes (edges are having different values). In order to model this graph I need to use MultiGraph instead of normal Graph. Unfortunately, it's not possible to run PageRank algo on it.
Any workarounds known ?
NetworkXNotImplemented: not implemented for multigraph type
You could create make a graph without parallel edges and then run pagerank.
Here is an example of summing edge weights of parallel edges to make a simple graph:
import networkx as nx
G = nx.MultiGraph()
G.add_edge(1,2,weight=7)
G.add_edge(1,2,weight=10)
G.add_edge(2,3,weight=9)
# make new graph with sum of weights on each edge
H = nx.Graph()
for u,v,d in G.edges(data=True):
w = d['weight']
if H.has_edge(u,v):
H[u][v]['weight'] += w
else:
H.add_edge(u,v,weight=w)
print H.edges(data=True)
#[(1, 2, {'weight': 17}), (2, 3, {'weight': 9})]
print nx.pagerank(H)
#{1: 0.32037465332634, 2: 0.4864858243244209, 3: 0.1931395223492388}
You can still compose a Digraph by combining the edges
while adding their weights.
# combining edges using defaultdict
# input-- combined list of all edges
# ouput-- list of edges with summed weights for duplicate edges
from collections import defaultdict
def combine_edges(combined_edge_list):
ddict = defaultdict(list)
for edge in combined_edge_list:
n1,n2,w = edge
ddict[(n1,n2)].append(w)
for k in ddict.keys():
ddict[k] = sum(ddict[k])
edges = list(zip( ddict.keys(), ddict.values() ) )
return [(n1,n2,w) for (n1,n2),w in edges]

How to add edges in an igraph object from a dictionary

I'm using a dictionary to represent a set of edges. I'm using the keys of the dictionary to represent edges and the values to represent the weights. The dictionary currently looks like this:
{(0, 1): 2, (1, 2): 6, (0, 2): 3}
I try this:
edges, weights = [], []
for edge, weight in dict_edges.items():
edges += [edge]
weights.append(weight)
g.add_edges(edges)
g.es["weight"] = weights
But, I don't if there is a faster way or more cleaner to do this.
Anyone have any suggestions how to improve my new?
What you do is perfectly fine; maybe the for loop could be replaced with a zip call. If you are using Python 2.x::
from itertools import izip
edges, weights = izip(*dict_edges.iteritems())
g = Graph(edges, edge_attrs={"weight": weights})
If you are using Python 3.x::
edges, weights = zip(*dict_edges.items())
g = Graph(edges, edge_attrs={"weight": weights})

Labelling the edges in a graph with python igraph

I have the adjacency matrix (i.e. a collection of weights) of a directed graph, and I would like to add labels (corresponding to the values of the weights) on the edges in the final plot.
In other words, I would like to obtain something like this.
I'm using python igraph, and my code is as follows:
import numpy as np
import igraph as ig
N = 6
adj_matr = np.random.random((N, N))
g = ig.Graph.Weighted_Adjacency(adj_matr.tolist(), mode=ig.ADJ_DIRECTED, attr="weight", loops=True)
ig.plot(g, "My_Graph.svg", vertex_label=map(str, np.arange(N)))
I have figured out how to set labels on the nodes, but I cannot find anything concrete about the edges (adding edge_label=... in the plot command doesn't work). Do you know how to fix the problem? Thanks in advance for your help!
using vertex_label= is equivalent to g.vs=
so to label your edges, use g.es=:
g.es["label"] = ["A", "B", "C"]
or
g.es["name"] = map(str, np.arange(N))

How do I add edges between two subgraphs in pydot?

Does anyone know how to add an edge between two subgraphs (clusters) in pydot?
callgraph = pydot.Dot(graph_type='digraph',fontname="Verdana")
cluster_foo=pydot.Cluster('foo',label='foo')
cluster_foo.add_node(pydot.Node('foo_method_1',label='method_1'))
callgraph.add_subgraph(cluster_foo)
cluster_bar=pydot.Cluster('bar',label='Component1')
cluster_bar.add_node(pydot.Node('bar_method_a'))
callgraph.add_subgraph(cluster_bar)
I tried:
callgraph.add_edge(pydot.Edge("foo","bar"))
but doesn't work. It just creates two more nodes labeled "foo" and "bar" in the initial graph and puts an edge between them!
Can anyone help, please?
Graphviz demands that an edge be between nodes in the 2 clusters.
Add graph parameter compound='true'.
Use edge parameters lhead= and ltail=.
So your code would become:
callgraph = pydot.Dot(graph_type='digraph', fontname="Verdana", compound='true')
cluster_foo=pydot.Cluster('foo',label='foo')
callgraph.add_subgraph(cluster_foo)
node_foo = pydot.Node('foo_method_1',label='method_1')
cluster_foo.add_node(node_foo)
cluster_bar=pydot.Cluster('bar',label='Component1')
callgraph.add_subgraph(cluster_bar)
node_bar = pydot.Node('bar_method_a')
cluster_bar.add_node(node_bar)
callgraph.add_edge(pydot.Edge(node_foo, node_bar, ltail=cluster_foo.get_name(), lhead=cluster_bar.get_name()))

Categories