igraph: how to use add_edges when there are attributes? - python

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)

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.

Equivalent of R igraph graph_from_data_frame() function in Python igraph?

Is there an equivalent of this igraph R function in Python igraph?
graph_from_data_frame(d, directed = TRUE, vertices = NULL)
This function creates an igraph graph from one or two data frames
containing the (symbolic) edge list and edge/vertex attributes.
Python does not have data frames so there is no direct equivalent. The closest equivalent could be Graph.DictList, which creates a graph from a list of dictionaries, or Graph.TupleList, which is the same for a list of tuples.
Right now you can use this:
from igraph import Graph
g = Graph.DataFrame(edges, directed=False, vertices=vertices, use_vids=False)
where "edges" is a Pandas dataframe with the edges, vertices are the names that will be used in each vertex, and use_vids if you want to assign indexes to name the edges instead of using the "vertices" data
https://igraph.org/python/api/0.9.7/igraph.Graph.html#DataFrame

Python- How to retrieve the vertex set by its attributes

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.

iGraph Python, convert edge list to tuple and add.edges

I have a Graph G1 with 50 nodes and 100 edges. All edges are weighted. I have created a list of edges (sorted by a pre-defined order, removing specific edges with large values), and they are indexed like:
Edgelist: [75, 35, 32, 1, ...]
I want to add the edges to a different graph G2 in batches of 10 (to save computation time), but add.edges seems to want a tuple list of vertex pairs. So,
How can I convert the Edge list above into a tuple list, e.g. [(40,2),(10,1),(10,11),(0,0),...]. I've tried a loop with G1.es[edge].tuple, but iGraph reads the [edge] variable as an attribute, whereas if you just write G1.es[75].tuple, it works fine.
How can I look up weights from G1 and add them to G2 in batches of 10?
You have to be aware that indexing G1.es with a single number will return an object of type Edge, while indexing it with a list of numbers will return an object of type EdgeSeq. Edge objects have a property named tuple, but EdgeSeq objects don't, so that's why G1.es[edgelist].tuple does not work However, you can do this:
sorted_tuples = [edge.tuple for edge in G1.es[edgelist]]
You can also extract the value of the weight attribute directly from the EdgeSeq object:
sorted_weights = G1.es[edgelist]["weight"]
Here you can make use of the fact that if G2 has M edges and you add m extra edges, then the IDs of these new edges will be in the range from M (inclusive) to M+m (exclusive):
M = G2.ecount()
m = len(sorted_tuples)
G2.add_edges(sorted_tuples)
G2.es[M:(M+m)] = sorted_weights
1) Graph G1 has had unwanted edges deleted already. Edgelist is the edge order for G1.
tuple_list=[]
for e in G1.es:
tuple_list.append(e.tuple)
sorted_tuples=[tuple_list[i] for i in Edgelist]
sorted_weights = [G1.es['weight'][o] for o in Edgelist]
2) Add edges - this can simply be looped for all edges in G1. Example below for first 10.
edges_to_add=sorted_tuples[0:10]
weights_to_add=sorted_weights[0:10]
G2.add_edges(edges_to_add)
for edge in range(len(edges_to_add)):
G2.es[G2.get_eid(edges_to_add[edge][0],edges_to_add[edge][1],0)]['weight'] = weights_to_add[edge]
Edge weights are added individually, which is a little slow, but there doesn't seem to be a way of adding edge weights in a batch in iGraph

igraph fill in node attributes after importing edgelist in Ncol() format?

I'm not sure if this is a merge or two separate imports, or something I should reconsider entirely. I started using igraph originally after playing in gephi, where I would always do a 2-stage import, first the edges, then node-data. Is this a sensible strategy for igraph?
So, thanks to some recent help, I have just imported an edge list that looked something like this:
123123 321321 1
222222 333333 2
123123 333333 3
222222 321321 4
...with the import command
import igraph
g = igraph.Graph.Read_Ncol('edgelist.txt')
I'd like to add attributes to the nodes this edgelist import generated for me. These would be something like...
123123 "color:red" "community:1"
222222 "color:blue" "community:2"
321321 "color:red" "community:1"
333333 "color:red" "community:2"
How can I append this data to my current graph? I see many formats for importing sophisticated edgelists, but none for node-lists. What am I missing? Is there no automatic append-node-data-to-appropriate-node function?
If not, can someone recommend an easier way to appropriately fill node data to an existing graph?
My instinct was something like...
[g.vs["color"] = x for x in node_list.color if g.vs["name"] == node_list.name]
[g.vs["community"] = x for x in node_list.community if g.vs["name"] == node_list.name]
But this looks extremely kludgy.
Well, you are on the right track and yes, it is going to be a bit kludgy. It is kludgy because igraph is a plain C library deep down in its core, and it is much easier to work with numbers (i.e. vertex and edge IDs) in C instead of names (i.e. vertex and edge names). That's why igraph uses integers from zero upwards to refer to vertices and edges instead of their names, and that's why you have to jump through one extra hoop to get to the vertex itself from its name.
I would probably do the following:
Read the edge list using Graph.Read_Ncol. (You have already done that).
Build a dictionary that maps vertex names back to their IDs:
>>> id_mapping = dict((v, k) for k, v in g.vs["name"])
Read your attribute file into node_list. I assume that node_list.name gives me a list of vertex names and node_list.color gives me a list containing the corresponding colors. You can then do the following:
>>> for name, color in izip(node_list.name, node_list.color):
... g.vs[id_mapping[name]]["color"] = color
An alternative approach in the 3rd step is to use g.vs.find(name), which gives you a Vertex object that refers to the vertex with the given name. You can then assign the attribute to this vertex; e.g:
>>> for name, color in izip(node_list.name, node_list.color):
... g.vs.find(name)["color"] = color
In this case you won't need the id_mapping. Actually, igraph maintains a name-to-ID mapping in the background for the name vertex attribute only, and g.vs.find makes use of this mapping. The id_mapping-based approach is more useful if you want to use a different vertex attribute as the unique key for your vertices and not name.

Categories