Reference

Data structures

Segment

class pyannote.core.Segment(start: float = 0.0, end: float = 0.0)[source]

Time interval

Parameters:
  • start (float) – interval start time, in seconds.

  • end (float) – interval end time, in seconds.

Segments can be compared and sorted using the standard operators:

>>> Segment(0, 1) == Segment(0, 1.)
True
>>> Segment(0, 1) != Segment(3, 4)
True
>>> Segment(0, 1) < Segment(2, 3)
True
>>> Segment(0, 1) < Segment(0, 2)
True
>>> Segment(1, 2) < Segment(0, 3)
False

Note

A segment is smaller than another segment if one of these two conditions is verified:

  • segment.start < other_segment.start

  • segment.start == other_segment.start and segment.end < other_segment.end

__and__(other)[source]

Intersection

>>> segment = Segment(0, 10)
>>> other_segment = Segment(5, 15)
>>> segment & other_segment
<Segment(5, 10)>

Note

When the intersection is empty, an empty segment is returned:

>>> segment = Segment(0, 10)
>>> other_segment = Segment(15, 20)
>>> intersection = segment & other_segment
>>> if not intersection:
...    # intersection is empty.
__bool__()[source]

Emptiness

>>> if segment:
...    # segment is not empty.
... else:
...    # segment is empty.

Note

A segment is considered empty if its end time is smaller than its start time, or its duration is smaller than 1μs.

__contains__(other: pyannote.core.segment.Segment)[source]

Inclusion

>>> segment = Segment(start=0, end=10)
>>> Segment(start=3, end=10) in segment:
True
>>> Segment(start=5, end=15) in segment:
False
__iter__() → Iterator[float][source]

Unpack segment boundaries >>> segment = Segment(start, end) >>> start, end = segment

__or__(other: pyannote.core.segment.Segment) → pyannote.core.segment.Segment[source]

Union

>>> segment = Segment(0, 10)
>>> other_segment = Segment(5, 15)
>>> segment | other_segment
<Segment(0, 15)>

Note

When a gap exists between the segment, their union covers the gap as well:

>>> segment = Segment(0, 10)
>>> other_segment = Segment(15, 20)
>>> segment | other_segment
<Segment(0, 20)
__post_init__()[source]

Round start and end up to SEGMENT_PRECISION precision (when required)

__repr__()[source]

Computer-readable representation

>>> Segment(1337, 1337 + 0.42)
<Segment(1337, 1337.42)>
__str__()[source]

Human-readable representation

>>> print(Segment(1337, 1337 + 0.42))
[ 00:22:17.000 -->  00:22:17.420]

Note

Empty segments are printed as “[]”

__weakref__

list of weak references to the object (if defined)

__xor__(other: pyannote.core.segment.Segment) → pyannote.core.segment.Segment[source]

Gap

>>> segment = Segment(0, 10)
>>> other_segment = Segment(15, 20)
>>> segment ^ other_segment
<Segment(10, 15)

Note

The gap between a segment and an empty segment is not defined.

>>> segment = Segment(0, 10)
>>> empty_segment = Segment(11, 11)
>>> segment ^ empty_segment
ValueError: The gap between a segment and an empty segment is not defined.
copy() → pyannote.core.segment.Segment[source]

Get a copy of the segment

Returns:

copy – Copy of the segment.

Return type:

Segment

property duration

Segment duration (read-only)

for_json()[source]

Serialization

classmethod from_json(data)[source]

Deserialization

intersects(other: pyannote.core.segment.Segment) → bool[source]

Check whether two segments intersect each other

Parameters:

other (Segment) – Other segment

Returns:

intersect – True if segments intersect, False otherwise

Return type:

bool

property middle

Segment mid-time (read-only)

overlaps(t: float) → bool[source]

Check if segment overlaps a given time

Parameters:

t (float) – Time, in seconds.

Returns:

overlap – True if segment overlaps time t, False otherwise.

Return type:

bool

static set_precision(ndigits: Optional[int] = None)[source]

Automatically round start and end timestamps to ndigits precision after the decimal point

To ensure consistency between Segment instances, it is recommended to call this method only once, right after importing pyannote.core.Segment.

>>> from pyannote.core import Segment
>>> Segment.set_precision(2)
>>> Segment(1/3, 2/3)
<Segment(0.33, 0.67)>

Timeline

class pyannote.core.Timeline(segments: Optional[Iterable[pyannote.core.segment.Segment]] = None, uri: str = None)[source]

Ordered set of segments.

A timeline can be seen as an ordered set of non-empty segments (Segment). Segments can overlap – though adding an already exisiting segment to a timeline does nothing.

Parameters:
  • segments (Segment iterator, optional) – initial set of (non-empty) segments

  • uri (string, optional) – name of segmented resource

Returns:

timeline – New timeline

Return type:

Timeline

__bool__()[source]

Emptiness

>>> if timeline:
...    # timeline is not empty
... else:
...    # timeline is empty
__contains__(included: Union[pyannote.core.segment.Segment, Timeline])[source]

Inclusion

Check whether every segment of included does exist in timeline.

Parameters:

included (Segment or Timeline) – Segment or timeline being checked for inclusion

Returns:

contains – True if every segment in included exists in timeline, False otherwise

Return type:

bool

Examples

>>> timeline1 = Timeline(segments=[Segment(0, 10), Segment(1, 13.37)])
>>> timeline2 = Timeline(segments=[Segment(0, 10)])
>>> timeline1 in timeline2
False
>>> timeline2 in timeline1
>>> Segment(1, 13.37) in timeline1
True
__eq__(other: pyannote.core.timeline.Timeline)[source]

Equality

Two timelines are equal if and only if their segments are equal.

>>> timeline1 = Timeline([Segment(0, 1), Segment(2, 3)])
>>> timeline2 = Timeline([Segment(2, 3), Segment(0, 1)])
>>> timeline3 = Timeline([Segment(2, 3)])
>>> timeline1 == timeline2
True
>>> timeline1 == timeline3
False
__getitem__(k: int) → pyannote.core.segment.Segment[source]

