Attributes and views¶
Attributes are arbitrary metadata on graph entities. Views expose graph state as dataframe-like tables.
In [1]:
Copied!
import annnet as an
import annnet as an
Build a graph with metadata¶
In [2]:
Copied!
G = an.AnnNet(directed=True)
G.add_vertices(['A', 'B', 'C', 'D', 'E'])
G.add_edges('A', 'B', edge_id='e1', weight=1.0)
G.add_edges('A', 'B', edge_id='e1_backup', weight=0.65)
G.add_edges('B', 'C', edge_id='e2', weight=2.0)
G.add_edges('C', 'D', edge_id='e3', weight=1.5)
G.add_edges('C', 'E', edge_id='complex_ce', directed=False, weight=0.8)
G.attrs.set_vertex_attrs('A', label='alpha', tier=1)
G.attrs.set_vertex_attrs_bulk(
{
'B': {'label': 'beta', 'tier': 1},
'C': {'label': 'gamma', 'tier': 2},
'D': {'label': 'delta', 'tier': 2},
'E': {'label': 'epsilon', 'tier': 2},
}
)
G.attrs.set_edge_attrs_bulk(
{
'e1': {'interaction': 'activation', 'confidence': 0.90},
'e1_backup': {'interaction': 'activation', 'confidence': 0.65},
'e2': {'interaction': 'inhibition', 'confidence': 0.70},
'e3': {'interaction': 'activation', 'confidence': 0.95},
'complex_ce': {'interaction': 'binding', 'confidence': 0.85},
}
)
G.uns['study'] = 'demo'
G = an.AnnNet(directed=True)
G.add_vertices(['A', 'B', 'C', 'D', 'E'])
G.add_edges('A', 'B', edge_id='e1', weight=1.0)
G.add_edges('A', 'B', edge_id='e1_backup', weight=0.65)
G.add_edges('B', 'C', edge_id='e2', weight=2.0)
G.add_edges('C', 'D', edge_id='e3', weight=1.5)
G.add_edges('C', 'E', edge_id='complex_ce', directed=False, weight=0.8)
G.attrs.set_vertex_attrs('A', label='alpha', tier=1)
G.attrs.set_vertex_attrs_bulk(
{
'B': {'label': 'beta', 'tier': 1},
'C': {'label': 'gamma', 'tier': 2},
'D': {'label': 'delta', 'tier': 2},
'E': {'label': 'epsilon', 'tier': 2},
}
)
G.attrs.set_edge_attrs_bulk(
{
'e1': {'interaction': 'activation', 'confidence': 0.90},
'e1_backup': {'interaction': 'activation', 'confidence': 0.65},
'e2': {'interaction': 'inhibition', 'confidence': 0.70},
'e3': {'interaction': 'activation', 'confidence': 0.95},
'complex_ce': {'interaction': 'binding', 'confidence': 0.85},
}
)
G.uns['study'] = 'demo'
Query attributes¶
In [3]:
Copied!
edge_names = {
row['edge_id']: f"{row['source']} -> {row['target']}"
if row['directed']
else f"{row['source']} -- {row['target']}"
for row in G.views.edges().iter_rows(named=True)
}
activation_edges = G.attrs.get_edges_by_attr('interaction', 'activation')
print('A attrs:', G.attrs.get_vertex_attrs('A'))
print('activation edges:', [edge_names[eid] for eid in sorted(activation_edges)])
print('graph attrs:', G.attrs.get_graph_attributes())
edge_names = {
row['edge_id']: f"{row['source']} -> {row['target']}"
if row['directed']
else f"{row['source']} -- {row['target']}"
for row in G.views.edges().iter_rows(named=True)
}
activation_edges = G.attrs.get_edges_by_attr('interaction', 'activation')
print('A attrs:', G.attrs.get_vertex_attrs('A'))
print('activation edges:', [edge_names[eid] for eid in sorted(activation_edges)])
print('graph attrs:', G.attrs.get_graph_attributes())
A attrs: {'label': 'alpha', 'tier': 1}
activation edges: ['A -> B', 'A -> B', 'C -> D']
graph attrs: {'study': 'demo'}
View tables¶
In [4]:
Copied!
G.views.vertices()
G.views.vertices()
Out[4]:
shape: (5, 3)
| vertex_id | label | tier |
|---|---|---|
| str | str | i64 |
| "A" | "alpha" | 1 |
| "B" | "beta" | 1 |
| "C" | "gamma" | 2 |
| "D" | "delta" | 2 |
| "E" | "epsilon" | 2 |
In [5]:
Copied!
G.views.edges().select(
['edge_id', 'source', 'target', 'interaction', 'confidence']
)
G.views.edges().select(
['edge_id', 'source', 'target', 'interaction', 'confidence']
)
Out[5]:
shape: (5, 5)
| edge_id | source | target | interaction | confidence |
|---|---|---|---|---|
| str | str | str | str | f64 |
| "e1" | "A" | "B" | "activation" | 0.9 |
| "e1_backup" | "A" | "B" | "activation" | 0.65 |
| "e2" | "B" | "C" | "inhibition" | 0.7 |
| "e3" | "C" | "D" | "activation" | 0.95 |
| "complex_ce" | "C" | "E" | "binding" | 0.85 |
Visual check¶
The drawing uses node IDs for readability and annotates edges with compact numeric weights plus the selected edge metadata.
In [6]:
Copied!
from annnet.utils import plotting
plotting.plot(
G,
backend='graphviz',
show_edge_labels=True,
edge_label_keys=['interaction'],
)
from annnet.utils import plotting
plotting.plot(
G,
backend='graphviz',
show_edge_labels=True,
edge_label_keys=['interaction'],
)
Out[6]:
Reserved keys are protected¶
In [7]:
Copied!
try:
G.attrs.set_edge_attrs('e1', source='X')
except ValueError as err:
print('caught:', err)
try:
G.attrs.set_edge_attrs('e1', source='X')
except ValueError as err:
print('caught:', err)
caught: edge attributes use reserved key(s): ['source']. These names are part of the structural / dispatch contract; rename your attribute(s) to use a different key.
Views are the inspection layer for the same annotated graph object; no separate table has to be kept in sync.