<jupyter_start><jupyter_text>BrkRaw Python API to access PvDataset<jupyter_code>import sys
import numpy as np
np.set_printoptions(precision=3, suppress=True)
import brkraw
import pprint as pp
path = '20190724_114946_BRKRAW_1_1.zip'
pvdset = brkraw.load(path)<jupyter_output><empty_output><jupyter_text>High-level API Printing out summary of dataset<jupyter_code>pvdset.info()<jupyter_output>Paravision 6.0.1
----------------
UserAccount:	nmrsu
Date:		2019-07-24
Researcher:	BRKRAW
Subject ID:	BRKRAW
Session ID:	1
Study ID:	1
Date of Birth:	10 Jul 2019
Sex:		unknown
Weight:		0.202 kg
Subject Type:	Quadruped
Position:	Supine		Entry:	HeadFirst

[ScanID]	Sequence::Protocol::[Parameters]
[001]	Bruker:FLASH::0_Localizer_GOP::
	[ TR: 100 ms, TE: 2.5 ms, pixelBW: 292.96875 Hz, FlipAngle: 30 degree]
    [01] dim: 2D, matrix_size: 256 x 256 x 3, fov_size: 50 x 50 (unit:mm)
         spatial_resol: 0.195 x 0.195 x 1.000 (unit:mm), temporal_resol: 12800.000 (unit:msec)
[002]	Bruker:RARE::T2_TurboRARE_3D_20180423::
	[ TR: 1800 ms, TE: 34 ms, pixelBW: 685.30701754386 Hz, FlipAngle: 90 degree]
    [01] dim: 3D, matrix_size: 144 x 144 x 64, fov_size: 28.8 x 28.8 x 12.8 (unit:mm)
         spatial_resol: 0.200 x 0.200 x 0.200 (unit:mm), temporal_resol: 1134000.000 (unit:msec)
