FlowMap
timelines.FlowMap(
source=None,
*,
id='',
resolve=None,
at=None,
source_length=None,
target_length=None,
)Coordinate transformation map for flow control.
A FlowMap enables bidirectional coordinate conversion between a source timeline (with flow control) and a target (linearized) timeline:
- Source -> Target conversion (1:N, since repeats duplicate coordinates)
- Target -> Source lookup (N:1, always unique)
The single positional argument, source, is polymorphic:
None— an empty map (no sections). Used by internal construction such as :meth:inverse, which fills the section tables afterwards.- a :class:
Flow— sections are derived from the flow’s measure-count ranges (integer MC space); id defaults to the flow’s mode value. - a single interval-like descriptor or an iterable of them — sections are built directly from the resulting
(start, end)ranges with a cumulative target position, so the played spans concatenate in the target axis and any gaps between them map to nothing. id defaults to"default". Accepted descriptors are region names (resolved through resolve),Regionobjects,(start, end)coordinate pairs,Timelineobjects, and interval events — see :func:~timetoalign.timelines.flow.sections._coerce_intervals.
Concatenation is only the default. Three interchangeable mechanisms place the played spans on the target axis instead, so the assembled timeline can hold holes — which is what an inverted cut needs:
- :class:
~timetoalign.timelines.flow.sections.Gapentries mixed into source, each pushing everything after it later by its own duration. - The at argument, giving the target coordinate of each played span outright.
- A
{target coordinate -> span}mapping as source, which pairs the two directly; see :meth:from_dict.
All three agree on the result, and no two may be combined in one call. See :meth:_build_from_entries for the placement rules.
FlowMap stores sections for efficient lookup:
_sections: List of FlowMapSection objects_target_boundaries: Sorted list of target section starts for binary search
Attributes
| Name | Type | Description |
|---|---|---|
| flow | Flow | None | The computed Flow, or None for interval-built maps. |
| id | str |
Identifier for this FlowMap. |
| source_length | Fraction | None |
Total extent of the source axis, when known. Recorded so that :meth:inverse can restore a target axis whose final stretch is a gap — material the flow drops off the end leaves no section to infer the length from. |
| target_length | Fraction | None |
Total extent of the target axis, when known. |
Methods
| Name | Description |
|---|---|
| fold | Map target coordinate back to source coordinate. |
| from_dict | Build a FlowMap from a {target coordinate -> span} mapping. |
| from_qb_sections | Create a FlowMap with QB-space source coordinates. |
| inverse | Create the inverse FlowMap (target -> source becomes source -> target). |
| iter_gaps | Report every stretch of target time that no source material fills. |
| unfold_coordinate | Map source coordinate to target coordinates. |
fold
timelines.FlowMap.fold(coord)Map target coordinate back to source coordinate.
The target timeline has unique coordinates, so this always returns a single value.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| coord | Fraction | float | int |
Coordinate in target timeline. | required |
Returns
| Name | Type | Description |
|---|---|---|
Fraction |
Coordinate in source timeline. |
Raises
| Name | Type | Description |
|---|---|---|
ValueError |
If coordinate is outside the flow range. |
Examples
>>> # Target coord 6 maps back to source coord 3
>>> flow_map.fold(6)
Fraction(3)from_dict
timelines.FlowMap.from_dict(
placements,
*,
id='default',
resolve=None,
source_length=None,
target_length=None,
)Build a FlowMap from a {target coordinate -> span} mapping.
The third way to state a placement, and the most direct: each key is the target coordinate at which its span begins. Where Gap entries describe the holes and at parallels the span list, a mapping puts coordinate and span side by side, which reads well when the placement comes from a table, a file, or an analysis::
FlowMap.from_dict({0: "A8_1", 129: "A8_2"}, resolve=tl.get_region)
Keys are sorted, so the mapping need not be written in target order. A value may also be a collection of spans, which are laid end to end from that coordinate on.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| placements | 'Mapping[Fraction | float | int, object]' | Mapping from target coordinate to one interval-like descriptor — or a collection of them — in the same shapes the constructor accepts (region names, Region objects, (start, end) pairs, Timeline objects, interval events). |
required |
| id | str |
Identifier for this FlowMap. | 'default' |
| resolve | Callable[[str], object] | None |
Callable mapping a region name to an interval-like object, needed only when the values carry region-name strings. | None |
| source_length | Fraction | float | int | None |
Total extent of the source axis, when known. | None |
| target_length | Fraction | float | int | None |
Total extent of the target axis, when known. | None |
Returns
| Name | Type | Description |
|---|---|---|
| 'FlowMap' | The constructed FlowMap, its spans placed at the given coordinates | |
| 'FlowMap' | and the space between them recorded as gaps. |
Raises
| Name | Type | Description |
|---|---|---|
ValueError |
If two spans would overlap on the target axis. |
Examples
>>> FlowMap.from_dict({0: (0, 123), 129: (123, 228)}, id="restored")
FlowMap(restored: 2 sections, 1 gap)from_qb_sections
timelines.FlowMap.from_qb_sections(flow, qb_sections, *, id='')Create a FlowMap with QB-space source coordinates.
Unlike the default constructor which derives source coordinates from MC numbers (integers), this factory accepts pre-computed quarterbeat boundaries. This is the correct approach for scores with non-uniform measure durations, where MC-number space != QB-coordinate space.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| flow | Flow | The computed Flow (retained for metadata and inverse ops). | required |
| qb_sections | list[tuple[Fraction, Fraction]] |
List of (qb_start, qb_end) tuples giving the quarterbeat boundaries of each section in the folded source timeline. Must have the same length as flow.sections. |
required |
| id | str |
Optional identifier. Defaults to flow.mode.value. |
'' |
Returns
| Name | Type | Description |
|---|---|---|
| 'FlowMap' | FlowMap with sections in QB-space. |
Raises
| Name | Type | Description |
|---|---|---|
ValueError |
If len(qb_sections) != len(flow.sections). |
See Also
compute_qb_sections: Computes QB boundaries from a Flow and ScoreFlowController.
inverse
timelines.FlowMap.inverse()Create the inverse FlowMap (target -> source becomes source -> target).
The inverse FlowMap swaps the source and target coordinate systems. This is useful for attaching to a target timeline to enable tracing back to the original source.
Because each section carries both ranges outright, inverting is a plain swap of the two. That is what makes an inverse placing rather than concatenating: a flow that drops material leaves its spans at their original source coordinates, so the inverse puts them back where they came from and the dropped stretch reappears as a gap. Applying the inverse with :meth:~timetoalign.timelines.Timeline.apply_flow therefore rebuilds a timeline laid out like the original.
Note
The inverse FlowMap’s unfold_coordinate() returns coordinates in the original source space, which may yield multiple results if the source coord is visited multiple times.
Returns
| Name | Type | Description |
|---|---|---|
| 'FlowMap' | A new FlowMap with inverted sections. |
iter_gaps
timelines.FlowMap.iter_gaps()Report every stretch of target time that no source material fills.
A hole reaches the map two ways, and both are reported here:
- Recorded — an insertion section, built from a :class:
~timetoalign.timelines.flow.sections.Gapentry or from anatplacement, which may carry a label. - Implied — the space left between two placed sections, or between the last section and a longer recorded
target_length. Inverting a FlowMap produces holes this way, since the inverse simply puts each span back at its source coordinates.
Returns
| Name | Type | Description |
|---|---|---|
list[tuple[Fraction, Fraction, str | None]] |
The (start, end, label) of each hole, in target order. |
|
list[tuple[Fraction, Fraction, str | None]] |
Adjacent holes are merged, and label is the recorded gap’s label | |
list[tuple[Fraction, Fraction, str | None]] |
or None. |
unfold_coordinate
timelines.FlowMap.unfold_coordinate(coord)Map source coordinate to target coordinates.
Since a source coordinate may be visited multiple times (due to repeats), this returns a list of all corresponding target coordinates.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| coord | Fraction | float | int |
Coordinate in source timeline. | required |
Returns
| Name | Type | Description |
|---|---|---|
list[Fraction] |
List of coordinates in target timeline. Empty list if coord | |
list[Fraction] |
is not within any section. |
Examples
>>> # Source coord 3 appears twice due to repeat
>>> flow_map.unfold_coordinate(3)
[Fraction(2), Fraction(6)]