Typed groves (BED / GFF)#

The schema-typed groves BedGrove (grove<genomic_coordinate, bed_entry>) and GffGrove (grove<genomic_coordinate, gff_entry>), their key and result wrappers, and the structured record types they carry. See the User Guide for usage.

Groves#

class pygenogrove.BedGrove#

Bases: pybind11_object

A B+ tree container for efficient genomic interval storage and querying.

The grove supports multi-index operations, where each index (e.g., chromosome) maintains its own B+ tree structure.

Parameters:

order (int, optional) – Maximum branching factor of the B+ tree (default: 3, minimum: 3). Controls the maximum number of keys per node (order - 1).

add_edge(self: pygenogrove.BedGrove, source: pygenogrove.BedKey, target: pygenogrove.BedKey) None#

Add a directed edge from source to target.

source and target must be Keys belonging to this Grove (returned by insert(), add_external_key(), or yielded by a QueryResult). Raises TypeError if either is None.

add_external_key(self: pygenogrove.BedGrove, key: pygenogrove.GenomicCoordinate, data: pygenogrove.BedEntry) pygenogrove.BedKey#

Add a key (coordinate + data) that lives outside the B+ tree index but can participate in the graph overlay.

Both the key and the data are copied into the Grove. Returns a stable Key that remains valid as long as the Grove is alive. External keys are not returned by intersect() queries. On the universal Grove the data defaults to None.

clear_graph(self: pygenogrove.BedGrove) None#

Remove all edges from the graph overlay. The keys themselves are left intact.

compact(self: pygenogrove.BedGrove) None#

Reclaim the dead storage slots left by remove_key() (storage shrinks to exactly the live key count).

WARNING: this INVALIDATES every Key previously returned for this grove’s indexed keys (by insert(), insert_bulk(), or yielded from intersect()/flanking()) — they become dangling and must NOT be used afterward (doing so is undefined behaviour). After compact(), re-discover keys via a fresh intersect()/flanking() query. Keys from add_external_key() are NOT affected.

static deserialize(path: str) pygenogrove.BedGrove#

Load a Grove previously written with serialize(). Returns a new Grove with the same intervals, associated data, and graph edges.

edge_count(self: pygenogrove.BedGrove) int#

Total number of directed edges in the graph overlay.

external_vertex_count(self: pygenogrove.BedGrove) int#

Number of external (graph-only) keys — those added with add_external_key(), not indexed in any B+ tree.

flanking(*args, **kwargs)#

Overloaded function.

  1. flanking(self: pygenogrove.BedGrove, query: pygenogrove.GenomicCoordinate, index: str) -> pygenogrove.BedFlankingResult

    Find the nearest non-overlapping keys on either side of the query within an index (the predecessor and successor).

    Returns a FlankingResult with .predecessor / .successor, each a Key or None. Keys that overlap the query are excluded; for nested intervals the predecessor is the one with the largest end (smallest gap), not the sort-order maximum. Compute the gap distance from the returned key, e.g. query.start - result.predecessor.value.end - 1.

  2. flanking(self: pygenogrove.BedGrove, query: pygenogrove.GenomicCoordinate, index: str, is_compatible: Callable[[pygenogrove.GenomicCoordinate, pygenogrove.GenomicCoordinate], bool]) -> pygenogrove.BedFlankingResult

    flanking(query, index, is_compatible) -> FlankingResult

    Predicate-filtered flanking: like flanking(query, index), but only candidate keys for which is_compatible(candidate, query) returns True are considered as neighbours. candidate and query are key values (e.g. GenomicCoordinate); the predicate is applied at every leaf candidate before the overlap/distance checks.

    The canonical use is strand-aware neighbours on a GenomicCoordinateGrove — the nearest non-overlapping key on the same strand:

    g.flanking(q, “chr1”,

    lambda cand, q: cand.strand == q.strand)

    (Internal-node pruning ignores the predicate, so subtrees holding only incompatible keys are still traversed and filtered at the leaves — correct, just not pruned. Exceptions raised by the predicate propagate out.)

get_neighbors(self: object, source: pygenogrove.BedKey) list#

Return the list of target Keys directly reachable from source.

The returned Keys point into this Grove’s storage and remain valid only while the Grove is alive.

get_order(self: pygenogrove.BedGrove) int#

Get the order (branching factor) of the B+ tree

