Concept

Concept#

EdgeGraph’s concept of operations is vertex-edge graphs implemented with object-oriented programming (OOP). It represents vertices (and edges) as first-class objects, which brings several advantages over more common, quick-to-implement approaches such as dictionaries or matricies:

  • Vertices can have arbitrary attributes, assigned on-the-fly, without any changes in graph handling code

  • Edges can also have arbitrary attributes, again assigned on-the-fly, without any changes in graph handling code

  • Every vertex carries with it full information of edges that interact with it (outbound and inbound)

  • Every edge carries with it full information of the vertices it connects

  • Vertices may be members of multiple graphs (EdgeGraph calls them Universes)

  • Vertices (and edges) can be inherited from with ease in a program that uses EdgeGraph, automatically making program data into a fully-fledged graph with no extra effort

The last bullet is really the true selling point of EdgeGraph. All of the traversal, graph-building, rendering, etc. functionality works with subclasses of Vertex – all you need to do is subclass that, and now you have a graph backend.

However, no lunch is free, so keep these points in mind. I haven’t benchmarked EdgeGraph against the more famed graph libraries for Python (NetworkX and co), so I don’t have hard numbers to give you yet. I do expect, though:

  • OOP approaches may consume more memory to represent the same graph structure as non-OOP methods

  • OOP approaches may consume more processing time to operate on than non-OOP methods

  • EdgeGraph is not application-specific. If you have existing knowledge of the data structure your application trends towards, EdgeGraph has no idea and won’t be able to take advantage of it. However, it does provide the building blocks to create your own traversal functions quickly.

For example, consider an application that represents many interlinked pieces of data:

 1#!python3
 2
 3from edgegraph.structure import Vertex
 4from edgegraph.builder import explicit
 5from edgegraph.traversal import breadthfirst
 6
 7class MyData (Vertex):
 8    '''
 9    Represents a piece of data.
10    '''
11
12    def __init__(self, value):
13        '''
14        Set up this piece of data.
15        '''
16        super().__init__(attributes={'value': value})
17
18def load_data():
19    d1 = MyData(1)
20    d2 = MyData(5)
21    d3 = MyData(100)
22
23    explicit.link_directed(d1, d2)
24    explicit.link_directed(d1, d3)
25    explicit.link_directed(d3, d2)
26
27    return Universe(vertices=[d1, d2, d3]), d1
28
29def main():
30    uni, d1 = load_data()
31
32    print(breadfirst.bft(uni, d1))
33
34if __name__ == '__main__':
35    main()

There it is – a complete example of loading some (admittedly, small) data and doing a bread-first traversal. Note that

  1. We defined our own data type

  2. We used it as a vertex in a graph

  3. We used an out-of-the-box traversal on a graph of our own data type

  4. No traversal code was implemented here

and yet, we have all the benefits of a graph backend.