Source code for vis.analyzers.indexers.repeat
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# -------------------------------------------------------------------- #
# Program Name: vis
# Program Description: Helps analyze music with computers.
#
# Filename: analyzers/indexers/repeat.py
# Purpose: Indexers that somehow consider repetition.
#
# Copyright (C) 2013, 2014, 2016 Christopher Antila and Alexander Morgan
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License along with this program. If not, see
# <http://www.gnu.org/licenses/>.
# -------------------------------------------------------------------- #
"""
.. codeauthor:: Christopher Antila <christopher@antila.ca>
.. codeauthor:: Alexander Morgan
Indexers that consider repetition in any way.
"""
import six
from vis.analyzers import indexer
[docs]class FilterByRepeatIndexer(indexer.Indexer):
"""
If the same event occurs many times in a row, remove all occurrences
but the one with the lowest ``offset`` value (i.e., the "first"
event).
Because of how a :class:`DataFrame`'s index works, many of the
events that would have been filtered will instead be replaced with
:const:`numpy.NaN`. Please be careful that the behaviour of this
indexer matches your expectations.
**Example:**
Prepare an indexed piece:
>>> from vis.models.indexed_piece import Importer
>>> ip = Importer('path_to_piece.xml')
This example filters the repeats out of the ``NoteRestIndexer``
results, but any can be passed:
>>> notes = ip.get_data('noterest')
>>> ip.get_data('repeat', data=notes)
"""
required_score_type = 'pandas.Series'
def __init__(self, score, settings=None):
"""
:param score: The indices from which to remove consecutive
identical events. There must be at least one part in the
score.
:type score: :class:`pandas.DataFrame` or list of
:class:`pandas.Series`
:param settings: This indexer uses no settings, so this is
ignored.
:type settings: dict or NoneType
:raises: :exc:`RuntimeError` if ``score`` is the wrong type.
:raises: :exc:`RuntimeError` if ``score`` is not a list of the
same types.
"""
super(FilterByRepeatIndexer, self).__init__(score, None)
# This Indexer uses pandas magic, not an _indexer_func().
self._indexer_func = None
[docs] def run(self):
"""
Make a new index of the piece, removing any event that is
identical to the preceding.
:returns: A :class:`DataFrame` of the new indices.
:rtype: :class:`pandas.DataFrame`
"""
post = [part[part != part.shift(1)] for part in self._score]
# prepare the proper return type
combinations = [[x] for x in range(len(self._score))]
return self.make_return([six.u(str(x))[1:-1]
for x in combinations], post)