Get segment by index (in chronological order)

>>> first_segment = timeline[0]
>>> penultimate_segment = timeline[-2]
__init__(segments: Optional[Iterable[pyannote.core.segment.Segment]] = None, uri: str = None)[source]

Initialize self. See help(type(self)) for accurate signature.

__iter__() → Iterable[pyannote.core.segment.Segment][source]

Iterate over segments (in chronological order)

>>> for segment in timeline:
...     # do something with the segment
__len__()[source]

Number of segments

>>> len(timeline)  # timeline contains three segments
3
__ne__(other: pyannote.core.timeline.Timeline)[source]

Inequality

__repr__()[source]

Computer-readable representation

>>> Timeline(segments=[Segment(0, 10), Segment(1, 13.37)])
<Timeline(uri=None, segments=[<Segment(0, 10)>, <Segment(1, 13.37)>])>
__str__()[source]

Human-readable representation

>>> timeline = Timeline(segments=[Segment(0, 10), Segment(1, 13.37)])
>>> print(timeline)
[[ 00:00:00.000 -->  00:00:10.000]
 [ 00:00:01.000 -->  00:00:13.370]]
__weakref__

list of weak references to the object (if defined)

add(segment: pyannote.core.segment.Segment) → pyannote.core.timeline.Timeline[source]

Add a segment (in place)

Parameters:

segment (Segment) – Segment that is being added

Returns:

self – Updated timeline.

Return type:

Timeline

Note

If the timeline already contains this segment, it will not be added again, as a timeline is meant to be a set of segments (not a list).

If the segment is empty, it will not be added either, as a timeline only contains non-empty segments.

co_iter(other: pyannote.core.timeline.Timeline) → Iterator[Tuple[pyannote.core.segment.Segment, pyannote.core.segment.Segment]][source]

Iterate over pairs of intersecting segments

>>> timeline1 = Timeline([Segment(0, 2), Segment(1, 2), Segment(3, 4)])
>>> timeline2 = Timeline([Segment(1, 3), Segment(3, 5)])
>>> for segment1, segment2 in timeline1.co_iter(timeline2):
...     print(segment1, segment2)
(<Segment(0, 2)>, <Segment(1, 3)>)
(<Segment(1, 2)>, <Segment(1, 3)>)
(<Segment(3, 4)>, <Segment(3, 5)>)
Parameters:

other (Timeline) – Second timeline

Returns:

iterable – Yields pairs of intersecting segments in chronological order.

Return type:

(Segment, Segment) iterable

copy(segment_func: Optional[Callable[[pyannote.core.segment.Segment], pyannote.core.segment.Segment]] = None) → pyannote.core.timeline.Timeline[source]

Get a copy of the timeline

If segment_func is provided, it is applied to each segment first.

Parameters:

segment_func (callable, optional) – Callable that takes a segment as input, and returns a segment. Defaults to identity function (segment_func(segment) = segment)

Returns:

timeline – Copy of the timeline

Return type:

Timeline

covers(other: pyannote.core.timeline.Timeline) → bool[source]

Check whether other timeline is fully covered by the timeline

otherTimeline

Second timeline

Returns:

covers – True if timeline covers “other” timeline entirely. False if at least one segment of “other” is not fully covered by timeline

Return type:

bool

crop(support: Union[Segment, Timeline], mode: typing_extensions.Literal['intersection', 'loose', 'strict'][intersection, loose, strict] = 'intersection', returns_mapping: bool = False) → Union[pyannote.core.timeline.Timeline, Tuple[pyannote.core.timeline.Timeline, Dict[pyannote.core.segment.Segment, pyannote.core.segment.Segment]]][source]

Crop timeline to new support

Parameters:
  • support (Segment or Timeline) – If support is a Timeline, its support is used.

  • mode ({'strict', 'loose', 'intersection'}, optional) – Controls how segments that are not fully included in support are handled. ‘strict’ mode only keeps fully included segments. ‘loose’ mode keeps any intersecting segment. ‘intersection’ mode keeps any intersecting segment but replace them by their actual intersection.

  • returns_mapping (bool, optional) – In ‘intersection’ mode, return a dictionary whose keys are segments of the cropped timeline, and values are list of the original segments that were cropped. Defaults to False.

Returns:

  • cropped (Timeline) – Cropped timeline

  • mapping (dict) – When ‘returns_mapping’ is True, dictionary whose keys are segments of ‘cropped’, and values are lists of corresponding original segments.

Examples

>>> timeline = Timeline([Segment(0, 2), Segment(1, 2), Segment(3, 4)])
>>> timeline.crop(Segment(1, 3))
<Timeline(uri=None, segments=[<Segment(1, 2)>])>
>>> timeline.crop(Segment(1, 3), mode='loose')
<Timeline(uri=None, segments=[<Segment(0, 2)>, <Segment(1, 2)>])>
>>> timeline.crop(Segment(1, 3), mode='strict')
<Timeline(uri=None, segments=[<Segment(1, 2)>])>
>>> cropped, mapping = timeline.crop(Segment(1, 3), returns_mapping=True)
>>> print(mapping)
{<Segment(1, 2)>: [<Segment(0, 2)>, <Segment(1, 2)>]}
crop_iter(support: Union[Segment, Timeline], mode: typing_extensions.Literal['intersection', 'loose', 'strict'][intersection, loose, strict] = 'intersection', returns_mapping: bool = False) → Iterator[Union[Tuple[pyannote.core.segment.Segment, pyannote.core.segment.Segment], pyannote.core.segment.Segment]][source]

Like crop but returns a segment iterator instead

discard(segment: pyannote.core.segment.Segment) → pyannote.core.timeline.Timeline[source]

Same as remove

duration() → float[source]

Timeline duration

The timeline duration is the sum of the durations of the segments in the timeline support.

Returns:

duration – Duration of timeline support, in seconds.

Return type:

float

empty() → pyannote.core.timeline.Timeline[source]

Return an empty copy

Returns:

empty – Empty timeline using the same ‘uri’ attribute.

Return type:

Timeline

extent() → pyannote.core.segment.Segment[source]

Extent

