Skip to content

Commit

Permalink
Merge pull request #153 from marl/023-deprecations
Browse files Browse the repository at this point in the history
0.2.3 -> 0.3.0 shims
  • Loading branch information
bmcfee authored May 13, 2017
2 parents 7c1ff90 + a54a040 commit 04cbd3b
Show file tree
Hide file tree
Showing 11 changed files with 169 additions and 46 deletions.
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ python:
- "2.7"
- "3.4"
- "3.5"
- "3.6"

before_install:
- bash .travis_dependencies.sh
Expand Down
47 changes: 34 additions & 13 deletions docs/changes.rst
Original file line number Diff line number Diff line change
@@ -1,34 +1,55 @@
Changes
=======

v0.2.3
------

- Deprecated the `JamsFrame` class
(`PR #153 <https://github.com/marl/jams/pull/153>`_):

- Moved `JamsFrame.to_interval_values()` to `Annotation.to_interval_values()`

- Any code that uses `pandas.DataFrame` methods on `Annotation.data` will cease to work
starting in 0.3.0.

- Forward compatibility with 0.3.0
(`PR #153 <https://github.com/marl/jams/pull/153>`_):

- Added the `jams.Observation` type

- Added iteration support to `Annotation` objects

- added type safety check in regexp search (`PR #146 <https://github.com/marl/jams/pull/146>`_).
- added support for `pandas=0.20` (`PR #150 <https://github.com/marl/jams/pull/150>`_).

v0.2.2
------
- added ``__contains__`` method to ``JObject``
(`PR #139 <https://github.com/marl/jams/pull/139`_).
(`PR #139 <https://github.com/marl/jams/pull/139>`_).
- Implemented ``JAMS.trim()`` method
(`PR #136 <https://github.com/marl/jams/pull/136`_).
(`PR #136 <https://github.com/marl/jams/pull/136>`_).
- Updates to the SALAMI tag namespaces
(`PR #134 <https://github.com/marl/jams/pull/134`_).
(`PR #134 <https://github.com/marl/jams/pull/134>`_).
- added `infer_duration` flag to ``import_lab``
(`PR #125 <https://github.com/marl/jams/pull/125`_).
(`PR #125 <https://github.com/marl/jams/pull/125>`_).
- namespace conversion validates input
(`PR #123 <https://github.com/marl/jams/pull/123`_).
(`PR #123 <https://github.com/marl/jams/pull/123>`_).
- Refactored the ``pitch`` namespaces
(`PR #121 <https://github.com/marl/jams/pull/121`_).
(`PR #121 <https://github.com/marl/jams/pull/121>`_).
- Fancy indexing for annotation arrays
(`PR #120 <https://github.com/marl/jams/pull/120`_).
(`PR #120 <https://github.com/marl/jams/pull/120>`_).
- ``jams.schema.values`` function to access enumerated types
(`PR #119 <https://github.com/marl/jams/pull/119`_).
(`PR #119 <https://github.com/marl/jams/pull/119>`_).
- ``jams.display`` submodule
(`PR #115 <https://github.com/marl/jams/pull/115`_).
(`PR #115 <https://github.com/marl/jams/pull/115>`_).
- support for `mir_eval >= 0.3`
(`PR #106 <https://github.com/marl/jams/pull/106`_).
(`PR #106 <https://github.com/marl/jams/pull/106>`_).
- Automatic conversion between namespaces
(`PR #105 <https://github.com/marl/jams/pull/105`_).
(`PR #105 <https://github.com/marl/jams/pull/105>`_).
- Fixed a type error in ``jams_to_lab``
(`PR #94 <https://github.com/marl/jams/pull/94`_).
(`PR #94 <https://github.com/marl/jams/pull/94>`_).
- ``jams.sonify`` module for sonification
(`PR #91 <https://github.com/marl/jams/pull/91`_).
(`PR #91 <https://github.com/marl/jams/pull/91>`_).

