How to simplify a proposed dictionary of different keys - python

I built a graph using NetworkX library. I used all_shortest_paths(graph, src, dest) that returns a list of a all possible shortest paths from a given source and a given destination (For example, between node 3 and 4 it may return [[3,5,4],[3,5,7,6,4]]). For the sake of my experiment, I want to store every returned list in a dictionary. My problem is how to utilize Python dictionary to do so. If I use the following scenario, it will be complicated:
dict = {'n1':['n2':[n1,n3,n4,n2], 'n3':[n1,n7,n3]], 'n2':['n6':[n2,n6,n8,n10,n2]], ...}
Is it possible in Python to have dictionary inside a dictionary where the the key will be src node and the value is another dictionary of a key dest and value all possible paths to the destination.
Thank you for any help.

You could represent your graph as an adjacency matrix. This is just a 2-dimensional array of 1's and 0's, of size (number of nodes x number of nodes) with the rows and columns representing the nodes, and an entry of 1 at a row and column where the nodes represented are neighbors, and a 0 where the nodes represented by that row and column are not neighbors.
If you plan to do any extensive work with graphs in Python, I strongly recommend looking into the NetworkX Python package. It is documented at http://networkx.github.io/ . If you use the Anaconda scientific Python distribution, NetworkX comes with it.
There are other methods in NetworkX, like all_pairs_shortest_path(), and floyd_warshall(), that return their results as a dictionary of shortest paths by node, keyed by source and destination node.
And all_pairs_shortest_path_length(), which returns its results as a dictionary of shortest path lengths, keyed by source and destination node.
Possibly one of these might work for you?

Related

Networkx tools in Python

Hi i am still quite new to networkx python.
does anyone know how i can get all of the intersection?
Intersection nodes are the red circled. This is for undirected Graph, I would also very keen to know if there is also a way to get intersection for directed graph
Once i got the intersection, I also would like to get the start and the end node. the reason is I wanted to put different group to the path (from start node to end node)
Can I achieve this result too :<
If with intersections you mean nodes with more than two neighbors than you can use that exact logic like
intersections = [node for node in G.nodes() if len(list(G.neighbors(node)))>2]
H = G.copy()
H.remove_nodes_from(intersections)
components = nx.connected_components(H)
For "spotting" intersection you can issue them an attribute like this:
intersections_subgraph = nx.subgraph(G, intersetions)
nx.set_node_attributes(intersections_subgraph, True, 'intersection')
Adding intersections back into the sections should works by looping through the intersections neighbors and adding the intersection to the section the neighbors are in.
For sorting I would loop through the section to find a start point (only one edge/neighbor) and then move from node to node. Note that sets are always unordered so you will have to switch over to an ordered structure like a list.
Ill leave implementing those to you

Creating a network where nodes store multiple attribute data with networkx

I have a dataframe as below:
and would like to create a network where nodes are from the con.taxonomy and res.taxonomy columns, the edges being created via geographic.location. I have managed to create the network, as follows:
G = nx.from_pandas_edgelist(swiz_lakes, "con.taxonomy", "res.taxonomy", "geographic.location")
however, I was wondering whether it was possible to add other attributes to the nodes, as it is possible to do via the edges. E.g. I could have
G = nx.from_pandas_edgelist(swiss_lakes, "con.taxonomy", "res.taxonomy", ["geographic.location", "con.metabolic.type", "con.movement.type", "res.metabolic.type", "res.movement.type"])
I want to know if something similar can be done so as to store further information in the nodes, but not as labels.
Is this possible, or if not, please could somebody explain why not?
Of course this is possible. In my opinion the easiest way to achieve this would be to create a dict of the nodes and the relevant information and use nx.set_node_attributes.
Convert your dataframe in a dict of dicts, where the first level keys are your node names and second level keys are your attribute names, and the values are the corresponding values from your dataframe. (Probably it is easiest to use: your_dict = df.to_dict(orient="your_node_name_colum")) and then use
nx.set_node_attributes(G, your_dict).
Check out the networkx documentation:
https://networkx.org/documentation/stable/reference/generated/networkx.classes.function.set_node_attributes.html

How to build graph paths from list of nodes in NetworkX