The extent of a timeline is the segment of minimum duration that contains every segments of the timeline. It is unique, by definition. The extent of an empty timeline is an empty segment.

A picture is worth a thousand words:

timeline
|------|    |------|     |----|
  |--|    |-----|     |----------|

timeline.extent()
|--------------------------------|
Returns:

extent – Timeline extent

Return type:

Segment

Examples

>>> timeline = Timeline(segments=[Segment(0, 1), Segment(9, 10)])
>>> timeline.extent()
<Segment(0, 10)>
extrude(removed: Union[Segment, Timeline], mode: typing_extensions.Literal['intersection', 'loose', 'strict'][intersection, loose, strict] = 'intersection') → pyannote.core.timeline.Timeline[source]

Remove segments that overlap removed support.

Parameters:
  • removed (Segment or Timeline) – If support is a Timeline, its support is used.

  • mode ({'strict', 'loose', 'intersection'}, optional) – Controls how segments that are not fully included in removed are handled. ‘strict’ mode only removes fully included segments. ‘loose’ mode removes any intersecting segment. ‘intersection’ mode removes the overlapping part of any intersecting segment.

Returns:

extruded – Extruded timeline

Return type:

Timeline

Examples

>>> timeline = Timeline([Segment(0, 2), Segment(1, 2), Segment(3, 5)])
>>> timeline.extrude(Segment(1, 2))
<Timeline(uri=None, segments=[<Segment(0, 1)>, <Segment(3, 5)>])>
>>> timeline.extrude(Segment(1, 3), mode='loose')
<Timeline(uri=None, segments=[<Segment(3, 5)>])>
>>> timeline.extrude(Segment(1, 3), mode='strict')
<Timeline(uri=None, segments=[<Segment(0, 2)>, <Segment(3, 5)>])>
for_json()[source]

Serialization

classmethod from_json(data)[source]

Deserialization

gaps(support: Union[Segment, Timeline, None] = None) → pyannote.core.timeline.Timeline[source]

Gaps

A picture is worth a thousand words:

timeline
|------|    |------|     |----|
  |--|    |-----|     |----------|

timeline.gaps()
       |--|        |--|
Parameters:

support (None, Segment or Timeline) – Support in which gaps are looked for. Defaults to timeline extent

Returns:

gaps – Timeline made of all gaps from original timeline, and delimited by provided support

Return type:

Timeline

gaps_iter(support: Union[Segment, Timeline, None] = None) → Iterator[pyannote.core.segment.Segment][source]

Like gaps but returns a segment generator instead

get_overlap() → pyannote.core.timeline.Timeline[source]

Get overlapping parts of the timeline.

A simple illustration:

timeline |------| |------| |----|

timeline.get_overlap()

|--| |---| |----|

Returns:

overlap – Timeline of the overlaps.

Return type:

pyannote.core.Timeline

index(segment: pyannote.core.segment.Segment) → int[source]

Get index of (existing) segment

Parameters:

segment (Segment) – Segment that is being looked for.

Returns:

position – Index of segment in timeline

Return type:

int

Raises:

ValueError if segment is not present.

overlapping(t: float) → List[pyannote.core.segment.Segment][source]

Get list of segments overlapping t

Parameters:

t (float) – Timestamp, in seconds.

Returns:

segments – List of all segments of timeline containing time t

Return type:

list

overlapping_iter(t: float) → Iterator[pyannote.core.segment.Segment][source]

Like overlapping but returns a segment iterator instead

remove(segment: pyannote.core.segment.Segment) → pyannote.core.timeline.Timeline[source]

Remove a segment (in place)

Parameters:

segment (Segment) – Segment that is being removed

Returns:

self – Updated timeline.

Return type:

Timeline

Note

If the timeline does not contain this segment, this does nothing

segmentation() → pyannote.core.timeline.Timeline[source]

Segmentation

Create the unique timeline with same support and same set of segment boundaries as original timeline, but with no overlapping segments.

A picture is worth a thousand words:

timeline
|------|    |------|     |----|
  |--|    |-----|     |----------|

timeline.segmentation()
|-|--|-|  |-|---|--|  |--|----|--|
Returns:

timeline – (unique) timeline with same support and same set of segment boundaries as original timeline, but with no overlapping segments.

Return type:

Timeline

support(collar: float = 0.0) → pyannote.core.timeline.Timeline[source]

Timeline support

The support of a timeline is the timeline with the minimum number of segments with exactly the same time span as the original timeline. It is (by definition) unique and does not contain any overlapping segments.

A picture is worth a thousand words:

collar
|---|

timeline
|------|    |------|      |----|
  |--|    |-----|      |----------|

timeline.support()
|------|  |--------|   |----------|

timeline.support(collar)
|------------------|   |----------|
Parameters:

collar (float, optional) – Merge separated by less than collar seconds. This is why there are only two segments in the final timeline in the above figure. Defaults to 0.

Returns:

support – Timeline support

Return type:

Timeline

support_iter(collar: float = 0.0) → Iterator[pyannote.core.segment.Segment][source]

Like support but returns a segment generator instead

to_annotation(generator: Union[str, Iterable[Hashable], None] = 'string', modality: Optional[str] = None) → Annotation[source]

Turn timeline into an annotation

Each segment is labeled by a unique label.

Parameters:
  • generator ('string', 'int', or iterable, optional) – If ‘string’ (default) generate string labels. If ‘int’, generate integer labels. If iterable, use it to generate labels.

  • modality (str, optional) –

Returns:

annotation – Annotation

Return type:

Annotation

union(timeline: pyannote.core.timeline.Timeline) → pyannote.core.timeline.Timeline[source]

Create new timeline made of union of segments

Parameters:

timeline (Timeline) – Timeline whose segments are being added

Returns:

union – New timeline containing the union of both timelines.

Return type:

Timeline

Note

This does the same as timeline.update(…) except it returns a new timeline, and the original one is not modified.

update(timeline: pyannote.core.segment.Segment) → pyannote.core.timeline.Timeline[source]

Add every segments of an existing timeline (in place)

Parameters:

