Add position to a NetworkX graph using dictionary - python

I have a DiGraph object called G1, a graph network with edges. G1 is composed by a list of nodes and I want to give them coordinates stored in a python dictionary.
This is the list of nodes:
LIST OF NODES
For every node I have built a python dictionary with node's name as keys and a tuple of coordinates as values:
DICTIONARY WITH COORDINATES
I want to add the attribute position (pos) to every node with those coordinates.
At the moment I have tried using this cycle:
FOR LOOP TO ADD COORDINATES
But as a result only the last node appears to have coordinates, it seems like the data are being subscribed with this method:
ERROR
The result should be a graph network plotted on a xy space with the right coordinates obtained with the code:
PLOT THE GRAPH
I am obtaining the following error:
KeyError: (78.44, 88.3)

I think it's mostly syntax errors here. Try this:
for node, pos in avg.items():
G1.nodes[node]['pos'] = pos
Then, when building your visual, build your list of positions beforehand like this and just use the pos=pos convention when calling nx.draw().
pos = {node: G.nodes[node]['pos'] for node in G.nodes()}
**** EDIT: ****
There's a built-in way to do this that is much cleaner:
nx.set_node_attributes(G1, avg, 'pos')
Then, when drawing, use:
nx.draw(G1, pos=nx.get_nodes_attributes(G1, 'pos'))

Related

How to get sorted list of nodes for a list of nodes in a NetworkX graph as approximation of TSP