graph_empty(self: pygenogrove.BedGrove) bool#

Return True if the graph overlay holds no edges.

has_edge(self: pygenogrove.BedGrove, source: pygenogrove.BedKey, target: pygenogrove.BedKey) bool#

Return True if a directed edge from source to target exists.

indexed_vertex_count(self: pygenogrove.BedGrove) int#

Number of indexed intervals (B+ tree leaf keys)

insert(*args, **kwargs)#

Overloaded function.

  1. insert(self: pygenogrove.BedGrove, index: str, key: pygenogrove.GenomicCoordinate, data: pygenogrove.BedEntry) -> pygenogrove.BedKey

    Insert a key with an associated data payload at the given index.

    indexstr

    The index name (e.g., chromosome name like “chr1”)

    keyGenomicCoordinate

    The key (copied into the grove). Drives B+ tree ordering — do not mutate it after insertion.

    dataobject

    The associated data payload (copied into the grove). On the universal Grove this is any JSON-serializable value (dict / list / scalar / None) and defaults to None.

    Key

    Stable reference to the inserted key.

  2. insert(self: pygenogrove.BedGrove, index: str, entry: pygenogrove.BedEntry) -> pygenogrove.BedKey

    insert(index, entry) -> Key

    Overload that takes a single file entry and derives the GenomicCoordinate key from its native coordinates + strand (BED half-open [s, e) -> [s, e-1]; GFF 1-based [s, e] -> [s-1, e-1]; strand from the BED6/GFF strand column, or ‘.’ if absent). The entry keeps its native coordinates as the payload.

insert_bulk(*args, **kwargs)#

Overloaded function.

  1. insert_bulk(self: object, index: str, items: list[tuple[pygenogrove.GenomicCoordinate, pygenogrove.BedEntry]], presorted: bool = False) -> list

    Bulk-insert many (interval, data) records at once. 10-20x faster than repeated insert() for large datasets — an empty index is built bottom-up in O(n); a non-empty index appends.

    indexstr

    The index name (e.g., chromosome name).

    itemslist[tuple[Interval, object]]

    The (interval, data) records to insert.

    presortedbool, optional

    If False (default) the records are sorted by interval first. If True, they are assumed already sorted ascending (skips the sort — fastest).

    list[Key]

    Stable key handles, in insertion (sorted) order.

    PRECONDITION (appending to a non-empty index): every inserted interval must be greater than every existing interval in the index. Violating this corrupts B+ tree ordering.

  2. insert_bulk(self: object, index: str, entries: list[pygenogrove.BedEntry], presorted: bool = False) -> list

    insert_bulk(index, entries, presorted=False) -> list[Key]

    Overload that takes a list of bare file entries (instead of (GenomicCoordinate, data) tuples) and derives each GenomicCoordinate key from the entry’s native coordinates + strand. Same append precondition as the explicit form.

insert_sorted(self: pygenogrove.BedGrove, index: str, interval: pygenogrove.GenomicCoordinate, data: pygenogrove.BedEntry) pygenogrove.BedKey#

Insert one (interval, data) record on the optimized sorted path (rightmost-append, no tree traversal).

PRECONDITION: the interval must be greater than every interval already present in this index. Insert in ascending order. Violating this corrupts B+ tree ordering (queries silently return wrong results). Use plain insert() if unsure.

intersect(*args, **kwargs)#

Overloaded function.

  1. intersect(self: pygenogrove.BedGrove, query: pygenogrove.GenomicCoordinate) -> pygenogrove.BedQueryResult

    Find all intervals that overlap with the query across all indices.

  2. intersect(self: pygenogrove.BedGrove, query: pygenogrove.GenomicCoordinate, index: str) -> pygenogrove.BedQueryResult

    Find all intervals that overlap with the query in a specific index.

key_storage_size(self: pygenogrove.BedGrove) int#

Total slots in the indexed-key storage: live leaf data keys + internal B+ tree separator keys + dead slots left behind by remove_key(). Grows across insert/remove cycles until compact() reclaims the dead slots — so it is >= indexed_vertex_count().

link_if(keys, predicate) -> None

Add an (unlabelled) directed edge between each adjacent pair (keys[i], keys[i+1]) for which predicate(keys[i], keys[i+1]) returns True. keys is typically the list returned by a bulk insert; the predicate receives two Keys. Use link_with() to attach edge metadata.

