jams.Annotation

class jams.Annotation(namespace, data=None, annotation_metadata=None, sandbox=None, time=0, duration=None)[source]

Bases: jams.core.JObject

Annotation base class.

__init__(self, namespace, data=None, annotation_metadata=None, sandbox=None, time=0, duration=None)[source]

Create an Annotation.

Note that, if an argument is None, an empty Annotation is created in its place. Additionally, a dictionary matching the expected structure of the arguments will be parsed (i.e. instantiating from JSON).

Parameters:
namespace : str

The namespace for this annotation

data : dict of lists, list of dicts, or list of Observations

Data for the new annotation

annotation_metadata : AnnotationMetadata (or dict), default=None.

Metadata corresponding to this Annotation.

sandbox : Sandbox (dict), default=None

Miscellaneous information; keep to native datatypes if possible.

time : non-negative number

The starting time for this annotation

duration : non-negative number

The duration of this annotation

Attributes

type The type (class name) of a derived JObject type

Methods

__init__(self, namespace[, data, …]) Create an Annotation.
append(self[, time, duration, value, confidence]) Append an observation to the data field
append_columns(self, columns) Add observations from column-major storage.
append_records(self, records) Add observations from row-major storage.
dumps(self, \*\*kwargs) Serialize the JObject to a string.
keys(self) Return a list of the attributes of the object.
loads(string) De-serialize a JObject
pop_data(self) Replace this observation’s data with a fresh container.
search(self, \*\*kwargs) Query this object (and its descendants).
slice(self, start_time, end_time[, strict]) Slice the annotation and return as a new Annotation object.
to_dataframe(self) Convert this annotation to a pandas dataframe.
to_event_values(self) Extract observation data in a mir_eval-friendly format.
to_html(self[, max_rows]) Render this annotation list in HTML
to_interval_values(self) Extract observation data in a mir_eval-friendly format.
to_samples(self, times[, confidence]) Sample the annotation at specified times.
trim(self, start_time, end_time[, strict]) Trim the annotation and return as a new Annotation object.
update(self, \*\*kwargs) Update the attributes of a JObject.
validate(self[, strict]) Validate this annotation object against the JAMS schema, and its data against the namespace schema.
append(self, time=None, duration=None, value=None, confidence=None)[source]

Append an observation to the data field

Parameters:
time : float >= 0
duration : float >= 0

The time and duration of the new observation, in seconds

value
confidence

The value and confidence of the new observations.

Types and values should conform to the namespace of the Annotation object.

Examples

>>> ann = jams.Annotation(namespace='chord')
>>> ann.append(time=3, duration=2, value='E#')
append_columns(self, columns)[source]

Add observations from column-major storage.

This is primarily used for deserializing densely packed data.

Parameters:
columns : dict of lists

Keys must be time, duration, value, confidence, and each much be a list of equal length.

append_records(self, records)[source]

Add observations from row-major storage.

This is primarily useful for deserializing sparsely packed data.

Parameters:
records : iterable of dicts or Observations

Each element of records corresponds to one observation.

pop_data(self)[source]

Replace this observation’s data with a fresh container.

Returns:
annotation_data : SortedKeyList

The original annotation data container

slice(self, start_time, end_time, strict=False)[source]

Slice the annotation and return as a new Annotation object.

Slicing has the same effect as trimming (see Annotation.trim) except that while trimming does not modify the start time of the annotation or the observations it contains, slicing will set the new annotation’s start time to max(0, trimmed_annotation.time - start_time) and the start time of its observations will be set with respect to this new reference start time.

This function documents the slice operation by adding a list of tuples to the annotation’s sandbox keyed by Annotation.sandbox.slice which documents each slice operation with a tuple (start_time, end_time, slice_start, slice_end), where slice_start and slice_end are given by trim_start and trim_end (see Annotation.trim).

Since slicing is implemented using trimming, the trimming operation will also be documented in Annotation.sandbox.trim as described in Annotation.trim.

This function is useful for example when trimming an audio file, allowing the user to trim the annotation while ensuring all time information matches the new trimmed audio file.

Parameters:
start_time : float

The desired start time for slicing in seconds.

end_time

The desired end time for slicing in seconds. Must be greater than start_time.

strict : bool

When False (default) observations that lie at the boundaries of the slice (see Annotation.trim for details) will have their time and/or duration adjusted such that only the part of the observation that lies within the slice range is kept. When True such observations are discarded and not included in the sliced annotation.

Returns:
sliced_ann : Annotation

The sliced annotation.

See also

Annotation.trim

Examples

>>> ann = jams.Annotation(namespace='tag_open', time=2, duration=8)
>>> ann.append(time=2, duration=2, value='one')
>>> ann.append(time=4, duration=2, value='two')
>>> ann.append(time=6, duration=2, value='three')
>>> ann.append(time=7, duration=2, value='four')
>>> ann.append(time=8, duration=2, value='five')
>>> ann_slice = ann.slice(5, 8, strict=False)
>>> print(ann_slice.time, ann_slice.duration)
(0, 3)
>>> ann_slice.to_dataframe()
   time  duration  value confidence