I have an undirected NetworkX graph (not necessarily complete, but connected). Also, I have a list of few nodes from all nodes of the above graph. I want to get the travel distance as per TSP result(or it's approximation).
I tried using networkx.approximation.traveling_salesman_problem(DS.G, nodes=['A0_S0_R0', 'A0_S14_R4', 'A0_S4_R4', 'A0_S14_R4', 'A0_S14_R4', 'A0_S7_R4']), but output list is a list of nodes to be used to cover given nodes in the order they appear in the given input list.
I want either total minimised distance or list of nodes in the order such that travelling distance is minimised and not according to their appearance in the input list.
The tsp function will return the list of nodes corresponding to best found path.
You can get the minimum distance using
nodes = [...] # list of nodes returned by traveling_salesman_problem()
# assuming you used `weight` key for edge weights
distances = [G.get_edge_data(nodes[i],node[i+1])['weight'] for i in range(len(nodes)-1)]
min_distance = sum(distances)

Computing distances in a river network for each node in Python(Arcpy)

I have a randomly created river network in ArcMap as Shapefile (Polyline). The goal is to calculate the distances from each node to the most distant source point and store them in a dictionary.
River network (red = source points, black = confluence points, green = estuary point)
I have already saved the lengths of the individual polyline segments in a new field in the shapefile. These lengths are also stored in a new dictionary in Python. Each key has a corresponding length. The topology is stored in two more dictionaries. One dictionary contains the edge numbers as key and the start and end point of the edge in the value. The second dictionary contains all nodes as key and the corresponding edges to each node as value.
length = {0:[10.25], 1:[9.58], 2:[11.99], 3:[9.50], 4:[26.28]}
edges = {0:[0,1], 1:[2,1], 2:[1,3], 3:[4,3], 4:[3,5]}
nodes = {0:[1], 1:[0], 2:[3], 3:[2,3,4], 4:[0,1,2], 5:[4]}
Moreover I have three lists with the source points, the estuary point and the confluence points respectively.
My problem is that I don't know how to use the given dictionaries to determine the distances of the nodes to the farthest source point. One consideration for my part is to save the distance planes from the point of intersection in another dictionary, but I don't know whether this helps or is necessary. This would look like this (Key = topology level, value = node):
dist = {0:[5], 1:[3], 2:[1,4], 3:[0,2]}
Any help would be extremely appreciated.
Thanks, Matthew

Remove reversible edges from directed graph networkx

Is there a way of removing reversible edges in a graph. For instance, let's say the following graph
import networkx as nx
G=nx.DiGraph()
G.add_edge(1,2)
G.add_edge(2,3)
G.add_edge(2,1)
G.add_edge(3,1)
print (G.edges())
[(1, 2), (2, 3), (2,1), (3,1)]
I want to remove (2,1) and (3,1), since I want the graph to be directed in just one direction. I know you can remove self-loops by using G.remove_edges_from(G.selfloop_edges()) but that's not the case here. The output I am looking for would be [(1, 2), (2, 3)]. Is there a way to remove this edges once the graph is created either by networkx or by other graph tool such as cytoscape?.
Method 1:
remove duplicate entries in edgelist -> remove everything from graph -> add back single edges => graph with single edges
Edges are stored as tuples. You could lose index information via temporary conversion to sets. You could then lose duplicate tuples, again, through temporary conversion to a set. After conversion back to a list, you have your list of edges, with duplicate entries removed, like so:
stripped_list = list(set([tuple(set(edge)) for edge in G.edges()]))
Then remove all edges from the graph that are currently there, and add back those that are in the list just created:
G.remove_edges_from([e for e in G.edges()])
G.add_edges_from(stripped_list)
Method 2:
find duplicate edges -> remove only those from graph => graph with single edges
again, losing positional information via conversion to sets:
set_list = [set(a) for a in G.edges()] # collect all edges, lose positional information
remove_list = [] # initialise
for i in range(len(set_list)):
edge = set_list.pop(0) # look at zeroth element in list:
# if there is still an edge like the current one in the list,
# add the current edge to the remove list:
if set_list.count(edge) > 0:
u,v = edge
# add the reversed edge
remove_list.append((v, u))
# alternatively, add the original edge:
# remove_list.append((u, v))
G.remove_edges_from(remove_list) # remove all edges collected above
As far as I know, networkx does not store the order that edges were added in, so unless you want to write further logic, you either remove all duplicate edges going from nodes with lower number to nodes with higher number, or the other way round.

Fetch connected nodes in a NetworkX graph

Straightforward question: I would like to retrieve all the nodes connected to a given node within a NetworkX graph in order to create a subgraph. In the example shown below, I just want to extract all the nodes inside the circle, given the name of one of any one of them.
I've tried the following recursive function, but hit Python's recursion limit, even though there are only 91 nodes in this network.
Regardless of whether or not the below code is buggy, what is the best way to do what I'm trying to achieve? I will be running this code on graphs of various sizes, and will not know beforehand what the maximum recursion depth will be.
def fetch_connected_nodes(node, neighbors_list):
for neighbor in assembly.neighbors(node):
print(neighbor)
if len(assembly.neighbors(neighbor)) == 1:
neighbors_list.append(neighbor)
return neighbors_list
else:
neighbors_list.append(neighbor)
fetch_connected_nodes(neighbor, neighbors_list)
neighbors = []
starting_node = 'NODE_1_length_6578_cov_450.665_ID_16281'
connected_nodes = fetch_connected_nodes(starting_node, neighbors)
Assuming the graph is undirected, there is a built-in networkx command for this:
node_connected_component(G, n)
The documentation is here. It returns all nodes in the connected component of G containing n.
It's not recursive, but I don't think you actually need or even want that.
comments on your code: You've got a bug that will often result an infinite recursion. If u and v are neighbors both with degree at least 2, then it will start with u, put v in the list and when processing v put u in the list and keep repeating. It needs to change to only process neighbors that are not in neighbors_list. It's expensive to check that, so instead use a set. There's also a small problem if the starting node has degree 1. Your test for degree 1 doesn't do what you're after. If the initial node has degree 1, but its neighbor has higher degree it won't find the neighbor's neighbors.
Here's a modification of your code:
def fetch_connected_nodes(G, node, seen = None):
if seen == None:
seen = set([node])
for neighbor in G.neighbors(node):
print(neighbor)
if neighbor not in seen:
seen.add(neighbor)
fetch_connected_nodes(G, neighbor, seen)
return seen
You call this like fetch_connected_nodes(assembly, starting_node).
You can simply use a Breadth-first search starting from your given node or any node.
In Networkx you can have the tree-graph from your starting node using the function:
bfs_tree(G, source, reverse=False)
Here is a link to the doc: Network bfs_tree.
Here is a recursive algorithm to get all nodes connected to an input node.
def create_subgraph(G,sub_G,start_node):
sub_G.add_node(start_node)
for n in G.neighbors_iter(start_node):
if n not in sub_G.neighbors(start_node):
sub_G.add_path([start_node,n])
create_subgraph(G,sub_G,n)
I believe the key thing here to prevent infinite recursive calls is the condition to check that node which is neighbor in the original graph is not already connected in the sub_G that is being created. Otherwise, you will always be going back and forth and edges between nodes that already have edges.
I tested it as follows:
G = nx.erdos_renyi_graph(20,0.08)
nx.draw(G,with_labels = True)
plt.show()
sub_G = nx.Graph()
create_subgraph(G,sub_G,17)
nx.draw(sub_G,with_labels = True)
plt.show()
You will find in the attached image, the full graph and the sub_graph that contains node 17.

Does adding new nodes to a graph change the indices of the old nodes?

I have a networkx graph object G. Each node has an index with respect to G.nodes(). I keep track of the nodes indices because I do some computations with the adjacency matrix, because each row index in the adjecency matrix corresponds to the node index in G.nodes(). But now I want to add new nodes to the graph, would that change the indices of the old nodes?
I'm not removing any nodes.
G = nx.Graph()
#add some nodes to G.
#record the indices of those nodes in a dictionary that maps from a node name to a node index from the list G.nodes()
#add more nodes and edges to G.
#Did the indices of the old nodes change?
NetworkX stores graph nodes in the attribute node of the class Graph. Since node is a dictionary, the order is not guaranteed and may change.
If you could give some more details about what you're trying to achieve, we could help you more. You could try keeping a dictionary mapping from nodes to names, or if all you need is the node names, you could also assign names to nodes directly:
G.add_node('John')
G.add_node('Jane')
You can also use node attributes, such as
G.add_node(0, name='John', age=24)
G.add_node(1, name='Jane', age=27)
and then read them as
G.node[0]
>>> {'name': 'John', 'age': 24}
You can also use arbitrary objects as graph nodes.

Categories

Resources