timeline (Timeline) – Timeline whose segments are being added

Returns:

self – Updated timeline

Return type:

Timeline

Note

Only segments that do not already exist will be added, as a timeline is meant to be a set of segments (not a list).

write_uem(file: TextIO)[source]

Dump timeline to file using UEM format

Parameters:
  • file (file object) –

  • Usage

  • -----

  • with open('file.uem', 'w') as file (>>>) –

  • timeline.write_uem(file) (..) –

Annotation

class pyannote.core.Annotation(uri: Optional[str] = None, modality: Optional[str] = None)[source]
Parameters:
  • uri (string, optional) – name of annotated resource (e.g. audio or video file)

  • modality (string, optional) – name of annotated modality

Returns:

annotation – New annotation

Return type:

Annotation

__bool__()[source]

Emptiness

>>> if annotation:
...    # annotation is not empty
... else:
...    # annotation is empty
__contains__(included: Union[pyannote.core.segment.Segment, pyannote.core.timeline.Timeline])[source]

Inclusion

Check whether every segment of included does exist in annotation.

Parameters:

included (Segment or Timeline) – Segment or timeline being checked for inclusion

Returns:

contains – True if every segment in included exists in timeline, False otherwise

Return type:

bool

__delitem__(key: Union[Segment, Tuple[Segment, Union[str, int]]])[source]

Delete one track

>>> del annotation[segment, track]

Delete all tracks of a segment

>>> del annotation[segment]
__eq__(other: pyannote.core.annotation.Annotation)[source]

Equality

>>> annotation == other

Two annotations are equal if and only if their tracks and associated labels are equal.

__getitem__(key: Union[Segment, Tuple[Segment, Union[str, int]]]) → Hashable[source]

Get track label

>>> label = annotation[segment, track]

Note

annotation[segment] is equivalent to annotation[segment, '_']

__init__(uri: Optional[str] = None, modality: Optional[str] = None)[source]

Initialize self. See help(type(self)) for accurate signature.

__len__()[source]

Number of segments

>>> len(annotation)  # annotation contains three segments
3
__mul__(other: pyannote.core.annotation.Annotation) → numpy.ndarray[source]

Cooccurrence (or confusion) matrix

>>> matrix = annotation * other
Parameters:

other (Annotation) – Second annotation

Returns:

cooccurrence – Cooccurrence matrix where n_self (resp. n_other) is the number of labels in self (resp. other).

Return type:

(n_self, n_other) np.ndarray

__ne__(other: pyannote.core.annotation.Annotation)[source]

Inequality

__setitem__(key: Union[Segment, Tuple[Segment, Union[str, int]]], label: Hashable)[source]

Add new or update existing track

>>> annotation[segment, track] = label

If (segment, track) does not exist, it is added. If (segment, track) already exists, it is updated.

Note

annotation[segment] = label is equivalent to annotation[segment, '_'] = label

Note

If segment is empty, it does nothing.

__str__()[source]

Human-friendly representation

__weakref__

list of weak references to the object (if defined)

argmax(support: Union[Segment, Timeline, None] = None) → Optional[Hashable][source]

Get label with longest duration

Parameters:

support (Segment or Timeline, optional) – Find label with longest duration within provided support. Defaults to whole extent.

Returns:

label – Label with longest intersection

Return type:

any existing label or None

Examples

>>> annotation = Annotation(modality='speaker')
>>> annotation[Segment(0, 10), 'speaker1'] = 'Alice'
>>> annotation[Segment(8, 20), 'speaker1'] = 'Bob'
>>> print "%s is such a talker!" % annotation.argmax()
Bob is such a talker!
>>> segment = Segment(22, 23)
>>> if not annotation.argmax(support):
...    print "No label intersecting %s" % segment
No label intersection [22 --> 23]
chart(percent: bool = False) → List[Tuple[Hashable, float]][source]

Get labels chart (from longest to shortest duration)

Parameters:

percent (bool, optional) – Return list of (label, percentage) tuples. Defaults to returning list of (label, duration) tuples.

Returns:

chart – List of (label, duration), sorted by duration in decreasing order.

Return type:

list

co_iter(other: pyannote.core.annotation.Annotation) → Iterator[Tuple[Tuple[pyannote.core.segment.Segment, Union[str, int]], Tuple[pyannote.core.segment.Segment, Union[str, int]]]][source]

Iterate over pairs of intersecting tracks

Parameters:

other (Annotation) – Second annotation

Returns:

iterable – Yields pairs of intersecting tracks, in chronological (then alphabetical) order.

Return type:

(Segment, object), (Segment, object) iterable

See also

co_iter()

copy() → pyannote.core.annotation.Annotation[source]

Get a copy of the annotation

Returns:

annotation – Copy of the annotation

Return type:

Annotation

crop(support: Union[Segment, Timeline], mode: typing_extensions.Literal['intersection', 'loose', 'strict'][intersection, loose, strict] = 'intersection') → pyannote.core.annotation.Annotation[source]

Crop annotation to new support

Parameters:
  • support (Segment or Timeline) – If support is a Timeline, its support is used.

  • mode ({'strict', 'loose', 'intersection'}, optional) – Controls how segments that are not fully included in support are handled. ‘strict’ mode only keeps fully included segments. ‘loose’ mode keeps any intersecting segment. ‘intersection’ mode keeps any intersecting segment but replace them by their actual intersection.

Returns:

cropped – Cropped annotation

Return type:

Annotation

Note

In ‘intersection’ mode, the best is done to keep the track names unchanged. However, in some cases where two original segments are cropped into the same resulting segments, conflicting track names are modified to make sure no track is lost.

discretize(support: Optional[pyannote.core.segment.Segment] = None, resolution: Union[float, pyannote.core.segment.SlidingWindow] = 0.01, labels: Optional[List[Hashable]] = None, duration: Optional[float] = None)[source]

Discretize

Parameters:
  • support (Segment, optional) – Part of annotation to discretize. Defaults to annotation full extent.

  • resolution (float or SlidingWindow, optional) – Defaults to 10ms frames.

  • labels (list of labels, optional) – Defaults to self.labels()

  • duration (float, optional) – Overrides support duration and ensures that the number of returned frames is fixed (which might otherwise not be the case because of rounding errors).

