Attributes
anet.attrs holds all attributes of a graph, at eight addresses: nodes,
edges, slices, aspects, layers, edge_slices, node_layers and
elementary_layers. You read and write each address the same way:
- a read (
nodes,table,row,rows) gives a copy; - a write is a named call (
update,replace,delete); selectis a live query, andfrom_framemakes a fixed selection from the rows of a table that you filtered yourself.
anet.attrs is an Attrs object. select and from_frame give a
RowSelection, and schema gives a Schema. The
annotations guide shows the use.
Addresses
An address is the thing that a set of attributes belongs to. Each address has its key:
| address | key | key columns in a table |
|---|---|---|
nodes |
node_id |
node_id |
edges |
edge_id |
edge_id |
slices |
slice_id |
slice_id |
aspects |
aspect |
aspect |
layers |
layer coordinate tuple | layer |
edge_slices |
(slice_id, edge_id) |
slice_id, edge_id |
node_layers |
(node_id, layer) |
node_id, layer |
elementary_layers |
(aspect, label) |
aspect, elementary_layer |
# Read: each call gives a copy. A change to the copy does not change the graph.
anet.attrs.nodes # the table of one address; one property for each address
anet.attrs.table('nodes', derived=False, backend=None, columns=None, limit=None, layout=None)
anet.attrs.row('nodes', key) # one row, as a dict
anet.attrs.rows('nodes', keys=None) # {key: dict}
anet.attrs.schema('nodes') # the keys and fields, without a table
# Write
anet.attrs.update('nodes', {key: {...}, ...}) # merge the given fields
anet.attrs.replace('nodes', table) # replace all attributes of the address
anet.attrs.delete('nodes', keys=None, names=None) # remove attributes
# Select
anet.attrs.select('nodes', score__gte=0.5) # a live selection
anet.attrs.from_frame('nodes', frame) # a fixed selection
anet.attrs has no item access, and you cannot assign to its table
properties. anet.attrs['nodes'] and anet.attrs.nodes = table raise
TypeError, with the name of the call to use.
Rules for writes
- A null value removes the field. If
updategetsNoneor NaN for a field, annnet removes the field from the row. A null cell in a table means the same. -
deleteremoves attributes, never elements. The node, edge, slice or layer stays. The return value is the number of rows that lost an attribute.keysnamesresult given not given remove all attributes of these rows not given given remove these fields from all rows given given remove these fields from these rows not given not given ValueErrorAn empty
keysornamesselects nothing. A name that the address does not have raisesKeyError. -replaceneeds the key columns of the address. A key that the table does not have loses its attributes. A table never adds or removes elements. - A write is all or nothing. annnet checks the full write before it changes anything. If one part fails, the attributes, the fields and their types, and the cached matrices stay as they were. - Reserved fields are refused withValueError: the key columns, and for edgessource,target,head,tail,members,weight,directed,kind,slice,slice_weight,flexibleandedge_type. - Keys are checked. An unknown key raisesKeyError, a key of the wrong shapeTypeError, and a key that occurs two times in one writeValueError. Fornode_layers, give(node_id, layer), or a node ID withlayer=inupdate.
Derived tables
table(address, derived=True) adds what the graph knows about each row. For
edges, these columns: kind (binary, hyper or node_edge), directed,
weight, ml_kind (intra, inter or coupling), source, target,
src_layer, dst_layer, head, tail and members.
With layout='incidences', the table has one row for each endpoint of each
edge: edge_id, position, entity_id, entity_kind, layer, layer_id,
role, coefficient, kind and directed. You can join an endpoint to its
node, layer and edge rows without parsing.
limit= builds that number of rows and no more: use it for a preview, not as
a selection. The arguments slice=, in_slice=, layer=, include_hyper=,
include_binary=, include_directed=, include_weight= and
resolved_weight= apply to the derived edge table only.
A live query and a filtered table
select is a query on the graph. It keeps its conditions, and gives a new
result after the graph changes. A table from anet.attrs.table is a copy of
one moment. To filter it, use your dataframe library, then make a selection
from the result:
table = anet.attrs.table('nodes')
kept = table.filter(pl.col('score') > 0.5)
chosen = anet.attrs.from_frame('nodes', kept) # a fixed selection
from_frame reads only the key columns. It gives the keys of the frame, in the
order of the address, without repeats. It does not keep the filter: a node
that you add later is not in it. A missing key column or a null key raises
ValueError, an unknown key KeyError.
A selection of node_layers or edge_slices changes into a selection of
another address only with project: select('node_layers', ...).project('nodes'),
select('edge_slices', ...).project('edges') or .project('slices').
annnet.core._attribute_api.Attrs
Every attribute of a graph, at eight addresses (anet.attrs).
See the module docstring for the shape. The reader protocol the selection
machinery uses is the set of underscored methods _domain, _row,
_rows_where, _key, _selection_owner and _root_reader.
Attributes
Functions
row
Return one row as a detached dict.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
address
|
str
|
One of :data: |
required |
key
|
key
|
The key of the row, as the address keys it: a node id, an edge id, a
slice id, an aspect name, a layer coordinate, a |
required |
Returns:
| Type | Description |
|---|---|
dict
|
|
Raises:
| Type | Description |
|---|---|
KeyError
|
For a key the address does not hold (or, on a view, one outside it). |
rows
Return detached row dictionaries keyed by the address's keys.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
address
|
str
|
One of :data: |
required |
keys
|
key | Iterable[key]
|
One key or many. Default: every key of the address. |
None
|
Returns:
| Type | Description |
|---|---|
dict
|
|
schema
Report what an address is keyed by and what it holds, cheaply.
No frame is built and no backing is scanned. The value fields are the names the store holds; their types are read off the column dtype or from the values present.
select
Select the rows of one address that satisfy every condition.
The conditions are the ones anet.N.select takes, over the address's
key columns, its stored fields, and — for the layer-keyed addresses —
the declared aspects, compared by their order when ordered. Keys are
kept as the address keys them; see :meth:RowSelection.project.
project_keys
The ids of target named by the rows, deduplicated in this reader's order.
update
Merge attribute rows at one address, all of them or none.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
address
|
str
|
One of :data: |
required |
updates
|
Mapping[key, Mapping[str, Any]] | Iterable[tuple[key, Mapping]]
|
The rows to merge. A field set to |
required |
layer
|
tuple
|
|
None
|
key
|
str
|
|
None
|
Returns:
| Type | Description |
|---|---|
int
|
The number of rows written. |
Raises:
| Type | Description |
|---|---|
KeyError
|
For a key the address does not hold. Nothing is written. |
ValueError
|
For a reserved field, a duplicate key or a composite-key collision. |
TypeError
|
For a row that is not a mapping or a value of the wrong type. |
Notes
Everything is checked before the first cell changes, and a failure
inside the commit — a flexible-direction policy raising after it has
re-oriented an edge, for instance — rolls back the rows, the
composite-key index and the rewritten incidence columns. See
:mod:annnet.core._transaction.
replace
Replace the attributes of a whole address with the rows of a table.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
address
|
str
|
One of :data: |
required |
table
|
DataFrame - like
|
A table in any supported backend with the address's key columns and one column per attribute. Null cells mean "no such attribute". |
required |
Notes
A key the table omits loses its attributes and keeps its existence: the
nodes, edges, slices and layers themselves are never added or removed
by a table. The table is validated whole before anything changes, and
the old attributes are restored if the write fails. Use :meth:update
to change some fields of some rows.
Raises:
| Type | Description |
|---|---|
ValueError
|
For a missing key column, a null or duplicate key or a reserved field. |
KeyError
|
For a key the address does not hold. |
delete
Remove attributes, never the structure that carries them.
================ ======================================================
keys names
================ ======================================================
given omitted: clear every attribute of those rows
omitted given: drop those fields from every row of the address
given given: drop those fields from those rows
omitted omitted: :class:ValueError, never "everything"
================ ======================================================
An explicit empty keys or names selects nothing and does nothing.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
address
|
str
|
One of :data: |
required |
keys
|
key | Iterable[key] | RowSelection
|
The rows, keyed as the address keys them. |
None
|
names
|
str | Iterable[str]
|
The attribute fields. |
None
|
Returns:
| Type | Description |
|---|---|
int
|
The number of rows that lost at least one attribute. |
Raises:
| Type | Description |
|---|---|
ValueError
|
When neither |
KeyError
|
For a key the address does not hold, or a name the address has no such attribute for. |
from_frame
Select the rows of a frame, by the keys it names.
Read a table, filter it with the dataframe library it came in, and pass what is left here to get a selection of the graph's own keys::
table = anet.attrs.table('nodes')
kept = table.filter(pl.col('score') > 0.5)
chosen = anet.attrs.from_frame('nodes', kept)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
address
|
str
|
One of :data: |
required |
frame
|
DataFrame - like
|
Any supported backend. Only the address's key columns are read. |
required |
Returns:
| Type | Description |
|---|---|
RowSelection
|
A selection of exactly those keys, in the address's own order and without repeats. It is fixed: it is the identities the frame named, not the condition that produced the frame, so a key added later is not picked up, and a key that is removed and added again is the same key. An empty frame gives an empty selection. |
Raises:
| Type | Description |
|---|---|
ValueError
|
For a missing key column or a null key. |
KeyError
|
For a key the address does not hold (or, on a view, one outside it). |
table
Render one address as a table, stored or derived.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
address
|
str
|
One of :data: |
required |
derived
|
bool
|
|
False
|
backend
|
str
|
One of the dataframe backends; defaults to :attr: |
None
|
columns
|
Iterable[str]
|
Keep only these value columns. The key columns are always kept. |
None
|
limit
|
int
|
Keep only the first |
None
|
layout
|
('edges', 'incidences')
|
|
"edges"
|
**query
|
Derived-table arguments: |
{}
|
Returns:
| Type | Description |
|---|---|
DataFrame - like
|
A caller-owned frame; editing it changes nothing. |
annnet.core._attribute_api.Schema
annnet.core._select.RowSelection
The rows of one attribute address that satisfy a query, keyed as the address keys them.
Built by anet.attrs.select / V.attrs.select. It keeps the full keys —
a node-layer row keeps its (node_id, layer) — until :meth:project is
called. It is live: .keys re-evaluates the query against the graph as
it is now, each leaf inside the scope it was asked in. Two selections of
the same address on the same graph combine with &, | and -;
the result keeps the address's own order.
Attributes
Functions
project
Project the selected rows onto one axis of their keys.
node_layers rows project to nodes; edge_slices rows project
to edges or slices. The projection is existential — an element
is selected when at least one matching row names it — and it keeps the
target axis's order with duplicates removed. It does not say "in every
slice"; that is a reduction over the frame, not a selection.
Returns:
| Type | Description |
|---|---|
NodeSequence | EdgeSequence | SliceSelection
|
A live selection of the target axis, in the scope of this selection. |
Predicates
All select calls (anet.N.select, anet.E.select, anet.attrs.select,
anet.layers.where) take the same conditions: field=value, or
field__operator=value. The operators are eq, ne, in, not_in, lt,
lte, gt, gte and isnull.
- A null value matches only
isnull=True. - An ordered aspect compares labels in their declared order. An ordering
operator on a categorical aspect raises
ValueError. - An unknown field raises
KeyError. Values that cannot be compared raiseTypeError. - For a field name that contains
__, give a mapping with(field, operator)keys.
annnet.core._predicate
The one predicate engine every selection surface shares.
anet.N.select(score__gt=0.5), anet.E.select(kind='hyper'),
anet.attrs.select('node_layers', score__gte=0.8) and
anet.layers.where(time__lte='12h') are four spellings of one question: which
rows of this axis satisfy these conditions. They parse the conditions here,
evaluate them here, and report a bad field, operator or value the same way.
A condition is field=value (equality) or field__operator=value with one
of :data:OPERATORS. A literal field whose own name contains __ wins over
suffix parsing, and a positional mapping may use explicit (field, operator)
keys where a keyword would be ambiguous.
Null handling is one rule everywhere: a missing value — None or a float
NaN — is excluded by every comparison, including ne and not_in, and
selected only by an explicit field__isnull=True.
An ordered aspect compares by its declared order, through order=; a
categorical aspect refuses the four ordering operators. A numeric attribute
compares numerically. Two values that cannot be compared raise, naming the
field and the operator, rather than silently dropping the row.
Attributes
OPERATORS
module-attribute
Functions
parse_conditions
Parse conditions into :class:Condition triples.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
conditions
|
Mapping
|
A positional mapping. A key is a keyword as below, or an explicit
|
None
|
fields
|
Iterable[str]
|
The fields the axis knows. A field that is not one of them raises,
naming the known fields. A field whose name holds |
None
|
noun
|
str
|
What a field is called in the error message ( |
"field"
|
**keywords
|
|
{}
|
Returns:
| Type | Description |
|---|---|
list[Condition]
|
|
Raises:
| Type | Description |
|---|---|
KeyError
|
If a field is not one of |
ValueError
|
If an operator is not one of :data: |
TypeError
|
If the value does not fit the operator (a membership operator needs a
collection, |