Purpose: demonstrate using dj.AttributeAdapter for convenient storage of arbitrary data types in DataJoint table attributes.
Imagine I want store graph objects of type networkx.Graph in the form of edge lists.
First, let’s create a few graphs:
%matplotlib inline
from matplotlib import pyplot as plt
import networkx as nx
graphs = [nx.lollipop_graph(4, 2), nx.star_graph(5), nx.barbell_graph(3, 1), nx.cycle_graph(5)]
fig, axx = plt.subplots(1, len(graphs) , figsize=(15, 3))
for g, ax in zip(graphs, axx.flatten()):
plt.sca(ax)
nx.draw(g)
import numpy as npThen we need to define an adapter object that convert target objects into an attribute type that datajoint can already store. The class must subclass dj.AttributeAdapter and define the property attribute_type, and methods get and put. These methods translate the adapted data type nx.Graph into a representation that can be stored in datajoint, a longblob storing the edge list.
import datajoint as dj
class GraphAdapter(dj.AttributeAdapter):
attribute_type = 'longblob' # this is how the attribute will be declared
def put(self, obj):
# convert the nx.Graph object into an edge list
assert isinstance(obj, nx.Graph)
return list(obj.edges)
def get(self, value):
# convert edge list back into an nx.Graph
return nx.Graph(value)
# instantiate for use as a datajoint type
graph = GraphAdapter()Now we can define a table that uses graph as its attribute type. These “adapted types” must be enclosed in angle brackets as in <graph>:
schema = dj.schema('test_graphs')
schema.drop() # drop previous contents
schema = dj.schema('test_graphs') # create de novoConnecting dbadmin@dimitri-proj0.cda95qzjbnvs.us-east-1.rds.amazonaws.com:3306
Proceed to delete entire schema `test_graphs`? [yes, No]: yes
# The following is necessary in DataJoint version 0.12.*
# while adapted types are in beta testing.
dj.errors._switch_adapted_types(True) @schema
class Connectivity(dj.Manual):
definition = """
conn_id : int
---
conn_graph = null : <graph> # a networkx.Graph object
"""Connectivity.describe();conn_id : int
---
conn_graph=null : <graph> # a networkx.Graph object
Now, populate the table with our example graphs and fetch them as objects¶
Inserting the graphs as objects
Connectivity.insert((i, g) for i, g in enumerate(graphs))We can now fetch the graphs as an array of objects and plot them to verify successful recovery.
result = Connectivity.fetch('conn_graph', order_by='conn_id')
fig, axx = plt.subplots(1, result.size, figsize=(15, 3))
for g, ax in zip(result, axx.flatten()):
plt.sca(ax)
nx.draw(g)