Returns:

discretized – (num_frames, num_labels)-shaped binary features.

Return type:

SlidingWindowFeature

empty() → pyannote.core.annotation.Annotation[source]

Return an empty copy

Returns:

empty – Empty annotation using the same ‘uri’ and ‘modality’ attributes.

Return type:

Annotation

extrude(removed: Union[Segment, Timeline], mode: typing_extensions.Literal['intersection', 'loose', 'strict'][intersection, loose, strict] = 'intersection') → pyannote.core.annotation.Annotation[source]

Remove segments that overlap removed support.

A simple illustration:

annotation A |------| |------| B |----------| C |--------------| |------|

removed Timeline

|-------| |-----------|

extruded Annotation with mode=”intersection” B |---| C |--| |------|

extruded Annotation with mode=”loose” C |------|

extruded Annotation with mode=”strict” A |------| B |----------| C |--------------| |------|

Parameters:
  • removed (Segment or Timeline) – If support is a Timeline, its support is used.

  • mode ({'strict', 'loose', 'intersection'}, optional) – Controls how segments that are not fully included in removed are handled. ‘strict’ mode only removes fully included segments. ‘loose’ mode removes any intersecting segment. ‘intersection’ mode removes the overlapping part of any intersecting segment.

Returns:

extruded – Extruded annotation

Return type:

Annotation

Note

In ‘intersection’ mode, the best is done to keep the track names unchanged. However, in some cases where two original segments are cropped into the same resulting segments, conflicting track names are modified to make sure no track is lost.

for_json() → Dict[source]

Serialization

classmethod from_json(data: Dict) → pyannote.core.annotation.Annotation[source]

Deserialization

classmethod from_records(records: Iterator[Tuple[pyannote.core.segment.Segment, Union[str, int], Hashable]], uri: Optional[str] = None, modality: Optional[str] = None) → pyannote.core.annotation.Annotation[source]

Annotation

Parameters:
  • records (iterator of tuples) – (segment, track, label) tuples

  • uri (string, optional) – name of annotated resource (e.g. audio or video file)

  • modality (string, optional) – name of annotated modality

Returns:

annotation – New annotation

Return type:

Annotation

get_labels(segment: pyannote.core.segment.Segment, unique: bool = True) → Union[Set[Hashable], List[Hashable]][source]

Query labels by segment

Parameters:
  • segment (Segment) – Query

  • unique (bool, optional) – When False, return the list of (possibly repeated) labels. Defaults to returning the set of labels.

Returns:

labels – Set (resp. list) of labels for segment if it exists, empty set (resp. list) otherwise if unique (resp. if not unique).

Return type:

set or list

Examples

>>> annotation = Annotation()
>>> segment = Segment(0, 2)
>>> annotation[segment, 'speaker1'] = 'Bernard'
>>> annotation[segment, 'speaker2'] = 'John'
>>> print sorted(annotation.get_labels(segment))
set(['Bernard', 'John'])
>>> print annotation.get_labels(Segment(1, 2))
set([])
get_overlap(labels: Optional[Iterable[Hashable]] = None) → pyannote.core.timeline.Timeline[source]

Get overlapping parts of the annotation.

A simple illustration:

annotation A |------| |------| |----| B |--| |-----| |----------| C |--------------| |------|

annotation.get_overlap()

|------| |-----| |--------|

annotation.get_overlap(for_labels=[“A”, “B”])

|--| |--| |----|

Parameters:

labels (optional list of labels) – Labels for which to consider the overlap

Returns:

overlap – Timeline of the overlaps.

Return type:

pyannote.core.Timeline

get_timeline(copy: bool = True) → pyannote.core.timeline.Timeline[source]

Get timeline made of all annotated segments

Parameters:

copy (bool, optional) – Defaults (True) to returning a copy of the internal timeline. Set to False to return the actual internal timeline (faster).

Returns:

timeline – Timeline made of all annotated segments.

Return type:

Timeline

Note

In case copy is set to False, be careful not to modify the returned timeline, as it may lead to weird subsequent behavior of the annotation instance.

get_tracks(segment: pyannote.core.segment.Segment) → Set[Union[str, int]][source]

Query tracks by segment

Parameters:

segment (Segment) – Query

Returns:

tracks – Set of tracks

Return type:

set

Note

This will return an empty set if segment does not exist.

has_track(segment: pyannote.core.segment.Segment, track: Union[str, int]) → bool[source]

Check whether a given track exists

Parameters:
  • segment (Segment) – Query segment

  • track – Query track

Returns:

exists – True if track exists for segment

Return type:

bool

itersegments()[source]

Iterate over segments (in chronological order)

>>> for segment in annotation.itersegments():
...     # do something with the segment
itertracks(yield_label: bool = False) → Iterator[Union[Tuple[pyannote.core.segment.Segment, Union[str, int]], Tuple[pyannote.core.segment.Segment, Union[str, int], Hashable]]][source]

Iterate over tracks (in chronological order)

Parameters:

yield_label (bool, optional) – When True, yield (segment, track, label) tuples, such that annotation[segment, track] == label. Defaults to yielding (segment, track) tuple.

Examples

>>> for segment, track in annotation.itertracks():
...     # do something with the track
>>> for segment, track, label in annotation.itertracks(yield_label=True):
...     # do something with the track and its label
label_duration(label: Hashable) → float[source]

Label duration

Equivalent to Annotation.label_timeline(label).duration()

Parameters:

label (object) – Query

Returns:

duration – Duration, in seconds.

Return type:

float

label_support(label: Hashable) → pyannote.core.timeline.Timeline[source]

Label support

Equivalent to Annotation.label_timeline(label).support()

Parameters:

label (object) – Query

Returns:

support – Label support

Return type:

Timeline

label_timeline(label: Hashable, copy: bool = True) → pyannote.core.timeline.Timeline[source]

Query segments by label

Parameters:
  • label (object) – Query

  • copy (bool, optional) – Defaults (True) to returning a copy of the internal timeline. Set to False to return the actual internal timeline (faster).

