ionique.core

Overview

The core module provides the hierarchical segment tree structure used throughout ionique. It defines classes for representing segments of ionic current data in a tree hierarchy, where each segment can contain child segments at different “ranks” (e.g., file → voltage step → event).

Key Concepts

Segments represent portions of ionic current traces with start/end indices.

Ranks define hierarchy levels. Common ranks include:

  • "file" - The top-level segment containing the entire trace

  • "vstep" - Voltage step segments within a file

  • "event" - Individual events detected within voltage steps

Parsing subdivides a segment into children at a new rank using parser objects.

Feature lookup traverses up the tree to find attributes (e.g., sampling_freq).

Classes

AbstractSegmentTree

The base class providing tree structure and traversal methods. Not typically instantiated directly.

from ionique.core import AbstractSegmentTree

# Tree traversal methods
segment.traverse_to_rank("event")  # Get all segments at rank "event"
segment.climb_to_rank("file")      # Go up to find the file-level segment
segment.get_feature("sampling_freq")  # Look up feature in self or ancestors

MetaSegment

A lightweight segment storing only metadata (start, end, statistics) without holding the actual current array. Used for memory-efficient storage of parsed results.

Basic Usage:

from ionique.core import MetaSegment

# Create a metadata segment
seg = MetaSegment(
    start=1000,
    end=2000,
    rank="event",
    unique_features={"amplitude": 0.5, "dwell_time": 0.01}
)

# Access properties
print(seg.n)       # Length: 1000
print(seg.start)   # 1000
print(seg.end)     # 2000

Accessing Current Data:

MetaSegment can retrieve current data by climbing to the file-level parent:

# If seg has a parent chain leading to a file with current data:
current_slice = seg.current  # Returns current[1000:2000] from file
print(seg.mean)              # Computes np.mean(current_slice)
print(seg.std)               # Computes np.std(current_slice)

Serialization:

# Convert to JSON
json_str = seg.to_json()
print(json_str)
# {
#     "mean": 1.234,
#     "std": 0.056,
#     "start": 1000,
#     "end": 2000,
#     "name": "MetaSegment"
# }

# Convert to dictionary
seg.to_dict()

Segment

A full segment holding the actual current data as a NumPy array. Use this when you need direct access to the raw signal values.

Basic Usage:

import numpy as np
from ionique.core import Segment

# Create sample current data
current = np.random.randn(1000) * 0.1 + 1.5  # ~1.5 nA with noise

# Create a segment
seg = Segment(
    current=current,
    start=0,
    end=1000,
    rank="event"
)

# Access statistics (computed on-the-fly)
print(f"Mean: {seg.mean:.3f}")
print(f"Std:  {seg.std:.3f}")
print(f"Min:  {seg.min:.3f}")
print(f"Max:  {seg.max:.3f}")
print(f"Length: {seg.n}")

Converting to MetaSegment:

To save memory after extracting statistics:

# Convert to lightweight MetaSegment (deletes current array)
seg.to_meta()
# seg is now a MetaSegment with cached mean, std, min, max

Working with the Tree Structure

Adding Children:

from ionique.core import MetaSegment

# Create parent segment
parent = MetaSegment(start=0, end=10000, rank="vstep")

# Create child segments
event1 = MetaSegment(start=100, end=500, rank="event", parent=parent)
event2 = MetaSegment(start=600, end=900, rank="event", parent=parent)

# Add children to parent
parent.add_children([event1, event2])

# Children are automatically sorted by start position
print(len(parent.children))  # 2

Traversing the Tree:

# Get all segments at a specific rank
all_events = parent.traverse_to_rank("event")

# Climb up to find ancestor at a rank
file_seg = event1.climb_to_rank("file")

# Get summary of ranks and counts
summary = parent.summary()
# {"vstep": 1, "event": 2}

Looking Up Features:

Features are looked up in the segment first, then in ancestors:

# Set a feature at file level
file_seg.unique_features["sampling_freq"] = 100000

# Child segments can access it
event = file_seg.children[0].children[0]  # Some nested event
freq = event.get_feature("sampling_freq")  # Returns 100000

Parsing Segments

Use the parse() method to subdivide segments using parser objects:

from ionique.parsers import SpikeParser

# Create a parser
parser = SpikeParser(
    prominence=0.15,
    distance=100,
    width=(10, 10000)
)