v0.2.1
------
Expand Down
68 changes: 66 additions & 2 deletions jams/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
JamsFrame
Sandbox
JObject
Observation
"""

import json
Expand All @@ -45,6 +45,10 @@
import gzip
import copy
import sys
from collections import namedtuple

from decorator import decorator


from .version import version as __VERSION__
from . import schema
Expand All @@ -54,7 +58,31 @@
__all__ = ['load',
'JObject', 'Sandbox', 'JamsFrame',
'Annotation', 'Curator', 'AnnotationMetadata',
'FileMetadata', 'AnnotationArray', 'JAMS']
'FileMetadata', 'AnnotationArray', 'JAMS',
'Observation']


def deprecated(version, version_removed):
'''This is a decorator which can be used to mark functions
as deprecated.
It will result in a warning being emitted when the function is used.'''

def __wrapper(func, *args, **kwargs):
'''Warn the user, and then proceed.'''
code = six.get_function_code(func)
warnings.warn_explicit(
"{:s}.{:s}\n\tDeprecated as of JAMS version {:s}."
"\n\tIt will be removed in JAMS version {:s}."
.format(func.__module__, func.__name__,
version, version_removed),
category=DeprecationWarning,
filename=code.co_filename,
lineno=code.co_firstlineno + 1
)
return func(*args, **kwargs)

return decorator(__wrapper)


@contextlib.contextmanager
Expand Down Expand Up @@ -489,6 +517,11 @@ def validate(self, strict=True):
return valid


Observation = namedtuple('Observation',
['time', 'duration', 'value', 'confidence'])
'''Core observation type: (time, duration, value, confidence).'''


class Sandbox(JObject):
"""Sandbox (unconstrained)
Expand Down Expand Up @@ -711,6 +744,7 @@ def add_observation(self, time=None, duration=None,
self.drop(n, inplace=True, errors='ignore')
six.reraise(SchemaError, SchemaError(str(exc)), sys.exc_info()[2])

@deprecated('0.2.3', '0.3.0')
def to_interval_values(self):
'''Extract observation data in a `mir_eval`-friendly format.
Expand Down Expand Up @@ -1168,6 +1202,34 @@ def slice(self, start_time, end_time, strict=False):

return sliced_ann

def to_interval_values(self):
'''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.
'''

times = timedelta_to_float(self.data.time.values)
duration = timedelta_to_float(self.data.duration.values)

return np.vstack([times, times + duration]).T, list(self.data.value)

def __iter_obs__(self):
for _, (t, d, v, c) in self.data.iterrows():
yield Observation(time=t.total_seconds(),
duration=d.total_seconds(),
value=v, confidence=c)

def __iter__(self):
return self.__iter_obs__()


class Curator(JObject):
"""Curator
Expand Down Expand Up @@ -1881,3 +1943,5 @@ def serialize_obj(obj):
return [serialize_obj(x) for x in obj]

return obj


10 changes: 5 additions & 5 deletions jams/display.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def pprint_jobject(obj, **kwargs):

def intervals(annotation, **kwargs):
'''Plotting wrapper for labeled intervals'''
times, labels = annotation.data.to_interval_values()
times, labels = annotation.to_interval_values()

return mir_eval.display.labeled_intervals(times, labels, **kwargs)

Expand All @@ -83,7 +83,7 @@ def pitch_contour(annotation, **kwargs):
# If the annotation is empty, we need to construct a new axes
ax = mir_eval.display.__get_axes(ax=ax)[0]

times, values = annotation.data.to_interval_values()
times, values = annotation.to_interval_values()

indices = np.unique([v['index'] for v in values])

Expand All @@ -102,7 +102,7 @@ def pitch_contour(annotation, **kwargs):
def event(annotation, **kwargs):
'''Plotting wrapper for events'''

times, values = annotation.data.to_interval_values()
times, values = annotation.to_interval_values()

if any(values):
labels = values
Expand All @@ -115,7 +115,7 @@ def event(annotation, **kwargs):
def beat_position(annotation, **kwargs):
'''Plotting wrapper for beat-position data'''

times, values = annotation.data.to_interval_values()
times, values = annotation.to_interval_values()

labels = [_['position'] for _ in values]

Expand All @@ -125,7 +125,7 @@ def beat_position(annotation, **kwargs):

def piano_roll(annotation, **kwargs):
'''Plotting wrapper for piano rolls'''
times, midi = annotation.data.to_interval_values()
times, midi = annotation.to_interval_values()

return mir_eval.display.piano_roll(times, midi=midi, **kwargs)

Expand Down
28 changes: 14 additions & 14 deletions jams/eval.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,8 @@ def beat(ref, est, **kwargs):
namespace = 'beat'
ref = coerce_annotation(ref, namespace)
est = coerce_annotation(est, namespace)
ref_interval, _ = ref.data.to_interval_values()
est_interval, _ = est.data.to_interval_values()
ref_interval, _ = ref.to_interval_values()
est_interval, _ = est.to_interval_values()

return mir_eval.beat.evaluate(ref_interval[:, 0], est_interval[:, 0], **kwargs)

Expand Down Expand Up @@ -145,8 +145,8 @@ def onset(ref, est, **kwargs):
namespace = 'onset'
ref = coerce_annotation(ref, namespace)
est = coerce_annotation(est, namespace)
ref_interval, _ = ref.data.to_interval_values()
est_interval, _ = est.data.to_interval_values()
ref_interval, _ = ref.to_interval_values()
est_interval, _ = est.to_interval_values()

return mir_eval.onset.evaluate(ref_interval[:, 0], est_interval[:, 0], **kwargs)

Expand Down Expand Up @@ -187,8 +187,8 @@ def chord(ref, est, **kwargs):
namespace = 'chord'
ref = coerce_annotation(ref, namespace)
est = coerce_annotation(est, namespace)
ref_interval, ref_value = ref.data.to_interval_values()
est_interval, est_value = est.data.to_interval_values()
ref_interval, ref_value = ref.to_interval_values()
est_interval, est_value = est.to_interval_values()

return mir_eval.chord.evaluate(ref_interval, ref_value,
est_interval, est_value, **kwargs)
Expand Down Expand Up @@ -229,8 +229,8 @@ def segment(ref, est, **kwargs):
namespace = 'segment_open'
ref = coerce_annotation(ref, namespace)
est = coerce_annotation(est, namespace)
ref_interval, ref_value = ref.data.to_interval_values()
est_interval, est_value = est.data.to_interval_values()
ref_interval, ref_value = ref.to_interval_values()
est_interval, est_value = est.to_interval_values()

return mir_eval.segment.evaluate(ref_interval, ref_value,
est_interval, est_value, **kwargs)
Expand All @@ -253,7 +253,7 @@ def hierarchy_flatten(annotation):
A list of lists of labels, ordered by increasing specificity.
'''

intervals, values = annotation.data.to_interval_values()
intervals, values = annotation.to_interval_values()

ordering = dict()

Expand Down Expand Up @@ -394,8 +394,8 @@ def melody(ref, est, **kwargs):
namespace = 'pitch_contour'
ref = coerce_annotation(ref, namespace)
est = coerce_annotation(est, namespace)
ref_interval, ref_p = ref.data.to_interval_values()
est_interval, est_p = est.data.to_interval_values()
ref_interval, ref_p = ref.to_interval_values()
est_interval, est_p = est.to_interval_values()

ref_freq = np.asarray([p['frequency'] * (-1)**(~p['voiced']) for p in ref_p])
est_freq = np.asarray([p['frequency'] * (-1)**(~p['voiced']) for p in est_p])
Expand Down Expand Up @@ -432,7 +432,7 @@ def pattern_to_mireval(ann):
patterns = defaultdict(lambda: defaultdict(list))

# Iterate over the data in interval-value format
for interval, observation in zip(*ann.data.to_interval_values()):
for interval, observation in zip(*ann.to_interval_values()):

pattern_id = observation['pattern_id']
occurrence_id = observation['occurrence_id']
Expand Down Expand Up @@ -525,8 +525,8 @@ def transcription(ref, est, **kwargs):
namespace = 'pitch_contour'
ref = coerce_annotation(ref, namespace)
est = coerce_annotation(est, namespace)
ref_intervals, ref_p = ref.data.to_interval_values()
est_intervals, est_p = est.data.to_interval_values()
ref_intervals, ref_p = ref.to_interval_values()
est_intervals, est_p = est.to_interval_values()

ref_pitches = np.asarray([p['frequency'] * (-1)**(~p['voiced']) for p in ref_p])
est_pitches = np.asarray([p['frequency'] * (-1)**(~p['voiced']) for p in est_p])
Expand Down
10 changes: 5 additions & 5 deletions jams/sonify.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def clicks(annotation, sr=22050, length=None, **kwargs):
events such as beats or segment boundaries.
'''

interval, _ = annotation.data.to_interval_values()
interval, _ = annotation.to_interval_values()

return filter_kwargs(mir_eval.sonify.clicks, interval[:, 0],
fs=sr, length=length, **kwargs)
Expand All @@ -56,7 +56,7 @@ def downbeat(annotation, sr=22050, length=None, **kwargs):
beat_click = mkclick(440 * 2, sr=sr)
downbeat_click = mkclick(440 * 3, sr=sr)

intervals, values = annotation.data.to_interval_values()
intervals, values = annotation.to_interval_values()

beats, downbeats = [], []

Expand Down Expand Up @@ -109,7 +109,7 @@ def chord(annotation, sr=22050, length=None, **kwargs):
This uses mir_eval.sonify.chords.
'''

intervals, chords = annotation.data.to_interval_values()
intervals, chords = annotation.to_interval_values()

return filter_kwargs(mir_eval.sonify.chords,
chords, intervals,
Expand All @@ -127,7 +127,7 @@ def pitch_contour(annotation, sr=22050, length=None, **kwargs):
are summed together.
'''

times, values = annotation.data.to_interval_values()
times, values = annotation.to_interval_values()

indices = np.unique([v['index'] for v in values])

Expand Down Expand Up @@ -159,7 +159,7 @@ def piano_roll(annotation, sr=22050, length=None, **kwargs):
namespace.
'''

intervals, pitches = annotation.data.to_interval_values()
intervals, pitches = annotation.to_interval_values()

# Construct the pitchogram
pitch_map = {f: idx for idx, f in enumerate(np.unique(pitches))}
Expand Down
1 change: 1 addition & 0 deletions jams/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
smkdirs
filebase
find_with_extension
_deprecated
"""

import os
Expand Down
2 changes: 1 addition & 1 deletion jams/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
"""Version info"""

short_version = '0.2'
version = '0.2.2'
version = '0.2.3'
Loading

0 comments on commit 04cbd3b

Please sign in to comment.