diff --git a/BIDS2JSONLD.ipynb b/BIDS2JSONLD.ipynb new file mode 100644 index 0000000..e8f0a99 --- /dev/null +++ b/BIDS2JSONLD.ipynb @@ -0,0 +1,209 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# BIDS dataset to a JSON-LD BIDS dataset" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This document illustrates an example showing how to go from a bids dataset to a JSON-LD BIDS dataset. More specifically, one wants to : \n", + "- add gently context into existing json files : T1w.json, taskxxx.json\n", + "- create an other JSON file with attached JSON-LD context to store metadata only present in the BIDS directory (bids_context.json findable at that location: https://github.com/incf-nidash/bids-ld/pull/1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1st step : we review existing JSON files with the metadata types in BIDS and compare them to the NIDM-Experiment data. \n", + "--> we list the bids attributes, the path to bids terms, the nidm attributes and their links to nidm objects. \n", + "\n", + "2st step : we create a context file only for bids terms labelled 'bids_context.json'.\n", + "--> At this time there is still no URIs for BIDS, so one must create one with the following prefix: \n", + " \"bids\": \"https://bids.neuroimaging.io#\"\n", + " Then to describe bids attributes : \n", + " \"Name\" : \"https://bids.neuroimaging.io#Name\"\n", + " \n", + "3rd step : we add this gently context into existing json files. " + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\r\n", + " \"@context\": {\r\n", + " \"@version\": 1.1,\r\n", + " \"records\": {\r\n", + " \"@id\": \"@graph\",\r\n", + " \"@container\": \"@type\"\r\n", + " },\r\n", + " \"bids\": \"https://bids.neuroimaging.io#\",\r\n", + " \"BIDSVersion\": \"https://bids.neuroimaging.io#BIDSVersion\",\r\n", + " \"Name\": \"https://bids.neuroimaging.io#Name\",\r\n", + " \"Acquisition Matrix\": \"https://bids.neuroimaging.io#AcquisitionMatrix\",\r\n", + " \"Coil Combination Method\": \"https://bids.neuroimaging.io#CoilCombinationMethod\",\r\n", + " \"Echo Time\": \"https://bids.neuroimaging.io#EchoTime\",\r\n", + " \"Field of View Dimensions\": \"https://bids.neuroimaging.io#FieldOfViewDimensions\", \r\n", + " \"Field of View Shape\": \"https://bids.neuroimaging.io#FieldOfViewShape\",\r\n", + " \"Flip Angle\": \"https://bids.neuroimaging.io#FlipAngle\",\r\n", + " \"Gradient Set Type\": \"https://bids.neuroimaging.io#GradientSetType\",\r\n", + " \"Inversion Time\": \"https://bids.neuroimaging.io#InversionTime\",\r\n", + " \"MatrixCoilMode\": \"https://bids.neuroimaging.io#MatrixCoilMode\",\r\n", + " \"Negative Contrast\": \"https://bids.neuroimaging.io#NegativeContrast\", \r\n", + " \"Number Of Slices\": \"https://bids.neuroimaging.io#NumberOfSlices\", \r\n", + " \"Number Shots\": \"https://bids.neuroimaging.io#NumberShots\",\r\n", + " \"Parallel Acquisition\": \"https://bids.neuroimaging.io#ParallelAcquisition\",\r\n", + " \"Parallel Acquisition Technique\": \"https://bids.neuroimaging.io#ParallelAcquisitionTechnique\",\r\n", + " \"Parallel Reduction Factor In-plane\": \"https://bids.neuroimaging.io#ParallelReductionFactorIn-plane\",\r\n", + " \"Phase Encoding Direction\": \"https://bids.neuroimaging.io#PhaseEncodingDirection\",\r\n", + " \"Pixel Bandwidth\": \"https://bids.neuroimaging.io#PixelBandwidth\",\r\n", + " \"Plane Orientation Sequence\": \"https://bids.neuroimaging.io#PlaneOrientationSequence\",\r\n", + " \"Receive Coil Type\": \"https://bids.neuroimaging.io#ReceiveCoilType\",\r\n", + " \"Receive Coil Name\": \"https://bids.neuroimaging.io#ReceiveCoilName\",\r\n", + " \"Scan Options\": \"https://bids.neuroimaging.io#ScanOptions\",\r\n", + " \"Scanning Sequence\": \"https://bids.neuroimaging.io#ScanningSequence\",\r\n", + " \"Sequence Name\": \"https://bids.neuroimaging.io#SequenceName\",\r\n", + " \"Sequence Variant\": \"https://bids.neuroimaging.io#SequenceVariant\",\r\n", + " \"Slice Acquisition Order\": \"https://bids.neuroimaging.io#SliceAcquisitionOrder\",\r\n", + " \"Slice Encoding Direction\": \"https://bids.neuroimaging.io#SliceEncodingDirection\",\r\n", + " \"Slice Thickness\": \"https://bids.neuroimaging.io#SliceThickness\",\r\n", + " \"Slice Timing\": \"https://bids.neuroimaging.io#SliceTiming\",\r\n", + " \"Spacing Between Slices\": \"https://bids.neuroimaging.io#SpacingBetweenSlices\",\r\n", + " \"Total Readout Time\": \"https://bids.neuroimaging.io#TotalReadoutTime\",\r\n", + " \"Manufacturer\": \"https://bids.neuroimaging.io#Manufacturer\",\r\n", + " \"Manufacturers Model Name\": \"https://bids.neuroimaging.io#ManufacturersModelName\",\r\n", + " \"Magnetic Field Strength\": \"https://bids.neuroimaging.io#MagneticFieldStrength\",\r\n", + " \"Device Serial Number\": \"https://bids.neuroimaging.io#DeviceSerialNumber\",\r\n", + " \"Software Versions\": \"https://bids.neuroimaging.io#SoftwareVersions\",\r\n", + " \"MR Transmit Coil Sequence\": \"https://bids.neuroimaging.io#MRTransmitCoilSequence\",\r\n", + " \"Partial Fourier\": \"https://bids.neuroimaging.io#PartialFourier\",\r\n", + " \"Partial Fourier Direction\": \"https://bids.neuroimaging.io#PartialFourierDirection\",\r\n", + " \"Effective Echo Spacing\": \"https://bids.neuroimaging.io#EffectiveEchoSpacing\",\r\n", + " \"Receive Coil Active Elements\": \"https://bids.neuroimaging.io#ReceiveCoilActiveElements\",\r\n", + " \"Non Linear Gradient Correction\": \"https://bids.neuroimaging.io#NonLinearGradientCorrection\",\r\n", + " \"Dwell Time\": \"https://bids.neuroimaging.io#DwellTime\",\r\n", + " \"Multiband Acceleration Factor\": \"https://bids.neuroimaging.io#MultibandAccelerationFactor\",\r\n", + " \"Anatomical Landmark Coordinates\": \"https://bids.neuroimaging.io#AnatomicalLandmarkCoordinates\",\r\n", + " \"Institution Name\": \"https://bids.neuroimaging.io#InstitutionName\",\r\n", + " \"Institution Address\": \"https://bids.neuroimaging.io#Institution Address\",\r\n", + " \"Institutional Department Name\": \"https://bids.neuroimaging.io#InstitutionalDepartmentName\",\r\n", + " \"Author\": \"https://bids.neuroimaging.io#Author\",\r\n", + " \"License\": \"https://bids.neuroimaging.io#License\",\r\n", + " \"Description\": \"https://bids.neuroimaging.io#Description\",\r\n", + " \"Age\": \"https://bids.neuroimaging.io#Age\",\r\n", + " \"Ethnicity\": \"https://bids.neuroimaging.io#Ethnicity\",\r\n", + " \"Family Name\": \"https://bids.neuroimaging.io#FamilyName\",\r\n", + " \"Handedness\": \"https://bids.neuroimaging.io#Handedness\",\r\n", + " \"Sex\": \"https://bids.neuroimaging.io#Sex\",\r\n", + " \"Race\": \"https://bids.neuroimaging.io#Race\",\r\n", + " \"Participant Id\": \"https://bids.neuroimaging.io#ParticipantId\",\r\n", + " \"Sampling Frequency\": \"https://bids.neuroimaging.io#SamplingFrequency\",\r\n", + " \"Trigger\": \"https://bids.neuroimaging.io#Trigger\",\r\n", + " \"Angiography\": \"https://bids.neuroimaging.io#Angiography\",\r\n", + " \"Combined Proton Density/T2\": \"https://bids.neuroimaging.io#CombinedProtonDensityT2\",\r\n", + " \"FLAIR\": \"https://bids.neuroimaging.io#FLAIR\",\r\n", + " \"FLASH\": \"https://bids.neuroimaging.io#FLASH\",\r\n", + " \"Proton Density Map\": \"https://bids.neuroimaging.io#ProtonDensityMap\",\r\n", + " \"T1 Map\": \"https://bids.neuroimaging.io#T1Map\",\r\n", + " \"T1 Rho Map\": \"https://bids.neuroimaging.io#T1RhoMap\",\r\n", + " \"T2 Map\": \"https://bids.neuroimaging.io#T2Map\",\r\n", + " \"Inplane T1\": \"https://bids.neuroimaging.io#InplaneT1\",\r\n", + " \"Inplane T2\": \"https://bids.neuroimaging.io#InplaneT2\",\r\n", + " \"Duration\": \"https://bids.neuroimaging.io#Duration\",\r\n", + " \"Onset\": \"https://bids.neuroimaging.io#Onset\",\r\n", + " \"Sample\": \"https://bids.neuroimaging.io#Sample\",\r\n", + " \"Response Time\": \"https://bids.neuroimaging.io#ResponseTime\",\r\n", + " \"Value\": \"https://bids.neuroimaging.io#Value\",\r\n", + " \"Trial Type\": \"https://bids.neuroimaging.io#TrialType\",\r\n", + " \"Acquisition Duration\": \"https://bids.neuroimaging.io#AcquisitionDuration\",\r\n", + " \"BOLD\": \"https://bids.neuroimaging.io#BOLD\",\r\n", + " \"Delay After Trigger\": \"https://bids.neuroimaging.io#DelayAfterTrigger\",\r\n", + " \"Delay Time\": \"https://bids.neuroimaging.io#DelayTime\",\r\n", + " \"Instructions\": \"https://bids.neuroimaging.io#Instructions\",\r\n", + " \"Number Of Volumes Discarded By Scanner\": \"https://bids.neuroimaging.io#NumberOfVolumesDiscardedByScanner\",\r\n", + " \"Number Of Volumes Discarded By User\": \"https://bids.neuroimaging.io#NumberOfVolumesDiscardedByUser\",\r\n", + " \"Phase\": \"https://bids.neuroimaging.io#Phase\",\r\n", + " \"Repetition Time\": \"https://bids.neuroimaging.io#RepetitionTime\",\r\n", + " \"Task Description\": \"https://bids.neuroimaging.io#TaskDescription\",\r\n", + " \"Task Name\": \"https://bids.neuroimaging.io#TaskName\",\r\n", + " \"Volume Timing\": \"https://bids.neuroimaging.io#VolumeTiming\",\r\n", + " \"CBV\": \"https://bids.neuroimaging.io#CBV\",\r\n", + " \"Cog Atlas ID\": \"https://bids.neuroimaging.io#CogAtlasID\",\r\n", + " \"CogPO ID\": \"https://bids.neuroimaging.io#CogPOID\",\r\n", + " \"b-value\": \"https://bids.neuroimaging.io#b-ValueFile\",\r\n", + " \"b-vector\": \"https://bids.neuroimaging.io#b-VectorFile\", \r\n", + " \"Cardiac\": \"https://bids.neuroimaging.io#HeartRateMonitor\",\r\n", + " \"Diffusion Tensor\": \"https://bids.neuroimaging.io#DiffusionTensor\",\r\n", + " \"Diffusion Weighted\": \"https://bids.neuroimaging.io#DiffusionWeighted\",\r\n", + " \"Gender\": \"https://bids.neuroimaging.io#Gender\",\r\n", + " \"Proton Density\": \"https://bids.neuroimaging.io#ProtonDensityWeighted\", \r\n", + " \"Respiratory\": \"https://bids.neuroimaging.io#RespirationRateMonitor\",\r\n", + " \"Session\": \"https://bids.neuroimaging.io#Session\",\r\n", + " \"Stimulus Response File\": \"https://bids.neuroimaging.io#StimulusResponseFile\",\r\n", + " \"T1 Weighted\": \"https://bids.neuroimaging.io#T1Weighted\",\r\n", + " \"T2-Star Weighted\": \"https://bids.neuroimaging.io#T2StarWeighted\",\r\n", + " \"T2 Weighted\": \"https://bids.neuroimaging.io#T2Weighted\",\r\n", + " \"Pulse Sequence Details\": \"https://bids.neuroimaging.io#PulseSequence\",\r\n", + " \"Pulse Sequence Type\": \"https://bids.neuroimaging.io#PulseType\",\r\n", + " \"Title\": \"https://bids.neuroimaging.io#title\",\r\n", + " \"Group\": \"https://bids.neuroimaging.io#Group\",\r\n", + " } \r\n", + "}\r\n", + "\r\n" + ] + } + ], + "source": [ + "cat bids_context.json\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "At that point, some bids terms present in the bids specification also appear in the nidm-experiment ontology such as: \"b-value\", \"b-vector\", \"T1 Weighted\" or \"Gender\" etc. We decided to not consider the existing prefixes, to avoid ambiguity. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "WIP: to adapt the code in BIDSMRI2NIDM.py to add properly the information from the json files. " + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.1" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/BIDS2NIDME.ipynb b/BIDS2NIDME.ipynb new file mode 100644 index 0000000..c89623c --- /dev/null +++ b/BIDS2NIDME.ipynb @@ -0,0 +1,360 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# BIDS dataset to a JSON-LD NIDM-Experiment dataset" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "(work under conda environment)\n", + "This document illustrates an example showing how to go from a BIDS dataset to a JSON-LD NIDM-experiment dataset.\n", + "We pick our bids dataset from DataLad where the hierarchy of folders follows the bids standard. For this example, we import the ABIDE DataLad dataset from CMU_a site : http://datasets.datalad.org/?dir=/abide/RawDataBIDS/CMU_a " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "conda install -c conda-forge git-annex\n", + "pip install datalad \n", + "datalad install ///abide/RawDataBIDS/CMU_a" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We use the BIDSMRI2NIDM.py file from PyNIDM/nidm/experiment/tools.\n", + "This program will convert a BIDS MRI dataset to a NIDM-Experiment RDF document. It will parse phenotype information and simply store variables/values and link to the associated json data dictionary file.\n", + "Argument used: \n", + "- -d [root directory of BIDS dataset]\n", + "- -jsonld [If flag set, output is json-ld not TURTLE]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "python ~/PyNIDM/nidm/experiment/tools/BIDSMRI2NIDM.py -d ~/bids_dataset/CMU_a/" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The Datalad hosted abide dataset doesn’t have participants.tsv files and doesn’t have a dataset_description.json file so it is really not even valid BIDS. The participants.tsv file is optional but we must have a datasaet_description.json file. \n", + "One has to create some basic dataset_description.json files for each abide and adhd200 site so one could run bidsmri2nidm on it and add it in the github repo.\n", + "For instance see https://bids-specification.readthedocs.io/en/stable/03-modality-agnostic-files.html to put the required fields in the dataset_description.json file. \n", + "Below our dataset_description.json file:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "{\n", + "\t\"Name\": \"ABIDE dataset CMU_a Site\",\n", + "\t\"BIDSVersion\": \"1.0.1\",\n", + "\t\"License\": \"CC BY-SA 4.0\"\n", + "\t\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "One must also parse other json files available at the root of the bids directory: T1w.json and taskxxx.json files. \n", + "if key from T1w.json file or taskxxx.json file is mapped to term in BIDS_Constants.py then add to NIDM object. \n", + "See function bidsmri2project(directory, args):\n", + "- for dataset_description.json file " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def bidsmri2project(directory, args):\n", + " #Parse dataset_description.json file in BIDS directory\n", + " if (os.path.isdir(os.path.join(directory))):\n", + " try:\n", + " with open(os.path.join(directory,'dataset_description.json')) as data_file:\n", + " dataset = json.load(data_file)\n", + " except OSError:\n", + " logging.critical(\"Cannot find dataset_description.json file which is required in the BIDS spec\")\n", + " exit(\"-1\")\n", + " else:\n", + " logging.critical(\"Error: BIDS directory %s does not exist!\" %os.path.join(directory))\n", + " exit(\"-1\")\n", + "\n", + " #create project / nidm-exp doc\n", + " project = Project()\n", + "\n", + " #add various attributes if they exist in BIDS dataset\n", + " for key in dataset:\n", + " #if key from dataset_description file is mapped to term in BIDS_Constants.py then add to NIDM object\n", + " if key in BIDS_Constants.dataset_description:\n", + " if type(dataset[key]) is list:\n", + " project.add_attributes({BIDS_Constants.dataset_description[key]:\"\".join(dataset[key])})\n", + " else:\n", + " project.add_attributes({BIDS_Constants.dataset_description[key]:dataset[key]})\n", + " #add absolute location of BIDS directory on disk for later finding of files which are stored relatively in NIDM document\n", + " project.add_attributes({Constants.PROV['Location']:directory})\n", + "\n", + " #get BIDS layout\n", + " bids_layout = BIDSLayout(directory) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- For T1w.json file " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + " if file_tpl.entities['datatype']=='anat':\n", + " #do something with anatomicals\n", + " acq_obj = MRObject(acq)\n", + " #add image contrast type\n", + " if file_tpl.entities['suffix'] in BIDS_Constants.scans:\n", + " acq_obj.add_attributes({Constants.NIDM_IMAGE_CONTRAST_TYPE:BIDS_Constants.scans[file_tpl.entities['suffix']]})\n", + " else:\n", + " logging.info(\"WARNING: No matching image contrast type found in BIDS_Constants.py for %s\" % file_tpl.entities['suffix'])\n", + "\n", + " #add image usage type\n", + " if file_tpl.entities['datatype'] in BIDS_Constants.scans:\n", + " acq_obj.add_attributes({Constants.NIDM_IMAGE_USAGE_TYPE:BIDS_Constants.scans[file_tpl.entities['datatype']]})\n", + " else:\n", + " logging.info(\"WARNING: No matching image usage type found in BIDS_Constants.py for %s\" % file_tpl.entities['datatype'])\n", + " #add file link\n", + " #make relative link to\n", + " acq_obj.add_attributes({Constants.NIDM_FILENAME:getRelPathToBIDS(join(file_tpl.dirname,file_tpl.filename), directory)})\n", + "\n", + " #add sha512 sum\n", + " if isfile(join(directory,file_tpl.dirname,file_tpl.filename)):\n", + " acq_obj.add_attributes({Constants.CRYPTO_SHA512:getsha512(join(directory,file_tpl.dirname,file_tpl.filename))})\n", + " else:\n", + " logging.info(\"WARNINGL file %s doesn't exist! No SHA512 sum stored in NIDM files...\" %join(directory,file_tpl.dirname,file_tpl.filename))\n", + " #get associated JSON file if exists\n", + " #There is T1w.json file with information \n", + " json_data = (bids_layout.get(suffix=file_tpl.entities['suffix'],subject=subject_id))[0].metadata\n", + " if len(json_data.info)>0:\n", + " for key in json_data.info.items():\n", + " if key in BIDS_Constants.json_keys:\n", + " if type(json_data.info[key]) is list:\n", + " acq_obj.add_attributes({BIDS_Constants.json_keys[key.replace(\" \", \"_\")]:''.join(str(e) for e in json_data.info[key])})\n", + " else:\n", + " acq_obj.add_attributes({BIDS_Constants.json_keys[key.replace(\" \", \"_\")]:json_data.info[key]})\n", + " \n", + " #Parse T1w.json file in BIDS directory to add the attributes contained inside\n", + " if (os.path.isdir(os.path.join(directory))):\n", + " try:\n", + " with open(os.path.join(directory,'T1w.json')) as data_file:\n", + " dataset = json.load(data_file)\n", + " except OSError:\n", + " logging.critical(\"Cannot find T1w.json file which is required in the BIDS spec\")\n", + " exit(\"-1\")\n", + " else:\n", + " logging.critical(\"Error: BIDS directory %s does not exist!\" %os.path.join(directory))\n", + " exit(\"-1\")\n", + "\n", + " #add various attributes if they exist in BIDS dataset\n", + " for key in dataset:\n", + " #if key from T1w.json file is mapped to term in BIDS_Constants.py then add to NIDM object\n", + " if key in BIDS_Constants.json_keys:\n", + " if type(dataset[key]) is list:\n", + " acq_obj.add_attributes({BIDS_Constants.json_keys[key]:\"\".join(dataset[key])})\n", + " else:\n", + " acq_obj.add_attributes({BIDS_Constants.json_keys[key]:dataset[key]}) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- for taskxxx.json file " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + " \n", + " elif file_tpl.entities['datatype'] == 'func':\n", + " #do something with functionals\n", + " acq_obj = MRObject(acq)\n", + " #add image contrast type\n", + " if file_tpl.entities['suffix'] in BIDS_Constants.scans:\n", + " acq_obj.add_attributes({Constants.NIDM_IMAGE_CONTRAST_TYPE:BIDS_Constants.scans[file_tpl.entities['suffix']]})\n", + " else:\n", + " logging.info(\"WARNING: No matching image contrast type found in BIDS_Constants.py for %s\" % file_tpl.entities['suffix'])\n", + "\n", + " #add image usage type\n", + " if file_tpl.entities['datatype'] in BIDS_Constants.scans:\n", + " acq_obj.add_attributes({Constants.NIDM_IMAGE_USAGE_TYPE:BIDS_Constants.scans[file_tpl.entities['datatype']]})\n", + " else:\n", + " logging.info(\"WARNING: No matching image usage type found in BIDS_Constants.py for %s\" % file_tpl.entities['datatype'])\n", + " #make relative link to\n", + " acq_obj.add_attributes({Constants.NIDM_FILENAME:getRelPathToBIDS(join(file_tpl.dirname,file_tpl.filename), directory)})\n", + " #add sha512 sum\n", + " if isfile(join(directory,file_tpl.dirname,file_tpl.filename)):\n", + " acq_obj.add_attributes({Constants.CRYPTO_SHA512:getsha512(join(directory,file_tpl.dirname,file_tpl.filename))})\n", + " else:\n", + " logging.info(\"WARNINGL file %s doesn't exist! No SHA512 sum stored in NIDM files...\" %join(directory,file_tpl.dirname,file_tpl.filename))\n", + "\n", + " if 'run' in file_tpl.entities:\n", + " acq_obj.add_attributes({BIDS_Constants.json_keys[\"run\"]:file_tpl.entities['run']})\n", + "\n", + " #get associated JSON file if exists\n", + " json_data = (bids_layout.get(suffix=file_tpl.entities['suffix'],subject=subject_id))[0].metadata\n", + "\n", + " if len(json_data.info)>0:\n", + " for key in json_data.info.items():\n", + " if key in BIDS_Constants.json_keys:\n", + " if type(json_data.info[key]) is list:\n", + " acq_obj.add_attributes({BIDS_Constants.json_keys[key.replace(\" \", \"_\")]:''.join(str(e) for e in json_data.info[key])})\n", + " else:\n", + " acq_obj.add_attributes({BIDS_Constants.json_keys[key.replace(\" \", \"_\")]:json_data.info[key]})\n", + " #get associated events TSV file\n", + " if 'run' in file_tpl.entities:\n", + " events_file = bids_layout.get(subject=subject_id, extensions=['.tsv'],modality=file_tpl.entities['datatype'],task=file_tpl.entities['task'],run=file_tpl.entities['run'])\n", + " else:\n", + " events_file = bids_layout.get(subject=subject_id, extensions=['.tsv'],modality=file_tpl.entities['datatype'],task=file_tpl.entities['task'])\n", + " #if there is an events file then this is task-based so create an acquisition object for the task file and link\n", + " if events_file:\n", + " #for now create acquisition object and link it to the associated scan\n", + " events_obj = AcquisitionObject(acq)\n", + " #add prov type, task name as prov:label, and link to filename of events file\n", + "\n", + " events_obj.add_attributes({PROV_TYPE:Constants.NIDM_MRI_BOLD_EVENTS,BIDS_Constants.json_keys[\"TaskName\"]: json_data[\"TaskName\"], Constants.NIDM_FILENAME:getRelPathToBIDS(events_file[0].filename, directory)})\n", + " #link it to appropriate MR acquisition entity\n", + " events_obj.wasAttributedTo(acq_obj)\n", + " \n", + " #Parse task-rest_bold.json file in BIDS directory to add the attributes contained inside\n", + " if (os.path.isdir(os.path.join(directory))):\n", + " try:\n", + " with open(os.path.join(directory,'task-rest_bold.json')) as data_file:\n", + " dataset = json.load(data_file)\n", + " except OSError:\n", + " logging.critical(\"Cannot find task-rest_bold.json file which is required in the BIDS spec\")\n", + " exit(\"-1\")\n", + " else:\n", + " logging.critical(\"Error: BIDS directory %s does not exist!\" %os.path.join(directory))\n", + " exit(\"-1\")\n", + "\n", + " #add various attributes if they exist in BIDS dataset\n", + " for key in dataset:\n", + " #if key from task-rest_bold.json file is mapped to term in BIDS_Constants.py then add to NIDM object\n", + " if key in BIDS_Constants.json_keys:\n", + " if type(dataset[key]) is list:\n", + " acq_obj.add_attributes({BIDS_Constants.json_keys[key]:\",\".join(map(str,dataset[key]))})\n", + " else:\n", + " acq_obj.add_attributes({BIDS_Constants.json_keys[key]:dataset[key]}) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The idea behind is to create acquisition objects for each scan for each subject using the information available in the bids directory. \n", + "Below, an extract of the nidme.json document created with the acquisition informations for one subject: " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + " {\n", + " \"@id\": \"nidm:8edfb514-b761-11e9-8f81-e1efbef5a165\",\n", + " \"@type\": [\n", + " \"Entity\",\n", + " \"AcquisitionObject\"\n", + " ],\n", + " \"crypto:sha512\": \"840affc90aeda40601a48f8d5cd3421fb73e0cbecc3111c4a3194aef74a716b732e7649b8b36d55f0b5559a88531ac10acd00bf27a95d52b59da78a88b7eeb8f\",\n", + " \"dicom:AcquisitionMatrix\": \"256x256\",\n", + " \"dicom:EchoTime\": 0.00248,\n", + " \"dicom:FlipAngle\": {\n", + " \"@type\": \"xsd:int\",\n", + " \"@value\": \"8\"\n", + " },\n", + " \"dicom:InversionTime\": 1.1,\n", + " \"dicom:MagneticFieldStrength\": {\n", + " \"@type\": \"xsd:int\",\n", + " \"@value\": \"3\"\n", + " },\n", + " \"dicom:PixelBandwidth\": 170.0,\n", + " \"dicom:RepetitionTime\": 1.87,\n", + " \"dicom:ScanningSequence\": \"MPRAGE\",\n", + " \"nidm:PhaseEncodingDirection\": \"j-\",\n", + " \"hadAcquisitionModality\": {\n", + " \"@id\": \"nidm:MagneticResonanceImaging\"\n", + " },\n", + " \"hadImageContrastType\": {\n", + " \"@id\": \"nidm:T1Weighted\"\n", + " },\n", + " \"HadImageUsageType\": {\n", + " \"@id\": \"nidm:Anatomical\"\n", + " },\n", + " \"filename\": \"/udd/nperez/sub-0050656/anat/sub-0050656_T1w.nii.gz\",\n", + " \"prov:wasGeneratedBy\": {\n", + " \"@id\": \"nidm:8edfacae-b761-11e9-8f81-e1efbef5a165\"\n", + " }\n", + " }," + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "However, some limitations appear: \n", + "- we only extract the data that map to BIDS_Constants.py and not all bids attributes are referenced in this document \n", + "- for bval and bvec files, what to do with those?" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.1" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..40095a5 --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +# Wrap-up BIDS and NIDM-E + +It is a great milestone to foster the complementary of both standards with the mapping from JSON attributes in BIDS to NIDM-experiment URLs. Indeed, NIDM adds to BIDS the capability to track provenance and disambiguate experimental details and data elements. + +This document will discuss how close/different those representations are, what could be done in future work to make them closer and what are the issues (if any) that seem much harder to solve. + +Currently, only a few numbers of attributes are commons between the two standards. + +According to the information provided in http://nidm.nidash.org/specs/nidm-experiment_dev.html and with analysis between BIDS and NIDM-Experiment we can assess that: + 1. The definition of attributes is more complete and relevant in NIDM. + 2. There is a substantial number of attributes related to acquisition method, data and image acquisition device, image usage type, image contrast type and k-space traversal scheme that do not appear in BIDS. + 3. BIDS provides more information on the patient (age, ethnicity, sex, race...). + +In the future, we could provide proper definitions to bids attributes as it was done for NIDM terms. Then, we must gather the information from both standards by adding the BIDS terms in an ontology file. Moreover, when two terms defined the same concept, we favour the bids term because nowadays the bids standard is more widely adopted by the neuroimaging community. + diff --git a/bids_context.json b/bids_context.json new file mode 100644 index 0000000..3de774b --- /dev/null +++ b/bids_context.json @@ -0,0 +1,120 @@ +{ + "@context": { + "@version": 1.1, + "records": { + "@id": "@graph", + "@container": "@type" + }, + "bids": "https://bids.neuroimaging.io#", + "BIDSVersion": "https://bids.neuroimaging.io#BIDSVersion", + "Name": "https://bids.neuroimaging.io#Name", + "Acquisition Matrix": "https://bids.neuroimaging.io#AcquisitionMatrix", + "Coil Combination Method": "https://bids.neuroimaging.io#CoilCombinationMethod", + "Echo Time": "https://bids.neuroimaging.io#EchoTime", + "Field of View Dimensions": "https://bids.neuroimaging.io#FieldOfViewDimensions", + "Field of View Shape": "https://bids.neuroimaging.io#FieldOfViewShape", + "Flip Angle": "https://bids.neuroimaging.io#FlipAngle", + "Gradient Set Type": "https://bids.neuroimaging.io#GradientSetType", + "Inversion Time": "https://bids.neuroimaging.io#InversionTime", + "MatrixCoilMode": "https://bids.neuroimaging.io#MatrixCoilMode", + "Negative Contrast": "https://bids.neuroimaging.io#NegativeContrast", + "Number Of Slices": "https://bids.neuroimaging.io#NumberOfSlices", + "Number Shots": "https://bids.neuroimaging.io#NumberShots", + "Parallel Acquisition": "https://bids.neuroimaging.io#ParallelAcquisition", + "Parallel Acquisition Technique": "https://bids.neuroimaging.io#ParallelAcquisitionTechnique", + "Parallel Reduction Factor In-plane": "https://bids.neuroimaging.io#ParallelReductionFactorIn-plane", + "Phase Encoding Direction": "https://bids.neuroimaging.io#PhaseEncodingDirection", + "Pixel Bandwidth": "https://bids.neuroimaging.io#PixelBandwidth", + "Plane Orientation Sequence": "https://bids.neuroimaging.io#PlaneOrientationSequence", + "Receive Coil Type": "https://bids.neuroimaging.io#ReceiveCoilType", + "Receive Coil Name": "https://bids.neuroimaging.io#ReceiveCoilName", + "Scan Options": "https://bids.neuroimaging.io#ScanOptions", + "Scanning Sequence": "https://bids.neuroimaging.io#ScanningSequence", + "Sequence Name": "https://bids.neuroimaging.io#SequenceName", + "Sequence Variant": "https://bids.neuroimaging.io#SequenceVariant", + "Slice Acquisition Order": "https://bids.neuroimaging.io#SliceAcquisitionOrder", + "Slice Encoding Direction": "https://bids.neuroimaging.io#SliceEncodingDirection", + "Slice Thickness": "https://bids.neuroimaging.io#SliceThickness", + "Slice Timing": "https://bids.neuroimaging.io#SliceTiming", + "Spacing Between Slices": "https://bids.neuroimaging.io#SpacingBetweenSlices", + "Total Readout Time": "https://bids.neuroimaging.io#TotalReadoutTime", + "Manufacturer": "https://bids.neuroimaging.io#Manufacturer", + "Manufacturers Model Name": "https://bids.neuroimaging.io#ManufacturersModelName", + "Magnetic Field Strength": "https://bids.neuroimaging.io#MagneticFieldStrength", + "Device Serial Number": "https://bids.neuroimaging.io#DeviceSerialNumber", + "Software Versions": "https://bids.neuroimaging.io#SoftwareVersions", + "MR Transmit Coil Sequence": "https://bids.neuroimaging.io#MRTransmitCoilSequence", + "Partial Fourier": "https://bids.neuroimaging.io#PartialFourier", + "Partial Fourier Direction": "https://bids.neuroimaging.io#PartialFourierDirection", + "Effective Echo Spacing": "https://bids.neuroimaging.io#EffectiveEchoSpacing", + "Receive Coil Active Elements": "https://bids.neuroimaging.io#ReceiveCoilActiveElements", + "Non Linear Gradient Correction": "https://bids.neuroimaging.io#NonLinearGradientCorrection", + "Dwell Time": "https://bids.neuroimaging.io#DwellTime", + "Multiband Acceleration Factor": "https://bids.neuroimaging.io#MultibandAccelerationFactor", + "Anatomical Landmark Coordinates": "https://bids.neuroimaging.io#AnatomicalLandmarkCoordinates", + "Institution Name": "https://bids.neuroimaging.io#InstitutionName", + "Institution Address": "https://bids.neuroimaging.io#Institution Address", + "Institutional Department Name": "https://bids.neuroimaging.io#InstitutionalDepartmentName", + "Author": "https://bids.neuroimaging.io#Author", + "License": "https://bids.neuroimaging.io#License", + "Description": "https://bids.neuroimaging.io#Description", + "Age": "https://bids.neuroimaging.io#Age", + "Ethnicity": "https://bids.neuroimaging.io#Ethnicity", + "Family Name": "https://bids.neuroimaging.io#FamilyName", + "Handedness": "https://bids.neuroimaging.io#Handedness", + "Sex": "https://bids.neuroimaging.io#Sex", + "Race": "https://bids.neuroimaging.io#Race", + "Participant Id": "https://bids.neuroimaging.io#ParticipantId", + "Sampling Frequency": "https://bids.neuroimaging.io#SamplingFrequency", + "Trigger": "https://bids.neuroimaging.io#Trigger", + "Angiography": "https://bids.neuroimaging.io#Angiography", + "Combined Proton Density/T2": "https://bids.neuroimaging.io#CombinedProtonDensityT2", + "FLAIR": "https://bids.neuroimaging.io#FLAIR", + "FLASH": "https://bids.neuroimaging.io#FLASH", + "Proton Density Map": "https://bids.neuroimaging.io#ProtonDensityMap", + "T1 Map": "https://bids.neuroimaging.io#T1Map", + "T1 Rho Map": "https://bids.neuroimaging.io#T1RhoMap", + "T2 Map": "https://bids.neuroimaging.io#T2Map", + "Inplane T1": "https://bids.neuroimaging.io#InplaneT1", + "Inplane T2": "https://bids.neuroimaging.io#InplaneT2", + "Duration": "https://bids.neuroimaging.io#Duration", + "Onset": "https://bids.neuroimaging.io#Onset", + "Sample": "https://bids.neuroimaging.io#Sample", + "Response Time": "https://bids.neuroimaging.io#ResponseTime", + "Value": "https://bids.neuroimaging.io#Value", + "Trial Type": "https://bids.neuroimaging.io#TrialType", + "Acquisition Duration": "https://bids.neuroimaging.io#AcquisitionDuration", + "BOLD": "https://bids.neuroimaging.io#BOLD", + "Delay After Trigger": "https://bids.neuroimaging.io#DelayAfterTrigger", + "Delay Time": "https://bids.neuroimaging.io#DelayTime", + "Instructions": "https://bids.neuroimaging.io#Instructions", + "Number Of Volumes Discarded By Scanner": "https://bids.neuroimaging.io#NumberOfVolumesDiscardedByScanner", + "Number Of Volumes Discarded By User": "https://bids.neuroimaging.io#NumberOfVolumesDiscardedByUser", + "Phase": "https://bids.neuroimaging.io#Phase", + "Repetition Time": "https://bids.neuroimaging.io#RepetitionTime", + "Task Description": "https://bids.neuroimaging.io#TaskDescription", + "Task Name": "https://bids.neuroimaging.io#TaskName", + "Volume Timing": "https://bids.neuroimaging.io#VolumeTiming", + "CBV": "https://bids.neuroimaging.io#CBV", + "Cog Atlas ID": "https://bids.neuroimaging.io#CogAtlasID", + "CogPO ID": "https://bids.neuroimaging.io#CogPOID", + "b-value": "https://bids.neuroimaging.io#b-ValueFile", + "b-vector": "https://bids.neuroimaging.io#b-VectorFile", + "Cardiac": "https://bids.neuroimaging.io#HeartRateMonitor", + "Diffusion Tensor": "https://bids.neuroimaging.io#DiffusionTensor", + "Diffusion Weighted": "https://bids.neuroimaging.io#DiffusionWeighted", + "Gender": "https://bids.neuroimaging.io#Gender", + "Proton Density": "https://bids.neuroimaging.io#ProtonDensityWeighted", + "Respiratory": "https://bids.neuroimaging.io#RespirationRateMonitor", + "Session": "https://bids.neuroimaging.io#Session", + "Stimulus Response File": "https://bids.neuroimaging.io#StimulusResponseFile", + "T1 Weighted": "https://bids.neuroimaging.io#T1Weighted", + "T2-Star Weighted": "https://bids.neuroimaging.io#T2StarWeighted", + "T2 Weighted": "https://bids.neuroimaging.io#T2Weighted", + "Pulse Sequence Details": "https://bids.neuroimaging.io#PulseSequence", + "Pulse Sequence Type": "https://bids.neuroimaging.io#PulseType", + "Title": "https://bids.neuroimaging.io#title", + "Group": "https://bids.neuroimaging.io#Group", + } +} +