From 24efbc1a6123f51c1d1caf1cc29a4b1bb182dfe1 Mon Sep 17 00:00:00 2001 From: Mainak Jas Date: Wed, 30 Aug 2017 03:16:54 +0530 Subject: [PATCH 1/7] Attempt on validator --- examples/plot_validator.py | 26 +++++++++++++++++++++++ examples/sub-01_task-audiovisual_meg.json | 26 +++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 examples/plot_validator.py create mode 100644 examples/sub-01_task-audiovisual_meg.json diff --git a/examples/plot_validator.py b/examples/plot_validator.py new file mode 100644 index 000000000..721d5152f --- /dev/null +++ b/examples/plot_validator.py @@ -0,0 +1,26 @@ +import json +from jsonschema import validate +import os.path as op + +from mne.datasets import sample + +data_path = sample.data_path() +json_fname = op.join('.', 'sub-01_task-audiovisual_meg.json') + +empty = {"type": "string", "maxLength": 0} + +# A sample schema, like what we'd get from json.load() +schema = { + "type": "object", + "properties": { + "TaskName": {"type": "string", "minLength": 1}, + "SamplingFrequency": {"type": "number"}, + "Manufacturer": {"type": "string", "minLength": 1}, + "ManufacturerModelName": {"anyOf": [{"type": "string"}, empty]}, + }, +} + +with open(json_fname) as json_data: + meg_json = json.load(json_data) + +validate(meg_json, schema) diff --git a/examples/sub-01_task-audiovisual_meg.json b/examples/sub-01_task-audiovisual_meg.json new file mode 100644 index 000000000..1560036de --- /dev/null +++ b/examples/sub-01_task-audiovisual_meg.json @@ -0,0 +1,26 @@ +{ + "TaskName": "audiovisual", + "SamplingFrequency": 600.614990234, + "Manufacturer": "Elekta", + "ManufacturerModelName": "Neuromag Vectorview 306", + "TaskDescription": "In this experiment, checkerboard patterns were presented to the subject into the left and right visual field, interspersed by tones to the left or right ear. The interval between the stimuli was 750 ms. Occasionally a smiley face was presented at the center of the visual field. The subject was asked to press a key with the right index finger as soon as possible after the appearance of the face.", + "MEGChannelCount": 306, + "MEGREFChannelCount": 0, + "EEGChannelCount": 60, + "EOGChannelCount": 1, + "ECGChannelCount": 0, + "EMGChannelCount": 0, + "MiscChannelCount": 0, + "TriggerChannelCount": 9, + "PowerLineFrequency": 60, + "HLCFrequency": [], + "EEGReference": "nose", + "MEGPosition": "upright", + "OnlineFilters": "0.10000000149 Hz high-pass, 172.176300049 Hz low-pass", + "RecordingType": "continuous", + "EyesClosed": "false", + "ContinuousHeadLocalization": "false", + "DigitizedLandmarks": "true", + "DigitizedHeadPoints": "true", + "SubjectArtefactDescription": "false" +} From 752846963ed80d926b0fd1a7be77753f00e50246 Mon Sep 17 00:00:00 2001 From: Dora Date: Tue, 29 Aug 2017 16:10:53 -0700 Subject: [PATCH 2/7] added meg json schema --- mne_bids/jsonschemas/schema_meg.py | 88 ++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 mne_bids/jsonschemas/schema_meg.py diff --git a/mne_bids/jsonschemas/schema_meg.py b/mne_bids/jsonschemas/schema_meg.py new file mode 100644 index 000000000..37f2eb521 --- /dev/null +++ b/mne_bids/jsonschemas/schema_meg.py @@ -0,0 +1,88 @@ +from jsonschema import validate +import numpy as np + +empty = { "type": "string", "maxLength": 0} + +NaN = np.nan; +# booleans have problems with capitals (e.g. True versus true), this is a string for now. + +# A sample MEG schema, like what we'd get from json.load() +schema = { + "type": "object", + "properties": { + "TaskName": {"type": "string","minLength": 1}, + "Manufacturer": {"type": "string","minLength": 1}, + "ManufacturerModelName": {"type": "string"}, + "TaskDescription": {"type": "string"}, + "Instructions": {"type": "string"}, + "PowerLineFrequency": {"type": "number"}, + "CogAtlasID": {"type": "string"}, + "CogPOID": {"type": "string"}, + "InstitutionName": {"type": "string"}, + "InstitutionAddress": {"type": "string"}, + "DeviceSerialNumber": {"type": "string"}, + "MEGChannelCount": {"type": "integer"}, + "MEGREFChannelCount": {"type": "integer"}, + "EEGChannelCount": {"type" : "integer"}, + "EOGChannelCount": {"type" : "integer"}, + "ECGChannelCount": {"type" : "integer"}, + "EMGChannelCount": {"type" : "integer"}, + "MiscChannelCount": {"type" : "integer"}, + "TriggerChannelCount": {"type" : "integer"}, + "PowerLineFrequency": {"type" : "number"}, + "EEGPlacementScheme": {"type" : "string"}, + "EEGReference": {"type" : "string"}, + "DewarPosition": {"type" : "string"}, + "SoftwareFilters": {"type" : "string"}, + "RecordingDuration": {"type" : "number"}, + "RecordingType": {"type" : "string"}, + "EpochLength": {"type" : "number"}, + "DeviceSoftwareVersion": {"type" : "string"}, + "ContinuousHeadLocalization": {"type" : "string"}, + "CoilFrequency": {"type" : "number"}, + "MaxMovement": {"type" : "number"}, + "SubjectArtefactDescription": {"type" : "string"}, + "DigitizedLandmarks": {"type" : "string"}, + "DigitizedHeadPoints": {"type" : "string"}, + }, + "required": [ "TaskName", + "Manufacturer", + "SamplingFrequency", + "MEGChannelCount", + "MEGREFChannelCount", + "EEGChannelCount", + "EOGChannelCount", + "ECGChannelCount", + "EMGChannelCount", + "MiscChannelCount", + "TriggerChannelCount"] + } + + +test = { + "TaskName": "audiovisual", + "SamplingFrequency": 500, + "Manufacturer": "test", + "ManufacturerModelName": "test", + "TaskDescription": "In this experiment...", + "MEGChannelCount": 306, + "MEGREFChannelCount": 0, + "EEGChannelCount": 60, + "EOGChannelCount": 1, + "ECGChannelCount": 0, + "EMGChannelCount": 0, + "MiscChannelCount": 0, + "TriggerChannelCount": 9, + "PowerLineFrequency": NaN, + "EEGReference": "nose", + "MEGPosition": "upright", + "OnlineFilters": "0.10000000149 Hz high-pass, 172.176300049 Hz low-pass", + "RecordingType": "continuous", + "EyesClosed": "false", + "ContinuousHeadLocalization": "false", + "DigitizedLandmarks": "true", + "DigitizedHeadPoints": "true", + "SubjectArtefactDescription": "", +} + +validate(test, schema) From 88d6ce1eeaef9e13d5c14c503ad5c35bcd269a83 Mon Sep 17 00:00:00 2001 From: Mainak Jas Date: Wed, 30 Aug 2017 05:13:14 +0530 Subject: [PATCH 3/7] Tweaks --- examples/plot_validator.py | 21 +--------- .../{schema_meg.py => schema_meg.json} | 42 +------------------ mne_bids/validator.py | 18 ++++++++ 3 files changed, 22 insertions(+), 59 deletions(-) rename mne_bids/jsonschemas/{schema_meg.py => schema_meg.json} (67%) create mode 100644 mne_bids/validator.py diff --git a/examples/plot_validator.py b/examples/plot_validator.py index 721d5152f..7e1c4cd85 100644 --- a/examples/plot_validator.py +++ b/examples/plot_validator.py @@ -1,26 +1,9 @@ -import json -from jsonschema import validate import os.path as op +from mne_bids.validator import validate_meg from mne.datasets import sample data_path = sample.data_path() json_fname = op.join('.', 'sub-01_task-audiovisual_meg.json') -empty = {"type": "string", "maxLength": 0} - -# A sample schema, like what we'd get from json.load() -schema = { - "type": "object", - "properties": { - "TaskName": {"type": "string", "minLength": 1}, - "SamplingFrequency": {"type": "number"}, - "Manufacturer": {"type": "string", "minLength": 1}, - "ManufacturerModelName": {"anyOf": [{"type": "string"}, empty]}, - }, -} - -with open(json_fname) as json_data: - meg_json = json.load(json_data) - -validate(meg_json, schema) +validate_meg(json_fname) diff --git a/mne_bids/jsonschemas/schema_meg.py b/mne_bids/jsonschemas/schema_meg.json similarity index 67% rename from mne_bids/jsonschemas/schema_meg.py rename to mne_bids/jsonschemas/schema_meg.json index 37f2eb521..5a11ac89f 100644 --- a/mne_bids/jsonschemas/schema_meg.py +++ b/mne_bids/jsonschemas/schema_meg.json @@ -1,13 +1,4 @@ -from jsonschema import validate -import numpy as np - -empty = { "type": "string", "maxLength": 0} - -NaN = np.nan; -# booleans have problems with capitals (e.g. True versus true), this is a string for now. - -# A sample MEG schema, like what we'd get from json.load() -schema = { +{ "type": "object", "properties": { "TaskName": {"type": "string","minLength": 1}, @@ -43,7 +34,7 @@ "MaxMovement": {"type" : "number"}, "SubjectArtefactDescription": {"type" : "string"}, "DigitizedLandmarks": {"type" : "string"}, - "DigitizedHeadPoints": {"type" : "string"}, + "DigitizedHeadPoints": {"type" : "string"} }, "required": [ "TaskName", "Manufacturer", @@ -56,33 +47,4 @@ "EMGChannelCount", "MiscChannelCount", "TriggerChannelCount"] - } - - -test = { - "TaskName": "audiovisual", - "SamplingFrequency": 500, - "Manufacturer": "test", - "ManufacturerModelName": "test", - "TaskDescription": "In this experiment...", - "MEGChannelCount": 306, - "MEGREFChannelCount": 0, - "EEGChannelCount": 60, - "EOGChannelCount": 1, - "ECGChannelCount": 0, - "EMGChannelCount": 0, - "MiscChannelCount": 0, - "TriggerChannelCount": 9, - "PowerLineFrequency": NaN, - "EEGReference": "nose", - "MEGPosition": "upright", - "OnlineFilters": "0.10000000149 Hz high-pass, 172.176300049 Hz low-pass", - "RecordingType": "continuous", - "EyesClosed": "false", - "ContinuousHeadLocalization": "false", - "DigitizedLandmarks": "true", - "DigitizedHeadPoints": "true", - "SubjectArtefactDescription": "", } - -validate(test, schema) diff --git a/mne_bids/validator.py b/mne_bids/validator.py new file mode 100644 index 000000000..819c04df1 --- /dev/null +++ b/mne_bids/validator.py @@ -0,0 +1,18 @@ +import os.path as op +import inspect + +import json +from jsonschema import validate + +FILE = inspect.getfile(inspect.currentframe()) +base_dir = op.join(op.dirname(op.abspath(FILE)), 'jsonschemas') + + +def validate_meg(fname): + with open(op.join(base_dir, 'schema_meg.json')) as json_data: + schema = json.load(json_data) + + with open(fname) as json_data: + meg_json = json.load(json_data) + + validate(meg_json, schema) From 72a91241b5ef0c6783a312ba1411f361919178f5 Mon Sep 17 00:00:00 2001 From: Mainak Jas Date: Wed, 30 Aug 2017 22:04:44 +0530 Subject: [PATCH 4/7] Remove file --- mne_bids/validator.py | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 mne_bids/validator.py diff --git a/mne_bids/validator.py b/mne_bids/validator.py deleted file mode 100644 index 819c04df1..000000000 --- a/mne_bids/validator.py +++ /dev/null @@ -1,18 +0,0 @@ -import os.path as op -import inspect - -import json -from jsonschema import validate - -FILE = inspect.getfile(inspect.currentframe()) -base_dir = op.join(op.dirname(op.abspath(FILE)), 'jsonschemas') - - -def validate_meg(fname): - with open(op.join(base_dir, 'schema_meg.json')) as json_data: - schema = json.load(json_data) - - with open(fname) as json_data: - meg_json = json.load(json_data) - - validate(meg_json, schema) From 46c95c59e710bf7016bbe1bf375d174753a87e07 Mon Sep 17 00:00:00 2001 From: Mainak Jas Date: Wed, 30 Aug 2017 22:38:16 +0530 Subject: [PATCH 5/7] Revert "Remove file" This reverts commit 72a91241b5ef0c6783a312ba1411f361919178f5. --- mne_bids/validator.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 mne_bids/validator.py diff --git a/mne_bids/validator.py b/mne_bids/validator.py new file mode 100644 index 000000000..819c04df1 --- /dev/null +++ b/mne_bids/validator.py @@ -0,0 +1,18 @@ +import os.path as op +import inspect + +import json +from jsonschema import validate + +FILE = inspect.getfile(inspect.currentframe()) +base_dir = op.join(op.dirname(op.abspath(FILE)), 'jsonschemas') + + +def validate_meg(fname): + with open(op.join(base_dir, 'schema_meg.json')) as json_data: + schema = json.load(json_data) + + with open(fname) as json_data: + meg_json = json.load(json_data) + + validate(meg_json, schema) From 0eb3c30ce4bd744457d2bd71385cf4118b501b24 Mon Sep 17 00:00:00 2001 From: Dora Date: Wed, 30 Aug 2017 11:31:09 -0700 Subject: [PATCH 6/7] added json schema for the MEG-BIDS _fid.json file --- examples/plot_validator.py | 8 +++-- examples/sub-testme01_meg_fid.json | 24 ++++++++++++++ mne_bids/jsonschemas/schema_meg.json | 2 +- mne_bids/jsonschemas/schema_meg_fid.json | 41 ++++++++++++++++++++++++ mne_bids/validator.py | 15 +++++++-- 5 files changed, 84 insertions(+), 6 deletions(-) create mode 100644 examples/sub-testme01_meg_fid.json create mode 100644 mne_bids/jsonschemas/schema_meg_fid.json diff --git a/examples/plot_validator.py b/examples/plot_validator.py index 7e1c4cd85..403dd19df 100644 --- a/examples/plot_validator.py +++ b/examples/plot_validator.py @@ -1,9 +1,13 @@ import os.path as op from mne_bids.validator import validate_meg -from mne.datasets import sample -data_path = sample.data_path() +# test an _meg.json file: json_fname = op.join('.', 'sub-01_task-audiovisual_meg.json') validate_meg(json_fname) + +# test an _fid.json file: +json_fname = op.join('.', 'sub-testme01_meg_fid.json') + +validate_meg(json_fname) diff --git a/examples/sub-testme01_meg_fid.json b/examples/sub-testme01_meg_fid.json new file mode 100644 index 000000000..9b0efb089 --- /dev/null +++ b/examples/sub-testme01_meg_fid.json @@ -0,0 +1,24 @@ +{ + "MEGCoordinateSystem": "not_empty", + "MEGCoordinateUnits": "not_empty", + "MEGCoordinateSystemDescription": "", + "EEGCoordinateSystem": "not_empty", + "EEGCoordinateUnits": "not_empty", + "EEGCoordinateSystemDescription": "", + "IntendedFor": "not_empty", + "AnatomicalMRICoordinateSystem": "not_empty", + "AnatomicalMRICoordinateUnits": "not_empty", + "AnatomicalMRICoordinateSystemDescription": "", + "CoilCoordinates": "not_empty", + "CoilCoordinateSystem": "not_empty", + "CoilCoordinateUnits": "not_empty", + "CoilCoordinateSystemDescription": "", + "LandmarkCoordinates": "not_empty", + "LandmarkCoordinateSystem": "not_empty", + "LandmarkCoordinateUnits": "not_empty", + "LandmarkCoordinateSystemDescription": "", + "DigitizedHeadPoints": "", + "DigitizedHeadPointsCoordinateSystem": "", + "DigitizedHeadPointsCoordinateUnits": "", + "DigitizedHeadPointsCoordinateSystemDescription": "" +} diff --git a/mne_bids/jsonschemas/schema_meg.json b/mne_bids/jsonschemas/schema_meg.json index 5a11ac89f..7b502b40a 100644 --- a/mne_bids/jsonschemas/schema_meg.json +++ b/mne_bids/jsonschemas/schema_meg.json @@ -27,7 +27,7 @@ "SoftwareFilters": {"type" : "string"}, "RecordingDuration": {"type" : "number"}, "RecordingType": {"type" : "string"}, - "EpochLength": {"type" : "number"}, + "EpochLength": {"type" : ["number","string"]}, "DeviceSoftwareVersion": {"type" : "string"}, "ContinuousHeadLocalization": {"type" : "string"}, "CoilFrequency": {"type" : "number"}, diff --git a/mne_bids/jsonschemas/schema_meg_fid.json b/mne_bids/jsonschemas/schema_meg_fid.json new file mode 100644 index 000000000..3f646addf --- /dev/null +++ b/mne_bids/jsonschemas/schema_meg_fid.json @@ -0,0 +1,41 @@ +{ + "type": "object", + "properties": { + "MEGCoordinateSystem": {"type": "string","minLength": 1}, + "MEGCoordinateUnits": {"type": "string","minLength": 1}, + "MEGCoordinateSystemDescription": {"type": "string"}, + "EEGCoordinateSystem": {"type": "string","minLength": 1}, + "EEGCoordinateUnits": {"type": "string","minLength": 1}, + "EEGCoordinateSystemDescription": {"type": "string"}, + "IntendedFor": {"type": "string","minLength": 1}, + "AnatomicalMRICoordinateSystem": {"type": "string","minLength": 1}, + "AnatomicalMRICoordinateUnits": {"type": "string","minLength": 1}, + "AnatomicalMRICoordinateSystemDescription": {"type": "string"}, + "CoilCoordinates": {"type": "string","minLength": 1}, + "CoilCoordinateSystem": {"type": "string","minLength": 1}, + "CoilCoordinateUnits": {"type": "string","minLength": 1}, + "CoilCoordinateSystemDescription": {"type": "string"}, + "LandmarkCoordinates": {"type": "string","minLength": 1}, + "LandmarkCoordinateSystem": {"type": "string","minLength": 1}, + "LandmarkCoordinateUnits": {"type": "string","minLength": 1}, + "LandmarkCoordinateSystemDescription": {"type": "string"}, + "DigitizedHeadPoints": {"type": "string"}, + "DigitizedHeadPointsCoordinateSystem": {"type": "string"}, + "DigitizedHeadPointsCoordinateUnits": {"type": "string"}, + "DigitizedHeadPointsCoordinateSystemDescription": {"type": "string"} + }, + "required": ["MEGCoordinateSystem", + "MEGCoordinateUnits", + "EEGCoordinateSystem", + "EEGCoordinateUnits", + "IntendedFor", + "AnatomicalMRICoordinateSystem", + "AnatomicalMRICoordinateUnits", + "CoilCoordinates", + "CoilCoordinateSystem", + "CoilCoordinateUnits", + "LandmarkCoordinates", + "LandmarkCoordinateSystem", + "LandmarkCoordinateUnits" + ] +} diff --git a/mne_bids/validator.py b/mne_bids/validator.py index 819c04df1..72ba051ce 100644 --- a/mne_bids/validator.py +++ b/mne_bids/validator.py @@ -9,10 +9,19 @@ def validate_meg(fname): - with open(op.join(base_dir, 'schema_meg.json')) as json_data: + # get the correct schema + if fname.endswith('_meg.json'): + schema_fname = 'schema_meg.json' + elif fname.endswith('_fid.json'): + schema_fname = 'schema_meg_fid.json' + + # open the schema + with open(op.join(base_dir, schema_fname)) as json_data: schema = json.load(json_data) + # open the BIDS json file to validate with open(fname) as json_data: - meg_json = json.load(json_data) + test_json = json.load(json_data) - validate(meg_json, schema) + # validate it + validate(test_json, schema) From dc0483654fab6cfc3ff723f3a29d7fa061e2af3a Mon Sep 17 00:00:00 2001 From: Dora Date: Wed, 30 Aug 2017 16:00:55 -0700 Subject: [PATCH 7/7] fixed a bug in schema_meg.json --- mne_bids/jsonschemas/schema_meg.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mne_bids/jsonschemas/schema_meg.json b/mne_bids/jsonschemas/schema_meg.json index 7b502b40a..d45f2e88a 100644 --- a/mne_bids/jsonschemas/schema_meg.json +++ b/mne_bids/jsonschemas/schema_meg.json @@ -6,7 +6,7 @@ "ManufacturerModelName": {"type": "string"}, "TaskDescription": {"type": "string"}, "Instructions": {"type": "string"}, - "PowerLineFrequency": {"type": "number"}, + "SamplingFrequency": {"type": "number"}, "CogAtlasID": {"type": "string"}, "CogPOID": {"type": "string"}, "InstitutionName": {"type": "string"},