0   0.0       1.0    two       None
1   1.0       2.0  three       None
2   2.0       1.0   four       None
>>> ann_slice_strict = ann.slice(5, 8, strict=True)
>>> print(ann_slice_strict.time, ann_slice_strict.duration)
(0, 3)
>>> ann_slice_strict.to_dataframe()
   time  duration  value confidence
0   1.0       2.0  three       None
to_dataframe(self)[source]

Convert this annotation to a pandas dataframe.

Returns:
df : pd.DataFrame

Columns are time, duration, value, confidence. Each row is an observation, and rows are sorted by ascending time.

to_event_values(self)[source]

Extract observation data in a mir_eval-friendly format.

Returns:
times : np.ndarray [shape=(n,), dtype=float]

Start-time of all observations

labels : list

List view of value field.

to_html(self, max_rows=None)[source]

Render this annotation list in HTML

Returns:
rendered : str

An HTML table containing this annotation’s data.

to_interval_values(self)[source]

Extract observation data in a mir_eval-friendly format.

Returns:
intervals : np.ndarray [shape=(n, 2), dtype=float]

Start- and end-times of all valued intervals

intervals[i, :] = [time[i], time[i] + duration[i]]

labels : list

List view of value field.

to_samples(self, times, confidence=False)[source]

Sample the annotation at specified times.

Parameters:
times : np.ndarray, non-negative, ndim=1

The times (in seconds) to sample the annotation

confidence : bool

If True, return both values and confidences. If False (default) only return values.

Returns:
values : list

values[i] is a list of observation values for intervals that cover times[i].

confidence : list (optional)

confidence values corresponding to values

trim(self, start_time, end_time, strict=False)[source]

Trim the annotation and return as a new Annotation object.

Trimming will result in the new annotation only containing observations that occur in the intersection of the time range spanned by the annotation and the time range specified by the user. The new annotation will span the time range [trim_start, trim_end] where trim_start = max(self.time, start_time) and trim_end = min(self.time + self.duration, end_time).

If strict=False (default) observations that start before trim_start and end after it will be trimmed such that they start at trim_start, and similarly observations that start before trim_end and end after it will be trimmed to end at trim_end. If strict=True such borderline observations will be discarded.

The new duration of the annotation will be trim_end - trim_start.

Note that if the range defined by [start_time, end_time] doesn’t intersect with the original time range spanned by the annotation the resulting annotation will contain no observations, will have the same start time as the original annotation and have duration 0.

This function also copies over all the annotation metadata from the original annotation and documents the trim operation by adding a list of tuples to the annotation’s sandbox keyed by Annotation.sandbox.trim which documents each trim operation with a tuple (start_time, end_time, trim_start, trim_end).

Parameters:
start_time : float

The desired start time for the trimmed annotation in seconds.

end_time

The desired end time for the trimmed annotation in seconds. Must be greater than start_time.

strict : bool

When False (default) observations that lie at the boundaries of the trimming range (given by [trim_start, trim_end] as described above), i.e. observations that start before and end after either the trim start or end time, will have their time and/or duration adjusted such that only the part of the observation that lies within the trim range is kept. When True such observations are discarded and not included in the trimmed annotation.

Returns:
ann_trimmed : Annotation

The trimmed annotation, returned as a new jams.Annotation object. If the trim range specified by [start_time, end_time] does not intersect at all with the original time range of the annotation a warning will be issued and the returned annotation will be empty.

Raises:
ParameterError

If end_time is not greater than start_time.

Examples

>>> ann = jams.Annotation(namespace='tag_open', time=2, duration=8)
>>> ann.append(time=2, duration=2, value='one')
>>> ann.append(time=4, duration=2, value='two')
>>> ann.append(time=6, duration=2, value='three')
>>> ann.append(time=7, duration=2, value='four')
>>> ann.append(time=8, duration=2, value='five')
>>> ann_trim = ann.trim(5, 8, strict=False)
>>> print(ann_trim.time, ann_trim.duration)
(5, 3)
>>> ann_trim.to_dataframe()
   time  duration  value confidence
0     5         1    two       None
1     6         2  three       None
2     7         1   four       None
>>> ann_trim_strict = ann.trim(5, 8, strict=True)
>>> print(ann_trim_strict.time, ann_trim_strict.duration)
(5, 3)
>>> ann_trim_strict.to_dataframe()
   time  duration  value confidence
0     6         2  three       None
validate(self, strict=True)[source]

Validate this annotation object against the JAMS schema, and its data against the namespace schema.

Parameters:
strict : bool

If True, then schema violations will cause an Exception. If False, then schema violations will issue a warning.

Returns:
valid : bool

True if the object conforms to schema. False if the object fails to conform to schema, but strict == False.

Raises:
SchemaError

If strict == True and the object fails validation

See also

JObject.validate