out_degree(self: pygenogrove.BedGrove, source: pygenogrove.BedKey) int#

Number of outgoing edges from source.

remove_all_edges(self: pygenogrove.BedGrove, key: pygenogrove.BedKey) int#

Remove every edge touching key, incoming and outgoing. Returns the total number removed.

remove_edge(self: pygenogrove.BedGrove, source: pygenogrove.BedKey, target: pygenogrove.BedKey) bool#

Remove the directed edge from source to target. Returns True if an edge was removed, False if it did not exist.

remove_edges_from(self: pygenogrove.BedGrove, source: pygenogrove.BedKey) int#

Remove all outgoing edges from source. Returns the number removed.

remove_edges_if(self: pygenogrove.BedGrove, predicate: Callable[[pygenogrove.BedKey], bool]) int#

remove_edges_if(predicate) -> int

Remove every edge whose target satisfies predicate(target: Key) -> bool, returning the number removed. (This grove’s edges carry no metadata, so the predicate gets only the target Key; the universal Grove also passes the edge metadata.)

remove_edges_to(self: pygenogrove.BedGrove, target: pygenogrove.BedKey) int#

Remove all incoming edges to target (O(E) scan over the graph). Returns the number removed.

remove_key(self: pygenogrove.BedGrove, index: str, key: pygenogrove.BedKey) bool#

Remove a key from the index’s B+ tree, rebalancing as needed.

Returns True if the key was found and removed, False otherwise (including a None key or an unknown index). All graph edges touching the key (incoming and outgoing) are also removed. The key remains in storage as a dead slot (not freed) — other Keys keep their pointers; only compact() reclaims the slot (and invalidates pointers — see its warning).

serialize(self: pygenogrove.BedGrove, path: str) None#

Serialize the Grove (intervals + associated data + graph overlay) to a zlib-compressed binary file at the given path.

size(self: pygenogrove.BedGrove) int#

Number of indexed intervals across all indices (alias of len)

to_sif(self: pygenogrove.BedGrove, path: str) None#

Write the grove to a SIF (Simple Interaction Format) text file for graph visualization (e.g. Cytoscape). Emits the B+ tree structure (nodelink / leaflink lines) and the graph-overlay edges (keylink lines) as tab-separated interactions; an empty grove writes an empty file.

Note: line and index iteration order are not stable across runs.

vertex_count(self: pygenogrove.BedGrove) int#

Total number of keys in the grove: indexed (B+ tree) plus external (graph-only) keys, including isolated ones with no edges.

vertex_count_with_edges(self: pygenogrove.BedGrove) int#

Number of keys that have at least one outgoing edge.

class pygenogrove.GffGrove#

Bases: pybind11_object

A B+ tree container for efficient genomic interval storage and querying.

The grove supports multi-index operations, where each index (e.g., chromosome) maintains its own B+ tree structure.

Parameters:

order (int, optional) – Maximum branching factor of the B+ tree (default: 3, minimum: 3). Controls the maximum number of keys per node (order - 1).

add_edge(self: pygenogrove.GffGrove, source: pygenogrove.GffKey, target: pygenogrove.GffKey) None#

Add a directed edge from source to target.

source and target must be Keys belonging to this Grove (returned by insert(), add_external_key(), or yielded by a QueryResult). Raises TypeError if either is None.

add_external_key(self: pygenogrove.GffGrove, key: pygenogrove.GenomicCoordinate, data: pygenogrove.GffEntry) pygenogrove.GffKey#

Add a key (coordinate + data) that lives outside the B+ tree index but can participate in the graph overlay.

Both the key and the data are copied into the Grove. Returns a stable Key that remains valid as long as the Grove is alive. External keys are not returned by intersect() queries. On the universal Grove the data defaults to None.

clear_graph(self: pygenogrove.GffGrove) None#

Remove all edges from the graph overlay. The keys themselves are left intact.

compact(self: pygenogrove.GffGrove) None#

Reclaim the dead storage slots left by remove_key() (storage shrinks to exactly the live key count).

WARNING: this INVALIDATES every Key previously returned for this grove’s indexed keys (by insert(), insert_bulk(), or yielded from intersect()/flanking()) — they become dangling and must NOT be used afterward (doing so is undefined behaviour). After compact(), re-discover keys via a fresh intersect()/flanking() query. Keys from add_external_key() are NOT affected.

