Python- How to retrieve the vertex set by its attributes - python

I am creating a graph with vertex and edges using networkx in python.
G= add_edge(vertex1,vertex2)
vertex1 and vertex2 are integers i.e.
G=add_edge(4,3),
G=add_edge(2,3)
etc..
Since, in python if we just give the edge list it creates the vertex and create the edges between the specified vertexes.
Now i need to add an attribute to the vertex of the graph i.e. i want to basically separate the vertex into groups based on the attribute.
Hence, i can do
G.node[your_vertex]['attribute'] = value
to add attribute to the already created graph G. #as suggested by BrenBarn.
Since there can be many different attributes and different values, how do i retrieve the vertex
By it's value.
By it's attribute.

This is described in the documentation:
G.node[1]['room'] = 714
You just do G.node[your_vertex]['attribute'] = value.

Related

Is there a way to preserve or track vertex correspondence after a series of vertex removals

In python-igraph, it seems to me that when you delete vertices from a graph, the vertices are renamed to using consecutive vertices from 0 to n.
To see what I mean, consider the following program:
from igraph import Graph
g=Graph.Full(4) # Vertex set is {0..3}
print g.neighbors(2) # Prints [0,1,3]
g.delete_vertices([1])
print g.neighbors(2) # Prints [0,1], but I'd want [0,3]
I could do my own manual bookkeeping, but is this already supported in the library somehow? Basically, I'd like to know after a series of vertex deletions, what the newly renamed vertices correspond to in the original graph (just like in the snippet above).
The easiest is to use the name vertex attribute to track the correspondence. Basically, if you assign names to the vertices, you can then use the names later wherever igraph expects a numeric vertex ID:
>>> g.vs["name"] = ["V{0}".format(i) for i in range(4)]
>>> g.vs[g.neighbors("V2")]["name"]
['V0', 'V1', 'V3']
>>> g.delete_vertices(["V1"])
>>> g.vs[g.neighbors("V2")]["name"]
['V0', 'V3']
The name attribute is indexed behind the scenes so looking up a vertex by name should have the same time complexity as a typical Python dict lookup.
For what it's worth, the vertex renumbering is a property of the underlying C library so there's not much that the Python interface can do about it.

Set list as vertex/edge attribute

I started using igraph for my B.Sc. thesis but i'm struggling when i try to assign a list as an attribute of a vertex.
Here's what i tried:
self.network.vs(node)[propertyName] = [0, value]
where network is my graph and node the name of the vertex.
When i try to access the elements i got an error (out of bounce) because the length of the list returned is 0.
How can I assign a list as a property of a vertex?
When you assign a list to a vertex property it is typically distributed over the vertices even though you give a specific vertex number. You have to specify that it is a list for a specific vertex. Such as the following.
self.network.vs(node)[propertyName] = [[0, value]]

Indexing vertex name

I am using python igraph version 0.6.5. I am bit unclear that in a code below:
g = igraph.Graph(directed=True)
g.add_vertex('A')
g.add_vertex('B')
g.add_vertex('A')
print g.vcount()
This gives me the count of vertex as 3 even though the vertex name 'A' is duplicated , why both vertex name 'A' are taken as 2 different vertex ? How can we index the vertex name ?
When you run g.add_vertex('A'), igraph does not add "A" as a vertex to the graph - it adds a completely new vertex and then assigns "A" to its name attribute, but names are not required to be unique in igraph. Internally vertices are represented by integers from zero to |V|-1, and the names are just attributes that are attacked to the vertices. So, if you want to make sure that you don't create duplicate vertices with the same name, you need to check whether a vertex exists with the same name:
try:
vertex = g.vs.find("A")
except ValueError:
g.add_vertex("A")
The name vertex attribute is treated specially by igraph as it is always backed by a dictionary that maps vertex names to the first vertex that has this name, so g.vs.find("A") is a fast operation (no need to scan the entire graph).

Plotting the same graph repeatedly -- how to get nodes in the same position?

I am working in Python, using NetworkX and Matplotlib.
When I plot the same graph over and over but with different colors, how can I get the nodes to take the same position every time? Right now I am getting:
But I am adding the nodes as keys of a dictionary, and the color of each node as the value, and then sorting the dictionary and passing the nodes as the keys of the sorted dictionary and the colors as the values of the sorted dict. The same nodes are always added in the same order. I thought that would work...
So, where x holds lists of nodes (branches):
for ct2,i in enumerate(x):
for ct,j in enumerate(i):
vertex = j[t]
if np.angle(j[t]) <0 or np.angle(j[t]) >= np.angle(cutoff):
C[vertex] = 0.0
else:
C[vertex] = .8- 3*(np.angle(j[t])/np.angle(cutoff))
COLORS = collections.OrderedDict(sorted(C.items()))
Then the graphing call:
pos=nx.graphviz_layout(G,'dot')
nx.draw_networkx_nodes(
G,pos,nodelist=COLORS.keys(),cmap=plt.get_cmap(cmap),
node_size=nodesize,alpha=.6,vmax=1,vmin=0, node_color = COLORS.values()
)
What am I doing wrong?
It would be good to see where the graphing call sits relative to your loop (inside? outside?)
But it looks like you've got pos=nx.graphviz_layout(G,'dot') within the loop. So each time within the loop it recalculates pos. This is the variable that tells the algorithm where to put the nodes. The position is somewhat random, so each call puts them in a different place (this is more obvious with spring_layout).
If this is what you've done, just move
pos=nx.graphviz_layout(G,'dot')
before the loop. Then it won't be regenerated each time.

igraph: how to use add_edges when there are attributes?

What if I need to create a graph in igraph and add a bunch of edges, but the edges have associated attributes? It looks like .add_edges can only take a list of edges without attributes, so I've been adding them one by one with .add_edge
graph.add_edge('A','B',weight = 20)
Here A and B are names of nodes
You can assign the attributes later; e.g.:
graph.es["weight"] = range(g.ecount())
This will assign weights to all the edges at once. If you want to assign attributes to only a subset of the edges, index or slice the edge sequence (g.es) in however you want:
graph.es[10:20]["weight"] = range(10)

Categories