What I am trying to do is build a graph in NetworkX, in which every node is a train station. To build the nodes I did:
G = nx.Graph()
G.add_nodes_from(trains['Stopping place'].unique())
which (at least as it looks like) it's working.
Now, since for each line I have the stops in sequence, I built my paths like so:
stops_by_line = ((belgium_trains.sort_values(['Train number','Actual arrival datetime']).groupby('Train number'))['Stopping place'].apply(list).to_dict())
paths = ([tuple(val) for val in stops_by_line.values()])
and the variable looks like this:
[('HERGENRATH',
'CHENEE',
'ANGLEUR',
'LIEGE-GUILLEMINS',
'ANS',
'LEUVEN',
'HERENT',
'VELTEM',
'ERPS-KWERPS',
'KORTENBERG',
'NOSSEGEM',
'ZAVENTEM',
'DIEGEM',
'HAREN-ZUID',
'SCHAARBEEK',
'BRUSSEL-NOORD',
'BRUSSEL-CONGRES',
'BRUSSEL-CENTRAAL',
'BRUSSEL-KAPELLEKERK',
'BRUSSEL-ZUID'),
(...other ordered tuples of stops),...)]
Now my question is, since all of these elements are also node names, how can I build the edges using these tuples sequentially (for example add an edge between BRUSSEL-NOORD and BRUSSEL-CONGRES, then from BRUSSEL-CONGRES to BRUSSEL-CENTRAAL and so on)?
You can simply use the add_path method in a loop:
for path in paths:
nx.add_path(G, path)
Sidemark, if you add an edge (like e.g. above), then networkx also directly adds the respective nodes to the graph. So probably (if all stops are covered by some train) you don't need to add the nodes manually before.

How to create two dimensional set objects under pyomo.environ module

I tried to create a LP model by using pyomo.environ. However, I'm having a hard time on creating sets. For my problem, I have to create two sets. One set is from a bunch of nodes, and the other one is from several arcs between nodes. I create a network by using Networkx to store my nodes and arcs.
The node data is saved like (Longitude, Latitude) in tuple form. The arcs are saved as (nodeA, nodeB), where nodeA and nodeB are both coordinates in tuple.
So, a node is something like:
(-97.97516252657978, 30.342243012086083)
And, an arc is something like:
((-97.97516252657978, 30.342243012086083),
(-97.976196300350608, 30.34247219922803))
The way I tried to create a set is as following:
# import pyomo.envrion as pe
# create a model m
m = pe.ConcreteModel()
# network is an object I created by Networkx module
m.node_set = pe.Set(initialize= self.network.nodes())
m.arc_set = pe.Set(initialize= self.network.edges())
However, I kept getting an error message on arc_set.
ValueError: The value=(-97.97516252657978, 30.342243012086083,
-97.976196300350608, 30.34247219922803) does not have dimension=2,
which is needed for set=arc_set
I found it's weird that somehow my arc_set turned into one tuple instead of two. Then I tried to convert my nodes and arcs into string but still got the error.
Could somebody show me some hint? Or how do delete this bug?
Thanks!
Underneath the hood, Pyomo "flattens" all indexing sets. That is, it removes nested tuples so that each set member is a single tuple of scalar values. This is generally consistent with other algebraic modeling languages, and helps to make sure that we can consistently (and correctly) retrieve component members regardless of how the user attempted to query them.
In your case, Pyomo will want each member of the the arc set as a single 4-member tuple. There is a utility in PyUtilib that you can use to flatten your tuples when constructing the set:
from pyutilib.misc import flatten
m.arc_set = pe.Set(initialize=(tuple(flatten(x)) for x in self.network.edges())
You can also perform some error checking, in this case to make sure that all edges start and end at known nodes:
from pyutilib.misc import flatten
m.node_set = pe.Set( initialize=self.network.nodes() )
m.arc_set = pe.Set(
within=m.node_set*m.node_set,
initialize=(tuple(flatten(x)) for x in self.network.edges() )
This is particularly important for models like this where you are using floating point numbers as indices, and subtle round-off errors can produce indices that are nearly the same but not mathematically equal.
There has been some discussion among the developers to support both structured and flattened indices, but we have not quite reached consensus on how to best support it in a backwards compatible manner.

Networkx node traversal

Using Python's Networkx library, I created an undirected graph to represent a relationship network between various people. A snippet of my code is below:
import networkx as nx
def creategraph(filepath):
G=nx.Graph()
#All the various nodes and edges are added in this stretch of code.
return G
From what I understand, each node is basically a dictionary. The problem that this presents to me is that I want to perform a different kind of Random Walk algorithm. Now before you jump on me and tell me to use one of the standard functions of the Networkx library, I want to point out that it is a custom algorithm. Suppose I run the creategraph function, and the G object is returned and stored in another object (let's call it X). I want to start off at a node called 'Bob.' Bob is connected to Alice and Joe. Now, I want to reassign Y to point to either Alice or Bob at random (with the data I'm dealing with, a given node could have hundreds of edges leaving it). How do I go about doing this? Also, how do I deal with unicode entries in a given node's dict (like how Alice and Joe are listed below?)
X = creategraph("filename")
Y=X['Bob']
print Y
>> {u'Alice': {}, u'Joe': {}}
The choice function in the random module could help with the selection process. You don't really need to worry about the distinction between unicode and string unless you're trying to write them out somewhere as sometimes unicode characters aren't translatable into the ASCII charset that Python defaults to.
The way you'd use random.choice would be something along the lines of:
Y = Y[random.choice(Y.keys())]

Categories