Search code examples
python-3.xgraph-tool

graph-tool: edge property cannot be set to type 'object'


I have worked with networkx and am trying graph-tool for potentially better performance. Working through the documentation I wish to create edges with properties. In networkx I can do something like this for some graph G:

G.add_edge(vertex_1, vertex_2, attr_dict={python dict of 'property: value'})

I wanted to do the same in graph-tool. From the docs I tried the example with a slight change in that one of the properties in a python dict instead of an int:

edge_list = [(0, 1, .3, {'name':'hello'}), (2, 3, .1,  {'name':'good'}), (2, 0, .4,  {'name':'by'})]
g = gt.Graph()
eweight = g.new_ep("double")
elayer = g.new_ep("object")
g.add_edge_list(edge_list, eprops=[eweight, elayer])
print(eweight.a)
print(elayer.a)
g.get_edges()

OUTPUT:

[0.3 0.1 0.4]
None
array([[0, 1],
       [2, 3],
       [2, 0]])

I can see that the edges were entered correctly why is 'None' returned for the 'elayer' property?

UPDATE:

I have looked at the Property Map docs and the example there looks like this:

eprop_dict = g.new_edge_property("object")                # Arbitrary Python object.
e = g.edges().next()
eprop_dict[e] = {"foo": "bar", "gnu": 42}                 # In this case, a dict.

Also had a look at the source code.


Solution

  • Let's look at what the documentation tells us:

    help(elayer)
    

    This gives us:

    a
        Shortcut to the :meth:`~PropertyMap.get_array` method
        as an attribute. This makes assignments more convenient, e.g.:
            
        >>> g = gt.Graph()
        >>> g.add_vertex(10)
        <...>
        >>> prop = g.new_vertex_property("double")
        >>> prop.a = np.random.random(10)           # Assignment from array
    

    Now let us look at the documentation of PropertyMap.get_array:

    help(elayer.get_array)
    
    
    get_array() method of graph_tool.EdgePropertyMap instance
        Get a :class:`numpy.ndarray` subclass (:class:`~graph_tool.PropertyArray`)
        with the property values.
        
        .. note::
        
           An array is returned *only if* the value type of the property map is
           a scalar. For vector, string or object types, ``None`` is returned
           instead. For vector and string objects, indirect array access is
           provided via the :func:`~graph_tool.PropertyMap.get_2d_array()` and
           :func:`~graph_tool.PropertyMap.set_2d_array()` member functions.
    

    The note above answers your question: the array interface is provided only for scalar types, not arbitrary python objects.

    For arbitrary types, assignment and lookup of properties is still possible using the standard interface based on edge descriptors, e.g.:

    for e in g.edges():
        print(elayer[e])
    

    which gives you

    {'name': 'hello'}
    {'name': 'good'}
    {'name': 'by'}