static deserialize(path: str) pygenogrove.GffGrove#

Load a Grove previously written with serialize(). Returns a new Grove with the same intervals, associated data, and graph edges.

edge_count(self: pygenogrove.GffGrove) int#

Total number of directed edges in the graph overlay.

external_vertex_count(self: pygenogrove.GffGrove) int#

Number of external (graph-only) keys — those added with add_external_key(), not indexed in any B+ tree.

flanking(*args, **kwargs)#

Overloaded function.

  1. flanking(self: pygenogrove.GffGrove, query: pygenogrove.GenomicCoordinate, index: str) -> pygenogrove.GffFlankingResult

    Find the nearest non-overlapping keys on either side of the query within an index (the predecessor and successor).

    Returns a FlankingResult with .predecessor / .successor, each a Key or None. Keys that overlap the query are excluded; for nested intervals the predecessor is the one with the largest end (smallest gap), not the sort-order maximum. Compute the gap distance from the returned key, e.g. query.start - result.predecessor.value.end - 1.

  2. flanking(self: pygenogrove.GffGrove, query: pygenogrove.GenomicCoordinate, index: str, is_compatible: Callable[[pygenogrove.GenomicCoordinate, pygenogrove.GenomicCoordinate], bool]) -> pygenogrove.GffFlankingResult

    flanking(query, index, is_compatible) -> FlankingResult

    Predicate-filtered flanking: like flanking(query, index), but only candidate keys for which is_compatible(candidate, query) returns True are considered as neighbours. candidate and query are key values (e.g. GenomicCoordinate); the predicate is applied at every leaf candidate before the overlap/distance checks.

    The canonical use is strand-aware neighbours on a GenomicCoordinateGrove — the nearest non-overlapping key on the same strand:

    g.flanking(q, “chr1”,

    lambda cand, q: cand.strand == q.strand)

    (Internal-node pruning ignores the predicate, so subtrees holding only incompatible keys are still traversed and filtered at the leaves — correct, just not pruned. Exceptions raised by the predicate propagate out.)

get_neighbors(self: object, source: pygenogrove.GffKey) list#

Return the list of target Keys directly reachable from source.

The returned Keys point into this Grove’s storage and remain valid only while the Grove is alive.

get_order(self: pygenogrove.GffGrove) int#

Get the order (branching factor) of the B+ tree

graph_empty(self: pygenogrove.GffGrove) bool#

Return True if the graph overlay holds no edges.

has_edge(self: pygenogrove.GffGrove, source: pygenogrove.GffKey, target: pygenogrove.GffKey) bool#

Return True if a directed edge from source to target exists.

indexed_vertex_count(self: pygenogrove.GffGrove) int#

Number of indexed intervals (B+ tree leaf keys)

insert(*args, **kwargs)#

Overloaded function.

  1. insert(self: pygenogrove.GffGrove, index: str, key: pygenogrove.GenomicCoordinate, data: pygenogrove.GffEntry) -> pygenogrove.GffKey

    Insert a key with an associated data payload at the given index.

    indexstr

    The index name (e.g., chromosome name like “chr1”)

    keyGenomicCoordinate

    The key (copied into the grove). Drives B+ tree ordering — do not mutate it after insertion.

    dataobject

    The associated data payload (copied into the grove). On the universal Grove this is any JSON-serializable value (dict / list / scalar / None) and defaults to None.

    Key

    Stable reference to the inserted key.

  2. insert(self: pygenogrove.GffGrove, index: str, entry: pygenogrove.GffEntry) -> pygenogrove.GffKey

    insert(index, entry) -> Key

    Overload that takes a single file entry and derives the GenomicCoordinate key from its native coordinates + strand (BED half-open [s, e) -> [s, e-1]; GFF 1-based [s, e] -> [s-1, e-1]; strand from the BED6/GFF strand column, or ‘.’ if absent). The entry keeps its native coordinates as the payload.

insert_bulk(*args, **kwargs)#

