Skip to content

Commit

Permalink
Merge pull request #174 from Forced-Alignment-and-Vowel-Extraction/17…
Browse files Browse the repository at this point in the history
…2-feature-request-time-shifting

Shift methods
  • Loading branch information
JoFrhwld authored Mar 2, 2024
2 parents 364bf5f + f683ed8 commit e9bd3fb
Show file tree
Hide file tree
Showing 12 changed files with 333 additions and 10 deletions.
2 changes: 1 addition & 1 deletion doc_src/objects.json

Large diffs are not rendered by default.

31 changes: 23 additions & 8 deletions doc_src/reference/AlignedTextGrid.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@ An aligned Textgrid

## Attributes

| Name | Type | Description |
|---------------|----------------------------------------------|------------------------------------------------------|
| entry_classes | list\[Sequence\[Type\[SequenceInterval\]\]\] | The entry classes for each tier within a tier group. |
| tier_groups | list\[TierGroup\] | a list of `TierGroup` |
| xmax | float | Maximum time |
| xmin | float | Minimum time |
| \[\] | | indexable |
| Name | Type | Description |
|---------------|----------------------------------------------------------|------------------------------------------------------|
| entry_classes | list\[Sequence\[Type\[SequenceInterval\]\]\] \| list\[\] | The entry classes for each tier within a tier group. |
| tier_groups | list\[TierGroup\] \| list\[\] | A list of `TierGroup` or an empty list. |
| tier_names | list\[str\] | A list of names for tiers in tier_groups. |
| xmax | float | Maximum time |
| xmin | float | Minimum time |
| \[\] | | indexable |

## Methods