Returns:

timeline – Timeline made of all segments for which at least one track is annotated as label

Return type:

Timeline

Note

If label does not exist, this will return an empty timeline.

Note

In case copy is set to False, be careful not to modify the returned timeline, as it may lead to weird subsequent behavior of the annotation instance.

labels() → List[Hashable][source]

Get sorted list of labels

Returns:

labels – Sorted list of labels

Return type:

list

new_track(segment: pyannote.core.segment.Segment, candidate: Union[str, int, None] = None, prefix: Optional[str] = None) → Union[str, int][source]

Generate a new track name for given segment

Ensures that the returned track name does not already exist for the given segment.

Parameters:
  • segment (Segment) – Segment for which a new track name is generated.

  • candidate (any valid track name, optional) – When provided, try this candidate name first.

  • prefix (str, optional) – Track name prefix. Defaults to the empty string ‘’.

Returns:

name – New track name

Return type:

str

relabel_tracks(generator: Union[typing_extensions.Literal['int', 'string'][int, string], Iterator[Hashable]] = 'string') → pyannote.core.annotation.Annotation[source]

Relabel tracks

Create a new annotation where each track has a unique label.

Parameters:

generator ('string', 'int' or iterable, optional) – If ‘string’ (default) relabel tracks to ‘A’, ‘B’, ‘C’, … If ‘int’ relabel to 0, 1, 2, … If iterable, use it to generate labels.

Returns:

renamed – New annotation with relabeled tracks.

Return type:

Annotation

rename_labels(mapping: Optional[Dict] = None, generator: Union[typing_extensions.Literal['int', 'string'][int, string], Iterator[Hashable]] = 'string', copy: bool = True) → pyannote.core.annotation.Annotation[source]

Rename labels

Parameters:
  • mapping (dict, optional) – {old_name: new_name} mapping dictionary.

  • generator ('string', 'int' or iterable, optional) – If ‘string’ (default) rename label to ‘A’, ‘B’, ‘C’, … If ‘int’, rename to 0, 1, 2, etc. If iterable, use it to generate labels.

  • copy (bool, optional) – Set to True to return a copy of the annotation. Set to False to update the annotation in-place. Defaults to True.

Returns:

renamed – Annotation where labels have been renamed

Return type:

Annotation

Note

Unmapped labels are kept unchanged.

Note

Parameter generator has no effect when mapping is provided.

rename_tracks(generator: Union[typing_extensions.Literal['int', 'string'][int, string], Iterator[Hashable]] = 'string') → pyannote.core.annotation.Annotation[source]

Rename all tracks

Parameters:

generator ('string', 'int', or iterable, optional) – If ‘string’ (default) rename tracks to ‘A’, ‘B’, ‘C’, etc. If ‘int’, rename tracks to 0, 1, 2, etc. If iterable, use it to generate track names.

Returns:

renamed – Copy of the original annotation where tracks are renamed.

Return type:

Annotation

Example

>>> annotation = Annotation()
>>> annotation[Segment(0, 1), 'a'] = 'a'
>>> annotation[Segment(0, 1), 'b'] = 'b'
>>> annotation[Segment(1, 2), 'a'] = 'a'
>>> annotation[Segment(1, 3), 'c'] = 'c'
>>> print(annotation)
[ 00:00:00.000 -->  00:00:01.000] a a
[ 00:00:00.000 -->  00:00:01.000] b b
[ 00:00:01.000 -->  00:00:02.000] a a
[ 00:00:01.000 -->  00:00:03.000] c c
>>> print(annotation.rename_tracks(generator='int'))
[ 00:00:00.000 -->  00:00:01.000] 0 a
[ 00:00:00.000 -->  00:00:01.000] 1 b
[ 00:00:01.000 -->  00:00:02.000] 2 a
[ 00:00:01.000 -->  00:00:03.000] 3 c
subset(labels: Iterable[Hashable], invert: bool = False) → pyannote.core.annotation.Annotation[source]

Filter annotation by labels

Parameters:
  • labels (iterable) – List of filtered labels

  • invert (bool, optional) – If invert is True, extract all but requested labels

Returns:

filtered – Filtered annotation

Return type:

Annotation

support(collar: float = 0.0) → pyannote.core.annotation.Annotation[source]

Annotation support

The support of an annotation is an annotation where contiguous tracks with same label are merged into one unique covering track.

A picture is worth a thousand words:

collar
|---|

annotation
|--A--| |--A--|     |-B-|
  |-B-|    |--C--|     |----B-----|

annotation.support(collar)
|------A------|     |------B------|
  |-B-|    |--C--|
Parameters:

collar (float, optional) – Merge tracks with same label and separated by less than collar seconds. This is why ‘A’ tracks are merged in above figure. Defaults to 0.

Returns:

support – Annotation support

Return type:

Annotation

Note

Track names are lost in the process.

update(annotation: pyannote.core.annotation.Annotation, copy: bool = False) → pyannote.core.annotation.Annotation[source]

Add every track of an existing annotation (in place)

Parameters:
  • annotation (Annotation) – Annotation whose tracks are being added

  • copy (bool, optional) – Return a copy of the annotation. Defaults to updating the annotation in-place.

Returns:

self – Updated annotation

Return type:

Annotation

Note

Existing tracks are updated with the new label.

write_rttm(file: TextIO)[source]

Dump annotation to file using RTTM format

Parameters:
  • file (file object) –

  • Usage

  • -----

  • with open('file.rttm', 'w') as file (>>>) –

  • annotation.write_rttm(file) (..) –

SlidingWindow

class pyannote.core.SlidingWindow(duration=0.03, step=0.01, start=0.0, end=None)[source]

Sliding window

Parameters:
  • duration (float > 0, optional) – Window duration, in seconds. Default is 30 ms.

  • step (float > 0, optional) – Step between two consecutive position, in seconds. Default is 10 ms.

  • start (float, optional) – First start position of window, in seconds. Default is 0.

  • end (float > start, optional) – Default is infinity (ie. window keeps sliding forever)

