dimcat 3.2.0__tar.gz → 3.4.0__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.
- {dimcat-3.2.0 → dimcat-3.4.0}/.pre-commit-config.yaml +5 -4
- {dimcat-3.2.0 → dimcat-3.4.0}/CONTRIBUTING.rst +26 -67
- {dimcat-3.2.0 → dimcat-3.4.0}/PKG-INFO +1 -1
- {dimcat-3.2.0 → dimcat-3.4.0}/docs/CHANGELOG.md +46 -0
- dimcat-3.4.0/docs/manual/developers.md +250 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/docs/manual/index.rst +1 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/docs/manual/quick.md +21 -21
- {dimcat-3.2.0 → dimcat-3.4.0}/docs/tutorial.ipynb +1 -1
- {dimcat-3.2.0 → dimcat-3.4.0}/setup.cfg +2 -1
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/base.py +10 -2
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/data/datasets/base.py +1 -9
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/data/resources/base.py +2 -1
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/data/resources/dc.py +1 -1
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/data/resources/facets.py +32 -17
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/data/resources/features.py +5 -5
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/data/resources/results.py +4 -3
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/data/resources/utils.py +7 -1
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/plotting.py +187 -4
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/steps/analyzers/base.py +1 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/steps/base.py +4 -2
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/steps/pipelines/base.py +5 -4
- dimcat-3.4.0/src/dimcat/steps/slicers/__init__.py +10 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/steps/slicers/feature_dimensions.py +18 -4
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat.egg-info/PKG-INFO +1 -1
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat.egg-info/SOURCES.txt +1 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat.egg-info/requires.txt +2 -1
- {dimcat-3.2.0 → dimcat-3.4.0}/tests/test_base.py +8 -3
- {dimcat-3.2.0 → dimcat-3.4.0}/tests/test_visualization_app.py +1 -0
- dimcat-3.2.0/src/dimcat/steps/slicers/__init__.py +0 -5
- {dimcat-3.2.0 → dimcat-3.4.0}/.coveragerc +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/.github/workflows/ci.yml +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/.github/workflows/release-please.yml +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/.gitignore +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/.gitmodules +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/.isort.cfg +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/.readthedocs.yml +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/AUTHORS.rst +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/COPYING +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/README.rst +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/docs/.nojekyll +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/docs/LICENSE.rst +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/docs/Makefile +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/docs/_static/.gitignore +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/docs/authors.rst +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/docs/conf.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/docs/contributing.rst +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/docs/diagrams/PipelineStep.uml +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/docs/environment.yml +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/docs/imprint.rst +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/docs/index.html +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/docs/index.rst +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/docs/manual/data.md +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/docs/manual/dcml_corpora.datapackage.json +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/docs/manual/dcml_corpora.zip +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/docs/manual/errors.md +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/docs/notebooks.rst +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/docs/requirements.txt +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/pyproject.toml +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/setup.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/__init__.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/cli.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/data/__init__.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/data/base.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/data/catalogs/__init__.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/data/catalogs/base.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/data/catalogs/inputs.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/data/catalogs/outputs.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/data/datasets/__init__.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/data/datasets/processed.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/data/packages/__init__.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/data/packages/base.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/data/packages/dc.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/data/packages/score.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/data/resources/__init__.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/data/utils.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/dc_exceptions.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/dc_warnings.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/enums.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/settings.ini +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/steps/__init__.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/steps/analyzers/__init__.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/steps/analyzers/counters.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/steps/analyzers/phrases.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/steps/analyzers/prevalence.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/steps/analyzers/proportions.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/steps/extractors/__init__.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/steps/extractors/base.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/steps/filters/__init__.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/steps/filters/annotations.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/steps/filters/base.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/steps/groupers/__init__.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/steps/groupers/annotations.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/steps/groupers/base.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/steps/groupers/columns.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/steps/groupers/metadata.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/steps/loaders/__init__.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/steps/loaders/base.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/steps/loaders/m21.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/steps/loaders/musescore.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/steps/loaders/utils.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/steps/pipelines/__init__.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/steps/slicers/base.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat/utils.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat.egg-info/dependency_links.txt +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat.egg-info/entry_points.txt +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat.egg-info/not-zip-safe +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/src/dimcat.egg-info/top_level.txt +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/tests/__init__.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/tests/app_tests.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/tests/conftest.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/tests/debugging.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/tests/enums.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/tests/loggers.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/tests/pytest.ini +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/tests/test_dataset.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/tests/test_feature.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/tests/test_grouper.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/tests/test_loaders.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/tests/test_package.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/tests/test_pipeline.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/tests/test_resource.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/tests/test_settings.py +0 -0
- {dimcat-3.2.0 → dimcat-3.4.0}/tox.ini +0 -0
|
@@ -2,7 +2,7 @@ exclude: '^docs/conf.py'
|
|
|
2
2
|
|
|
3
3
|
repos:
|
|
4
4
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
5
|
-
rev:
|
|
5
|
+
rev: v5.0.0
|
|
6
6
|
hooks:
|
|
7
7
|
- id: trailing-whitespace
|
|
8
8
|
- id: check-ast
|
|
@@ -32,12 +32,13 @@ repos:
|
|
|
32
32
|
hooks:
|
|
33
33
|
- id: seed-isort-config
|
|
34
34
|
- repo: https://github.com/pycqa/isort
|
|
35
|
-
rev:
|
|
35
|
+
rev: 6.0.1
|
|
36
36
|
hooks:
|
|
37
37
|
- id: isort
|
|
38
|
+
args: ["--profile", "black", "--filter-files"]
|
|
38
39
|
|
|
39
40
|
- repo: https://github.com/ambv/black
|
|
40
|
-
rev:
|
|
41
|
+
rev: 25.1.0
|
|
41
42
|
hooks:
|
|
42
43
|
- id: black
|
|
43
44
|
language_version: python3.10
|
|
@@ -50,7 +51,7 @@ repos:
|
|
|
50
51
|
# additional_dependencies: [black]
|
|
51
52
|
|
|
52
53
|
- repo: https://github.com/PyCQA/flake8
|
|
53
|
-
rev:
|
|
54
|
+
rev: 7.1.2
|
|
54
55
|
hooks:
|
|
55
56
|
- id: flake8
|
|
56
57
|
args:
|
|
@@ -132,7 +132,6 @@ Clone the repository
|
|
|
132
132
|
|
|
133
133
|
#. Install |pre-commit|_::
|
|
134
134
|
|
|
135
|
-
pip install pre-commit
|
|
136
135
|
pre-commit install
|
|
137
136
|
|
|
138
137
|
``DiMCAT`` comes with a lot of hooks configured to automatically help the
|
|
@@ -202,57 +201,7 @@ Submit your contribution
|
|
|
202
201
|
DiMCAT architecture
|
|
203
202
|
-------------------
|
|
204
203
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
a. :class:`~.DimcatObject` ("object"): the base class for all objects that manages object creation and serialization and subclass registration.
|
|
208
|
-
The DimcatObject class has a class attribute called _registry that is a dictionary of all subclasses of DimcatObject.
|
|
209
|
-
Each DimcatObject has a nested class called Schema that inherits from DimcatSchema.
|
|
210
|
-
#. :class:`~.DimcatSchema` ("schema"): the base class for all nested Schema classes, inheriting from marshmallow.Schema.
|
|
211
|
-
The Schema defines the valid values ranges for all attributes of the DimcatObject and how to serialize and deserialize them.
|
|
212
|
-
#. :class:`~.DimcatConfig` ("config"): a DimcatObject that can represent a subset of the attributes of another DimcatObject and instantiate it using the .create() method.
|
|
213
|
-
It derives from MutableMapping and used for communicating about and checking the compatibility of DimcatObjects.
|
|
214
|
-
|
|
215
|
-
#. The nested Schema corresponding to each DimcatObject is instantiated as a singleton and can be retrieved via the class attribute :attr:`~.DimcatObject.schema`.
|
|
216
|
-
Using this Schema, a DimcatObject can be serialized to and deserialized from:
|
|
217
|
-
|
|
218
|
-
a. a dictionary using the :meth:`~.DimcatObject.to_dict` and :meth:`~.DimcatObject.from_dict` methods.
|
|
219
|
-
#. a DimcatConfig object using the :meth:`~.DimcatObject.to_config` and :meth:`~.DimcatObject.from_config` methods.
|
|
220
|
-
#. a JSON string using the :meth:`~.DimcatObject.to_json` and :meth:`~.DimcatObject.from_json` methods.
|
|
221
|
-
#. a JSON file using the :meth:`~.DimcatObject.to_json_file` and :meth:`~.DimcatObject.from_json_file` methods.
|
|
222
|
-
|
|
223
|
-
In the following, by "serialized object" we mean its representation as a DimcatConfig if not otherwise specified.
|
|
224
|
-
|
|
225
|
-
#. All objects that are neither a schema nor a config are one of the two following subclasses of DimcatObject:
|
|
226
|
-
|
|
227
|
-
a. :class:`~.Data`: a DimcatObject that represents a dataset, a subset of a dataset, or a an individual resource such as a dataframe.
|
|
228
|
-
#. :class:`~.PipelineStep`: a DimcatObject that accepts a Data object as input and returns a Data object as output.
|
|
229
|
-
|
|
230
|
-
#. The principal Data object is called :class:`~.Dataset` and is the one that users will interact with the most.
|
|
231
|
-
The Dataset provides convenience methods that are equivalent to applying the corresponding PipelineStep.
|
|
232
|
-
Every PipelineStep applied to it will return a new Dataset that can be serialized and deserialized to re-start the pipeline from that point.
|
|
233
|
-
To that aim, every Dataset stores a serialization of the applied PipelineSteps and of the original Dataset that served as initial input.
|
|
234
|
-
This initial input is specified as a :class:`~.DimcatCatalog` which is a collection of :class:`DimcatPackages <.data.dataset.base.DimcatPackage>`,
|
|
235
|
-
each of which is a collection of :class:`DimcatResources <.data.resources.base.DimcatResource>`,
|
|
236
|
-
as defined by the `Frictionless Data specifications <https://frictionlessdata.io>`__.
|
|
237
|
-
The preferred structure of a DimcatPackage is a .zip and a datapackage.json file, where the former contains one or several .tsv files (resources) described in the latter.
|
|
238
|
-
Since the data that DiMCAT transforms and analyzes comes from very heterogeneous sources, each original corpus is pre-processed and stored as a `frictionless.Package <https://framework.frictionlessdata.io/docs/framework/package.html>`__ together with the metadata relevant for reproducing the pre-processing.
|
|
239
|
-
#. It follows that the Dataset is mainly a container for :class:`DimcatResources <.data.resources.base.DimcatResource>` namely:
|
|
240
|
-
|
|
241
|
-
a. Facets, i.e. the resources described in the original datapackage.json. They aim to stay as faithful as possible to the original data, applying only mild standardization and normalization.
|
|
242
|
-
All Facet resources come with several columns that represent timestamps both in absolute and in musical time, allowing for the alignment of different corpora.
|
|
243
|
-
The `Frictionless resource <https://framework.frictionlessdata.io/docs/framework/resource.html>`__ descriptors listed in the datapackage.json contain both the column schema and the piece IDs that are present in each of the facets.
|
|
244
|
-
#. :class:`Features <.data.resources.features.Feature>`, i.e. resources derived from Facets by applying PipelineSteps. They are standardized objects that are requested by the PipelineSteps to compute statistics and visualizations.
|
|
245
|
-
To allow for straightforward serialization of the Dataset, all Feature resources are represented as a DimcatCatalog called `outputs`, which can be stored as .tsv files in one or several .zip files.
|
|
246
|
-
|
|
247
|
-
#. A :class:`~.DimcatResource` functions similarly to the `frictionless.Resource <https://framework.frictionlessdata.io/docs/framework/resource.html>`__ that it wraps, meaning that it grants access to the metadata without having to load the dataframes into memory.
|
|
248
|
-
It can be instantiated in two different ways, either from a resource descriptor or from a dataframe.
|
|
249
|
-
At any given moment, the :attr:`~.DimcatResource.status` attribute returns an Enum value reflecting the availability and state of the/a dataframe.
|
|
250
|
-
When a Dataset is serialized, all dataframes from the outputs catalog that haven't been stored to disk yet are written into one or several .zip files so that they can be referenced by resource descriptors.
|
|
251
|
-
#. One of the most important methods, used by most PipelineSteps, is :meth:`.Dataset.get_feature`, which accepts a Feature config and returns a Feature resource.
|
|
252
|
-
The Feature config is a :class:`~.DimcatConfig` that specifies the type of Feature to be returned and the parameters to be used for its computation. Furthermore, it is also used
|
|
253
|
-
|
|
254
|
-
a. to determine for each piece in every loaded DimcatPackage an Availability value, ranging from not available over available with heavy computation to available instantly.
|
|
255
|
-
#. to determine whether the Feature resource had already been requested and stored in the outputs catalog.
|
|
204
|
+
See `Developers guide <https://dimcat.readthedocs.io/en/latest/manual/data.html>`__.
|
|
256
205
|
|
|
257
206
|
|
|
258
207
|
Coding Conventions
|
|
@@ -267,21 +216,31 @@ Commit messages
|
|
|
267
216
|
``DiMCAT`` uses `Conventional Commits <https://www.conventionalcommits.org/>`__ to determine the next SemVer version number. Please make sure to prefix each
|
|
268
217
|
message with one of:
|
|
269
218
|
|
|
270
|
-
|
|
271
|
-
| Commit Type
|
|
272
|
-
|
|
273
|
-
|
|
|
274
|
-
|
|
275
|
-
|
|
|
276
|
-
|
|
277
|
-
|
|
|
278
|
-
|
|
279
|
-
|
|
|
280
|
-
|
|
281
|
-
|
|
|
282
|
-
|
|
283
|
-
|
|
|
284
|
-
|
|
219
|
+
+---------------+--------------------------+-------------------------------------------------------------------------------------------------------------+--------+
|
|
220
|
+
| Commit Type | Title | Description | SemVer |
|
|
221
|
+
+===============+==========================+=============================================================================================================+========+
|
|
222
|
+
| ``feat`` | Features | A new feature | MINOR |
|
|
223
|
+
+---------------+--------------------------+-------------------------------------------------------------------------------------------------------------+--------+
|
|
224
|
+
| ``fix`` | Bug Fixes | A bug Fix | PATCH |
|
|
225
|
+
+---------------+--------------------------+-------------------------------------------------------------------------------------------------------------+--------+
|
|
226
|
+
| ``docs`` | Documentation | Documentation only changes | PATCH |
|
|
227
|
+
+---------------+--------------------------+-------------------------------------------------------------------------------------------------------------+--------+
|
|
228
|
+
| ``style`` | Styles | Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc) | PATCH |
|
|
229
|
+
+---------------+--------------------------+-------------------------------------------------------------------------------------------------------------+--------+
|
|
230
|
+
| ``refactor`` | Code Refactoring | A code change that neither fixes a bug nor adds a feature | PATCH |
|
|
231
|
+
+---------------+--------------------------+-------------------------------------------------------------------------------------------------------------+--------+
|
|
232
|
+
| ``perf`` | Performance Improvements | A code change that improves performance | PATCH |
|
|
233
|
+
+---------------+--------------------------+-------------------------------------------------------------------------------------------------------------+--------+
|
|
234
|
+
| ``test`` | Tests | Adding missing tests or correcting existing tests | PATCH |
|
|
235
|
+
+---------------+--------------------------+-------------------------------------------------------------------------------------------------------------+--------+
|
|
236
|
+
| ``build`` | Builds | Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm) | PATCH |
|
|
237
|
+
+---------------+--------------------------+-------------------------------------------------------------------------------------------------------------+--------+
|
|
238
|
+
| ``ci`` | Continuous Integrations | Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs) | PATCH |
|
|
239
|
+
+---------------+--------------------------+-------------------------------------------------------------------------------------------------------------+--------+
|
|
240
|
+
| ``chore`` | Chores | Other changes that don't modify src or test files | PATCH |
|
|
241
|
+
+---------------+--------------------------+-------------------------------------------------------------------------------------------------------------+--------+
|
|
242
|
+
| ``revert`` | Reverts | Reverts a previous commit | PATCH |
|
|
243
|
+
+---------------+--------------------------+-------------------------------------------------------------------------------------------------------------+--------+
|
|
285
244
|
|
|
286
245
|
In the case of breaking changes, which result in a new major version, please add a ``!`` after the type, e.g., ``refactor!:``.
|
|
287
246
|
This type of commit message needs to come with a body, starting with ``BREAKING CHANGE:``, which explains in great detail everything
|
|
@@ -1,5 +1,51 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [3.4.0](https://github.com/DCMLab/dimcat/compare/v3.3.0...v3.4.0) (2025-04-28)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* allows for retrieving pipeline steps via subscript ([f774987](https://github.com/DCMLab/dimcat/commit/f7749874f9c1fb930d7542637c11efae05ce7056))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* adds default value column to Measures feature ([85f12c6](https://github.com/DCMLab/dimcat/commit/85f12c67435a2d5aa8c8d28de9ec90b859dea79b))
|
|
14
|
+
* avoids an error due to missing columns ([efe6947](https://github.com/DCMLab/dimcat/commit/efe6947af215dd88c7c8321ca6243452e71772ab))
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Documentation
|
|
18
|
+
|
|
19
|
+
* extends docstring for FeatureDimensionSlicer ([cb897da](https://github.com/DCMLab/dimcat/commit/cb897da170c3b6d0b29cae12e6800b674837c11a))
|
|
20
|
+
|
|
21
|
+
## [3.3.0](https://github.com/DCMLab/dimcat/compare/v3.2.0...v3.3.0) (2024-11-18)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
### Features
|
|
25
|
+
|
|
26
|
+
* make_histogram() and make_violin_plot() ([ec89ce2](https://github.com/DCMLab/dimcat/commit/ec89ce2799d822f244aae11cbae5125202eee69f))
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
### Bug Fixes
|
|
30
|
+
|
|
31
|
+
* avoids duplicate column when applying stage criterion ([66aa952](https://github.com/DCMLab/dimcat/commit/66aa952980ec6161efbcae5ba68f46ea8b450fb0))
|
|
32
|
+
* check column directly for the time being (fields are not yet updated automatically) ([aa3376c](https://github.com/DCMLab/dimcat/commit/aa3376c48c43180a63aae0e148a27561fffdcf22))
|
|
33
|
+
* correct inner range index even if its start positions overlap those of the outer start mask ([eb45b17](https://github.com/DCMLab/dimcat/commit/eb45b1787fa3745fe63034126826d40bf0a0ce6b))
|
|
34
|
+
* stop Dataset.iter_features() after iterating through all ([6035174](https://github.com/DCMLab/dimcat/commit/6035174c7289ca5bbb71f4454acb0ea039931776))
|
|
35
|
+
* workaround for avoiding PermissionError on Windows when using tempfile ([e5f3823](https://github.com/DCMLab/dimcat/commit/e5f382392b5476e46f5b5816723812b440f6e950))
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
### Documentation
|
|
39
|
+
|
|
40
|
+
* adds developer's guide notebook ([4fcd554](https://github.com/DCMLab/dimcat/commit/4fcd554d1e60a514c1803fdd1afefc73c1c7516a))
|
|
41
|
+
* Dataset ([7717f16](https://github.com/DCMLab/dimcat/commit/7717f1668a0fc091a485004463e72445c9dbc0cd))
|
|
42
|
+
* Dataset for developers ([b52692d](https://github.com/DCMLab/dimcat/commit/b52692d09355b67cff495cf878a171a4a3cf76c0))
|
|
43
|
+
* fixes table in CONTRIBUTING.rst ([813da3f](https://github.com/DCMLab/dimcat/commit/813da3fe7fcaa6c49a42baaa3939aa811c591d3e))
|
|
44
|
+
* more work on the developers docs ([fed676b](https://github.com/DCMLab/dimcat/commit/fed676b64fbf089b9b9ee647cd54d2cf577ef0ee))
|
|
45
|
+
* moves architecture primer to developers guide ([19c7373](https://github.com/DCMLab/dimcat/commit/19c737388e53e0da2722cf952feb7d3211231088))
|
|
46
|
+
* removes pip install (pre-commit is part of the [docs] optional requirements) ([ba2258f](https://github.com/DCMLab/dimcat/commit/ba2258fe4d23d5838ae6374c9c9c1d2f2550d2ea))
|
|
47
|
+
* several docstrings ([a735464](https://github.com/DCMLab/dimcat/commit/a7354648abfe1290b06d582d836d61e410657bc0))
|
|
48
|
+
|
|
3
49
|
## [3.2.0](https://github.com/DCMLab/dimcat/compare/v3.1.0...v3.2.0) (2024-01-30)
|
|
4
50
|
|
|
5
51
|
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
---
|
|
2
|
+
jupytext:
|
|
3
|
+
formats: ipynb,md:myst
|
|
4
|
+
text_representation:
|
|
5
|
+
extension: .md
|
|
6
|
+
format_name: myst
|
|
7
|
+
format_version: 0.13
|
|
8
|
+
jupytext_version: 1.16.4
|
|
9
|
+
kernelspec:
|
|
10
|
+
display_name: dimcat
|
|
11
|
+
language: python
|
|
12
|
+
name: dimcat
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# Developers guide
|
|
16
|
+
|
|
17
|
+
This guide is an introduction into `DiMCAT's` code architecture. Users who want to contribute to `DiMCAT` are invited to refer to the [contribution guidelines](https://dimcat.readthedocs.io/en/latest/contributing.html) which contain coding conventions and instructions how to set up the development environment.
|
|
18
|
+
|
|
19
|
+
+++
|
|
20
|
+
|
|
21
|
+
## Introduction
|
|
22
|
+
|
|
23
|
+
The library is called DiMCAT and has three high-level objects:
|
|
24
|
+
|
|
25
|
+
1. {class}`~.DimcatObject` ("object"): the base class for all objects that manages object creation and serialization and subclass registration.
|
|
26
|
+
The DimcatObject class has a class attribute called _registry that is a dictionary of all subclasses of DimcatObject.
|
|
27
|
+
Each DimcatObject has a nested class called {class}`~.DimcatObject.Schema` that inherits from {class}`~.DimcatSchema`.
|
|
28
|
+
2. {class}`~.DimcatSchema` ("schema"): the base class for all nested Schema classes, inheriting from [marshmallow.Schema](https://marshmallow.readthedocs.io/en/stable/marshmallow.schema.html).
|
|
29
|
+
The Schema defines the valid values ranges for all attributes of the DimcatObject and how to serialize and deserialize them.
|
|
30
|
+
3. {class}`~.DimcatConfig` ("config"): a DimcatObject that can represent a subset of the attributes of another DimcatObject and instantiate it using the {meth}`~.DimcatConfig.create` method.
|
|
31
|
+
It derives from MutableMapping and is used for communicating about and checking the compatibility of DimcatObjects.
|
|
32
|
+
|
|
33
|
+
The three classes are defined in the `src\dimcat\base.py` module.
|
|
34
|
+
|
|
35
|
+
+++
|
|
36
|
+
|
|
37
|
+
### Serializing `DiMCAT` objects
|
|
38
|
+
|
|
39
|
+
The nested Schema corresponding to each DimcatObject is instantiated as a singleton and can be retrieved via the class attribute {attr}`~.DimcatObject.schema`.
|
|
40
|
+
Using this Schema, a DimcatObject can be serialized to and deserialized from:
|
|
41
|
+
|
|
42
|
+
1. a dictionary using the {meth}`~.DimcatObject.to_dict` and {meth}`~.DimcatObject.from_dict` methods.
|
|
43
|
+
2. a DimcatConfig object using the {meth}`~.DimcatObject.to_config` and {meth}`~.DimcatObject.from_config` methods.
|
|
44
|
+
3. a JSON string using the {meth}`~.DimcatObject.to_json` and {meth}`~.DimcatObject.from_json` methods.
|
|
45
|
+
4. a JSON file using the {meth}`~.DimcatObject.to_json_file` and {meth}`~.DimcatObject.from_json_file` methods.
|
|
46
|
+
|
|
47
|
+
Under the hood, methods 2-4 use method 1. In addition, `DiMCAT` has the following standalone functions to deserialize serialized DimcatObjects:
|
|
48
|
+
|
|
49
|
+
1. {func}`~.deserialize_dict`
|
|
50
|
+
2. {func}`~.deserialize_config`
|
|
51
|
+
3. {func}`~.deserialize_json_str`
|
|
52
|
+
4. {func}`~.deserialize_json_file`
|
|
53
|
+
|
|
54
|
+
This is possible because each deserialized object includes a value for the field `dtype` specifying the object's class name from which the schema can be retrieved thanks to the class attribute {attr}`~.DimcatObject.schema`. Other functions that are relevant in this context are {func}`~.get_class` and {func}`~.get_schema` (see [](#class-registry))
|
|
55
|
+
|
|
56
|
+
#### Example
|
|
57
|
+
|
|
58
|
+
```{code-cell}
|
|
59
|
+
import dimcat as dc
|
|
60
|
+
cfg = dc.DimcatConfig("DimcatObject")
|
|
61
|
+
obj = cfg.create()
|
|
62
|
+
print("This object is a", type(obj))
|
|
63
|
+
json_str = obj.to_json()
|
|
64
|
+
obj_copy = dc.base.DimcatObject.from_json(json_str)
|
|
65
|
+
another_copy = dc.deserialize_json_str(json_str)
|
|
66
|
+
print(f"The two deserialized objects are equivalent: ", obj_copy == another_copy)
|
|
67
|
+
print(f"The two deserialized objects are identical: ", obj_copy is another_copy)
|
|
68
|
+
obj_copy # DimcatObject.__repr__() uses .to_dict() under the hood
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
#### Implementation
|
|
72
|
+
|
|
73
|
+
The implementation is centered on two methods of the respective object's nested {class}`~.DimcatSchema` which derives from [marshmallow.Schema](https://marshmallow.readthedocs.io/en/stable/marshmallow.schema.html): [schema.dump()](https://marshmallow.readthedocs.io/en/stable/marshmallow.schema.html#marshmallow.schema.Schema.dump) and [schema.load()](https://marshmallow.readthedocs.io/en/stable/marshmallow.schema.html#marshmallow.schema.Schema.load). The former takes an object and returns a dictionary, whereas the latter takes a dictionary and returns an object. Correspondingly, {meth}`.DimcatObject.to_dict` and {meth}`.DimcatObject.from_dict` retrieve the relevant schema singleton from {attr}`.DimcatObject.schema` to call these two methods respectively.
|
|
74
|
+
|
|
75
|
+
+++
|
|
76
|
+
|
|
77
|
+
### Creating a new type of DimcatObject
|
|
78
|
+
|
|
79
|
+
All objects in `DiMCAT` (except {class}`~.DimcatSchema`) inherit from {class}`~.DimcatObject`. Inheritance also concerns the nested schema class. Effectively, this means that if you subclass an existing object type without adding new initialization arguments, your new class can simply inherit its parent's `Schema` class and serialization will just work as described above. However, if you add a property, meaning that you will also need to add the corresponding initialization argument, you also need to include a nested `Schema` class which inherits from the parent's schema. Each property that is to be serialized needs to be declared as [marshmallow field](https://marshmallow.readthedocs.io/en/stable/marshmallow.fields.html) corresponding to the datatype.
|
|
80
|
+
|
|
81
|
+
```{code-cell}
|
|
82
|
+
from marshmallow import fields
|
|
83
|
+
|
|
84
|
+
class NewType(dc.base.DimcatObject):
|
|
85
|
+
|
|
86
|
+
class Schema(dc.base.DimcatObject.Schema):
|
|
87
|
+
new_property = fields.Str()
|
|
88
|
+
|
|
89
|
+
def __init__(self, new_property: str, **kwargs):
|
|
90
|
+
super().__init__(**kwargs)
|
|
91
|
+
self.new_property = new_property
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
new_obj = NewType("some string value")
|
|
95
|
+
as_dict = new_obj.to_dict()
|
|
96
|
+
new_obj_copy = dc.deserialize_dict(as_dict)
|
|
97
|
+
new_obj_copy
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
In cases where an attribute should point to a DimcatObject (e.g. all {class}`~.Result` objects referencing the analyzed {class}`~.DimcatResource` via the {attr}`~.analyzed_resource` property), we can use the type {class}`~.DimcatObjectField` in the schema.
|
|
101
|
+
|
|
102
|
+
+++
|
|
103
|
+
|
|
104
|
+
(class-registry)=
|
|
105
|
+
### The class registry
|
|
106
|
+
|
|
107
|
+
Every {class}`~.DimcatObject` comes with the attribute {attr}`~._registry` which is a dictionary mapping the names of all DimcatObjects to their classes.
|
|
108
|
+
It is implemented using [__init_subclass__](https://docs.python.org/3/reference/datamodel.html#object.__init_subclass__).
|
|
109
|
+
We don't need to interact directy with the registry thanks to the convenience function {func}`~.get_class` which takes the name of an object as a string and returns the respective class.
|
|
110
|
+
In the code, this would typically look like this:
|
|
111
|
+
|
|
112
|
+
```{code-cell}
|
|
113
|
+
Constructor = dc.get_class("FeatureExtractor")
|
|
114
|
+
feature_extractor = Constructor()
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Schemas are not part of the registry. For retrieving a class's schema we can use `Constructor.schema` (building on the example) or the convenience function {func}`~.get_schema`.
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
### Public and private methods
|
|
121
|
+
|
|
122
|
+
The DiMCAT project differentiates between private methods whose names begin with `_` and public methods whose names don't.
|
|
123
|
+
Semantically, public methods are those that users interact with and which therefore often perform additional checks, e.g. of user input;
|
|
124
|
+
then, the public method calls the private method of the same name which performs the actual job.
|
|
125
|
+
In most cases, subclasses override only private methods.
|
|
126
|
+
|
|
127
|
+
#### Example
|
|
128
|
+
|
|
129
|
+
For example, compare the public {meth}`.PipelineStep.process_dataset` with its private counterpart:
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
def _process_dataset(self, dataset: Dataset) -> Dataset:
|
|
133
|
+
"""Apply this PipelineStep to a :class:`Dataset` and return a copy containing the output(s)."""
|
|
134
|
+
new_dataset = self._make_new_dataset(dataset)
|
|
135
|
+
self.fit_to_dataset(new_dataset)
|
|
136
|
+
# this is where subclasses create a new package and add it to the dataset
|
|
137
|
+
return new_dataset
|
|
138
|
+
|
|
139
|
+
def process_dataset(self, dataset: Dataset) -> Dataset:
|
|
140
|
+
"""Apply this PipelineStep to a :class:`Dataset` and return a copy containing the output(s)."""
|
|
141
|
+
self.check_dataset(dataset)
|
|
142
|
+
return self._process_dataset(dataset)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
+++
|
|
146
|
+
|
|
147
|
+
## Two types of DimcatObjects
|
|
148
|
+
|
|
149
|
+
All classes that are neither a schema nor a config inherit from one of the two following subclasses of DimcatObject:
|
|
150
|
+
|
|
151
|
+
1. {class}`~.Data`: a DimcatObject that represents a dataset, a subset of a dataset, or an individual resource such as a dataframe.
|
|
152
|
+
2. {class}`~.PipelineStep`: a DimcatObject that accepts a Data object as input and returns a Data object as output.
|
|
153
|
+
|
|
154
|
+
They are organized in two packages, {mod}`dimcat.data` and {mod}`dimcat.steps`. Objects defined in {mod}`dimcat.steps` operate on objects defined in {mod}`dimcat.data` and can import from it, but not the other way around.
|
|
155
|
+
In a few exceptional cases where Data objects need to actively use PipelineStep (which is the case, for example, for {meth}`.Dataset.extract_feature`), we circumvent circular imports by summoning them via {func}`~.get_class` (and not using type hints for the summoned object).
|
|
156
|
+
|
|
157
|
+
### Data objects
|
|
158
|
+
|
|
159
|
+
Data is organized into a hierarchical hierarchy of four objects (from top to bottom):
|
|
160
|
+
|
|
161
|
+
* {class}`~.Dataset`, consisting of two catalogs, called `inputs` and `outputs`;
|
|
162
|
+
* {class}`~.DimcatCatalog` ("catalog"), a collection of packages;
|
|
163
|
+
* {class}`~.DimcatPackage` ("package"), a collection of resources;
|
|
164
|
+
* {class}`~.DimcatResource` ("resource"), a wrapper around a dataframe.
|
|
165
|
+
|
|
166
|
+
There are three main types of resources, namely
|
|
167
|
+
|
|
168
|
+
* {class}`~.Facet`, a representation of score-related elements that represents the loaded data with minimal standardization (e.g. {class}`~.MuseScoreNotes`);
|
|
169
|
+
* {class}`~.Feature`, some aspect extracted from a facet, standardized by ``Dimcat`` (e.g., {class}`~.Notes`);
|
|
170
|
+
* {class}`~.Result`, a result of applying a {class}`~.PipelineStep` to a feature.
|
|
171
|
+
|
|
172
|
+
``Dimcat`` cannot process facets directly; the relevant features need to be extracted first. Many PipelineSteps extract the required feature automatically.
|
|
173
|
+
|
|
174
|
+
#### Dataset
|
|
175
|
+
|
|
176
|
+
The principal Data object is the {class}`~.Dataset` and is the one that users usually interact with the most. Its three principal properties are:
|
|
177
|
+
|
|
178
|
+
* {attr}`~.inputs`, an {class}`~.InputsCatalog`
|
|
179
|
+
* {attr}`~.outputs`, an {class}`~.OutputsCatalog`
|
|
180
|
+
* {attr}`~.pipeline`, a {class}`~.Pipeline` consisting of all previously applied {class}`PipelineSteps <~.PipelineStep>`.
|
|
181
|
+
|
|
182
|
+
After applying a {class}`~.PipelineStep` to a {class}`~.Dataset`,
|
|
183
|
+
its {attr}`~.outputs` MUST correspond to the result of applying the {attr}`~.pipeline` to {attr}`~.inputs`.
|
|
184
|
+
A serialized Dataset is therefore suited for communicating results in a reproducible manner.
|
|
185
|
+
Any {class}`~.PipelineStep` applied on a dataset will be performed on all eligible resources that the packages in {attr}`~.inputs` contain and result in a new dataset containing the relevant output packages/resources under {attr}`~.outputs`.
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
Datasets are passive 'by nature', meaning that, in general, they are being manipulated by PipelineSteps or by the user.
|
|
189
|
+
PipelineSteps process a Dataset by requesting one or several features using {meth}`.Dataset.get_feature`,
|
|
190
|
+
processing each {class}`~.Feature`, and adding the processed Feature(s) to the Dataset's OutputsCatalog.
|
|
191
|
+
However, in one case, the Dataset *does* play an active role, namely in the extraction of features from the InputsCatalog.
|
|
192
|
+
When prompted with `.get_feature(F)` where `F` is some specification of a {class}`~.Feature`, the Dataset will
|
|
193
|
+
|
|
194
|
+
* look up the feature in its OutputCatalog and return it if present,
|
|
195
|
+
* call {meth}`.Dataset.extract_feature` otherwise and return its output.
|
|
196
|
+
|
|
197
|
+
Since the actual extraction happens on the level of a single resource (a {class}`~.Facet` which names the feature among its {attr}`~.DimcatResource.extractable_features`), the latter case invokes the following call chain:
|
|
198
|
+
|
|
199
|
+
* {meth}`.Dataset.extract_feature` calls
|
|
200
|
+
* {meth}`.InputsCatalog.extract_feature` calls
|
|
201
|
+
* {meth}`.Package.extract_feature` calls
|
|
202
|
+
* {meth}`.DimcatResource.extract_feature`.
|
|
203
|
+
|
|
204
|
+
The Dataset applies all previously applied PipelineSteps to the thus extracted {class}`~.Feature`,
|
|
205
|
+
adds it to its {class}`~.OutputsCatalog` and appends the {class}`~.FeatureExtractor` to its {class}`~.Pipeline`.
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
+++
|
|
209
|
+
|
|
210
|
+
#### DimcatCatalog
|
|
211
|
+
|
|
212
|
+
As per the [Frictionless Data specifications](https://frictionlessdata.io), a catalog is a collection of packages. In ``Dimcat``, catalogs appear only in a single place: Every {class}`~.Dataset` consists of two {class}`DimcatCatalogs <.DimcatCatalog>`, namely an {class}`~.InputsCatalog` and an {class}`~.OutputsCatalog`.
|
|
213
|
+
{attr}`~.inputs` includes all loaded datapackages, and {attr}`~.outputs` all (processed or unprocessed) features extracted from them, as well as all other
|
|
214
|
+
processing results.
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
#### DimcatPackage
|
|
218
|
+
|
|
219
|
+
The preferred structure of a DimcatPackage is a ``.zip`` and a ``.datapackage.json`` file, where the former contains one or several ``.tsv`` files (resources) described in the latter.
|
|
220
|
+
The ``.datapackage.json`` file follows the [Frictionless](https://frictionlessdata.io) Data specifications for packages and allows ``DiMCAT`` to know what's in a package without having to actually load the data from the ``.tsv`` files.
|
|
221
|
+
|
|
222
|
+
Since the data that DiMCAT transforms and analyzes comes from very heterogeneous sources, each original corpus is pre-processed and stored as a [frictionless.Package](https://framework.frictionlessdata.io/docs/framework/package.html). This task is achieved by loaders. When your aim is to enable ``DiMCAT`` to load a new type of dataset, you will have to implement a new {class}`~.Loader`. Please approach the developers by [creating an issue](https://github.com/DCMLab/dimcat/issues).
|
|
223
|
+
|
|
224
|
+
#### DimcatResource
|
|
225
|
+
|
|
226
|
+
From all this follows that the Dataset is mainly a structured container for {class}`DimcatResources <.DimcatResource>`, of which there are three main types:
|
|
227
|
+
|
|
228
|
+
1. {class}`Facets <.Facet>`, i.e. the resources described in the original datapackage.json. They aim to stay as faithful as possible to the original data, applying only mild standardization and normalization.
|
|
229
|
+
All Facet resources come with several columns that represent timestamps both in absolute and in musical time, allowing for the alignment of different corpora.
|
|
230
|
+
2. {class}`Features <.Feature>`, i.e. resources derived from Facets explicitly (via {meth}`.Dataset.extract_feature`) or implicitly (by applying PipelineSteps which extract features automatically). They are standardized objects that are required by PipelineSteps to compute statistics and visualizations.
|
|
231
|
+
To allow for straightforward serialization of the Dataset, all Feature resources are represented as a DimcatCatalog called {attr}`~.Dataset.outputs`.
|
|
232
|
+
3. {class}`Results <.Result>`, i.e., resources that represent the results of applying an {class}`~.Analyzer` to a {class}`~.Feature`. They are equally stored in the {attr}`~.Dataset.outputs` catalog and come with the appropriate methods for plotting the results.
|
|
233
|
+
|
|
234
|
+
Although [Frictionless resources](https://framework.frictionlessdata.io/docs/framework/resource.html) can be stored as individual ``.tsv`` files with their own ``.resource.json`` descriptors,
|
|
235
|
+
``DiMCAT`` typically stores multiple resources as a datapackage, i.e., a ``.zip`` file containing one ``.tsv`` file per resource, accompanied with a single ``.datapackage.json`` file detailing the metadata for all of them.
|
|
236
|
+
In both cases, the descriptor specifies the column schema for each resource, allowing ``DiMCAT`` to "lazy-load" the data, meaning that the Dataframes are loaded into memory only the moment when they are actually needed (using {meth}`.DimcatResource.load`).
|
|
237
|
+
|
|
238
|
+
A DimcatResource can be instantiated in two different ways, either from a descriptor or from a dataframe.
|
|
239
|
+
At any given moment, the {attr}`~.DimcatResource.status` attribute returns an Enum value reflecting the availability and state of the/a dataframe. This is relevant for keeping datapackages stored on disk up-to-date.
|
|
240
|
+
When a Dataset is serialized, all dataframes from the outputs catalog that haven't been stored to disk yet are written into one or several .zip files so that they can be referenced by the updated descriptor(s).
|
|
241
|
+
|
|
242
|
+
If you want to create a new type of DimcatResource, please inherit from the relevant subclass and refer to the docstrings of {class}`~.DimcatResource` in the module {mod}`.dc` for understanding how to use the class variables.
|
|
243
|
+
|
|
244
|
+
+++
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
```{code-cell}
|
|
249
|
+
|
|
250
|
+
```
|
|
@@ -5,7 +5,7 @@ jupytext:
|
|
|
5
5
|
extension: .md
|
|
6
6
|
format_name: myst
|
|
7
7
|
format_version: 0.13
|
|
8
|
-
jupytext_version: 1.16.
|
|
8
|
+
jupytext_version: 1.16.1
|
|
9
9
|
kernelspec:
|
|
10
10
|
display_name: dimcat
|
|
11
11
|
language: python
|
|
@@ -16,7 +16,7 @@ kernelspec:
|
|
|
16
16
|
|
|
17
17
|
## Import dimcat and load data
|
|
18
18
|
|
|
19
|
-
```{code-cell}
|
|
19
|
+
```{code-cell} ipython3
|
|
20
20
|
import dimcat as dc
|
|
21
21
|
from dimcat.data import resources
|
|
22
22
|
from dimcat.steps import analyzers, extractors, groupers
|
|
@@ -28,7 +28,7 @@ dataset
|
|
|
28
28
|
|
|
29
29
|
## Show metadata
|
|
30
30
|
|
|
31
|
-
```{code-cell}
|
|
31
|
+
```{code-cell} ipython3
|
|
32
32
|
dataset.get_metadata()
|
|
33
33
|
```
|
|
34
34
|
|
|
@@ -38,7 +38,7 @@ dataset.get_metadata()
|
|
|
38
38
|
|
|
39
39
|
Here we pass the extracted notes to the counter.
|
|
40
40
|
|
|
41
|
-
```{code-cell}
|
|
41
|
+
```{code-cell} ipython3
|
|
42
42
|
notes = dataset.get_feature("notes")
|
|
43
43
|
result = analyzers.Counter().process(notes)
|
|
44
44
|
result.plot()
|
|
@@ -46,14 +46,14 @@ result.plot()
|
|
|
46
46
|
|
|
47
47
|
The `FeatureExtractor` is added to the dataset's pipeline implicitly, but the `Counter` is not because it's applied only to the extracted feature:
|
|
48
48
|
|
|
49
|
-
```{code-cell}
|
|
49
|
+
```{code-cell} ipython3
|
|
50
50
|
dataset
|
|
51
51
|
```
|
|
52
52
|
|
|
53
53
|
The pitch-class distributions shown by `.plot()` correspond to the current **unit of analysis**, which defaults to the piece-level.
|
|
54
54
|
Results also come with a second plotting method, `.plot_grouped()`. Since no groupers have been applied, the entire dataset is treated as a single group:
|
|
55
55
|
|
|
56
|
-
```{code-cell}
|
|
56
|
+
```{code-cell} ipython3
|
|
57
57
|
result.plot_grouped()
|
|
58
58
|
```
|
|
59
59
|
|
|
@@ -61,7 +61,7 @@ result.plot_grouped()
|
|
|
61
61
|
|
|
62
62
|
Here we pass the dataset to the counter.
|
|
63
63
|
|
|
64
|
-
```{code-cell}
|
|
64
|
+
```{code-cell} ipython3
|
|
65
65
|
counter = analyzers.Counter(features="notes")
|
|
66
66
|
analyzed_dataset = counter.process(dataset)
|
|
67
67
|
analyzed_dataset.get_result().plot()
|
|
@@ -70,13 +70,13 @@ analyzed_dataset.get_result().plot()
|
|
|
70
70
|
Applying an `Analyzer` to a `Dataset` yields an `AnalyzedDataset` that includes one `Result` resource per analyzed `Feature`.
|
|
71
71
|
Both are to be found in the respective packages in the outputs catalog:
|
|
72
72
|
|
|
73
|
-
```{code-cell}
|
|
73
|
+
```{code-cell} ipython3
|
|
74
74
|
analyzed_dataset
|
|
75
75
|
```
|
|
76
76
|
|
|
77
77
|
### Variant 3: Define a Pipeline with FeatureExtractor and Counter
|
|
78
78
|
|
|
79
|
-
```{code-cell}
|
|
79
|
+
```{code-cell} ipython3
|
|
80
80
|
pipeline = dc.Pipeline([
|
|
81
81
|
extractors.FeatureExtractor("notes"),
|
|
82
82
|
analyzers.Counter()
|
|
@@ -96,7 +96,7 @@ Let's define a CustomPieceGrouper from random piece groups:
|
|
|
96
96
|
this level to any processed Resource (provided it contains the grouped pieces). This changes the behaviour of the grouped resource,
|
|
97
97
|
e.g. when plotting it.
|
|
98
98
|
|
|
99
|
-
```{code-cell}
|
|
99
|
+
```{code-cell} ipython3
|
|
100
100
|
n_groups = 3
|
|
101
101
|
n_members = 30
|
|
102
102
|
|
|
@@ -107,12 +107,12 @@ grouper
|
|
|
107
107
|
### Applying the grouper to the analysis result
|
|
108
108
|
```
|
|
109
109
|
|
|
110
|
-
```{code-cell}
|
|
110
|
+
```{code-cell} ipython3
|
|
111
111
|
grouped_result = grouper.process(result)
|
|
112
112
|
grouped_result
|
|
113
113
|
```
|
|
114
114
|
|
|
115
|
-
```{code-cell}
|
|
115
|
+
```{code-cell} ipython3
|
|
116
116
|
grouped_result.plot_grouped()
|
|
117
117
|
```
|
|
118
118
|
|
|
@@ -120,7 +120,7 @@ As promised, the grouped result plots differently: Instead of showing pitch-clas
|
|
|
120
120
|
(which we can still obtain by calling `.plot()`), it shows the pitch-class distributions for each of the groups.
|
|
121
121
|
However, for closer inspection, the area of a circle is not ideal, so let's view it as a bar plot:
|
|
122
122
|
|
|
123
|
-
```{code-cell}
|
|
123
|
+
```{code-cell} ipython3
|
|
124
124
|
grouped_result.make_bar_plot()
|
|
125
125
|
```
|
|
126
126
|
|
|
@@ -131,22 +131,22 @@ resources (to the `Notes` feature and to the `Counts` result) and to a dataset c
|
|
|
131
131
|
Another way to achieve the same goal is by applying steps to data. Let's start with a fresh dataset and
|
|
132
132
|
apply the grouper and the analyzer once more:
|
|
133
133
|
|
|
134
|
-
```{code-cell}
|
|
134
|
+
```{code-cell} ipython3
|
|
135
135
|
D = dc.Dataset.from_package(package_path)
|
|
136
136
|
analyzed_dataset = D.apply_step(grouper, counter)
|
|
137
137
|
analyzed_dataset
|
|
138
138
|
```
|
|
139
139
|
|
|
140
|
-
```{code-cell}
|
|
140
|
+
```{code-cell} ipython3
|
|
141
141
|
result = analyzed_dataset.get_result()
|
|
142
142
|
result
|
|
143
143
|
```
|
|
144
144
|
|
|
145
|
-
```{code-cell}
|
|
145
|
+
```{code-cell} ipython3
|
|
146
146
|
result.default_groupby
|
|
147
147
|
```
|
|
148
148
|
|
|
149
|
-
```{code-cell}
|
|
149
|
+
```{code-cell} ipython3
|
|
150
150
|
analyzed_dataset.get_result().make_bar_plot()
|
|
151
151
|
```
|
|
152
152
|
|
|
@@ -158,14 +158,14 @@ or invalid values [are rejected](./errors.md#invalid-option).
|
|
|
158
158
|
|
|
159
159
|
Any DimcatObject can be expressed as a config by calling its `.to_config()` method:
|
|
160
160
|
|
|
161
|
-
```{code-cell}
|
|
161
|
+
```{code-cell} ipython3
|
|
162
162
|
config = counter.to_config()
|
|
163
163
|
config
|
|
164
164
|
```
|
|
165
165
|
|
|
166
166
|
Any config can be used to instantiate a DimcatObject:
|
|
167
167
|
|
|
168
|
-
```{code-cell}
|
|
168
|
+
```{code-cell} ipython3
|
|
169
169
|
counter_copy = config.create()
|
|
170
170
|
print(f"""The new object and the old object are
|
|
171
171
|
equal: {counter == counter_copy}
|
|
@@ -174,7 +174,7 @@ identical: {counter is counter_copy}""")
|
|
|
174
174
|
|
|
175
175
|
Wherever DiMCAT operates with configs, it also accepts dictionaries:
|
|
176
176
|
|
|
177
|
-
```{code-cell}
|
|
177
|
+
```{code-cell} ipython3
|
|
178
178
|
step_configs = [
|
|
179
179
|
dict(dtype="FeatureExtractor", features=[dict(dtype="Notes", format="FIFTHS")]),
|
|
180
180
|
dict(dtype='CustomPieceGrouper', grouped_units=grouping),
|
|
@@ -184,7 +184,7 @@ pl = dc.Pipeline.from_step_configs(step_configs)
|
|
|
184
184
|
pl
|
|
185
185
|
```
|
|
186
186
|
|
|
187
|
-
```{code-cell}
|
|
187
|
+
```{code-cell} ipython3
|
|
188
188
|
resulting_dataset = pl.process(dataset)
|
|
189
189
|
resulting_dataset.get_result().make_bar_plot()
|
|
190
190
|
```
|