patkit 0.22.1__tar.gz → 0.22.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {patkit-0.22.1 → patkit-0.22.2}/PKG-INFO +5 -6
- {patkit-0.22.1 → patkit-0.22.2}/README.md +4 -5
- {patkit-0.22.1 → patkit-0.22.2}/patkit/configuration/configuration.py +4 -3
- {patkit-0.22.1 → patkit-0.22.2}/patkit/constants.py +64 -1
- {patkit-0.22.1 → patkit-0.22.2}/patkit/data_structures/__init__.py +1 -1
- {patkit-0.22.1 → patkit-0.22.2}/patkit/data_structures/base_classes.py +1 -1
- {patkit-0.22.1 → patkit-0.22.2}/patkit/data_structures/data_structures.py +110 -33
- {patkit-0.22.1 → patkit-0.22.2}/patkit/data_structures/metadata_classes.py +49 -1
- {patkit-0.22.1 → patkit-0.22.2}/patkit/gui/__init__.py +3 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/gui/annotator_window.py +103 -35
- patkit-0.22.2/patkit/gui/audio_player.py +141 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/gui/boundary_animation.py +4 -4
- {patkit-0.22.1 → patkit-0.22.2}/patkit/gui/dialog_template.py +3 -3
- patkit-0.22.2/patkit/gui/exercise_dialogs.py +190 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/gui/list_selection_dialog.py +31 -0
- patkit-0.22.2/patkit/gui/plot_controller.py +905 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/gui/select_scenario_dialog.py +5 -3
- {patkit-0.22.1 → patkit-0.22.2}/patkit/patgrid.py +18 -4
- {patkit-0.22.1 → patkit-0.22.2}/patkit/path_resolution.py +31 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/plot_and_publish/__init__.py +2 -1
- {patkit-0.22.1 → patkit-0.22.2}/patkit/qt_annotator.py +329 -807
- {patkit-0.22.1 → patkit-0.22.2}/patkit/save_and_load/__init__.py +7 -2
- {patkit-0.22.1 → patkit-0.22.2}/patkit/save_and_load/load.py +113 -7
- {patkit-0.22.1 → patkit-0.22.2}/patkit/save_and_load/save.py +77 -6
- {patkit-0.22.1 → patkit-0.22.2}/patkit/save_and_load/save_and_load_schemas.py +31 -1
- {patkit-0.22.1 → patkit-0.22.2}/patkit/simulation/simulate.py +3 -2
- {patkit-0.22.1 → patkit-0.22.2}/pyproject.toml +10 -1
- {patkit-0.22.1 → patkit-0.22.2}/.gitignore +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/LICENSE.markdown +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/__init__.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/annotations/__init__.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/annotations/peaks.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/audio_processing/__init__.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/audio_processing/audio_processing.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/cli.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/cli_commands.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/computational.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/configuration/__init__.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/configuration/configuration_models.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/configuration/configuration_parsers.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/configuration/exclusion_list_functions.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/data_import/AAA_raw_ultrasound.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/data_import/AAA_recordings.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/data_import/AAA_splines.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/data_import/RASL_3D_ultrasound_recordings.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/data_import/__init__.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/data_import/audio.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/data_import/session_import_config.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/data_import/spline_import_config.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/data_import/three_dim_ultrasound.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/data_import/video.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/data_import/wav_recordings.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/data_loader.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/data_processor.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/default_configuration/patkit-data.yaml +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/default_configuration/patkit-gui.yaml +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/default_configuration/patkit-publish.yaml +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/default_configuration/patkit_logging_configuration.json +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/errors.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/export/__init__.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/export/images.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/export/metadata.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/export/modality_data.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/external_class_extensions/__init__.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/external_class_extensions/base_model_extensions.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/external_class_extensions/enum_extensions.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/get_modality_types.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/gui/image_save_dialog.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/gui/list_save_dialog.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/gui/ofbrowse.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/gui/player_controls.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/gui/replace_dialog.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/import_formats/__init__.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/import_formats/avi_read.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/import_formats/dicom_ultra_read.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/import_formats/rasl_dat_to_wav.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/import_formats/splines_read.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/import_formats/ult_read.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/import_formats/wav_read.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/initialise.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/interpolate_raw_uti.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/interpreter.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/metrics/__init__.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/metrics/aggregate_image.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/metrics/calculate_aggregate_images.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/metrics/calculate_distance_matrices.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/metrics/calculate_intensity.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/metrics/calculate_pd.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/metrics/calculate_spline_metric.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/metrics/distance_matrix.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/metrics/downsample_metric.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/metrics/intensity.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/metrics/metrics_helpers.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/metrics/ofreg.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/metrics/pd.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/metrics/spline_metric.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/metrics/tongue_shape_analysis.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/modalities/__init__.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/modalities/recorded_metadata_classes.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/modalities/recorded_modalities.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/modalities/splines.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/plot_and_publish/legend_generation.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/plot_and_publish/plot.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/plot_and_publish/plot_utilities.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/plot_and_publish/publish.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/simulation/__init__.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/simulation/contour_tools.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/simulation/metric_calculations.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/simulation/perturbation_series_plots.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/simulation/rays_on_contours.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/simulation/simulation_datastructures.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/simulation/simulation_plots.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/ui_callbacks.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/utility_functions/__init__.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/utility_functions/logging_helpers.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/utility_functions/path.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/utility_functions/processing_helpers.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/utility_functions/string_formatters.py +0 -0
- {patkit-0.22.1 → patkit-0.22.2}/patkit/utility_functions/types.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: patkit
|
|
3
|
-
Version: 0.22.
|
|
3
|
+
Version: 0.22.2
|
|
4
4
|
Summary: Phonetic Analysis ToolKit: Tools for processing phonetic data
|
|
5
5
|
Project-URL: bug_tracker, https://github.com/giuthas/patkit/issues
|
|
6
6
|
Project-URL: changelog, https://github.com/giuthas/patkit/blob/main/docs/Release_notes.markdown
|
|
@@ -715,6 +715,7 @@ Requires-Dist: sounddevice>=0.5.5
|
|
|
715
715
|
Requires-Dist: strictyaml>=1.7.3
|
|
716
716
|
Description-Content-Type: text/markdown
|
|
717
717
|
|
|
718
|
+
[](https://github.com/giuthas/patkit/actions/workflows/test.yaml)
|
|
718
719
|
# PATKIT - Phonetic Analysis ToolKIT
|
|
719
720
|
|
|
720
721
|

|
|
@@ -748,10 +749,7 @@ thesis](https://eresearch.qmu.ac.uk/handle/20.500.12289/10163).
|
|
|
748
749
|
- See [uv](https://docs.astral.sh/uv/#getting-started) for more details.
|
|
749
750
|
- On the commandline run `uv tool install patkit`
|
|
750
751
|
- Run `patkit --help` for instructions.
|
|
751
|
-
- If you want to run the example data,
|
|
752
|
-
[github](https://github.com/giuthas/patkit).
|
|
753
|
-
- Run `patkit scenarios/minimal` in the folder where you downloaded the data
|
|
754
|
-
and experiment from there.
|
|
752
|
+
- If you want to run the example data, see 'What's included' below for instructions.
|
|
755
753
|
|
|
756
754
|
- If on Linux of the debian variety (ubuntu, popos, others), you may also need
|
|
757
755
|
to run the following:
|
|
@@ -785,8 +783,9 @@ contents of the directory.
|
|
|
785
783
|
Place the unzipped directories in the same directory and after installing
|
|
786
784
|
patkit try running
|
|
787
785
|
```
|
|
788
|
-
patkit scenarios
|
|
786
|
+
patkit scenarios/minimal
|
|
789
787
|
```
|
|
788
|
+
and experiment from there.
|
|
790
789
|
|
|
791
790
|
TODO 1.0: Move the data elsewhere to be optionally loaded.
|
|
792
791
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
[](https://github.com/giuthas/patkit/actions/workflows/test.yaml)
|
|
1
2
|
# PATKIT - Phonetic Analysis ToolKIT
|
|
2
3
|
|
|
3
4
|

|
|
@@ -31,10 +32,7 @@ thesis](https://eresearch.qmu.ac.uk/handle/20.500.12289/10163).
|
|
|
31
32
|
- See [uv](https://docs.astral.sh/uv/#getting-started) for more details.
|
|
32
33
|
- On the commandline run `uv tool install patkit`
|
|
33
34
|
- Run `patkit --help` for instructions.
|
|
34
|
-
- If you want to run the example data,
|
|
35
|
-
[github](https://github.com/giuthas/patkit).
|
|
36
|
-
- Run `patkit scenarios/minimal` in the folder where you downloaded the data
|
|
37
|
-
and experiment from there.
|
|
35
|
+
- If you want to run the example data, see 'What's included' below for instructions.
|
|
38
36
|
|
|
39
37
|
- If on Linux of the debian variety (ubuntu, popos, others), you may also need
|
|
40
38
|
to run the following:
|
|
@@ -68,8 +66,9 @@ contents of the directory.
|
|
|
68
66
|
Place the unzipped directories in the same directory and after installing
|
|
69
67
|
patkit try running
|
|
70
68
|
```
|
|
71
|
-
patkit scenarios
|
|
69
|
+
patkit scenarios/minimal
|
|
72
70
|
```
|
|
71
|
+
and experiment from there.
|
|
73
72
|
|
|
74
73
|
TODO 1.0: Move the data elsewhere to be optionally loaded.
|
|
75
74
|
|
|
@@ -85,7 +85,7 @@ class ConfigPaths:
|
|
|
85
85
|
|
|
86
86
|
class Configuration:
|
|
87
87
|
"""
|
|
88
|
-
Main configuration class of patkit.
|
|
88
|
+
Main configuration class of patkit.
|
|
89
89
|
"""
|
|
90
90
|
|
|
91
91
|
# TODO: implement save functionality.
|
|
@@ -95,7 +95,7 @@ class Configuration:
|
|
|
95
95
|
configuration_paths: ConfigPaths
|
|
96
96
|
) -> None:
|
|
97
97
|
"""
|
|
98
|
-
Init the main configuration object.
|
|
98
|
+
Init the main configuration object.
|
|
99
99
|
|
|
100
100
|
Run only once. Updates should be done with methods of the class.
|
|
101
101
|
|
|
@@ -113,7 +113,8 @@ class Configuration:
|
|
|
113
113
|
self._data_yaml = load_data_params(
|
|
114
114
|
self._config_paths.data_config)
|
|
115
115
|
self._data_config = DataConfig(**self._data_yaml.data)
|
|
116
|
-
recorded =
|
|
116
|
+
recorded = \
|
|
117
|
+
self._config_paths.path/self._data_config.recorded_data_path
|
|
117
118
|
self._data_config.recorded_data_path = recorded.resolve()
|
|
118
119
|
else:
|
|
119
120
|
self._data_config = None
|
|
@@ -49,6 +49,7 @@ from patkit.external_class_extensions import (
|
|
|
49
49
|
# TODO 1.0: Decouple program and file format versions at version 1.0.
|
|
50
50
|
PATKIT_VERSION = version('patkit')
|
|
51
51
|
PATKIT_FILE_VERSION = PATKIT_VERSION
|
|
52
|
+
EXERCISE_FILE_VERSION = PATKIT_VERSION
|
|
52
53
|
|
|
53
54
|
DEFAULT_ENCODING = 'utf-8'
|
|
54
55
|
|
|
@@ -192,6 +193,7 @@ class PatkitConfigFile(str, Enum):
|
|
|
192
193
|
SESSION: how PATKIT should read a session based on recorded data
|
|
193
194
|
SPLINE: spline formatting
|
|
194
195
|
"""
|
|
196
|
+
ANSWER = "patkit-answer.yaml"
|
|
195
197
|
EXERCISE = "patkit-exercise.yaml"
|
|
196
198
|
DATA = "patkit-data.yaml"
|
|
197
199
|
GUI = "patkit-gui.yaml"
|
|
@@ -208,6 +210,21 @@ class PatkitConfigFile(str, Enum):
|
|
|
208
210
|
return self.value
|
|
209
211
|
|
|
210
212
|
|
|
213
|
+
class PatkitDirectory(str, Enum):
|
|
214
|
+
"""
|
|
215
|
+
Standard directory names used in PATKIT.
|
|
216
|
+
"""
|
|
217
|
+
ANSWERS = "answers"
|
|
218
|
+
EXAMPLE = "example"
|
|
219
|
+
EXERCISE = "exercise"
|
|
220
|
+
|
|
221
|
+
def __str__(self) -> str:
|
|
222
|
+
"""
|
|
223
|
+
Ensure f-strings and print() output the string value.
|
|
224
|
+
"""
|
|
225
|
+
return self.value
|
|
226
|
+
|
|
227
|
+
|
|
211
228
|
class PatkitSuffix(str, Enum):
|
|
212
229
|
"""
|
|
213
230
|
Suffixes for files saved by patkit.
|
|
@@ -231,7 +248,7 @@ class SavedObjectTypes(Enum):
|
|
|
231
248
|
"""
|
|
232
249
|
Represent type of a saved patkit object in .meta.
|
|
233
250
|
"""
|
|
234
|
-
|
|
251
|
+
EXERCISE = "Exercise"
|
|
235
252
|
DATASET = "Dataset"
|
|
236
253
|
MODALITY = "Modality"
|
|
237
254
|
RECORDING = "Recording"
|
|
@@ -454,3 +471,49 @@ class ExerciseMode(ListablePrintableEnum, metaclass=ValueComparedEnumMeta):
|
|
|
454
471
|
"""
|
|
455
472
|
ANSWER = "Answer"
|
|
456
473
|
EXAMPLE = "Example"
|
|
474
|
+
|
|
475
|
+
|
|
476
|
+
class ExerciseScrambler(
|
|
477
|
+
ListablePrintableEnum, metaclass=ValueComparedEnumMeta
|
|
478
|
+
):
|
|
479
|
+
"""
|
|
480
|
+
Ways of scrambling boundaries for an Exercise.
|
|
481
|
+
"""
|
|
482
|
+
EQUIDISTANT = "Equidistant"
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
class DefaultCanvasColors(str, Enum):
|
|
486
|
+
"""
|
|
487
|
+
Default background colors for the Matplotlib figure canvas.
|
|
488
|
+
|
|
489
|
+
These represent the hardcoded default theme colors for different
|
|
490
|
+
annotator and exercise modes until config overrides are implemented.
|
|
491
|
+
"""
|
|
492
|
+
ANNOTATOR_LIGHT = "white"
|
|
493
|
+
ANNOTATOR_DARK = "black"
|
|
494
|
+
|
|
495
|
+
EXAMPLE_LIGHT = "#e7eaff"
|
|
496
|
+
EXAMPLE_DARK = "#000212"
|
|
497
|
+
|
|
498
|
+
ANSWER_LIGHT = "#e6ffe9"
|
|
499
|
+
ANSWER_DARK = "#001202"
|
|
500
|
+
|
|
501
|
+
def __str__(self) -> str:
|
|
502
|
+
"""
|
|
503
|
+
Ensure f-strings and print() output the string value.
|
|
504
|
+
"""
|
|
505
|
+
return self.value
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
class DefaultCursorColors(str, Enum):
|
|
509
|
+
"""
|
|
510
|
+
Default colors for GUI cursor and selection elements.
|
|
511
|
+
"""
|
|
512
|
+
SELECTION = "deepskyblue"
|
|
513
|
+
PLAYBACK = "red"
|
|
514
|
+
|
|
515
|
+
def __str__(self) -> str:
|
|
516
|
+
"""
|
|
517
|
+
Ensure f-strings and print() output the string value.
|
|
518
|
+
"""
|
|
519
|
+
return self.value
|
|
@@ -43,7 +43,7 @@ from .data_structures import (
|
|
|
43
43
|
Exercise, Answer, Manifest, Modality, Recording, Session
|
|
44
44
|
)
|
|
45
45
|
from .metadata_classes import (
|
|
46
|
-
FileInformation,
|
|
46
|
+
AnswerMetadata, ExerciseMetadata, FileInformation,
|
|
47
47
|
ModalityData, ModalityMetaData, PointAnnotations,
|
|
48
48
|
RecordingMetaData, StatisticMetaData
|
|
49
49
|
)
|
|
@@ -385,7 +385,7 @@ class AbstractDataContainer(AbstractDataObject):
|
|
|
385
385
|
"""
|
|
386
386
|
Abstract baseclass for Recording, Session, and DataSet.
|
|
387
387
|
|
|
388
|
-
This class collects behaviors that are shared by the
|
|
388
|
+
This class collects behaviors that are shared by the database classes i.e.
|
|
389
389
|
classes which collect DataContainers and/or AbstractDataContainers.
|
|
390
390
|
"""
|
|
391
391
|
|
|
@@ -32,20 +32,6 @@
|
|
|
32
32
|
"""PATKIT's main datastructures."""
|
|
33
33
|
|
|
34
34
|
from __future__ import annotations
|
|
35
|
-
from .metadata_classes import (
|
|
36
|
-
FileInformation, ModalityData, ModalityMetaData, PointAnnotations,
|
|
37
|
-
RecordingMetaData
|
|
38
|
-
)
|
|
39
|
-
from .base_classes import AbstractDataContainer, AbstractData, Statistic
|
|
40
|
-
from patkit.patgrid import PatGrid
|
|
41
|
-
from patkit.utility_functions import stem_path
|
|
42
|
-
from patkit.errors import (
|
|
43
|
-
DimensionMismatchError, MissingDataError, OverwriteError
|
|
44
|
-
)
|
|
45
|
-
from patkit.constants import AnnotationType, SourceSuffix
|
|
46
|
-
from patkit.configuration import SessionConfig
|
|
47
|
-
import textgrids
|
|
48
|
-
import numpy as np
|
|
49
35
|
|
|
50
36
|
import abc
|
|
51
37
|
import logging
|
|
@@ -54,11 +40,30 @@ from copy import deepcopy
|
|
|
54
40
|
from pathlib import Path
|
|
55
41
|
from textwrap import indent
|
|
56
42
|
|
|
43
|
+
import textgrids
|
|
44
|
+
import numpy as np
|
|
45
|
+
|
|
46
|
+
from patkit.configuration import SessionConfig
|
|
47
|
+
from patkit.constants import (
|
|
48
|
+
AnnotationType, PatkitDirectory, SourceSuffix
|
|
49
|
+
)
|
|
50
|
+
from patkit.errors import (
|
|
51
|
+
DimensionMismatchError, MissingDataError, OverwriteError
|
|
52
|
+
)
|
|
53
|
+
from patkit.patgrid import PatGrid
|
|
54
|
+
from patkit.utility_functions import stem_path
|
|
55
|
+
|
|
56
|
+
from .metadata_classes import (
|
|
57
|
+
AnswerMetadata, ExerciseMetadata, FileInformation,
|
|
58
|
+
ModalityData, ModalityMetaData, PointAnnotations,
|
|
59
|
+
RecordingMetaData
|
|
60
|
+
)
|
|
61
|
+
from .base_classes import AbstractDataContainer, AbstractData, Statistic
|
|
57
62
|
|
|
58
63
|
_logger = logging.getLogger('patkit.data_structures')
|
|
59
64
|
|
|
60
65
|
|
|
61
|
-
class Answer(UserList):
|
|
66
|
+
class Answer(AbstractDataContainer, UserList):
|
|
62
67
|
"""
|
|
63
68
|
Answer is an answer to an Exercise and consists of PatGrids.
|
|
64
69
|
|
|
@@ -69,23 +74,42 @@ class Answer(UserList):
|
|
|
69
74
|
self,
|
|
70
75
|
container: Exercise,
|
|
71
76
|
scenario: Session,
|
|
72
|
-
|
|
73
|
-
name: str
|
|
74
|
-
author: str = "",
|
|
77
|
+
metadata: AnswerMetadata,
|
|
78
|
+
name: str,
|
|
75
79
|
cursor: int = 0,
|
|
80
|
+
file_info: FileInformation | None = None,
|
|
76
81
|
):
|
|
77
|
-
|
|
82
|
+
"""
|
|
83
|
+
Initialize an Answer object containing PatGrids for an Exercise.
|
|
84
|
+
|
|
85
|
+
Parameters
|
|
86
|
+
----------
|
|
87
|
+
container : Exercise
|
|
88
|
+
The Exercise this Answer belongs to.
|
|
89
|
+
scenario : Session
|
|
90
|
+
The Session containing the recordings.
|
|
91
|
+
name : str
|
|
92
|
+
The name of the answer.
|
|
93
|
+
cursor : int
|
|
94
|
+
The cursor index pointing to the active recording.
|
|
95
|
+
file_info : FileInformation | None
|
|
96
|
+
The FileInformation metadata for the answer.
|
|
97
|
+
"""
|
|
98
|
+
if file_info is None:
|
|
99
|
+
file_info = FileInformation()
|
|
100
|
+
|
|
101
|
+
super().__init__(name=name, metadata=metadata,
|
|
102
|
+
container=container, file_info=file_info)
|
|
78
103
|
self.container = container
|
|
79
104
|
self.scenario = scenario
|
|
80
|
-
self.name = name
|
|
81
|
-
self.author = author
|
|
82
105
|
self.cursor = cursor
|
|
83
106
|
|
|
84
107
|
for recording in self.scenario:
|
|
85
108
|
patgrid = deepcopy(recording.patgrid)
|
|
86
109
|
self.append(patgrid)
|
|
87
110
|
|
|
88
|
-
|
|
111
|
+
# TODO: this will probably break loading edited answers
|
|
112
|
+
if self.metadata.scramble:
|
|
89
113
|
for patgrid in self:
|
|
90
114
|
for tier in patgrid:
|
|
91
115
|
patgrid[tier].scramble()
|
|
@@ -100,6 +124,20 @@ class Answer(UserList):
|
|
|
100
124
|
representation += indent(text=patgrid_string, prefix="\t")
|
|
101
125
|
return representation
|
|
102
126
|
|
|
127
|
+
@property
|
|
128
|
+
def patkit_data_path(self) -> Path:
|
|
129
|
+
"""Dynamically compute the path to the answer directory."""
|
|
130
|
+
# Route example answers directly to the example directory
|
|
131
|
+
if (
|
|
132
|
+
self.container.example is not None and
|
|
133
|
+
self is self.container.example
|
|
134
|
+
):
|
|
135
|
+
return self.container.patkit_path / PatkitDirectory.EXAMPLE
|
|
136
|
+
|
|
137
|
+
return (
|
|
138
|
+
self.container.patkit_path / PatkitDirectory.ANSWERS / self.name
|
|
139
|
+
)
|
|
140
|
+
|
|
103
141
|
def current(self) -> PatGrid:
|
|
104
142
|
"""
|
|
105
143
|
The PatGrid at the current index.
|
|
@@ -151,7 +189,7 @@ class Answer(UserList):
|
|
|
151
189
|
return self.cursor
|
|
152
190
|
|
|
153
191
|
|
|
154
|
-
class Exercise(UserDict):
|
|
192
|
+
class Exercise(AbstractDataContainer, UserDict):
|
|
155
193
|
"""
|
|
156
194
|
Exercise is list of Answers relating to a Scenario (Session).
|
|
157
195
|
|
|
@@ -162,24 +200,46 @@ class Exercise(UserDict):
|
|
|
162
200
|
def __init__(
|
|
163
201
|
self,
|
|
164
202
|
scenario: Session,
|
|
203
|
+
name: str,
|
|
204
|
+
metadata: ExerciseMetadata,
|
|
165
205
|
answers: list[Answer] | None = None,
|
|
166
206
|
example: dict[str, Answer] | None = None,
|
|
167
207
|
index: int = 0,
|
|
208
|
+
file_info: FileInformation | None = None,
|
|
168
209
|
):
|
|
169
|
-
|
|
210
|
+
"""
|
|
211
|
+
Initialize an Exercise.
|
|
212
|
+
|
|
213
|
+
Parameters
|
|
214
|
+
----------
|
|
215
|
+
scenario : Session
|
|
216
|
+
The Session containing the recordings for this exercise.
|
|
217
|
+
answers : list[Answer] | None
|
|
218
|
+
A list of Answer objects to populate the exercise.
|
|
219
|
+
example : dict[str, Answer] | None
|
|
220
|
+
The example scrambled Answer to present to the user.
|
|
221
|
+
index : int
|
|
222
|
+
The cursor index.
|
|
223
|
+
"""
|
|
224
|
+
super().__init__(name=name, metadata=metadata, file_info=file_info)
|
|
170
225
|
if example is None:
|
|
171
226
|
_logger.debug("Creating an example answer")
|
|
227
|
+
metadata = AnswerMetadata(
|
|
228
|
+
scramble=False,
|
|
229
|
+
)
|
|
172
230
|
self.example = Answer(
|
|
173
231
|
container=self,
|
|
174
232
|
scenario=scenario,
|
|
175
|
-
|
|
233
|
+
metadata=metadata,
|
|
234
|
+
name=PatkitDirectory.EXAMPLE,
|
|
176
235
|
)
|
|
177
236
|
else:
|
|
178
237
|
self.example = example
|
|
179
238
|
self.scenario = scenario
|
|
180
239
|
|
|
181
240
|
if answers is not None:
|
|
182
|
-
|
|
241
|
+
for answer in answers:
|
|
242
|
+
self[answer.name] = answer
|
|
183
243
|
|
|
184
244
|
self.cursor = index
|
|
185
245
|
|
|
@@ -202,6 +262,14 @@ class Exercise(UserDict):
|
|
|
202
262
|
def current_answer(self) -> Answer:
|
|
203
263
|
return self[list(self.keys())[self.cursor]]
|
|
204
264
|
|
|
265
|
+
@property
|
|
266
|
+
def patkit_path(self) -> Path | None:
|
|
267
|
+
return self.file_info.patkit_path
|
|
268
|
+
|
|
269
|
+
@patkit_path.setter
|
|
270
|
+
def patkit_path(self, path: Path) -> None:
|
|
271
|
+
self.file_info.patkit_path = path
|
|
272
|
+
|
|
205
273
|
def new_blank_answer(
|
|
206
274
|
self,
|
|
207
275
|
cursor: int = 0,
|
|
@@ -218,7 +286,7 @@ class Exercise(UserDict):
|
|
|
218
286
|
name : str | None
|
|
219
287
|
Name of the new Answer, by default None. If None is passed the new
|
|
220
288
|
name will be autogenerated and have the form
|
|
221
|
-
`f"
|
|
289
|
+
`f"Answer_{len(self)+1}"`.
|
|
222
290
|
author : str
|
|
223
291
|
Name of the new Answer's author, by default an empty string.
|
|
224
292
|
"""
|
|
@@ -226,15 +294,19 @@ class Exercise(UserDict):
|
|
|
226
294
|
|
|
227
295
|
# TODO 1.0: Is this the best place to name answers?
|
|
228
296
|
if name is None:
|
|
229
|
-
name = f"
|
|
297
|
+
name = f"Answer_{len(self)+1}"
|
|
230
298
|
|
|
299
|
+
metadata = AnswerMetadata(
|
|
300
|
+
scramble=True,
|
|
301
|
+
author=author
|
|
302
|
+
)
|
|
231
303
|
blank = Answer(
|
|
232
304
|
container=self,
|
|
233
305
|
scenario=self.scenario,
|
|
234
|
-
|
|
306
|
+
name=name,
|
|
307
|
+
metadata=metadata,
|
|
235
308
|
cursor=cursor,
|
|
236
309
|
)
|
|
237
|
-
name = f"Answer {len(self)+1}"
|
|
238
310
|
self[name] = blank
|
|
239
311
|
|
|
240
312
|
|
|
@@ -336,11 +408,15 @@ class Session(AbstractDataContainer, UserList):
|
|
|
336
408
|
config: SessionConfig,
|
|
337
409
|
file_info: FileInformation,
|
|
338
410
|
recordings: list[Recording] | None = None,
|
|
339
|
-
statistics: dict[str, Statistic] | None = None
|
|
411
|
+
statistics: dict[str, Statistic] | None = None,
|
|
412
|
+
exercise: Exercise | None = None,
|
|
340
413
|
) -> None:
|
|
341
414
|
super().__init__(
|
|
342
|
-
container=None,
|
|
343
|
-
|
|
415
|
+
container=None,
|
|
416
|
+
name=name,
|
|
417
|
+
metadata=config,
|
|
418
|
+
file_info=file_info,
|
|
419
|
+
statistics=statistics)
|
|
344
420
|
|
|
345
421
|
if recordings is not None:
|
|
346
422
|
for recording in recordings:
|
|
@@ -349,6 +425,7 @@ class Session(AbstractDataContainer, UserList):
|
|
|
349
425
|
self.extend(recordings)
|
|
350
426
|
|
|
351
427
|
self.config = config
|
|
428
|
+
self.exercise = exercise
|
|
352
429
|
|
|
353
430
|
def __repr__(self) -> str:
|
|
354
431
|
representation = "Session:\n"
|
|
@@ -42,7 +42,7 @@ from pydantic import PositiveInt
|
|
|
42
42
|
from patkit.configuration import (
|
|
43
43
|
PointAnnotationParams
|
|
44
44
|
)
|
|
45
|
-
from patkit.constants import AnnotationType
|
|
45
|
+
from patkit.constants import AnnotationType, ExerciseScrambler
|
|
46
46
|
from patkit.external_class_extensions import PatkitBaseModel
|
|
47
47
|
from patkit.utility_functions import (
|
|
48
48
|
is_sequence_form, stem_path
|
|
@@ -116,6 +116,54 @@ class FileInformation:
|
|
|
116
116
|
return stem_path(basepath)
|
|
117
117
|
|
|
118
118
|
|
|
119
|
+
class AnswerMetadata(PatkitBaseModel):
|
|
120
|
+
"""
|
|
121
|
+
Metadata of an Exercise Answer.
|
|
122
|
+
|
|
123
|
+
Parameters
|
|
124
|
+
----------
|
|
125
|
+
scramble : bool
|
|
126
|
+
Whether to scramble the PatGrids upon creation.
|
|
127
|
+
author : str
|
|
128
|
+
The author/user of the answer.
|
|
129
|
+
time_created : str | None
|
|
130
|
+
ISO formatted timestamp of when this answer was created.
|
|
131
|
+
time_last_edited : str | None
|
|
132
|
+
ISO formatted timestamp of when this answer was last edited.
|
|
133
|
+
"""
|
|
134
|
+
scramble: bool
|
|
135
|
+
author: str = ""
|
|
136
|
+
time_created: str | None = None
|
|
137
|
+
time_last_edited: str | None = None
|
|
138
|
+
|
|
139
|
+
def model_post_init(self, __context):
|
|
140
|
+
now = datetime.now().isoformat()
|
|
141
|
+
if self.time_created is None:
|
|
142
|
+
self.time_created = now
|
|
143
|
+
if self.time_last_edited is not None:
|
|
144
|
+
self.time_last_edited = now
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class ExerciseMetadata(PatkitBaseModel):
|
|
148
|
+
"""
|
|
149
|
+
Metadata for an Exercise.
|
|
150
|
+
|
|
151
|
+
Parameters
|
|
152
|
+
----------
|
|
153
|
+
time_created : str | None
|
|
154
|
+
ISO formatted timestamp of when this exercise was created.
|
|
155
|
+
scrambling_method : str
|
|
156
|
+
The method used to scramble the exercise TextGrids.
|
|
157
|
+
"""
|
|
158
|
+
time_created: str | None = None
|
|
159
|
+
scrambling_method: ExerciseScrambler = ExerciseScrambler.EQUIDISTANT
|
|
160
|
+
|
|
161
|
+
def model_post_init(self, __context):
|
|
162
|
+
now = datetime.now().isoformat()
|
|
163
|
+
if self.time_created is None:
|
|
164
|
+
self.time_created = now
|
|
165
|
+
|
|
166
|
+
|
|
119
167
|
@dataclass
|
|
120
168
|
class ModalityData:
|
|
121
169
|
"""
|
|
@@ -32,9 +32,12 @@
|
|
|
32
32
|
"""GUI elements."""
|
|
33
33
|
|
|
34
34
|
from .annotator_window import UiMainWindow
|
|
35
|
+
from .audio_player import AudioPlayer
|
|
35
36
|
from .boundary_animation import BoundaryAnimator
|
|
37
|
+
from .exercise_dialogs import NewAnswerDialog, NewExerciseDialog
|
|
36
38
|
from .image_save_dialog import ImageSaveDialog
|
|
37
39
|
from .list_save_dialog import ListSaveDialog
|
|
38
40
|
from .list_selection_dialog import ListSelectionDialog
|
|
39
41
|
from .player_controls import PlayerControls
|
|
42
|
+
from .plot_controller import PlotController
|
|
40
43
|
from .replace_dialog import ReplaceDialog
|