From 2b8ba882e4e638365180b45cd7d143588837517f Mon Sep 17 00:00:00 2001 From: Remi Gau Date: Mon, 6 Nov 2023 16:44:52 +0100 Subject: [PATCH] [MAINT] merge main in dev (#644) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * BIDS schema update (#628) Co-authored-by: Remi-Gau * Bump actions/checkout from 3 to 4 (#629) Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * BIDS schema update (#633) Co-authored-by: Remi-Gau * BIDS schema update (#634) Co-authored-by: Remi-Gau * BIDS schema update (#635) Co-authored-by: Remi-Gau * [pre-commit.ci] pre-commit autoupdate (#636) updates: - [github.com/pre-commit/pre-commit-hooks: v4.4.0 → v4.5.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.4.0...v4.5.0) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> * BIDS schema update (#637) Co-authored-by: Remi-Gau * BIDS schema update (#639) Co-authored-by: Remi-Gau * BIDS schema update (#640) Co-authored-by: Remi-Gau * Bump matlab-actions/setup-matlab from 1.2.4 to 1.2.5 (#641) Bumps [matlab-actions/setup-matlab](https://github.com/matlab-actions/setup-matlab) from 1.2.4 to 1.2.5. - [Release notes](https://github.com/matlab-actions/setup-matlab/releases) - [Commits](https://github.com/matlab-actions/setup-matlab/compare/v1.2.4...v1.2.5) --- updated-dependencies: - dependency-name: matlab-actions/setup-matlab dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump matlab-actions/run-command from 1.2.1 to 1.2.2 (#642) Bumps [matlab-actions/run-command](https://github.com/matlab-actions/run-command) from 1.2.1 to 1.2.2. - [Release notes](https://github.com/matlab-actions/run-command/releases) - [Commits](https://github.com/matlab-actions/run-command/compare/v1.2.1...v1.2.2) --- updated-dependencies: - dependency-name: matlab-actions/run-command dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * [FIX] update test after schema update (#643) * fix test after schema update * set os version for doc * update schema * fix typos * update tests --------- Signed-off-by: dependabot[bot] Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Remi-Gau Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .../+transformers_list/Merge_identical_rows.m | 2 +- +bids/transformers.m | 24 ++++----- .github/workflows/run_tests_matlab.yml | 1 + .github/workflows/run_tests_octave.yml | 2 +- .github/workflows/update_schema.yml | 2 +- .pre-commit-config.yaml | 3 +- .readthedocs.yml | 6 ++- demos/spm/facerep/code/convert_facerep_ds.m | 2 +- schema.json | 2 +- tests/test_bids_file.m | 11 ++-- tests/test_bids_schema.m | 52 ++++++++++++++++--- .../test_transformers_side_functions.m | 2 +- tests/tests_private/test_append_to_layout.m | 9 ++-- 13 files changed, 84 insertions(+), 34 deletions(-) diff --git a/+bids/+transformers_list/Merge_identical_rows.m b/+bids/+transformers_list/Merge_identical_rows.m index 0aab8d14..16da3545 100644 --- a/+bids/+transformers_list/Merge_identical_rows.m +++ b/+bids/+transformers_list/Merge_identical_rows.m @@ -26,7 +26,7 @@ % - If a variable is found, but is empty, it is ignored % - The content of the other columns corresponds to the last row being merged: % this means that the content from other columns but the one specified in will be deleted - % execpt for the last one + % except for the last one % % CODE EXAMPLE % ------------ diff --git a/+bids/transformers.m b/+bids/transformers.m index e487e00c..c04c88f2 100644 --- a/+bids/transformers.m +++ b/+bids/transformers.m @@ -39,10 +39,10 @@ % (C) Copyright 2022 BIDS-MATLAB developers - SUPPORTED_TRANSFORMERS = lower(cat(1, basic_transfomers, ... - munge_transfomers, ... - logical_transfomers, ... - compute_transfomers)); + SUPPORTED_TRANSFORMERS = lower(cat(1, basic_transformers, ... + munge_transformers, ... + logical_transformers, ... + compute_transformers)); p = inputParser; @@ -98,16 +98,16 @@ switch transformerName - case lower(basic_transfomers) + case lower(basic_transformers) output = bids.transformers_list.Basic(trans, data); - case lower(logical_transfomers) + case lower(logical_transformers) output = bids.transformers_list.Logical(trans, data); - case lower(munge_transfomers) + case lower(munge_transformers) output = apply_munge(trans, data); - case lower(compute_transfomers) + case lower(compute_transformers) output = apply_compute(trans, data); otherwise @@ -211,7 +211,7 @@ function not_implemented(name) false); end -function BASIC = basic_transfomers() +function BASIC = basic_transformers() BASIC = {'Add' 'Divide' 'Multiply' @@ -219,13 +219,13 @@ function not_implemented(name) 'Subtract'}; end -function LOGICAL = logical_transfomers() +function LOGICAL = logical_transformers() LOGICAL = {'And' 'Or' 'Not'}; end -function MUNGE = munge_transfomers() +function MUNGE = munge_transformers() MUNGE = {'Assign' 'Concatenate' 'Constant' @@ -242,7 +242,7 @@ function not_implemented(name) 'Split'}; end -function COMPUTE = compute_transfomers() +function COMPUTE = compute_transformers() COMPUTE = {'Mean' 'Product' 'Scale' diff --git a/.github/workflows/run_tests_matlab.yml b/.github/workflows/run_tests_matlab.yml index db6731d9..86530e4a 100644 --- a/.github/workflows/run_tests_matlab.yml +++ b/.github/workflows/run_tests_matlab.yml @@ -50,6 +50,7 @@ jobs: - name: Install bids validator run: npm install -g bids-validator + - name: Install bids example run: | cd tests diff --git a/.github/workflows/run_tests_octave.yml b/.github/workflows/run_tests_octave.yml index 9e855168..ecb165af 100644 --- a/.github/workflows/run_tests_octave.yml +++ b/.github/workflows/run_tests_octave.yml @@ -31,7 +31,7 @@ jobs: steps: - name: Clone bids-matlab - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: true fetch-depth: 1 diff --git a/.github/workflows/update_schema.yml b/.github/workflows/update_schema.yml index 38a5632e..5485a1bd 100644 --- a/.github/workflows/update_schema.yml +++ b/.github/workflows/update_schema.yml @@ -49,7 +49,7 @@ jobs: steps: - name: Clone bids-matlab - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Get BIDS schema run: make update_schema diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 26db9aa4..c34e1ae5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,7 +3,7 @@ exclude: schema.json repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.4.0 + rev: v4.5.0 hooks: - id: trailing-whitespace - id: end-of-file-fixer @@ -12,7 +12,6 @@ repos: - id: check-json - repo: local - hooks: - id: mh_style name: mh_style diff --git a/.readthedocs.yml b/.readthedocs.yml index 2244e577..43bb9f9d 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -6,6 +6,11 @@ # Required version: 2 +build: + os: ubuntu-22.04 + tools: + python: '3.12' + # Build documentation in the docs/ directory with Sphinx sphinx: configuration: docs/source/conf.py @@ -22,6 +27,5 @@ formats: # Optionally set the version of Python and requirements required to build your docs python: - version: '3.8' install: - requirements: requirements.txt diff --git a/demos/spm/facerep/code/convert_facerep_ds.m b/demos/spm/facerep/code/convert_facerep_ds.m index e3d2349e..fb87a39b 100644 --- a/demos/spm/facerep/code/convert_facerep_ds.m +++ b/demos/spm/facerep/code/convert_facerep_ds.m @@ -302,7 +302,7 @@ function create_readme(output_dir) '- 2 presentations of 26 Famous and 26 Nonfamous Greyscale photographs, ' ' for 0.5s, randomly intermixed, for fame judgment task ' ' (one of two right finger key presses).' - '- Parameteric factor "lag" = number of faces intervening ' + '- Parametric factor "lag" = number of faces intervening ' ' between repetition of a specific face + 1' '- Minimal SOA=4.5s, with probability 2/3 (ie 1/3 null events)' '' diff --git a/schema.json b/schema.json index 824b1af5..e642f5d8 100644 --- a/schema.json +++ b/schema.json @@ -1 +1 @@ -{"schema_version": "0.7.2-dev", "bids_version": "1.9.0-dev", "meta": {"associations": {"events": {"selectors": ["task in entities", "extension != '.json'"], "target": {"suffix": "events", "extension": ".tsv"}, "inherit": true}, "aslcontext": {"selectors": ["suffix == 'asl'", "match(extension, '\\.nii(\\.gz)?$')"], "target": {"suffix": "aslcontext", "extension": ".tsv"}, "inherit": true}, "m0scan": {"selectors": ["suffix == 'asl'", "match(extension, '\\.nii(\\.gz)?$')"], "target": {"suffix": "m0scan", "extension": [".nii", ".nii.gz"]}, "inherit": false}, "magnitude": {"selectors": ["suffix == 'fieldmap'", "match(extension, '\\.nii(\\.gz)?$')"], "target": {"suffix": "magnitude", "extension": [".nii", ".nii.gz"]}, "inherit": false}, "magnitude1": {"selectors": ["match(suffix, 'phase(diff|1)$')", "match(extension, '\\.nii(\\.gz)?$')"], "target": {"suffix": "magnitude1", "extension": [".nii", ".nii.gz"]}, "inherit": false}, "bval": {"selectors": ["suffix == 'dwi'", "match(extension, '\\.nii(\\.gz)?$')"], "target": {"extension": ".bval"}, "inherit": true}, "bvec": {"selectors": ["suffix == 'dwi'", "match(extension, '\\.nii(\\.gz)?$')"], "target": {"extension": ".bvec"}, "inherit": true}, "channels": {"selectors": ["intersects([suffix], ['eeg', 'ieeg', 'meg', 'nirs', 'motion', 'optodes'])", "extension != '.json'"], "target": {"suffix": "channels", "extension": ".tsv"}, "inherit": true}, "coordsystem": {"selectors": ["intersects([suffix], ['eeg', 'ieeg', 'meg', 'nirs', 'motion', 'electrodes', 'optodes'])", "extension != '.json'"], "target": {"suffix": "coordsystem", "extension": ".json"}, "inherit": true}}, "context": {"context": {"type": "object", "properties": {"schema": {"description": "The BIDS specification schema", "type": "object"}, "dataset": {"description": "Properties and contents of the entire dataset", "type": "object", "properties": {"dataset_description": {"description": "Contents of /dataset_description.json", "type": "object"}, "files": {"description": "List of all files in dataset", "type": "array"}, "tree": {"description": "Tree view of all files in dataset", "type": "object"}, "ignored": {"description": "Set of ignored files", "type": "array"}, "datatypes": {"description": "Data types present in the dataset", "type": "array"}, "modalities": {"description": "Modalities present in the dataset", "type": "array"}, "subjects": {"description": "Collections of subjects in dataset", "type": "object", "properties": {"sub_dirs": {"description": "Subjects as determined by sub-*/ directories", "type": "array", "items": {"type": "string"}}, "participant_id": {"description": "The participant_id column of participants.tsv", "type": "array", "items": {"type": "string"}}, "phenotype": {"description": "The union of participant_id columns in phenotype files", "type": "array", "items": {"type": "string"}}}}}}, "subject": {"description": "Properties and contents of the current subject", "type": "object", "properties": {"sessions": {"description": "Collections of sessions in subject", "type": "object", "properties": {"ses_dirs": {"description": "Sessions as determined by ses-*/ directories", "type": "array", "items": {"type": "string"}}, "session_id": {"description": "The session_id column of sessions.tsv", "type": "array", "items": {"type": "string"}}, "phenotype": {"description": "The union of session_id columns in phenotype files", "type": "array", "items": {"type": "string"}}}}}}, "path": {"description": "Path of the current file", "type": "string"}, "size": {"description": "Length of the current file in bytes", "type": "int"}, "entities": {"description": "Entities parsed from the current filename", "type": "object"}, "datatype": {"description": "Datatype of current file, for examples, anat", "type": "string"}, "suffix": {"description": "Suffix of current file", "type": "string"}, "extension": {"description": "Extension of current file including initial dot", "type": "string"}, "modality": {"description": "Modality of current file, for examples, MRI", "type": "string"}, "sidecar": {"description": "Sidecar metadata constructed via the inheritance principle", "type": "object"}, "associations": {"description": "Associated files, indexed by suffix, selected according to the inheritance principle\n", "type": "object", "properties": {"events": {"description": "Events file", "type": "object", "properties": {"path": {"description": "Path to associated events file", "type": "string"}, "onset": {"description": "Contents of the onset column", "type": "array", "items": {"type": "string"}}}}, "aslcontext": {"description": "ASL context file", "type": "object", "properties": {"path": {"description": "Path to associated aslcontext file", "type": "string"}, "n_rows": {"description": "Number of rows in aslcontext.tsv", "type": "integer"}, "volume_type": {"description": "Contents of the volume_type column", "type": "array", "items": {"type": "string"}}}}, "m0scan": {"description": "M0 scan file", "type": "object", "properties": {"path": {"description": "Path to associated M0 scan file", "type": "string"}}}, "magnitude": {"description": "Magnitude image file", "type": "object", "properties": {"path": {"description": "Path to associated magnitude file", "type": "string"}}}, "magnitude1": {"description": "Magnitude1 image file", "type": "object", "properties": {"path": {"description": "Path to associated magnitude1 file", "type": "string"}}}, "bval": {"description": "B value file", "type": "object", "properties": {"path": {"description": "Path to associated bval file", "type": "string"}, "n_cols": {"description": "Number of columns in bval file", "type": "integer"}}}, "bvec": {"description": "B vector file", "type": "object", "properties": {"path": {"description": "Path to associated bvec file", "type": "string"}, "n_cols": {"description": "Number of columns in bvec file", "type": "integer"}}}, "channels": {"description": "Channels file", "type": "object", "properties": {"path": {"description": "Path to associated channels file", "type": "string"}, "type": {"description": "Contents of the type column", "type": "array", "items": {"type": "string"}}}}, "coordsystem": {"description": "Coordinate system file", "type": "object", "properties": {"path": {"description": "Path to associated coordsystem file", "type": "string"}}}}}, "columns": {"description": "TSV columns, indexed by column header, values are arrays with column contents", "type": "object", "additionalProperties": {"type": "array"}}, "json": {"description": "Contents of the current JSON file", "type": "object"}, "gzip": {"description": "Parsed contents of gzip header", "type": "object", "properties": {"timestamp": {"description": "Modification time, unix timestamp", "type": "number"}, "filename": {"description": "Filename", "type": "string"}, "comment": {"description": "Comment", "type": "string"}}}, "nifti_header": {"name": "NIfTI Header", "description": "Parsed contents of NIfTI header referenced elsewhere in schema.", "type": "object", "properties": {"dim_info": {"name": "Dimension Information", "description": "Metadata about dimensions data.", "type": "object", "properties": {"freq": {"name": "Frequency", "description": "These fields encode which spatial dimension (1, 2, or 3).", "type": "integer"}, "phase": {"name": "Phase", "description": "Corresponds to which acquisition dimension for MRI data.", "type": "integer"}, "slice": {"name": "Slice", "description": "Slice dimensions.", "type": "integer"}}}, "dim": {"name": "Data Dimensions", "description": "Data seq dimensions.", "type": "array", "minItems": 8, "maxItems": 8, "items": {"type": "integer"}}, "pixdim": {"name": "Pixel Dimension", "description": "Grid spacings (unit per dimension).", "type": "array", "minItems": 8, "maxItems": 8, "items": {"type": "number"}}, "shape": {"name": "Data shape", "description": "Data array shape, equal to dim[1:dim[0] + 1]", "type": "array", "minItems": 0, "maxItems": 7, "items": {"type": "integer"}}, "voxel_sizes": {"name": "Voxel sizes", "description": "Voxel sizes, equal to pixdim[1:dim[0] + 1]", "type": "array", "minItems": 0, "maxItems": 7, "items": {"type": "number"}}, "xyzt_units": {"name": "XYZT Units", "description": "Units of pixdim[1..4]", "type": "object", "properties": {"xyz": {"name": "XYZ Units", "description": "String representing the unit of voxel spacing.", "type": "string", "enum": ["unknown", "meter", "mm", "um"]}, "t": {"name": "Time Unit", "description": "String representing the unit of inter-volume intervals.", "type": "string", "enum": ["unknown", "sec", "msec", "usec"]}}}, "qform_code": {"name": "qform code", "description": "Use of the quaternion fields.", "type": "integer"}, "sform_code": {"name": "sform code", "description": "Use of the affine fields.", "type": "integer"}}}, "ome": {"name": "Open Microscopy Environment fields", "description": "Parsed contents of OME-XML header, which may be found in OME-TIFF or OME-ZARR files", "type": "object", "properties": {"PhysicalSizeX": {"name": "PhysicalSizeX", "description": "Pixels / @PhysicalSizeX", "type": "float"}, "PhysicalSizeY": {"name": "PhysicalSizeY", "description": "Pixels / @PhysicalSizeY", "type": "float"}, "PhysicalSizeZ": {"name": "PhysicalSizeZ", "description": "Pixels / @PhysicalSizeZ", "type": "float"}, "PhysicalSizeXUnit": {"name": "PhysicalSizeXUnit", "description": "Pixels / @PhysicalSizeXUnit", "type": "string"}, "PhysicalSizeYUnit": {"name": "PhysicalSizeYUnit", "description": "Pixels / @PhysicalSizeYUnit", "type": "string"}, "PhysicalSizeZUnit": {"name": "PhysicalSizeZUnit", "description": "Pixels / @PhysicalSizeZUnit", "type": "string"}}}, "tiff": {"name": "TIFF", "description": "TIFF file format metadata", "type": "object", "properties": {"version": {"name": "Version", "description": "TIFF file format version (the second 2-byte block)", "type": "int"}}}}}}, "expression_tests": [{"expression": "sidecar.MissingValue", "result": null}, {"expression": "null.anything", "result": null}, {"expression": "(null)", "result": null}, {"expression": "null[0]", "result": null}, {"expression": "null && true", "result": null}, {"expression": "null || true", "result": null}, {"expression": "true && null", "result": null}, {"expression": "false && null", "result": false}, {"expression": "true || null", "result": true}, {"expression": "false || null", "result": null}, {"expression": "!null", "result": null}, {"expression": "null + 1", "result": null}, {"expression": "null - 1", "result": null}, {"expression": "null * 1", "result": null}, {"expression": "null / 1", "result": null}, {"expression": "1 + null", "result": null}, {"expression": "1 - null", "result": null}, {"expression": "1 * null", "result": null}, {"expression": "1 / null", "result": null}, {"expression": "'str1' + null", "result": null}, {"expression": "null + 'str1'", "result": null}, {"expression": "intersects([], null)", "result": null}, {"expression": "intersects(null, [])", "result": null}, {"expression": "match(null, 'pattern')", "result": null}, {"expression": "match('string', null)", "result": null}, {"expression": "substr(null, 1, 4)", "result": null}, {"expression": "substr('string', null, 4)", "result": null}, {"expression": "substr('string', 1, null)", "result": null}, {"expression": "min(null)", "result": null}, {"expression": "max(null)", "result": null}, {"expression": "length(null)", "result": null}, {"expression": "type(null)", "result": "null"}, {"expression": "null == false", "result": false}, {"expression": "null == true", "result": false}, {"expression": "null != false", "result": true}, {"expression": "null != true", "result": true}, {"expression": "null != 1.5", "result": true}, {"expression": "null == null", "result": true}, {"expression": "null == 1", "result": false}, {"expression": "\"VolumeTiming\" in null", "result": false}, {"expression": "exists(null, \"bids-uri\")", "result": false}, {"expression": "exists([], null)", "result": false}, {"expression": "evaluate(true)", "result": true}, {"expression": "evaluate(false)", "result": false}, {"expression": "evaluate(null)", "result": false}, {"expression": "1 + 2", "result": 3}, {"expression": "\"cat\" + \"dog\"", "result": "catdog"}, {"expression": "1 + \"cat\"", "result": null}, {"expression": "match('string', '.*')", "result": true}, {"expression": "match('', '.')", "result": false}, {"expression": "substr('string', 1, 4)", "result": "tri"}, {"expression": "substr('string', 0, 20)", "result": "string"}, {"expression": "type(1)", "result": "number"}, {"expression": "type([])", "result": "array"}, {"expression": "type({})", "result": "object"}, {"expression": "type(true)", "result": "boolean"}, {"expression": "intersects([1], [1, 2])", "result": true}, {"expression": "intersects([1], [])", "result": false}, {"expression": "length([1, 2, 3])", "result": 3}, {"expression": "length([])", "result": 0}, {"expression": "count([1, 2, 3], 1)", "result": 1}, {"expression": "index([\"i\", \"j\", \"k\"], \"i\")", "result": 0}, {"expression": "index([\"i\", \"j\", \"k\"], \"j\")", "result": 1}, {"expression": "index([\"i\", \"j\", \"k\"], \"x\")", "result": null}, {"expression": "sorted([3, 2, 1])", "result": [1, 2, 3]}, {"expression": "min([-1, \"n/a\", 1])", "result": -1}, {"expression": "max([-1, \"n/a\", 1])", "result": 1}, {"expression": "[3, 2, 1][0]", "result": 3}, {"expression": "\"string\"[0]", "result": "s"}], "versions": ["1.9.0", "1.8.0", "1.7.0", "1.6.0", "1.5.0", "1.4.1", "1.4.0", "1.3.0", "1.2.2", "1.2.1", "1.2.0", "1.1.2", "1.1.1", "1.1.0", "1.0.2", "1.0.1", "1.0.0"]}, "objects": {"columns": {"HED": {"name": "HED", "display_name": "HED Tag", "description": "Hierarchical Event Descriptor (HED) Tag.\nSee the [HED Appendix](SPEC_ROOT/appendices/hed.md) for details.\n", "type": "string"}, "abbreviation": {"name": "abbreviation", "display_name": "Abbreviation", "description": "The unique label abbreviation\n", "type": "string"}, "acq_time__scans": {"name": "acq_time", "display_name": "Scan acquisition time", "description": "Acquisition time refers to when the first data point in each run was acquired.\nFurthermore, if this header is provided, the acquisition times of all files\nfrom the same recording MUST be identical.\nDatetime format and their anonymization are described in\n[Units](SPEC_ROOT/common-principles.md#units).\n", "type": "string", "format": "datetime"}, "acq_time__sessions": {"name": "acq_time", "display_name": "Session acquisition time", "description": "Acquisition time refers to when the first data point of the first run was acquired.\nDatetime format and their anonymization are described in\n[Units](SPEC_ROOT/common-principles.md#units).\n", "type": "string", "format": "datetime"}, "age": {"name": "age", "display_name": "Subject age", "description": "Numeric value in years (float or integer value).\n\nIt is recommended to tag participant ages that are 89 or higher as 89+,\nfor privacy purposes.\n", "type": "number", "unit": "year"}, "cardiac": {"name": "cardiac", "display_name": "Cardiac measurement", "description": "continuous pulse measurement\n", "type": "number"}, "color": {"name": "color", "display_name": "Color label", "description": "Hexadecimal. Label color for visualization.\n", "type": "string", "unit": "hexadecimal"}, "component": {"name": "component", "display_name": "Component", "description": "Description of the spatial axis or label of quaternion component associated with the channel.\nFor example, `x`,`y`,`z` for position channels,\nor `quat_x`, `quat_y`, `quat_z`, `quat_w` for quaternion orientation channels.\n", "type": "string", "enum": ["x", "y", "z", "quat_x", "quat_y", "quat_z", "quat_w", "n/a"]}, "detector__channels": {"name": "detector", "display_name": "Detector Name", "description": "Name of the detector as specified in the `*_optodes.tsv` file.\n`n/a` for channels that do not contain NIRS signals (for example, acceleration).\n", "anyOf": [{"type": "string"}, {"type": "string", "enum": ["n/a"]}]}, "detector_type": {"name": "detector_type", "display_name": "Detector Type", "description": "The type of detector. Only to be used if the field `DetectorType` in `*_nirs.json` is set to `mixed`.\n", "anyOf": [{"type": "string"}]}, "derived_from": {"name": "derived_from", "display_name": "Derived from", "description": "`sample-