I'd like to specify the coordinates of the vertices of a graph in graph-tool in an efficient way.
Given a csv which looks like:
Node,X,Y
1,2.5,3.8
2,3.4,2.9
...
I'd like graph-tool to plot vertex 1 at position (2.5,3.8) etc...
A non efficient solution is given in :
Explicit vertex position in python graph-tool , so I can basically use a for loop over all my coordinates and save them in the property map 'pos'. If my graph is 'g' and my csv is read using pandas in the dataframe 'coordinates', I can do:
for i in range(1,numnodes+1):
pos[g.vertex(i)] = (coordinates.values[i-1,1],coordinates.values[i-1,2])
The problem is that my number of nodes, numnodes is big (~10^7), and this can take some time.
Is there a more efficient way to do this operation by inputting directly the data in the property map 'pos' ?
I found an answer to my question, an efficient way to do this is to use the .set_2d_array() function;
pos.set_2d_array(coordinates[['X','Y']].values.T)
does the trick.
Here ".T" is the transposition function, part of the numpy library.
I would try this:
pos = coordinates[['X','Y']].values
if graph-tool accepts numpy arrays, otherwise:
pos = [tuple(t) for t in coordinates[['X','Y']].values]
Related
I just started using OpenMesh in Python. I started off by trying to make a PolyMesh consisting of a single quad. This is what I did:
from openmesh import *
mesh = PolyMesh();
vh0 = mesh.add_vertex(PolyMesh.Point(0,0,0));
vh1 = mesh.add_vertex(PolyMesh.Point(1,0,0));
vh2 = mesh.add_vertex(PolyMesh.Point(1,1,0));
vh3 = mesh.add_vertex(PolyMesh.Point(0,1,0));
vh_list = [vh0, vh1, vh2, vh3];
fh0 = mesh.add_face(vh_list);
This creates a single quad mesh. Then, wanting to refine the quad once, I thought to try:
vh4 = mesh.add_vertex(PolyMesh.Point(0.5,0,0));
vh5 = mesh.add_vertex(PolyMesh.Point(0.5,1,0));
vh_list = [vh4, vh1, vh2, vh5];
fh1 = mesh.add_face(vh_list);
The above gives me a complex edge error. I understand from one of the other questions on SO that this is because vh_list in the second case does not define a consistent orientation wrt the first face. However, I did not want to add a new face. That is, I thought the operation would simply split fh0 at x = 0.5 and not create a new face attached to fh0 at edge index 1. Can someone say something about how this can be done? I could not find a "split_face" function in the documentation.
Also, how do I access handles of particular edges/mesh components in Python? (I found answers only for C++.) For instance, I know that I can iterate over the edges with,
for eh in mesh.edges():
but how can I directly get the handle for edge 2 and use it as follows, for example?
mesh.split_edge(eh,vh5)
Thank you!
Edit 1
I found the function split in OpenMesh documentation, but it takes as input a single vertexhandle at which I can split the face. And post-splitting, it converts the mesh to a mesh of triangles. I do not want this. I want to split the quadrilateral into two quadrilaterals at x = 0.5. Thank you.
Edit 2
I tried an alternate approach: first delete fh0, and then add two new faces fh0 and fh1 based on the refinement I want. I tried doing
mesh.delete_face(fh0)
and Python segfaulted and exited.
If you want to split the face fh0 into two faces you should delete fh0 first and then create the two new faces. This should do the job :
mesh.delete_face(fh0, deleted_isolated_vertices = False)
mesh.garbage_collection()
fh0 = mesh.add_face(vh0,vh4,vh5,vh3)
fh1 = mesh.add_face(vh4,vh1,vh2,vh5)
To verify you get what you want, ask for print(mesh.face_vertex_indices()), you should get two lists listing indices of vertices of each face.
Also, to access a known edge handle you can use
eh = mesh.edge_handle(edge_index)
where edge_index is int, index of your edge of interest.
Hope this helps,
Charles.
I have a graph and I want to implement a modification of the Page Rank algorithm. I am stuck on the following point. I don't know how to get all the neighboring vertices from a node.
Currently I am receiving the list of the edges using:
g.incident("a", mode="out")
This returns me the list of the edges indexes.
How can I get the vertex name from that?
For example I need to know that "a" is linked to "b" and "d"
g.neighbors("a", mode="out") will give you the vertex indices for the neighbors. You can then get the names as follows:
>>> neis = g.neighbors("a", mode="out")
>>> g.vs[neis]["name"]
But actually, if I were you, I would try to work with vertex indices as much as possible because it's way faster to work with the indices than with the names.
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.
I have a list with two elements like this:
list_a = [27.666521, 85.437447]
and another list like this:
big_list = [[27.666519, 85.437477], [27.666460, 85.437622], ...]
And I want to find the closest match of list_a within list_b.
For example, here the closest match would be [27.666519, 85.437477].
How would I be able to achieve this?
I found a similar problem here for finding the closest match of a string in an array but was unable to reproduce it similarly for the above mentioned problem.
P.S.The elements in the list are the co-ordinates of points on the earth.
From your question, it's hard to tell how you want to measure the distance, so I simply assume you mean Euclidean distance.
You can use the key parameter to min():
from functools import partial
def distance_squared(x, y):
return (x[0] - y[0])**2 + (x[1] - y[1])**2
print min(big_list, key=partial(distance_squared, list_a))
Assumptions:
You intend to make this type query more than once on the same list of lists
Both the query list and the lists in your list of lists represent points in a n-dimensional euclidean space (here: a 2-dimensional space, unlike GPS positions that come from a spherical space).
This reads like a nearest neighbor search. Probably you should take into consideration a library dedicated for this, like scikits.ann.
Example:
import scikits.ann as ann
import numpy as np
k = ann.kdtree(np.array(big_list))
indices, distances = k.knn(list_a, 1)
This uses euclidean distance internally. You should make sure, that the distance measure you apply complies your idea of proximity.
You might also want to have a look on Quadtree, which is another data structure that you could apply to avoid the brute force minimum search through your entire list of lists.
Having not worked with cartesian graphs since high school, I have actually found a need for them relevant to real life. It may be a strange need, but I have to allocate data to points on a cartesian graph, that will be accessible by calling cartesian coordinates. There needs to be infinite points on the graphs. For Eg.
^
[-2-2,a ][ -1-2,f ][0-2,k ][1-2,p][2-2,u]
[-2-1,b ][ -1-1,g ][0-1,l ][1-1,q][1-2,v]
<[-2-0,c ][ -1-0,h ][0-0,m ][1-0,r][2-0,w]>
[-2--1,d][-1--1,i ][0--1,n][1-1,s][2-1,x]
[-2--2,e][-1--2,j ][0--2,o][1-2,t][2-2,y]
v
The actual values aren't important. But, say I am on variable m, this would be 0-0 on the cartesian graph. I need to calculate the cartesian coordinates for if I moved up one space, which would leave me on l.
Theoretically, say I have a python variable which == ("0-1"), I believe I need to split it at the -, which would leave x=0, y=1. Then, I would need to perform (int(y)+1), then re-attach x to y with a '-' in between.
What I want to be able to do is call a function with the argument (x+1,y+0), and for the program to perform the above, and then return the cartesian coordinate it has calculated.
I don't actually need to retrieve the value of the space, just the cartesian coordinate. I imagine I could utilise re.sub(), however I am not sure how to format this function correctly to split around the '-', and I'm also not sure how to perform the calculation correctly.
How would I do this?
To represent an infinite lattice, use a dictionary which maps tuples (x,y) to values.
grid[(0,0)] = m
grid[(0,1)] = l
print(grid[(0,0)])
I'm not sure I fully understand the problem but I would suggest using a list of lists to get the 2D structure.
Then to look up a particular value you could do coords[x-minX][y-minY] where x,y are the integer indices you want, and minX and minY are the minimum values (-2 in your example).
You might also want to look at NumPy which provides an n-dim object array type that is much more flexible, allowing you to 'slice' each axis or get subranges. The NumPy documentation might be helpful if you are new to working with arrays like this.
EDIT:
To split a string like 0-1 into the constituent integers you can use:
s = '0-1'
[int(x) for x in s.split('-')]
You want to create a bidirectional mapping between the variable names and the coordinates, then you can look up coordinates by variable name, apply your function to it, then find the next variable using the new set of coordinates produced by your function.
Mapping between numeric tuples you can apply your function to, and strings usable as keys in a dict, and back, is easy.