Network graphs

TODO: Import the graph tooling documentation into this documentation:


class followthemoney.graph.Graph(edge_types={<iban>, <identifier>, <url>, <ip>, <phone>, <checksum>, <entity>, <address>, <name>, <email>})

A set of nodes and edges, derived from entities and their properties. This represents an alternative interpretation of FtM data as a property graph.

This class is meant to be extensible in order to support additional backends, like Aleph.


Add an EntityProxy to the graph and make it either a Node or an Edge.


Remove all nodes, edges and proxies from the graph.

get_adjacent(node, prop=None)

Get all adjacent edges of the given node.

get_inbound(node, prop=None)

Get all edges pointed at the given node.

get_outbound(node, prop=None)

Get all edges pointed out from the given node.


Iterate all edges in the graph.


Iterate all nodes in the graph.

queue(id_, proxy=None)

Register a reference to an entity in the graph.

property queued

Return a list of all the entities which are referenced from the graph but that haven’t been loaded yet. This can be used to get a list of entities that should be included to expand the whole graph by one degree.


Return a dictionary with the graph nodes and edges.

class followthemoney.graph.Node(type_, value, proxy=None, schema=None)

A node represents either an entity that can be rendered as a node in a graph, or as a re-ified value, like a name, email address or phone number.

property caption

A user-facing label for the current node.

classmethod from_proxy(proxy)

For a given EntityProxy, return a node based on the entity.

property is_entity

Check to see if the node represents an entity. If this is false, the node represents a non-entity property value that has been reified, like a phone number or a name.


Return a simple dictionary to reflect this graph node.

class followthemoney.graph.Edge(graph, source, target, proxy=None, prop=None, value=None)

A link between two nodes.

property source

The graph node from which the edge originates.

property source_prop

Get the entity property originating this edge.

property target

The graph node to which the edge points.

property target_prop

Get the entity property originating this edge.

property type_name

Return a machine-readable descripton of the type of the edge. This is either a property name or a schema name.


How entities are translated to a graph

Below are some notes about the semantics of followthemoney (FtM) as a graph, and how it might be converted to a (Neo4J-style) property graph model. This is how we’ve been thinking about it in the past, and we can change it, but it would almost certainly require adaptation of the FtM model and the complete re-generation of all Aleph data from scratch to do cleanly.

  1. The normal case for what a link is in FtM is a property value (see References). When turning this into a property graph model, both the Passport and the Person become nodes, and the holder property becomes an edge with no attributes attached to it.

  2. Sometimes we want to talk about the inverse of one of these edges. That’s why holder has an inverse, passports that is added to the Person schema. This is mostly used to store the labels that should be used to talk about the passports linked to a person. But it’s a stub that cannot be written.

  3. The weakness of this model is that edges don’t have properties, whereas relationships in society always have metadata :) Many of them are limited in time (hence Interval). So we added a work-around that allows some schema to sort of contract upon generating a property graph and turn into an edge, rather than a node. For example, Membership, Ownership. But it’s important to keep considering this a special shortcut, not the normal case for edges in FtM.

  4. Because this is a work-around, it leaves the stub properties in a bit of an awkward place: it’s not clear conceptually if they refer to the original edge (e.g. a link between a Person.directorshipsDirector -> Directorship.director) or the contracted edge (Person -> directorOf -> Organization)… It’s not been a problem in practice as we get the required metadata from the edge annotation of the contracted schema, but it’s a sort of weird “place”.