Overloaded function.

  1. insert_bulk(self: object, index: str, items: list[tuple[pygenogrove.GenomicCoordinate, pygenogrove.GffEntry]], presorted: bool = False) -> list

    Bulk-insert many (interval, data) records at once. 10-20x faster than repeated insert() for large datasets — an empty index is built bottom-up in O(n); a non-empty index appends.

    indexstr

    The index name (e.g., chromosome name).

    itemslist[tuple[Interval, object]]

    The (interval, data) records to insert.

    presortedbool, optional

    If False (default) the records are sorted by interval first. If True, they are assumed already sorted ascending (skips the sort — fastest).

    list[Key]

    Stable key handles, in insertion (sorted) order.

    PRECONDITION (appending to a non-empty index): every inserted interval must be greater than every existing interval in the index. Violating this corrupts B+ tree ordering.

  2. insert_bulk(self: object, index: str, entries: list[pygenogrove.GffEntry], presorted: bool = False) -> list

    insert_bulk(index, entries, presorted=False) -> list[Key]

    Overload that takes a list of bare file entries (instead of (GenomicCoordinate, data) tuples) and derives each GenomicCoordinate key from the entry’s native coordinates + strand. Same append precondition as the explicit form.

insert_sorted(self: pygenogrove.GffGrove, index: str, interval: pygenogrove.GenomicCoordinate, data: pygenogrove.GffEntry) pygenogrove.GffKey#

Insert one (interval, data) record on the optimized sorted path (rightmost-append, no tree traversal).

PRECONDITION: the interval must be greater than every interval already present in this index. Insert in ascending order. Violating this corrupts B+ tree ordering (queries silently return wrong results). Use plain insert() if unsure.

intersect(*args, **kwargs)#

Overloaded function.

  1. intersect(self: pygenogrove.GffGrove, query: pygenogrove.GenomicCoordinate) -> pygenogrove.GffQueryResult

    Find all intervals that overlap with the query across all indices.

  2. intersect(self: pygenogrove.GffGrove, query: pygenogrove.GenomicCoordinate, index: str) -> pygenogrove.GffQueryResult

    Find all intervals that overlap with the query in a specific index.

key_storage_size(self: pygenogrove.GffGrove) int#

Total slots in the indexed-key storage: live leaf data keys + internal B+ tree separator keys + dead slots left behind by remove_key(). Grows across insert/remove cycles until compact() reclaims the dead slots — so it is >= indexed_vertex_count().

link_if(keys, predicate) -> None

Add an (unlabelled) directed edge between each adjacent pair (keys[i], keys[i+1]) for which predicate(keys[i], keys[i+1]) returns True. keys is typically the list returned by a bulk insert; the predicate receives two Keys. Use link_with() to attach edge metadata.

out_degree(self: pygenogrove.GffGrove, source: pygenogrove.GffKey) int#

Number of outgoing edges from source.

remove_all_edges(self: pygenogrove.GffGrove, key: pygenogrove.GffKey) int#

Remove every edge touching key, incoming and outgoing. Returns the total number removed.

remove_edge(self: pygenogrove.GffGrove, source: pygenogrove.GffKey, target: pygenogrove.GffKey) bool#

Remove the directed edge from source to target. Returns True if an edge was removed, False if it did not exist.

remove_edges_from(self: pygenogrove.GffGrove, source: pygenogrove.GffKey) int#

Remove all outgoing edges from source. Returns the number removed.

remove_edges_if(self: pygenogrove.GffGrove, predicate: Callable[[pygenogrove.GffKey], bool]) int#

remove_edges_if(predicate) -> int

Remove every edge whose target satisfies predicate(target: Key) -> bool, returning the number removed. (This grove’s edges carry no metadata, so the predicate gets only the target Key; the universal Grove also passes the edge metadata.)

remove_edges_to(self: pygenogrove.GffGrove, target: pygenogrove.GffKey) int#

Remove all incoming edges to target (O(E) scan over the graph). Returns the number removed.

remove_key(self: pygenogrove.GffGrove, index: str, key: pygenogrove.GffKey) bool#

Remove a key from the index’s B+ tree, rebalancing as needed.

Returns True if the key was found and removed, False otherwise (including a None key or an unknown index). All graph edges touching the key (incoming and outgoing) are also removed. The key remains in storage as a dead slot (not freed) — other Keys keep their pointers; only compact() reclaims the slot (and invalidates pointers — see its warning).

serialize(self: pygenogrove.GffGrove, path: str) None#

Serialize the Grove (intervals + associated data + graph overlay) to a zlib-compressed binary file at the given path.