# Parse events within each voltage step
file_segment.parse(
    parser=parser,
    newrank="event",
    at_child_rank="vstep"  # Parse at vstep level, not file level
)

# Access detected events
events = file_segment.traverse_to_rank("event")
print(f"Detected {len(events)} events")

Note

Segments store references to data arrays, not copies. Modifying the underlying array affects all segments referencing it.

Warning

The current property on MetaSegment requires a valid parent chain up to a file-level segment. It returns None if the chain is broken.

API Reference

loose adaptation from “core.py” by Jacob Scheriber https://github.com/jmschrei/PyPore – Original License included in “PYPORE_LICENSE.txt”.

This holds the core data types which may be abstracted in many different applications. This module defines a tree-based framework for representing, parsing, and annotating segments of ionic current data.

class ionique.core.AbstractSegmentTree

Bases: object

Class for managing hierarchical segments.

This class supports a tree structure where each segment can contain multiple child segments, enabling recursive parsing and analysis of nested data. It provides utilities to manage relationships between segments, apply parsers, and extract subsegments by rank.

parent

Parent segment in the tree, or None if this is the root.

Type:

AbstractSegmentTree or None

children

List of child segments belonging to this node.

Type:

list of AbstractSegmentTree

start

Start index of the segment in the underlying data array.

Type:

int or None

end

End index of the segment in the underlying data array.

Type:

int or None

rank

Label identifying the depth level or type of this segment.

Type:

str or None

__init__() None

Initialize the segment with default empty state.

add_child(child: AnySegment) None

Add a single child

add_children(children: list[AnySegment]) None

Add multiple children if: 1. Child position is the within parent’s segment. 2. The length of the child’s segment is > 0 3. There is no overlap between consecutive children

Or add children with no check

children: list[AnySegment]
clear_children()

Clear the list of children

climb_to_rank(rank: str) AnySegment | None

Traverse upward through the tree to find the nearest ancestor with the given rank.

Parameters:

rank (str) – The rank label to search for.

Returns:

The nearest ancestor (or self) that has the specified rank, or None if no such segment exists in the chain.

Return type:

AbstractSegmentTree or None

end: int | None
get_feature(name: str)

Get a named feature from the current segment or the nearest ancestor that has it.

Parameters:

name (str) – The name of the feature to retrieve.

Returns:

The feature value if found in this segment’s unique_features, as a direct attribute, or by climbing the parent chain; None if not found anywhere.

Return type:

object or None

get_top_parent() AnySegment

Recursively traverse upward and return the topmost parent node.

Returns:

The root ancestor of this segment.

Return type:

AbstractSegmentTree

property n: int

Get the length of the segment.

Returns:

Number of samples in the segment (end - start).

Return type:

int

parent: AnySegment | None
parse(parser, newrank: str, at_child_rank: str | None = None, **kwargs) bool

Parse the segment data into child segments with a new rank.

Parses the data in the segment or at a particular rank of child segments into children segments with a new rank.

Parameters:
  • parser (Parser) – A parser object with a parse method and required input attributes.

  • newrank (str) – Rank to assign to the newly created child segments.

  • at_child_rank (str or None, optional) – Determines whether to traverse the children tree down to a given rank. Defaults to None.

  • **kwargs – Additional arguments to pass to the parser.

Returns:

True if parsing was successful, otherwise raises an exception.

Return type:

bool

rank: str
property relative_end: int

Get the end position relative to the parent segment.

Returns:

End index offset from the parent’s start, or the absolute end if there is no parent.

Return type:

int

property relative_slice: ndarray

Compute the numpy slice object spanning this segment’s relative start to relative end.

Returns:

A numpy.s_ slice object for the range [relative_start:relative_end].

Return type:

numpy.ndarray

property relative_start: int

Get the start position relative to the parent segment.

Returns:

Start index offset from the parent’s start, or the absolute start if there is no parent.

Return type:

int

property slice: ndarray

Compute the numpy slice object spanning this segment’s start to end.

Returns:

A numpy.s_ slice object for the range [start:end].

Return type:

numpy.ndarray

start: int | None
summary()

Provide a summary of existing ranks and the count of elements at each rank.

Returns:

Mapping of rank label to count of segments at that rank, ordered from root toward children.

Return type:

dict

traverse_to_rank(rank: str) list

Traverse the tree downward and collect all segments at the given rank.

Parameters:

rank (str) – The rank label to search for among descendants.

Returns:

All segments in the subtree (including self) that have the specified rank.

Return type:

list of AbstractSegmentTree

class ionique.core.MetaSegment(start: int, end: int, parent: AnySegment | None = None, rank: str | None = None, unique_features: dict | None = {}, **kwargs)

Bases: AbstractSegmentTree

Lightweight segment node storing only position and metadata, without raw signal data.

All information about a segment can be loaded without requiring the underlying array of ionic current values.

Parameters:
  • start (int) – Start index of the segment.

  • end (int) – End index of the segment.

  • parent (AbstractSegmentTree or None, optional) – Parent segment in the tree. Defaults to None.

  • rank (str or None, optional) – Rank identifier for this segment. Defaults to None.

  • unique_features (dict or None, optional) – Dictionary of metadata features associated with this segment. Defaults to an empty dict.

  • **kwargs – Additional keyword arguments (currently unused).

__init__(start: int, end: int, parent: AnySegment | None = None, rank: str | None = None, unique_features: dict | None = {}, **kwargs)

Initialize the MetaSegment with positional and metadata information.

property current

Get the ionic current data for this segment by slicing the parent file’s array.

Returns:

Current values from the root file segment sliced to this segment’s start/end range, or None if the file rank cannot be reached.

Return type:

numpy.ndarray or None

delete()

Delete itself. There are no arrays with which to delete references for.

property duration: float

Get the duration of the segment in time units.

Returns:

Time elapsed from the first to the last sample of the segment.

Return type:

float

classmethod from_json(filename=None, in_json=None)

Read in a metasegment from a JSON and return a metasegment object. Either pass in a file which has a segment stored, or an actual JSON object.

property max

Calculate the maximum value of the current array.

Returns:

Maximum value of the current array.

Return type:

float

property mean

Calculate the mean of the current array.

Returns:

Mean value of the current array.

Return type:

float

property min

Calculate the minimum value of the current array.

Returns:

Minimum value of the current array.

Return type:

float

property std

Calculate the standard deviation of the current array.

Returns:

Standard deviation of the current array.

Return type:

float

property time

Get the time array for this segment sliced from the root file segment.

Returns:

Time values from the root file segment sliced to this segment’s range.

Return type:

numpy.ndarray

to_dict()

Return a dict representation of the metadata, usually used prior to converting the dict to a JSON.

to_json(filename=None)

Return a JSON representation of this, by reporting the important metadata.

to_meta()

Kept to allow for error handling, but since it’s already a metasegment it won’t actually do anything.

unique_features
class ionique.core.Segment(current, **kwargs)

Bases: AbstractSegmentTree

A data-containing segment of ionic current with computed statistics.

The ionic current is expected to be passed as a numpy array of floats. Metadata methods (mean, std, min, max) are decorated as properties to reduce overall computational time, making them calculated on the fly rather than during analysis.

Parameters:
  • current (numpy.ndarray) – Numpy array of ionic current data points.

  • **kwargs – Additional attributes such as start, end, rank, etc. Cannot override statistical measurements.

__init__(current, **kwargs)

Initialize the segment with an ionic current array and optional metadata.

children: list[AnySegment]
delete()

Deleting this segment requires deleting its reference to the ionic current array, and then deleting itself.

end: int | None
classmethod from_json(filename=None, json=None)

Read in a segment from a JSON and return a metasegment object. Either pass in a file which has a segment stored, or an actual JSON object.

property max

Calculate the maximum value of the current array.

Returns:

Maximum value of the current array.

Return type:

float

property mean

Calculate the mean of the current array.

Returns:

Mean value of the current array.

Return type:

float

property min

Calculate the minimum value of the current array.

Returns:

Minimum value of the current array.

Return type:

float

property n

Get the number of elements in the current array.

Returns:

Number of elements in the current array.

Return type:

int

parent: AnySegment | None
rank: str
scale(sampling_freq)

Rescale all of the values to go from samples to seconds.

start: int | None
property std

Calculate the standard deviation of the current array.

Returns:

Standard deviation of the current array.

Return type:

float

to_dict()

Return a dict representation of the metadata, usually used prior to converting the dict to a JSON.

to_json(filename=None)

Return a JSON representation of this, by reporting the important metadata.

to_meta()

Convert from a segment to a ‘metasegment’, which stores only metadata about the segment and not the full array of ionic current.