Examples

>>> sw = SlidingWindow(duration, step, start)
>>> frame_range = (a, b)
>>> frame_range == sw.toFrameRange(sw.toSegment(*frame_range))
... True
>>> segment = Segment(A, B)
>>> new_segment = sw.toSegment(*sw.toFrameRange(segment))
>>> abs(segment) - abs(segment & new_segment) < .5 * sw.step
>>> sw = SlidingWindow(end=0.1)
>>> print(next(sw))
[ 00:00:00.000 -->  00:00:00.030]
>>> print(next(sw))
[ 00:00:00.010 -->  00:00:00.040]
__call__(support: Union[pyannote.core.segment.Segment, Timeline], align_last: bool = False) → Iterable[pyannote.core.segment.Segment][source]

Slide window over support

supportSegment or Timeline

Support on which to slide the window.

align_lastbool, optional

Yield a final segment so that it aligns exactly with end of support.

Yields:

chunk (Segment)

Example

>>> window = SlidingWindow(duration=2., step=1.)
>>> for chunk in window(Segment(3, 7.5)):
...     print(tuple(chunk))
(3.0, 5.0)
(4.0, 6.0)
(5.0, 7.0)
>>> for chunk in window(Segment(3, 7.5), align_last=True):
...     print(tuple(chunk))
(3.0, 5.0)
(4.0, 6.0)
(5.0, 7.0)
(5.5, 7.5)
__getitem__(i: int) → pyannote.core.segment.Segment[source]
Parameters:

i (int) – Index of sliding window position

Returns:

segment – Sliding window at ith position

Return type:

Segment

__init__(duration=0.03, step=0.01, start=0.0, end=None)[source]

Initialize self. See help(type(self)) for accurate signature.

__iter__() → pyannote.core.segment.SlidingWindow[source]

Sliding window iterator

Use expression ‘for segment in sliding_window’

Examples

>>> window = SlidingWindow(end=0.1)
>>> for segment in window:
...     print(segment)
[ 00:00:00.000 -->  00:00:00.030]
[ 00:00:00.010 -->  00:00:00.040]
[ 00:00:00.020 -->  00:00:00.050]
[ 00:00:00.030 -->  00:00:00.060]
[ 00:00:00.040 -->  00:00:00.070]
[ 00:00:00.050 -->  00:00:00.080]
[ 00:00:00.060 -->  00:00:00.090]
[ 00:00:00.070 -->  00:00:00.100]
[ 00:00:00.080 -->  00:00:00.110]
[ 00:00:00.090 -->  00:00:00.120]
__len__() → int[source]

Number of positions

Equivalent to len([segment for segment in window])

Returns:

length – Number of positions taken by the sliding window (from start times to end times)

Return type:

int

__weakref__

list of weak references to the object (if defined)

closest_frame(t: float) → int[source]

Closest frame to timestamp.

Parameters:

t (float) – Timestamp, in seconds.

Returns:

index – Index of frame whose middle is the closest to timestamp

Return type:

int

copy() → pyannote.core.segment.SlidingWindow[source]

Duplicate sliding window

crop(focus: Union[pyannote.core.segment.Segment, Timeline], mode: typing_extensions.Literal['center', 'loose', 'strict'][center, loose, strict] = 'loose', fixed: Optional[float] = None, return_ranges: Optional[bool] = False) → Union[numpy.ndarray, List[List[int]]][source]

Crop sliding window

Parameters:
  • focus (Segment or Timeline) –

  • mode ({'strict', 'loose', 'center'}, optional) – In ‘strict’ mode, only indices of segments fully included in ‘focus’ support are returned. In ‘loose’ mode, indices of any intersecting segments are returned. In ‘center’ mode, first and last positions are chosen to be the positions whose centers are the closest to ‘focus’ start and end times. Defaults to ‘loose’.

  • fixed (float, optional) – Overrides Segment ‘focus’ duration and ensures that the number of returned frames is fixed (which might otherwise not be the case because of rounding erros).

  • return_ranges (bool, optional) – Return as list of ranges. Defaults to indices numpy array.

Returns:

indices – Array of unique indices of matching segments

Return type:

np.array (or list of ranges)

property duration

Sliding window duration in seconds.

duration_to_samples(duration: float) → int[source]

Returns samples in duration

property end

Sliding window end time in seconds.

range_to_segment(i0: int, n: int) → pyannote.core.segment.Segment[source]

Convert 0-indexed frame range to segment

Each frame represents a unique segment of duration ‘step’, centered on the middle of the frame.

The very first frame (i0 = 0) is the exception. It is extended to the sliding window start time.

Parameters:
  • i0 (int) – Index of first frame

  • n (int) – Number of frames

Returns:

segment

Return type:

Segment

Examples

>>> window = SlidingWindow()
>>> print window.range_to_segment(3, 2)
[ --> ]
samples(from_duration: float, mode: typing_extensions.Literal['center', 'loose', 'strict'][center, loose, strict] = 'strict') → int[source]

Number of frames

Parameters:
  • from_duration (float) – Duration in seconds.

  • mode ({'strict', 'loose', 'center'}) – In ‘strict’ mode, computes the maximum number of consecutive frames that can be fitted into a segment with duration from_duration. In ‘loose’ mode, computes the maximum number of consecutive frames intersecting a segment with duration from_duration. In ‘center’ mode, computes the average number of consecutive frames where the first one is centered on the start time and the last one is centered on the end time of a segment with duration from_duration.

samples_to_duration(n_samples: int) → float[source]

Returns duration of samples

segment_to_range(segment: pyannote.core.segment.Segment) → Tuple[int, int][source]

Convert segment to 0-indexed frame range

Parameters:

segment (Segment) –

Returns:

  • i0 (int) – Index of first frame

  • n (int) – Number of frames

Examples

>>> window = SlidingWindow()
>>> print window.segment_to_range(Segment(10, 15))
i0, n
property start

Sliding window start time in seconds.

property step

Sliding window step in seconds.

SlidingWindowFeature

class pyannote.core.SlidingWindowFeature(data: numpy.ndarray, sliding_window: pyannote.core.segment.SlidingWindow, labels: List[str] = None)[source]