size(self: pygenogrove.GffGrove) int#

Number of indexed intervals across all indices (alias of len)

to_sif(self: pygenogrove.GffGrove, path: str) None#

Write the grove to a SIF (Simple Interaction Format) text file for graph visualization (e.g. Cytoscape). Emits the B+ tree structure (nodelink / leaflink lines) and the graph-overlay edges (keylink lines) as tab-separated interactions; an empty grove writes an empty file.

Note: line and index iteration order are not stable across runs.

vertex_count(self: pygenogrove.GffGrove) int#

Total number of keys in the grove: indexed (B+ tree) plus external (graph-only) keys, including isolated ones with no edges.

vertex_count_with_edges(self: pygenogrove.GffGrove) int#

Number of keys that have at least one outgoing edge.

Grove views (partial random-access readers)#

Read-only, partial readers over a serialized .gg. See the Serialization guide.

class pygenogrove.BedGroveView#

Bases: pybind11_object

A read-only, partial reader over a serialized (format 0.2) .gg grove.

Unlike Grove.deserialize(), which loads the whole grove into memory, a GroveView reads only the block directory up front, then pages in individual blocks on demand as a query descends the tree — and caches them for the view’s lifetime (no eviction). Use it to query a large on-disk index without loading it whole.

Query-only: it has no insert() or serialize(). Not thread-safe (a query mutates the block cache). The Keys it returns point into the view’s own storage and are valid only while the GroveView is alive.

Create one with GroveView.open(path); a file written by Grove.serialize() is read directly (data_offset=0).

block_count(self: pygenogrove.BedGroveView) int#

Total number of blocks in the serialized grove (0 for an empty grove).

blocks_loaded(self: pygenogrove.BedGroveView) int#

Number of blocks paged in so far — proof a query loaded only part of the file (compare with block_count()).

get_neighbors(self: object, source: pygenogrove.BedKey) list#

Return the target Keys directly reachable from source via graph edges, paging in each target’s block on demand. source must be a Key this GroveView produced (via intersect() or a prior get_neighbors()). The returned Keys are valid only while the view is alive. Raises TypeError if source is None.

intersect(*args, **kwargs)#

Overloaded function.

  1. intersect(self: pygenogrove.BedGroveView, query: pygenogrove.GenomicCoordinate) -> pygenogrove.BedQueryResult

    Find all intervals overlapping the query across all indices, loading only the blocks the search touches.

  2. intersect(self: pygenogrove.BedGroveView, query: pygenogrove.GenomicCoordinate, index: str) -> pygenogrove.BedQueryResult

    Find all intervals overlapping the query within a single index, loading only the blocks on the descent path and overlapping leaves.

static open(path: str, data_offset: int = 0) pygenogrove.BedGroveView#

open(path, data_offset=0) -> GroveView

Open a serialized grove for partial reading. path is a file written by Grove.serialize() (a bare grove stream; data_offset=0). Pass a non-zero data_offset only for a .gg embedded after a leading header (e.g. a genogrove CLI index). Raises RuntimeError if the file cannot be opened, the magic is wrong, the source is not seekable, or the directory is malformed.

class pygenogrove.GffGroveView#

Bases: pybind11_object

A read-only, partial reader over a serialized (format 0.2) .gg grove.

Unlike Grove.deserialize(), which loads the whole grove into memory, a GroveView reads only the block directory up front, then pages in individual blocks on demand as a query descends the tree — and caches them for the view’s lifetime (no eviction). Use it to query a large on-disk index without loading it whole.

Query-only: it has no insert() or serialize(). Not thread-safe (a query mutates the block cache). The Keys it returns point into the view’s own storage and are valid only while the GroveView is alive.

Create one with GroveView.open(path); a file written by Grove.serialize() is read directly (data_offset=0).

block_count(self: pygenogrove.GffGroveView) int#

Total number of blocks in the serialized grove (0 for an empty grove).

blocks_loaded(self: pygenogrove.GffGroveView) int#

Number of blocks paged in so far — proof a query loaded only part of the file (compare with block_count()).

get_neighbors(self: object, source: pygenogrove.GffKey) list#

Return the target Keys directly reachable from source via graph edges, paging in each target’s block on demand. source must be a Key this GroveView produced (via intersect() or a prior get_neighbors()). The returned Keys are valid only while the view is alive. Raises TypeError if source is None.