[003]	Bruker:EPI::2_BOLD_EPI_isotropic_wholebrain::
	[ TR: 2000 ms, TE: 14 ms, pixelBW: 3472.22222222222 Hz, FlipAngle[...]<jupyter_text>Check session start time<jupyter_code>pvdset.get_scan_time()<jupyter_output><empty_output><jupyter_text>Check scan start time<jupyter_code>visu_pars = pvdset.get_visu_pars(5, 1)
pvdset.get_scan_time(visu_pars)<jupyter_output><empty_output><jupyter_text>Specify scan id and reco id to access data object<jupyter_code>scan_id = 5
reco_id = 1<jupyter_output><empty_output><jupyter_text>Printing out BIDS specific meta data<jupyter_code>pvdset.print_bids(scan_id, reco_id)<jupyter_output>Manufacturer:				Bruker BioSpin MRI GmbH
ManufacturersModelName:			Biospec 94/30
DeviceSerialNumber:			BT001005
StationName:				Biospec 94/30
SoftwareVersion:			6.0.1
MagneticFieldStrength:			9.403088884004417
ReceiveCoilName:			None
ReceiveCoilActiveElements:		None
GradientSetType:			None
MRTransmitCoilSequence:			{'Name': None, 'Manufacture': None, 'Type': None}
CoilConfigName:				None
MatrixCoilMode:				ParallelExperiment
CoilCombinationMethod:			None
PulseSequenceType:			EPI.ppg
ScanningSequence:			Bruker:EPI
SequenceVariant:			Both
ScanOptions:				{'RG': 'No', 'CG': 'No', 'PFF': 1, 'PFP': 1.4, 'FC': 'FlowNone', 'SP': 'On', 'FP': 'NoSuppression'}
SequenceName:				2_BOLD_EPI_isotropic_wholebrain
PulseSequenceDetails:			2_BOLD_EPI_isotropic_wholebrain (E6)
NonlinearGradientCorrection:		RectilinearTraversal
NumberShots:				1
ParallelReductionFactorInPlane:		1
ParallelAcquisitionTechnique:		None
PartialFourier:				1,1.4
PartialFourierDirection:		None
PhaseEncodingDirection:			j
Effecti[...]<jupyter_text>BIDS parser syntax Metadata Field Mapping for Bruker PvDataset    - BIDS Metadata will be automatically created according to below reference.    - If list is entered as value, each parameter will be tested and the first available value will be returned.    - If dict is entered as value, below condition will be tested.    - If key - where pair:  parse value from given key and return index of 'where' from these values    - If key - idx pair:    parse value from given key and return value of given 'idx'    - If 'Equation' in key: each key assigned as local variable and test in Equation will be executed to return the value    - Else, new key - value dictionary will be return (for the cases with sub-keys)    - If string is entered as value, The value of given parameter will be parsed from parameter files<jupyter_code># the default metadata reference.
pp.pprint(brkraw.lib.reference.METADATA_FILED_INFO)<jupyter_output>{'AnatomicalLandmarkCoordinates': None,
 'CoilCombinationMethod': None,
 'CoilConfigName': 'ACQ_coil_config_file',
 'DeviceSerialNumber': 'VisuSystemOrderNumber',
 'DwellTime': {'BWhzPixel': 'VisuAcqPixelBandwidth', 'Equation': '1/BWhzPixel'},
 'EchoTime': 'VisuAcqEchoTime',
 'EffectiveEchoSpacing': {'ACCfactor': 'ACQ_phase_factor',
                          'BWhzPixel': 'VisuAcqPixelBandwidth',
                          'Equation': '(1 / (MatSizePE * BWhzPixel)) / '
                                      'ACCfactor',
                          'MatSizePE': {'idx': [{'key': 'VisuAcqGradEncoding',
                                                 'where': 'phase_enc'},
                                                {'key': 'VisuAcqImagePhaseEncDir',
                                                 'where': 'col_dir'}],
                                        'key': 'VisuCoreSize'}},
 'FlipAngle': 'VisuAcqFlipAngle',
 'GradientSetType': 'ACQ_status',
 'InstitutionAddress': None,
 'Institut[...]<jupyter_text>Example of using custom metadata reference<jupyter_code>metadata_ref = dict(ThisIsFlipAngle='VisuAcqFlipAngle',  # any parameter key among method, acqp, visupars can be used here
                    ThisIsJustTest='Im just string value',
                    
                    # If any operation required to set value, below example can be used.
                    ThisIsEquation=dict(a=3, 
                                        b=4, 
                                        Equation='a+b'),
                    
                    # Any standard and numpy method can be utilized to evaluate the value if needed.
                    Hierarchy=dict(SecondLevel='I am in the second level!',
                                   TryEquation=dict(abc='3',
                                                    Equation='list(range(abc))')),
                    
                    # Some parameter does not exists depends on the version of Paravision, this case
                    # You can use multiple keys to parse the first available value.
                    SequenceName = ['VisuAcquisitionProtocol', 'ACQ_protocol_name'],  
                    
                    # If no keys exists in parameter files, then you can set default string.
                    DefaultKeyIfNone = ['ImNotExistingKey', 'ImNeither', 'I am default value if nothing exists']
                   )

pvdset.print_bids(scan_id, reco_id, metadata=metadata_ref)
visu_pars = pvdset.get_visu_pars(scan_id, reco_id)
# Some key contains multiple values
visu_pars.parameters['VisuAcqPartialFourier']
# To parse only one value, you can use index
metadata_ref = dict(IHaveTwoValues='VisuAcqPartialFourier',
                    IWillTakeOnlyFirstValue=dict(key='VisuAcqPartialFourier',
                                                 idx=0),
                    ImCuriousTheIndexOfSpecificValue=dict(key='VisuAcqPartialFourier',
                                                 where=1.4))
pvdset.print_bids(scan_id, reco_id, metadata=metadata_ref)<jupyter_output>IHaveTwoValues:				1,1.4
IWillTakeOnlyFirstValue:		1
ImCuriousTheIndexOfSpecificValue:	1<jupyter_text>Generate Your Own BIDS metadata reference for conversion set of data- To use your own reference file for bids_converter function in command-line tool, please modify the json file generated by bids_list function. The Python API can be used for debuging purpose, and in case you want to implement your python dictionaty object instead of using file generated, dump your dictionary into JSON file as below<jupyter_code>import json
with open('your_filename.json', 'w') as f:
    json.dump(metadata_ref, f, indent=4)
# The dumbed file will look like this.
with open('your_filename.json', 'r') as f:
    for l in f.readlines():
        print(l)<jupyter_output>{

    "IHaveTwoValues": "VisuAcqPartialFourier",

    "IWillTakeOnlyFirstValue": {

        "key": "VisuAcqPartialFourier",

        "idx": 0

    },

    "ImCuriousTheIndexOfSpecificValue": {

        "key": "VisuAcqPartialFourier",

        "where": 1.4

    }

}<jupyter_text>Access Diffusion Direction for DTI image<jupyter_code>pvdset.get_bdata(scan_id)  # bval, bvec, bmat will be returned (no example DTI file provided here)<jupyter_output><empty_output><jupyter_text>Access nibabel NifTi1Image object with header.<jupyter_code>niiobj1 = pvdset.get_niftiobj(scan_id, reco_id)
print(niiobj1.affine, niiobj1.dataobj.shape)
print(niiobj1.header)<jupyter_output><class 'nibabel.nifti1.Nifti1Header'> object, endian='<'
sizeof_hdr      : 348
data_type       : b''
db_name         : b''
extents         : 0
session_error   : 0
regular         : b''
dim_info        : 48
dim             : [ 3 72 72 32  1  1  1  1]
intent_p1       : 0.0
intent_p2       : 0.0
intent_p3       : 0.0
intent_code     : none
datatype        : int16
bitpix          : 16
slice_start     : 0
pixdim          : [-1.   0.4  0.4  0.4  2.   1.   1.   1. ]
vox_offset      : 0.0
scl_slope       : 0.017385513
scl_inter       : 0.0
slice_end       : 31
slice_code      : alternating increasing
xyzt_units      : 10
cal_max         : 0.0
cal_min         : 0.0
slice_duration  : 0.0625
toffset         : 0.0
glmax           : 0
glmin           : 0
descrip         : b''
aux_file        : b''
qform_code      : scanner
sform_code      : unknown
quatern_b       : 0.999986
quatern_c       : 0.0
quatern_d       : -0.005292898
qoffset_x       : -14.381493
qoffset_y       : 14.96818
qoffset_z       [...]<jupyter_text>Access SimpleITK image object (the header is not preserved well compared to the nifti)<jupyter_code>sitkobj = pvdset.get_sitkimg(scan_id, reco_id)
print(sitkobj.GetSpacing())
print(sitkobj.GetSize())
print(sitkobj.GetDirection())
print(sitkobj.GetOrigin())
# Construct affine matrix from SimpleITK image object.
from nibabel.affines import from_matvec
resol = np.diag(sitkobj.GetSpacing())
direction = np.asarray(sitkobj.GetDirection())[:9].reshape([3, 3])
direction = resol.dot(direction)
origin = np.asarray(sitkobj.GetOrigin())[:3]
affine_from_sitk = from_matvec(direction, origin)
affine_from_sitk = np.diag([-1, -1, 1, 1]).dot(affine_from_sitk)
print(affine_from_sitk)
# export nifti data
pvdset.save_as(scan_id, reco_id, 'your_filename', 
               dir='./', ext='nii.gz', 
               crop=[10, 100])  # you can crop the data thorugh this option


# export diffution parameters !! This will only function when image has diffusion direction in their header, 
# the example data does not have it.
pvdset.save_bdata(scan_id, 'your_filename', 
                  dir='./')

# export BIDS json file with your metadata_ref
pvdset.save_json(scan_id, reco_id, 'your_filename', 
                 dir='./', metadata=metadata_ref)<jupyter_output><empty_output><jupyter_text>Low-level API load JCAMP-DX parameter objects- Using the methods below, each parameter can be accessed as dictionary object. and the value is converted to python compatible type (some value may not converted due to the complex structure)<jupyter_code>acqp        = pvdset.get_acqp(scan_id)
method      = pvdset.get_method(scan_id)
visu_pars   = pvdset.get_visu_pars(scan_id, reco_id)
pvdset._subject.parameters<jupyter_output><empty_output><jupyter_text>- All parameter object has attibutes of headers and parameters<jupyter_code>acqp.headers
acqp.parameters
method.headers
method.parameters
visu_pars.headers
visu_pars.parameters<jupyter_output><empty_output><jupyter_text>Useful method to get parameters for data reconstruction and conversion.- All function listed above is private methods<jupyter_code>pvdset._get_dim_info(visu_pars)
pvdset._get_gradient_encoding_info(visu_pars)
pvdset._get_frame_group_info(visu_pars)
pvdset._get_slice_info(visu_pars)
pvdset._get_spatial_info(visu_pars)
pvdset._get_temp_info(visu_pars)
pvdset._get_orient_info(visu_pars, method)
pvdset._get_disk_slice_order(visu_pars)<jupyter_output><empty_output><jupyter_text>Access dataobj<jupyter_code>dataobj     = pvdset.get_dataobj(scan_id, reco_id, slp_correct=False)     
matrix_size = pvdset.get_matrix_size(scan_id, reco_id)  
affine      = pvdset.get_affine(scan_id, reco_id)   
print(dataobj.shape, matrix_size)
print(affine)
dataobj.dtype<jupyter_output><empty_output><jupyter_text>- If slp_correct option is False, the dataobj returned the rescaled int16 data, - If slp_correct option is True, below step will performed internally<jupyter_code>from brkraw.lib.utils import is_all_element_same
data_slope = visu_pars.parameters['VisuCoreDataSlope']
data_offset = visu_pars.parameters['VisuCoreDataOffs']
print(is_all_element_same(data_slope), # check if all elements are same.
      is_all_element_same(data_offset)
     )
# correcting intensity to original value
orj_dataobj = dataobj * data_slope[0] + data_offset[0]
print(orj_dataobj.dtype)

# build nibabel object
import nibabel as nib
niiobj2 = nib.Nifti1Image(orj_dataobj, affine)<jupyter_output>float64<jupyter_text>Access binary FID file obj- The FID handling is currently experimental, only showing here to present potential application.<jupyter_code>from brkraw.lib.reference import WORDTYPE
print(acqp.parameters['GO_raw_data_format'])

dt_code = WORDTYPE[acqp.parameters['GO_raw_data_format'][2:]]
print(dt_code)

fid_binary = pvdset.get_fid(scan_id)

# convert to numpy array
fid = np.frombuffer(fid_binary, dt_code)
fid.shape<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.09253234470757359, 'fraction_numerical': 0.030037073465990768, 'mean_word_length': 3.4928619986403806, 'pattern_counts': {'":': 7, '<': 68, '<?xml version=': 0, '>': 67, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 1, 'word_list_counts': {'cursed_substrings.json': 18, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '18', 'dir': 'jupyter-structured-clean-dedup', 'id': '70757', 'license': 'CC-BY-4.0', 'n_tokens_mistral': 4762, 'n_tokens_neox': 4358, 'n_words': 1093, 'path': 'nmr/BrkRaw_PythonAPI.ipynb', 'repo_name': 'jameshtwose/han_jms_collabs', 'size': '13217'}