Periodic feature vectors

Parameters:
  • data ((n_frames, n_features) numpy array) –

  • sliding_window (SlidingWindow) –

  • labels (list, optional) – Textual description of each dimension.

__getitem__(i: int) → numpy.ndarray[source]

Get ith feature vector

__init__(data: numpy.ndarray, sliding_window: pyannote.core.segment.SlidingWindow, labels: List[str] = None)[source]

Initialize self. See help(type(self)) for accurate signature.

__len__()[source]

Number of feature vectors

align(to: pyannote.core.feature.SlidingWindowFeature) → pyannote.core.feature.SlidingWindowFeature[source]

Align features by linear temporal interpolation

Parameters:

to (SlidingWindowFeature) – Features to align with.

Returns:

aligned – Aligned features

Return type:

SlidingWindowFeature

crop(focus: Union[pyannote.core.segment.Segment, pyannote.core.timeline.Timeline], mode: typing_extensions.Literal['center', 'loose', 'strict'][center, loose, strict] = 'loose', fixed: Optional[float] = None, return_data: bool = True) → Union[numpy.ndarray, pyannote.core.feature.SlidingWindowFeature][source]

Extract frames

Parameters:
  • focus (Segment or Timeline) –

  • mode ({'loose', 'strict', 'center'}, optional) – In ‘strict’ mode, only frames fully included in ‘focus’ support are returned. In ‘loose’ mode, any intersecting frames are returned. In ‘center’ mode, first and last frames are chosen to be the ones whose centers are the closest to ‘focus’ start and end times. Defaults to ‘loose’.

  • fixed (float, optional) – Overrides Segment ‘focus’ duration and ensures that the number of returned frames is fixed (which might otherwise not be the case because of rounding errors).

  • return_data (bool, optional) – Return a numpy array (default). For Segment ‘focus’, setting it to False will return a SlidingWindowFeature instance.

Returns:

data – Frame features.

Return type:

numpy.ndarray or SlidingWindowFeature

property dimension

Dimension of feature vectors

iterfeatures(window: Optional[bool] = False) → Iterator[Union[Tuple[numpy.ndarray, pyannote.core.segment.Segment], numpy.ndarray]][source]

Feature vector iterator

Parameters:

window (bool, optional) – When True, yield both feature vector and corresponding window. Default is to only yield feature vector

Serialization

pyannote.core.json.dump(resource: Union[Segment, Timeline, SlidingWindowFeature, Annotation], fp: TextIO)[source]

Serialize

Parameters:
  • resource (pyannote.core data structure) – Resource to serialize

  • fp (file) – File in which resource serialization is written

pyannote.core.json.dump_to(resource: Union[Segment, Timeline, SlidingWindowFeature, Annotation], path: Union[str, pathlib.Path])[source]

Serialize

Parameters:
  • resource (pyannote.core data structure) – Resource to serialize

  • path (string) – Path to file in which resource serialization is written

pyannote.core.json.dumps(resource: Union[Segment, Timeline, SlidingWindowFeature, Annotation]) → str[source]

Serialize to string

Parameters:

resource (pyannote.core data structure) –

Returns:

serialization

Return type:

string

pyannote.core.json.load(fp: TextIO) → Union[Segment, Timeline, SlidingWindowFeature, Annotation][source]

Deserialize

Parameters:

fp (file) – File containing serialized pyannote.core data structure

Returns:

deserialized

Return type:

pyannote.core data structure

pyannote.core.json.load_from(path: Union[str, pathlib.Path]) → Union[Segment, Timeline, SlidingWindowFeature, Annotation][source]

Deserialize

Parameters:

path (string or Path) – Path to file containing serialized pyannote.core data structure

Returns:

deserialized

Return type:

pyannote.core data structure

pyannote.core.json.loads(s: str) → Union[Segment, Timeline, SlidingWindowFeature, Annotation][source]

Deserialize

Parameters:

s (string) – String containing serialized pyannote.core data structure

Returns:

deserialized

Return type:

pyannote.core data structure

pyannote.core.json.object_hook(d)[source]

Utility function for deserialization

>>> with open('file.json', 'r') as f:
...   json.load(f, object_hook=object_hook)

Visualization

Visualization

pyannote.core.Segment, pyannote.core.Timeline, pyannote.core.Annotation and pyannote.core.SlidingWindowFeature instances can be directly visualized in notebooks.

You will however need to install pytannote.core’s additional dependencies for notebook representations (namely, matplotlib):

pip install pyannote.core[notebook]

Segments

In [1]: from pyannote.core import Segment

In [2]: segment = Segment(start=5, end=15)
  ....: segment

(Source code, png, hires.png, pdf)

_images/segment.png

Timelines

In [25]: from pyannote.core import Timeline, Segment

In [26]: timeline = Timeline()
   ....: timeline.add(Segment(1, 5))
   ....: timeline.add(Segment(6, 8))
   ....: timeline.add(Segment(12, 18))
   ....: timeline.add(Segment(7, 20))
   ....: timeline

(Source code, png, hires.png, pdf)

_images/timeline.png

Annotations

In [1]: from pyannote.core import Annotation, Segment

In [6]: annotation = Annotation()
   ...: annotation[Segment(1, 5)] = 'Carol'
   ...: annotation[Segment(6, 8)] = 'Bob'
   ...: annotation[Segment(12, 18)] = 'Carol'
   ...: annotation[Segment(7, 20)] = 'Alice'
   ...: annotation

(Source code, png, hires.png, pdf)

_images/annotation.png
pyannote.core.notebook.repr_annotation(annotation: pyannote.core.annotation.Annotation)[source]

Get png data for annotation

pyannote.core.notebook.repr_feature(feature: pyannote.core.feature.SlidingWindowFeature)[source]

Get png data for feature

pyannote.core.notebook.repr_segment(segment: pyannote.core.segment.Segment)[source]

Get png data for segment

pyannote.core.notebook.repr_timeline(timeline: pyannote.core.timeline.Timeline)[source]

Get png data for timeline