Expand All @@ -31,6 +32,7 @@ An aligned Textgrid
| [interleave_class](#aligned_textgrid.aligned_textgrid.AlignedTextGrid.interleave_class) | Interleave a new entry class. |
| [return_textgrid](#aligned_textgrid.aligned_textgrid.AlignedTextGrid.return_textgrid) | Convert this `AlignedTextGrid` to a `praatio` `Textgrid` |
| [save_textgrid](#aligned_textgrid.aligned_textgrid.AlignedTextGrid.save_textgrid) | Saves the current AlignedTextGrid |
| [shift](#aligned_textgrid.aligned_textgrid.AlignedTextGrid.shift) | Shift all times (interval starts & ends and point times) |

### get_class_by_name { #aligned_textgrid.aligned_textgrid.AlignedTextGrid.get_class_by_name }

Expand Down Expand Up @@ -116,4 +118,17 @@ Uses the `praatio.data_classes.textgrid.Textgrid.save()` method.
| Name | Type | Description | Default |
|-------------|-----------------------------------------------------------------------|------------------------------|-------------------|
| `save_path` | str | path for saving the textgrid | _required_ |
| `format` | Literal\['short_textgrid', 'long_textgrid', 'json', 'textgrid_json'\] | Save format. | `'long_textgrid'` |
| `format` | Literal\['short_textgrid', 'long_textgrid', 'json', 'textgrid_json'\] | Save format. | `'long_textgrid'` |

### shift { #aligned_textgrid.aligned_textgrid.AlignedTextGrid.shift }

`aligned_textgrid.AlignedTextGrid.shift(increment)`

Shift all times (interval starts & ends and point times)
by the given increment.

#### Parameters

| Name | Type | Description | Default |
|-------------|--------|---------------------------------------------------------------------------|------------|
| `increment` | float | The increment by which to shift all times. Could be positive or negative. | _required_ |
14 changes: 14 additions & 0 deletions doc_src/reference/TierGroup.qmd
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Tier Grouping
| Name | Description |
| --- | --- |
| [get_intervals_at_time](#aligned_textgrid.sequences.tiers.TierGroup.get_intervals_at_time) | Get intervals at time |
| [shift](#aligned_textgrid.sequences.tiers.TierGroup.shift) | Shift the start and end times of all intervals within |
| [show_structure](#aligned_textgrid.sequences.tiers.TierGroup.show_structure) | Show the hierarchical structure |

### get_intervals_at_time { #aligned_textgrid.sequences.tiers.TierGroup.get_intervals_at_time }
Expand All @@ -48,6 +49,19 @@ Returns a list of intervals at `time` for each tier.
|-------------|--------------------------------------------------------------|
| list\[int\] | A list of interval indices, one for each tier in `tier_list` |

### shift { #aligned_textgrid.sequences.tiers.TierGroup.shift }

`sequences.tiers.TierGroup.shift(increment)`

Shift the start and end times of all intervals within
the TierGroup by the increment size

#### Parameters

| Name | Type | Description | Default |
|-------------|--------|--------------------------------------------------------------------------------------------------------|------------|
| `increment` | float | The time increment by which to shift the intervals within the TierGroup. Could be positive or negative | _required_ |

### show_structure { #aligned_textgrid.sequences.tiers.TierGroup.show_structure }

`sequences.tiers.TierGroup.show_structure()`
Expand Down
15 changes: 15 additions & 0 deletions src/aligned_textgrid/aligned_textgrid.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,21 @@ def xmax(self):
raise ValueError('No maximum time for empty TextGrid.')
return np.array([tgroup.xmax for tgroup in self.tier_groups]).max()

def shift(
self,
increment: float
):
"""Shift all times (interval starts & ends and point times)
by the given increment.
Args:
increment (float):
The increment by which to shift all times.
Could be positive or negative.
"""
for gr in self:
gr.shift(increment)

def interleave_class(
self,
name:str,
Expand Down
11 changes: 11 additions & 0 deletions src/aligned_textgrid/points/points.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,14 @@ def __getitem__(self, idex):
return None

## Properties
@property
def time(self):
return self._time

@time.setter
def time(self, time):
self._time = time

@property
def fol_distance(self):
if self.fol and self.fol.time:
Expand Down Expand Up @@ -102,6 +110,9 @@ def prev_distance(self):
return None

## methods
def _shift(self, increment):
self.time += increment

def distance_from(
self,
entry: Self|SequenceInterval
Expand Down
28 changes: 28 additions & 0 deletions src/aligned_textgrid/points/tiers.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,14 @@ def times(self):
[x.time for x in self.sequence_list]
)

@times.setter
def times(self, new_times):
if not len(self.sequence_list) == len(new_times):
raise Exception("There aren't the same number of new start times as intervals")

for p, t in zip(self.sequence_list, new_times):
p.time = t

@property
def labels(self):
return [x.label for x in self.sequence_list]
Expand All @@ -110,6 +118,9 @@ def xmax(self):
return self.sequence_list[-1].time
else:
return None

def _shift(self, increment):
self.times += increment

def get_nearest_point_index(
self,
Expand Down Expand Up @@ -184,6 +195,23 @@ def __init__(
super().__init__()
self.tier_list = tiers
self.contains = self.tier_list

def shift(
self,
increment: float
):
"""Shift the times of all points within
the PointsGroup by the increment size
Args:
increment (float):
The time increment by which to shift the
points within the PointsGroup. Could be
positive or negative
"""

for tier in self.tier_list:
tier._shift(increment)

def get_nearest_points_index(
self,
Expand Down
20 changes: 20 additions & 0 deletions src/aligned_textgrid/sequences/sequences.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,22 @@ def __repr__(self) -> str:
return out_string

# properties
@property
def start(self):
return self._start

@start.setter
def start(self, time):
self._start = time

@property
def end(self):
return self._end

@end.setter
def end(self, time):
self._end = time

@property
def sub_starts(self):
if len(self.subset_list) > 0:
Expand Down Expand Up @@ -411,6 +427,10 @@ def sub_labels(self):
return lab_list
else:
return []

def _shift(self, increment):
self.start += increment
self.end += increment

## Fusion
def fuse_rightwards(
Expand Down
38 changes: 37 additions & 1 deletion src/aligned_textgrid/sequences/tiers.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,31 @@ def __repr__(self):
@property
def starts(self):
return np.array([x.start for x in self.sequence_list])

@starts.setter
def starts(self, times):
if not len(self.sequence_list) == len(times):
raise Exception("There aren't the same number of new start times as intervals")

for t, i in zip(times, self.sequence_list):
i.start = t

@property
def ends(self):
return np.array([x.end for x in self.sequence_list])


@ends.setter
def ends(self, times):
if not len(self.sequence_list) == len(times):
raise Exception("There aren't the same number of new start times as intervals")

for t, i in zip(times, self.sequence_list):
i.end = t

def _shift(self, increment):
self.starts += increment
self.ends += increment

@property
def labels(self):
return [x.label for x in self.sequence_list]
Expand Down Expand Up @@ -297,6 +317,22 @@ def xmin(self):
@property
def xmax(self):
return np.array([tier.xmax for tier in self.tier_list]).min()

def shift(
self,
increment: float
):
"""Shift the start and end times of all intervals within
the TierGroup by the increment size
Args:
increment (float):
The time increment by which to shift the
intervals within the TierGroup. Could be
positive or negative
"""
for tier in self.tier_list:
tier._shift(increment)

def get_intervals_at_time(
self,
Expand Down
65 changes: 65 additions & 0 deletions tests/test_aligned_textgrid.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,35 @@ def test_tiergroup_name(self):

assert isinstance(tg.IVR, TierGroup)

class TestTierGroupShift:
def test_tiergroup_shift(self):
tg = AlignedTextGrid(
textgrid_path="tests/test_data/KY25A_1.TextGrid",
entry_classes=[Word, Phone]
)

tgr = tg[0]
orig_starts = [
tier.starts for tier in tgr
]
orig_ends = [
tier.ends for tier in tgr
]

tgr.shift(3)

new_starts = [
tier.starts for tier in tgr
]
new_ends = [
tier.ends for tier in tgr
]

for o, n in zip(orig_starts, new_starts):
assert np.all(np.isclose(n-o, 3))
for o, n in zip(orig_ends, new_ends):
assert np.all(np.isclose(n-o, 3))

class TestInterleave:


Expand Down Expand Up @@ -419,3 +448,39 @@ def test_exceptions(self):
below = Word,
timing_from="Word"
)

class TestTextGridShift:

def test_positive_shift(self):
tg = AlignedTextGrid(
textgrid_path="tests/test_data/KY25A_1.TextGrid",
entry_classes=custom_classes(["Word", "Phone"])
)

orig_xmin = tg.xmin
orig_xmax = tg.xmax

tg.shift(3)

new_xmin = tg.xmin
new_xmax = tg.xmax

assert np.isclose(new_xmin - orig_xmin, 3)
assert np.isclose(new_xmax - orig_xmax, 3)

def test_negative_shift(self):
tg = AlignedTextGrid(
textgrid_path="tests/test_data/KY25A_1.TextGrid",
entry_classes=custom_classes(["Word", "Phone"])
)

orig_xmin = tg.xmin
orig_xmax = tg.xmax

tg.shift(-3)

new_xmin = tg.xmin
new_xmax = tg.xmax

assert np.isclose(new_xmin - orig_xmin, -3)
assert np.isclose(new_xmax - orig_xmax, -3)
8 changes: 8 additions & 0 deletions tests/test_sequences/test_points.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@ def test_return(self):
assert isinstance(out_point, Point)


class TestTiming:

def test_shift(self):
seq_point_a = SequencePoint(Point(1, "a"))

seq_point_a._shift(2)
assert seq_point_a.time == 3

class TestDistances:
seq_point_a = SequencePoint(Point(1, "a"))
seq_point_b = SequencePoint(Point(2, "b"))
Expand Down
Loading

0 comments on commit e9bd3fb

Please sign in to comment.