NeurodataWithoutBorders / matnwb

A Matlab interface for reading and writing NWB files
BSD 2-Clause "Simplified" License
50 stars 32 forks source link

Change data_unit of already existing nwb file #511

Closed GoktugAlkan closed 1 year ago

GoktugAlkan commented 1 year ago

Hello,

There is an already existing nwb file where we need to do the following modification. In the field nwb.acquisition there is an ElectricalSeries object. The unit of the recorded data (i.e. .data_unit) is 'mV'. We want to change this entry to 'uV'. Hence, I am wondering whether there is a way to overwrite this entry without recreating the whole nwb file from scratch.

Observations: When I load the nwb file with nwbRead and execute nwb.acquisition.get('allTasks').data_unit (remark: the name of the ElectricalSeries object in this case is 'allTasks') I see 'mV' in the command window. When I execute nwb.acquisition.get('allTasks').data_unit = 'uV', export this nwb file on the same path with nwbExport, load this exported file again with nwbRead, and check nwb.acquisition.get('allTasks').data_unit I see the answer 'uV'. That's why I assumed that this procedure overwrites this entry successfully.

However, when I load the same file in pyNWB the unit of the ElectricalSeries object is just shown as 'volts'. Hence, I think that the applied procedure is possibly wrong or pyNWB reads the unit of an ElectricalSeries object as 'volts' even though this was specified to something else when the nwb file was generated.

Could you help me out?

Many thanks in advance!

rly commented 1 year ago

@GoktugAlkan

In the NWB schema, the unit of measurement for the data dataset of an ElectricalSeries is fixed (set) to "volts". Having a different value means the file is not compliant with the NWB schema. PyNWB enforces that rule. Note that PyNWB does not seem to check whether the data being read has a different value for data/unit than "volts" - I just created an issue for that https://github.com/NeurodataWithoutBorders/pynwb/issues/1700

To store your data values in uV, please set the conversion attribute on the data dataset to 1e6, so that data * conversion + offset results in the data being in volts. The unit attribute should then be changed to "volts" to be compliant with NWB.

To change the values, @lawrence-mbf or @bendichter will be able to answer whether matnwb supports overwriting attributes after reading them from a file - I do not remember. If it is not supported, you can modify the HDF5-based NWB file directly and overwrite attributes in the file in Python using the h5py library or in Matlab using the h5write and h5writeatt functions.

GoktugAlkan commented 1 year ago

@rly Thanks for your respone! I understand the conversion attribute better now. However, according to your explanation, isn't conversion supposed to be 1e-6? The data that is stored in the ElectricalSeries object is in uV, hence data * 1e-6 would result in the data being in volts. Or don't I get your explanation correctly?

Another point is that overwriting these attributes without creating the files from scratch seems to work. I applied the following procedure:

  1. Load already existing nwb file with nwbRead in matNWB.
  2. Execute nwb.acquisition.get('allTasks').data_conversion = 1e-6 to set the conversion rate according to your explanation.
  3. Execute nwb.acquisition.get('allTasks').data_unit = 'volts' to set the unit according to your explanation.
  4. Store the modified nwb file with nwbExport.

Testing this procedure resulted in the following:

  1. Read the modified nwb file with nwbRead in matNWB and check if nwb.acquisition.get('allTasks').data_conversion and nwb.acquisition.get('allTasks').data_unit are set correctly. Result: nwb.acquisition.get('allTasks').data_conversion has the value 1e-6 and nwb.acquisition.get('allTasks').data_unit has the value 'volts'.

  2. Read the modified nwb file (the same one as in step 1) in pyNWB and check if nwb.acquisition['allTasks'].conversion and nwb.acquisition['allTasks'].unit are set correctly. Result: nwb.acquisition['allTasks'].conversion has the value 1e-6 and nwb.acquisition['allTasks'].unit has the value 'volts'.

GoktugAlkan commented 1 year ago

@rly Is the value for conversion correct in this specific case? If so, I will close this issue

rly commented 1 year ago

@GoktugAlkan sorry for the delay. Yes, you are correct. The conversion factor in this case would be 1e-6.

GoktugAlkan commented 1 year ago

@rly No problem, thanks for the response! From my side there is nothing to add/ask. If you wish you can close the issue. Many thanks!