AlignmentBundle
alignment.AlignmentBundle(
id='',
name=None,
timelines=dict(),
groups=dict(),
timeline_to_group=dict(),
meta=dict(),
cross_group_claims=list(),
cross_group_claim_fields=list(),
support_policy=SupportPolicy.omit,
_uid_to_timeline_id=dict(),
_timeline_id_to_uid=dict(),
_warp_map_cache=dict(),
_matchline_cache=dict(),
_matchgraph_cache=dict(),
_cache_claims_hash=0,
)The primary entry point for all alignment workflows.
An AlignmentBundle manages timelines and their alignment relationships. Within a group, coordinate transfer uses linear interpolation (TimelineGroup.convert()). Across groups, transfer is mediated by the MatchClaim → MatchLine → WarpMap pipeline.
The bundle provides:
- Timeline registration and lookup
- Group management (collections of perfectly aligned timelines)
- Coordinate transfer between any two timelines (same-group or cross-group via
MatchClaim/WarpMap)
IMPORTANT: The resulting bundle structure is order-independent. Adding timelines in any order produces the same alignment relationships and coordinate transfer results.
Attributes
| Name | Type | Description |
|---|---|---|
| id | str |
Unique identifier for this bundle. |
| name | str | None |
Optional human-readable name. |
| timelines | dict[str, 'Timeline'] |
Dictionary mapping bundle UIDs to Timeline objects. |
| groups | dict[str, TimelineGroup] |
Dictionary mapping group IDs to TimelineGroup objects. |
| timeline_to_group | dict[str, str] |
Mapping from bundle UID to its containing group ID. |
| cross_group_claims | list[MatchClaim] |
MatchClaims connecting timelines across groups (the per-claim Python-list store). |
| cross_group_claim_fields | list[MatchClaimField] |
Columnar MatchClaimField stores of dense synchronous-instant pairwise claims, queried vectorized without materialising the full claim list. |
Note
The two claim stores are interchangeable as far as queries are concerned: every reader consults both, so a bundle whose claims live in a MatchClaimField answers exactly as a bundle holding the same claims in the Python list. What differs is cost — MatchClaimField queries stay vectorized, and get_claim_fields() is the accessor that keeps them that way.
Note
The bundle maintains a UID mapping layer. Users interact with bundle UIDs (e.g., “tl1”, “tl2”), while groups internally use the actual timeline.id. The bundle translates between these two namespaces transparently.
Examples
>>> bundle = AlignmentBundle()
>>> bundle.add_timeline(score_timeline, uid="score")
>>> bundle.add_timeline(audio_timeline, uid="audio", aligned_to="score")
>>> stamp = bundle.get_matchstamp_at(100.0, "score")
>>> stamp.get("audio")
45.5Methods
| Name | Description |
|---|---|
| add_group | Add a pre-built TimelineGroup with all its timelines at once. |
| add_match_claim_field | Add a columnar MatchClaimField of cross-group claims. |
| add_match_claims | Add MatchClaims connecting timelines across different groups. |
| add_timeline | Add a timeline, optionally aligned to an existing timeline. |
| are_commensurable | Check if two timelines can be connected via transfer. |
| create_match_claims | Create MatchClaims from a list of event pairs. |
| diagram | Generate ASCII diagram for this bundle. |
| from_bundles | Merge multiple bundles’ groups, standalone timelines, and claims. |
| get_claim_fields | Query the columnar claim stores, materialising nothing. |
| get_group | Get a group by ID. |
| get_group_for_timeline | Get the group containing a timeline. |
| get_match_claims | Query MatchClaims connecting timelines across groups. |
| get_matchstamp_at | Get a cross-group MatchStamp at a coordinate on a timeline. |
| get_matchstamp_table | Get a PyArrow table of MatchStamps for alignment queries. |
| get_matchstamps | Get MatchStamps for a list of MatchClaims or query coordinates. |
| get_timeline | Get a timeline by ID. |
| get_timelines | Get multiple timelines by their IDs. |
| summary | Get a summary of the bundle contents. |
| transfer | Transfer a coordinate from one timeline to another. |
| transfer_interval | Transfer an interval from one timeline to another. |
add_group
alignment.AlignmentBundle.add_group(group, *, uid_map=None)Add a pre-built TimelineGroup with all its timelines at once.
This is the bulk-registration counterpart of add_timeline(..., as_group=...). It registers the group and every timeline it already contains into the bundle’s bookkeeping (UID mapping, timeline registry, group registry).
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| group | TimelineGroup | A TimelineGroup that already contains timelines. |
required |
| uid_map | dict[str, str] | None |
Optional mapping from timeline.id to desired bundle UID. If not provided, each timeline’s id is used as its bundle UID. |
None |
Returns
| Name | Type | Description |
|---|---|---|
| 'AlignmentBundle' | self (for method chaining) |
Raises
| Name | Type | Description |
|---|---|---|
ValueError |
If the group ID already exists in the bundle, or if any timeline UID would collide with an existing one. |
Examples
Add a recording group with 5 DPTs:
>>> grp = TimelineGroup(id="normal", timelines=[dpt1, dpt2, dpt3])
>>> bundle.add_group(grp)
With custom UIDs:
>>> bundle.add_group(grp, uid_map={"dpt:1": "audio", "dpt:2": "midi"})
add_match_claim_field
alignment.AlignmentBundle.add_match_claim_field(claim_field)Add a columnar MatchClaimField of cross-group claims.
This is the columnar counterpart of :meth:add_match_claims. The field is stored as-is (one PyArrow struct column) and queried vectorized by :meth:get_matchstamp_at / :meth:_get_or_build_matchgraph, which filter the struct column and materialise only the handful of claims at the queried coordinate. A dense whole-work field (on the order of a million claims) is therefore never exploded into a Python list.
It complements the per-claim list path: a bundle may hold both a Python-list cross_group_claims and one or more cross_group_claim_fields at once.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| claim_field | MatchClaimField | A :class:MatchClaimField of synchronous instant pairwise claims. |
required |
Returns
| Name | Type | Description |
|---|---|---|
| 'AlignmentBundle' | self (for method chaining) |
add_match_claims
alignment.AlignmentBundle.add_match_claims(claims)Add MatchClaims connecting timelines across different groups.
MatchClaims encode coordinate correspondences between timelines in different groups (e.g., EEP recording notes matched to ABC score notes). They enable cross-group coordinate transfer via MatchLine → WarpMap.
WarpMaps are built lazily on first transfer() or get_matchstamp_at() call, so adding claims is cheap.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| claims | list[MatchClaim] |
List of MatchClaim objects. Each synchronous claim connects two timelines via its start_anchor. |
required |
Returns
| Name | Type | Description |
|---|---|---|
| 'AlignmentBundle' | self (for method chaining) |
add_timeline
alignment.AlignmentBundle.add_timeline(
timeline,
*,
uid=None,
aligned_to=None,
as_group=None,
start=None,
end=None,
)Add a timeline, optionally aligned to an existing timeline.
This is the primary method for adding timelines to the bundle. Timelines can be standalone or aligned to existing timelines.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| timeline | 'Timeline' | The Timeline to add. | required |
| uid | str | None |
Optional explicit ID. If None, uses timeline.id. | None |
| aligned_to | str | None |
ID of existing timeline to align with. If provided, both timelines become part of the same group. If the target timeline is not yet in a group, a new group is created with the target as reference. | None |
| as_group | str | None |
Name for the group if creating a new one. | None |
| start | CoordinateSpec | None |
Where this timeline’s 0-origin starts in the group. - CoordinateSpec: Coordinate in the aligned_to timeline - IdCoordinate: Coordinate with explicit timeline_id (preferred) - float: Coordinate in the aligned_to timeline - None: Use group’s current start (default for linear alignment) | None |
| end | CoordinateSpec | None |
Where this timeline’s end (length) aligns in the group. - Same options as start - None: Use group’s current end (default for linear alignment) | None |
Returns
| Name | Type | Description |
|---|---|---|
| 'AlignmentBundle' | self (for method chaining) |
Raises
| Name | Type | Description |
|---|---|---|
ValueError |
If uid already exists in bundle. | |
KeyError |
If aligned_to references a non-existent timeline. |
Examples
Linear (full-extent) alignment:
>>> bundle.add_timeline(audio, uid="dgt1")
>>> bundle.add_timeline(midi, uid="dlt1", aligned_to="dgt1")
Partial alignment (SUPRA piano roll) using IdCoordinate:
>>> from timetoalign import IdCoordinate, TimeUnit
>>> bundle.add_timeline(image, uid="dgt1") # Full image
>>> bundle.add_timeline(
... holes,
... uid="dgt1_holes",
... aligned_to="dgt1",
... start=IdCoordinate(15343.0, TimeUnit.pixels, "dgt1"),
... end=IdCoordinate(293119.0, TimeUnit.pixels, "dgt1"),
... )
are_commensurable
alignment.AlignmentBundle.are_commensurable(timeline_a, timeline_b)Check if two timelines can be connected via transfer.
Two timelines are commensurable if they share the same group or if a cross-group path exists via MatchClaims.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| timeline_a | str |
First timeline ID (bundle UID). | required |
| timeline_b | str |
Second timeline ID (bundle UID). | required |
Returns
| Name | Type | Description |
|---|---|---|
bool |
True if coordinates can be transferred between them. |
create_match_claims
alignment.AlignmentBundle.create_match_claims(
event_pairs,
*,
synchronous=True,
agent='user',
agent_identifier='manual',
)Create MatchClaims from a list of event pairs.
Convenience factory for creating multiple MatchClaims from paired events. Each tuple specifies two events and their timeline IDs.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| event_pairs | list[tuple[dict | str | None, str, dict | str | None, str]] |
List of tuples, each containing: (event_a, timeline_a_id, event_b, timeline_b_id). event_a/event_b are each one of: an event dict (must have at least a start key with a coordinate; an end key on both sides produces an interval match), the id string of an existing event on the paired timeline (resolved via Timeline.get_event()), or None. Exactly one of event_a/event_b may be None, producing a NOMATCH claim for the other side’s event. The forms may be mixed within a pair. |
required |
| synchronous | bool |
Whether the matches are temporally synchronous. Ignored for NOMATCH pairs, which are always non-synchronous. | True |
| agent | str |
Name of the agent creating the claims (for provenance). | 'user' |
| agent_identifier | str |
The agent’s stable identifier — a version string for a software agent or a URI for a human agent (e.g. "manual", "dynamic_time_warping"). Stored as Agent.identifier. |
'manual' |
Returns
| Name | Type | Description |
|---|---|---|
list[MatchClaim] |
List of MatchClaim objects. Also automatically adds them to | |
list[MatchClaim] |
the bundle’s cross_group_claims. |
Raises
| Name | Type | Description |
|---|---|---|
ValueError |
If event dicts are missing required keys, an event id string doesn’t resolve to an existing event, or both event_a and event_b are None. |
Examples
>>> pairs = [
... ({"start": 0.0}, "score", {"start": 45.5}, "audio"),
... ("note:000010", "score", "note:000042", "audio"),
... ("note:000099", "score", None, "audio"), # NOMATCH
... ]
>>> claims = bundle.create_match_claims(pairs, agent="manual_alignment")
>>> len(claims)
3diagram
alignment.AlignmentBundle.diagram(
width=80,
show_children=True,
max_children=6,
max_standalone=6,
unicode=True,
)Generate ASCII diagram for this bundle.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| width | int |
Total width of the diagram in characters. | 80 |
| show_children | bool |
Whether to expand child timelines. | True |
| max_children | int |
Maximum children per timeline. | 6 |
| max_standalone | int |
Maximum standalone timelines to display before truncating with an ellipsis. | 6 |
| unicode | bool |
Use Unicode characters (True) or ASCII fallback (False). | True |
Returns
| Name | Type | Description |
|---|---|---|
| 'Diagram' | Diagram object (displays as ASCII in terminal, rich HTML in Jupyter). |
Examples
>>> print(bundle.diagram())
AlignmentBundle[thoresen_alignment]TimelineGroup[dgt1_group] (2 timelines, 2 timestamps) ┌──────────────────────────────────────────────────────┐ │ DiscreteGraphicalTimeline[dgt1:1] (11 events) │ │ 0 ∶∶∶∶∶∶∶∶∶∶∶∶∶∶∶∶∶∶∶∶∶∶∶∶∶∶∶∶∶∶∶∶∶∶∶ 4835 pixels │ └──────────────────────────────────────────────────────┘ Timestamps: 2
MatchClaims: 5
from_bundles
alignment.AlignmentBundle.from_bundles(bundles, *, id='', name=None)Merge multiple bundles’ groups, standalone timelines, and claims.
Registers every group and standalone timeline from each source bundle into a new bundle, preserving each source’s bundle-UID namespace, and carries over every cross-group MatchClaim (both the per-claim list and any columnar MatchClaimField stores) unchanged. Groups from different source bundles remain distinct — merging does not itself align timelines across bundles. Add cross-group MatchClaims (e.g. via :meth:create_match_claims) afterwards to align them.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| bundles | list['AlignmentBundle'] |
The bundles to merge, in order. | required |
| id | str |
Explicit ID for the merged bundle. Auto-generated if omitted. | '' |
| name | str | None |
Optional human-readable name for the merged bundle. | None |
Returns
| Name | Type | Description |
|---|---|---|
| 'AlignmentBundle' | A new AlignmentBundle containing every group, standalone | |
| 'AlignmentBundle' | timeline, and cross-group claim from bundles. |
Raises
| Name | Type | Description |
|---|---|---|
ValueError |
If two source bundles share a group ID, or a timeline UID collision would occur across bundles. |
Examples
>>> merged = AlignmentBundle.from_bundles([score_bundle, audio_bundle])
>>> merged.groups.keys() == score_bundle.groups.keys() | audio_bundle.groups.keys()
Trueget_claim_fields
alignment.AlignmentBundle.get_claim_fields(
timeline_id=None,
timeline_ids=None,
id_pattern=None,
between=None,
synchronous_only=False,
nomatch_only=False,
include_domains=None,
include_units=None,
)Query the columnar claim stores, materialising nothing.
This is the scalable counterpart of :meth:get_match_claims for bundles whose claims live in a MatchClaimField — a dense pairwise alignment can hold hundreds of thousands of claims, and turning each one into a Python object costs orders of magnitude more than the columnar answer. Every filter is applied as a vectorized PyArrow mask, and the result is a list of filtered fields, one per store that still has rows.
The filter parameters are exactly those of :meth:get_match_claims and carry the same meaning. Because a MatchClaimField holds synchronous claims only, synchronous_only is a no-op here and nomatch_only returns nothing.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| timeline_id | str | None |
Keep claims involving this bundle UID. | None |
| timeline_ids | set[str] | None |
Keep claims involving any of these bundle UIDs. | None |
| id_pattern | str | None |
Regex matched against bundle UIDs via re.search(). |
None |
| between | tuple[str, str] | None |
Keep claims connecting exactly these two bundle UIDs (order-independent). | None |
| synchronous_only | bool |
No-op (every stored claim is synchronous). | False |
| nomatch_only | bool |
Returns an empty list. | False |
| include_domains | set['Domain'] | None |
Only timelines in these domains. | None |
| include_units | set['TimeUnit'] | None |
Only timelines with these units. | None |
Returns
| Name | Type | Description |
|---|---|---|
list[MatchClaimField] |
Filtered MatchClaimField objects, empty stores dropped. |
Examples
>>> fields = bundle.get_claim_fields(timeline_id="rec-a:cpt1")
>>> sum(len(f) for f in fields)
66780get_group
alignment.AlignmentBundle.get_group(uid)Get a group by ID.
Supports partial string and regex matching: 1. Exact match: If uid matches an ID exactly, returns it. 2. Substring match: If uid is a substring of exactly one ID, returns that group. If multiple match, returns the first and warns. 3. Regex match: If uid is a valid regex, matches via re.search(). Same first-match logic with warning.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| uid | str |
The group’s unique identifier, or a partial/regex pattern. | required |
Returns
| Name | Type | Description |
|---|---|---|
| TimelineGroup | The TimelineGroup object. |
Raises
| Name | Type | Description |
|---|---|---|
KeyError |
If no group matches the pattern. |
Examples
>>> bundle.get_group("score") # Substring match
>>> bundle.get_group(r"^perf") # Regex matchget_group_for_timeline
alignment.AlignmentBundle.get_group_for_timeline(timeline_id)Get the group containing a timeline.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| timeline_id | str |
The timeline’s unique identifier. | required |
Returns
| Name | Type | Description |
|---|---|---|
| TimelineGroup | None | The TimelineGroup containing the timeline, or None if standalone. |
get_match_claims
alignment.AlignmentBundle.get_match_claims(
timeline_id=None,
timeline_ids=None,
id_pattern=None,
between=None,
synchronous_only=False,
nomatch_only=False,
include_domains=None,
include_units=None,
)Query MatchClaims connecting timelines across groups.
This is the primary interface for accessing alignment information. All parameters are optional; when none are provided, returns all claims.
Filters are combined with AND logic: a claim must satisfy every non-None criterion. Uses the Unified Filter API.
Both claim stores are queried: the per-claim Python list and every columnar MatchClaimField. The columnar matches are filtered vectorized but then materialised, one MatchClaim per surviving row — for a dense pairwise alignment that is O(n) Python objects. Use :meth:get_claim_fields when the columnar answer suffices, or narrow the query first.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| timeline_id | str | None |
Return claims involving this bundle UID. | None |
| timeline_ids | set[str] | None |
Return claims involving any of these bundle UIDs. | None |
| id_pattern | str | None |
Regex pattern matched against bundle UIDs via re.search(). Example: r"^perf:" matches all performance timelines. |
None |
| between | tuple[str, str] | None |
Return claims connecting exactly these two bundle UIDs (order-independent). | None |
| synchronous_only | bool |
Exclude non-synchronous (NOMATCH) claims. | False |
| nomatch_only | bool |
Return only non-synchronous (NOMATCH) claims. | False |
| include_domains | set['Domain'] | None |
Only timelines in these domains. | None |
| include_units | set['TimeUnit'] | None |
Only timelines with these units. | None |
Returns
| Name | Type | Description |
|---|---|---|
list[MatchClaim] |
Filtered list of MatchClaims. |
Examples
Get all synchronous claims for a performer::
>>> claims = bundle.get_match_claims(
... id_pattern=r"dlt1$", synchronous_only=True
... )
Get NOMATCH claims for a specific pair::
>>> nomatches = bundle.get_match_claims(
... between=("score:clt1", "perf:dlt5"),
... nomatch_only=True,
... )
get_matchstamp_at
alignment.AlignmentBundle.get_matchstamp_at(
coordinate,
timeline_id=None,
*,
support_policy=None,
conversion_maps=False,
timeline_ids=None,
id_pattern=None,
include_domains=None,
include_units=None,
)Get a cross-group MatchStamp at a coordinate on a timeline.
This is the primary interface for cross-domain coordinate transfer. Given a coordinate on one timeline, returns coordinates on ALL connected timelines across ALL groups.
The stamp is the transitive cross-group union reachable from the query. Exact-anchor coordinates from the coordinate’s MatchGraph are overlaid first (exact wins over interpolated), then the assembly walks outward across groups to closure: every reached timeline expands into its own group (by interpolation) and warps into not-yet-reached groups (by WarpMap). is_interpolated is False exactly when the query node itself carries an explicit anchor.
A timeline whose transferred coordinate falls outside alignment support — the entering coordinate lies outside the transferring WarpMap’s source-anchor hull, or the produced coordinate would fall outside [0, length] — is handled by support_policy. No policy ever yields a negative coordinate or one beyond a timeline’s length.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| coordinate | CoordinateSpec |
The query coordinate. Can be: - int/float/Fraction: Raw value, timeline_id required. - Coordinate: Value with unit, timeline_id required. - IdCoordinate: Value with unit AND timeline_id (timeline_id param optional). |
required |
| timeline_id | str | None |
Bundle UID of the source timeline. Required unless coordinate is an IdCoordinate, in which case the coordinate’s own timeline_id is used. |
None |
| support_policy | 'SupportPolicy | str | None' | How to treat out-of-support timelines (omit / clamp / extrapolate). Accepts a :class:~timetoalign.core.SupportPolicy or its string name. None (the default) uses the bundle’s support_policy setting, itself omit by default. The query timeline’s own coordinate is never dropped, clamped, or altered. |
None |
| conversion_maps | 'ConversionMapsSpec' | C-map conversions available through unit lookup and display. Opt-in: defaults to False. |
False |
| timeline_ids | set[str] | None |
Only include these bundle UIDs in the result. | None |
| id_pattern | str | None |
Regex filter for bundle UIDs in the result. | None |
| include_domains | set['Domain'] | None |
Only these domains in the result. | None |
| include_units | set['TimeUnit'] | None |
Only these units in the result. | None |
Returns
| Name | Type | Description |
|---|---|---|
| MatchStamp | MatchStamp spanning all connected timelines. |
Raises
| Name | Type | Description |
|---|---|---|
TypeError |
If coordinate is not int/float/Fraction/Coordinate/ IdCoordinate. | |
ValueError |
If timeline_id is None and coordinate is not an IdCoordinate. | |
KeyError |
If timeline_id is not in the bundle. |
Examples
>>> ms = bundle.get_matchstamp_at(10.0, "score:clt1")
>>> ms.n_timelines
23 # score + 22 performersget_matchstamp_table
alignment.AlignmentBundle.get_matchstamp_table(
claims=None,
*,
coordinates=None,
timeline_id=None,
timeline_filter=None,
from_graph=False,
conversion_maps=False,
)Get a PyArrow table of MatchStamps for alignment queries.
Analogous to get_timestamp_table() but for cross-group alignment. Fields are timeline IDs holding their coordinate values; what a row is depends on from_graph:
from_graph=False(default) — one row per synchronous claim. A pairwise claim fills exactly two cells and leaves the rest null, so a dense pairwise alignment produces one sparse row per claim.from_graph=True— one row per connected component of the(timeline_id, coordinate)graph the claims induce. The pairwise rows above collapse into the cross-section they describe: one row per aligned instant, every participating timeline filled.
When claims is None both claim stores are read: the per-claim Python list and every columnar MatchClaimField. The columnar stores are read four Arrow columns at a time — no MatchClaim is ever materialised — which is what keeps a hundreds-of-thousands-of-rows alignment tabulable.
When coordinates is given instead of claims, each coordinate is resolved through :meth:get_matchstamp_at and becomes exactly one row — a full transitive cross-section, every reached timeline filled — in input order. from_graph does not apply on this path (the stamps are already collapsed cross-sections) and is ignored.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| claims | list[MatchClaim] | None |
List of MatchClaims to tabulate. If None, uses every cross-group claim in the bundle (both stores). When given, only those claims are tabulated. Mutually exclusive with coordinates. |
None |
| coordinates | Iterable[CoordinateSpec] | None |
Query coordinates to resolve through :meth:get_matchstamp_at, one row per coordinate in input order. Each element is a raw int/float/Fraction or Coordinate (needing timeline_id) or an IdCoordinate (carrying its own timeline). Mutually exclusive with claims. |
None |
| timeline_id | str | None |
Source timeline for the coordinates batch; may be None when every element is an IdCoordinate. Ignored on the claims path. |
None |
| timeline_filter | set[str] | None |
Only include these timeline fields. | None |
| from_graph | bool |
Collapse claims into one row per connected component instead of one row per claim. Ignored on the coordinates path. |
False |
| conversion_maps | 'ConversionMapsSpec' | C-map conversions to add as derived columns, one per (timeline, enabled unit-conversion map). Opt-in: defaults to False. Only numeric unit-conversion maps (a target_unit set) become columns; label/structured maps appear in stamp display but never as table columns. |
False |
Returns
| Name | Type | Description |
|---|---|---|
| 'pa.Table' | PyArrow Table with one field per timeline. Non-synchronous claims | |
| 'pa.Table' | are excluded. Empty input yields an empty table. |
Raises
| Name | Type | Description |
|---|---|---|
ValueError |
If both claims and coordinates are given. |
Note
Collapsed rows are ordered by the coordinate on the lexicographically smallest timeline ID present in the component, then by that ID — a total order, since two components can never share a (timeline_id, coordinate) node. A component that somehow carries two coordinates for one timeline (which a well-formed alignment never does) keeps the smaller one.
Examples
>>> table = bundle.get_matchstamp_table()
>>> table.num_rows
100
>>> table.column_names
['score:clt1', 'perf:dlt1', 'perf:dlt2', ...]
>>> bundle.get_matchstamp_table(from_graph=True).num_rows
25
>>> bundle.get_matchstamp_table(
... coordinates=[0.0, 50.0], timeline_id="score:clt1"
... ).num_rows
2get_matchstamps
alignment.AlignmentBundle.get_matchstamps(
claims=None,
*,
coordinates=None,
timeline_id=None,
from_graph=True,
conversion_maps=False,
)Get MatchStamps for a list of MatchClaims or query coordinates.
Convenience method for retrieving MatchStamps for multiple claims at once. Uses the bundle’s caching mechanism for efficient retrieval.
When coordinates is given instead of claims, each coordinate is resolved through :meth:get_matchstamp_at — the coordinate-first entry point for callers who hold coordinates rather than MatchClaim objects. Input order is preserved and every coordinate yields exactly one stamp (a full transitive cross-section).
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| claims | list[MatchClaim] | None |
List of MatchClaims to get stamps for. If None, uses every cross-group claim in the bundle — the per-claim list and every columnar MatchClaimField (see :meth:get_match_claims, which materialises the columnar rows). Mutually exclusive with coordinates. |
None |
| coordinates | Iterable[CoordinateSpec] | None |
Query coordinates to resolve through :meth:get_matchstamp_at, one stamp per coordinate in input order. Each element is a raw int/float/Fraction or Coordinate (needing timeline_id) or an IdCoordinate (carrying its own timeline). Mutually exclusive with claims. |
None |
| timeline_id | str | None |
Source timeline for the coordinates batch; may be None when every element is an IdCoordinate. Ignored on the claims path. |
None |
| from_graph | bool |
If True (default), return full MatchStamps from the MatchGraph (all connected timelines). If False, return reduced 2-timeline stamps. Ignored on the coordinates path, where each stamp is already a full cross-section. |
True |
| conversion_maps | 'ConversionMapsSpec' | C-map conversions available through unit lookup and display. Opt-in: defaults to False. |
False |
Returns
| Name | Type | Description |
|---|---|---|
list[MatchStamp] |
List of MatchStamp objects. Non-synchronous claims yield None | |
list[MatchStamp] |
entries (filtered out). |
Raises
| Name | Type | Description |
|---|---|---|
ValueError |
If both claims and coordinates are given. |
Examples
>>> stamps = bundle.get_matchstamps()
>>> len(stamps)
100
>>> stamps[0].n_timelines
23
>>> coord_stamps = bundle.get_matchstamps(
... coordinates=[0.0, 50.0], timeline_id="score:clt1"
... )
>>> coord_stamps[1].get("score:clt1")
50.0get_timeline
alignment.AlignmentBundle.get_timeline(uid)Get a timeline by ID.
Supports partial string and regex matching: 1. Exact match: If uid matches an ID exactly, returns it. 2. Substring match: If uid is a substring of exactly one ID, returns that timeline. If multiple match, returns the first and warns. 3. Regex match: If uid is a valid regex, matches via re.search(). Same first-match logic with warning.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| uid | str |
The timeline’s unique identifier, or a partial/regex pattern. | required |
Returns
| Name | Type | Description |
|---|---|---|
| 'Timeline' | The Timeline object. |
Raises
| Name | Type | Description |
|---|---|---|
KeyError |
If no timeline matches the pattern. |
Examples
>>> bundle.get_timeline("clt1") # Exact match
>>> bundle.get_timeline("score") # Substring match
>>> bundle.get_timeline(r"^perf:") # Regex matchget_timelines
alignment.AlignmentBundle.get_timelines(ids)Get multiple timelines by their IDs.
Convenience method for retrieving several timelines at once. Each ID supports partial string and regex matching (via get_timeline()).
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| ids | list[str] |
List of timeline IDs (or partial/regex patterns). | required |
Returns
| Name | Type | Description |
|---|---|---|
list['Timeline'] |
List of Timeline objects in the same order as the input IDs. |
Raises
| Name | Type | Description |
|---|---|---|
KeyError |
If any timeline ID is not found. |
Examples
>>> timelines = bundle.get_timelines(["score", "audio", "midi"])
>>> len(timelines)
3summary
alignment.AlignmentBundle.summary()Get a summary of the bundle contents.
Returns a deterministic representation suitable for comparison. Keys and timeline lists are sorted for order-independence.
Returns
| Name | Type | Description |
|---|---|---|
dict[str, Any] |
Dictionary with bundle information. |
transfer
alignment.AlignmentBundle.transfer(coord, from_timeline, to_timeline)Transfer a coordinate from one timeline to another.
Automatically determines the conversion path:
- If both timelines are in the same group: direct conversion via
TimelineGroup.convert(). - If in different groups with MatchClaims: builds a
MatchLineand a cachedWarpMapand calls it to interpolate the coordinate. - If no path exists: returns
None.
Low-level coordinate transfer utility. For user-facing coordinate queries, use get_matchstamp_at() which returns a full cross-section as a MatchStamp.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| coord | CoordinateSpec |
The coordinate value to transfer. | required |
| from_timeline | str |
Bundle UID of the source timeline. | required |
| to_timeline | str |
Bundle UID of the target timeline. | required |
Returns
| Name | Type | Description |
|---|---|---|
float | None |
The transferred coordinate, or None if no path exists. |
Raises
| Name | Type | Description |
|---|---|---|
KeyError |
If either timeline is not in the bundle. |
transfer_interval
alignment.AlignmentBundle.transfer_interval(
start,
end,
from_timeline,
to_timeline,
)Transfer an interval from one timeline to another.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| start | CoordinateSpec |
Start coordinate in source timeline. Accepts a raw int/float/Fraction, a Coordinate, or an IdCoordinate. | required |
| end | CoordinateSpec |
End coordinate in source timeline. Accepts a raw int/float/Fraction, a Coordinate, or an IdCoordinate. | required |
| from_timeline | str |
ID of the source timeline. | required |
| to_timeline | str |
ID of the target timeline. | required |
Returns
| Name | Type | Description |
|---|---|---|
tuple[float, float] | None |
Tuple of (start, end) in target timeline, or None if no path. |