intersect(*args, **kwargs)#

Overloaded function.

  1. intersect(self: pygenogrove.GffGroveView, query: pygenogrove.GenomicCoordinate) -> pygenogrove.GffQueryResult

    Find all intervals overlapping the query across all indices, loading only the blocks the search touches.

  2. intersect(self: pygenogrove.GffGroveView, query: pygenogrove.GenomicCoordinate, index: str) -> pygenogrove.GffQueryResult

    Find all intervals overlapping the query within a single index, loading only the blocks on the descent path and overlapping leaves.

static open(path: str, data_offset: int = 0) pygenogrove.GffGroveView#

open(path, data_offset=0) -> GroveView

Open a serialized grove for partial reading. path is a file written by Grove.serialize() (a bare grove stream; data_offset=0). Pass a non-zero data_offset only for a .gg embedded after a leading header (e.g. a genogrove CLI index). Raises RuntimeError if the file cannot be opened, the magic is wrong, the source is not seekable, or the directory is malformed.

Keys and results#

class pygenogrove.BedKey#

Bases: pybind11_object

A key wrapping a key value stored in the grove structure.

Returned by Grove.insert() and yielded by QueryResult iteration. Wraps a pointer into the grove’s storage, so the key remains valid only as long as the originating Grove is alive (the key keeps the Grove alive).

property data#

The associated data payload (not part of B+ tree ordering). On the typed BedKey/GffKey it is a live, mutable reference into grove storage (mutating it in place is safe). On the universal Grove the payload is JSON, so .data returns a freshly decoded copy each access — mutating that copy does not persist; re-insert to change it.

property value#

The key value (returned by value/copy, so mutating it cannot corrupt the grove’s B+ tree ordering)

class pygenogrove.GffKey#

Bases: pybind11_object

A key wrapping a key value stored in the grove structure.

Returned by Grove.insert() and yielded by QueryResult iteration. Wraps a pointer into the grove’s storage, so the key remains valid only as long as the originating Grove is alive (the key keeps the Grove alive).

property data#

The associated data payload (not part of B+ tree ordering). On the typed BedKey/GffKey it is a live, mutable reference into grove storage (mutating it in place is safe). On the universal Grove the payload is JSON, so .data returns a freshly decoded copy each access — mutating that copy does not persist; re-insert to change it.

property value#

The key value (returned by value/copy, so mutating it cannot corrupt the grove’s B+ tree ordering)

class pygenogrove.BedQueryResult#

Bases: pybind11_object

Result of an intersect() query: the query interval plus the matching keys.

property keys#

List of matching keys; each Key keeps this result (and its Grove) alive.

property query#

The query interval used for this search

class pygenogrove.GffQueryResult#

Bases: pybind11_object

Result of an intersect() query: the query interval plus the matching keys.

property keys#

List of matching keys; each Key keeps this result (and its Grove) alive.

property query#

The query interval used for this search

class pygenogrove.BedFlankingResult#

Bases: pybind11_object

Result of a Grove.flanking() query: the nearest non-overlapping keys on either side of the query, in the grove’s sort order.

predecessor is the closest key entirely before the query (largest end with no overlap); successor is the closest key entirely after it (smallest start with no overlap). Either is None if no such key exists. Distance is computed by the caller from the key values, e.g. for a query Q and predecessor P: Q.start - P.value.end - 1 (closed coordinates).

property predecessor#

Nearest non-overlapping key before the query (a Key), or None.

property successor#

Nearest non-overlapping key after the query (a Key), or None.

class pygenogrove.GffFlankingResult#

Bases: pybind11_object

Result of a Grove.flanking() query: the nearest non-overlapping keys on either side of the query, in the grove’s sort order.

predecessor is the closest key entirely before the query (largest end with no overlap); successor is the closest key entirely after it (smallest start with no overlap). Either is None if no such key exists. Distance is computed by the caller from the key values, e.g. for a query Q and predecessor P: Q.start - P.value.end - 1 (closed coordinates).

property predecessor#

Nearest non-overlapping key before the query (a Key), or None.

property successor#

Nearest non-overlapping key after the query (a Key), or None.

Record types#

class pygenogrove.BedEntry#

Bases: pybind11_object

A single BED record.

Coordinates are BED-native: 0-based, half-open [start, end). This is the raw record’s own coordinate system and is distinct from the closed [start, end] of Interval used as the grove key. Optional fields are None when absent.

Parameters:
  • chrom (str)

  • start (int) – 0-based start (BED chromStart).

  • end (int) – 0-based exclusive end (BED chromEnd).

property blocks#

Optional[BlockInfo] block structure (BED12)

property chrom#

Chromosome name

property end#

0-based exclusive end position (BED chromEnd)

property item_rgb#

Optional[RgbColor] display color (BED9+)

property name#

Optional[str] feature name (BED4+)

property score#

Optional[int] score (BED5+)

property start#

0-based start position (BED chromStart)

property strand#

Optional[str] strand — a single character (‘+’, ‘-’, ‘.’); assigning an empty or multi-character string raises ValueError, None clears it (BED6+)

property thickness#

Optional[ThickInfo] thick range (BED7+)

class pygenogrove.GffEntry#

Bases: pybind11_object

A single GFF3/GTF record (one line of a GFF file).

Coordinates are GFF-native: 1-based, both endpoints inclusive. This is distinct from both Interval (0-based closed) and BedEntry (0-based half-open), so convert deliberately when building the grove key. Optional columns are None when absent (‘.’).

Parameters:
  • seqid (str) – Sequence/chromosome name (column 1).

  • start (int) – 1-based inclusive start (column 4).

  • end (int) – 1-based inclusive end (column 5).

  • type (str) – Feature type, e.g. “gene”, “exon”, “CDS” (column 3).

property attributes#

dict[str, str] of column-9 key/value attributes (assigned/returned by copy)

property end#

1-based inclusive end (column 5)

property format#

GffFormat detected for this record

get_attribute(self: pygenogrove.GffEntry, key: str) str | None#

Return the value of a column-9 attribute, or None if absent.

get_exon_number(self: pygenogrove.GffEntry) int | None#

GTF exon_number attribute as int, or None.

get_gene_biotype(self: pygenogrove.GffEntry) str | None#

GTF gene_biotype/gene_type attribute, or None.

get_gene_id(self: pygenogrove.GffEntry) str | None#

GTF gene_id attribute, or None.

get_gene_name(self: pygenogrove.GffEntry) str | None#

GTF gene_name attribute, or None.

get_transcript_id(self: pygenogrove.GffEntry) str | None#

GTF transcript_id attribute, or None.

is_gff3(self: pygenogrove.GffEntry) bool#

True if this record was parsed as GFF3.

is_gtf(self: pygenogrove.GffEntry) bool#

True if this record was parsed as GTF.

property phase#

Optional[int] CDS phase (0, 1, or 2; column 8)

property score#

Optional[float] score (column 6)

property seqid#

Sequence/chromosome name (column 1)

property source#

Source of the feature (column 2)

property start#

1-based inclusive start (column 4)

property strand#

Optional[str] strand — a single character (‘+’, ‘-’, ‘.’, ‘?’); assigning an empty or multi-character string raises ValueError, None clears it (column 7)

property type#

Feature type, e.g. gene/exon/CDS (column 3)

class pygenogrove.ThickInfo#

Bases: pybind11_object

BED thick-drawing range (thickStart, thickEnd).

property end#

thickEnd

property start#

thickStart

class pygenogrove.RgbColor#

Bases: pybind11_object

BED itemRgb display color. Each channel is an int in [0, 255].

property blue#

Blue channel (0-255)

property green#

Green channel (0-255)

property red#

Red channel (0-255)

class pygenogrove.BlockInfo#

Bases: pybind11_object

BED12 block (exon) structure: parallel arrays of block sizes and block starts (starts are relative to the entry’s chromStart).

property count#

Number of blocks (BED blockCount)

property sizes#

Block sizes (list[int]; assigned/returned by copy)

property starts#

Block starts relative to chromStart (list[int]; by copy)

class pygenogrove.GffFormat#

Bases: pybind11_object

The format of a GFF record, auto-detected during parsing.

Members:

GFF3 : GFF3 (key=value attributes)

GTF : GTF/GTF2 (key “value” attributes)

UNKNOWN : Format not yet determined

GFF3 = <GffFormat.GFF3: 0>#
GTF = <GffFormat.GTF: 1>#
UNKNOWN = <GffFormat.UNKNOWN: 2>#
property name#
property value#