未提供项目描述
项目描述
LINDI - 链接数据接口
LINDI是一种云友好的文件格式和Python库,专为管理科学数据设计,特别是用于管理“没有边界的神经数据”(NWB)数据集。它提供了对HDF5和Zarr的替代方案,同时保持与两者的兼容性,并提供针对链接到云中存储的远程数据集(例如DANDI存档中的数据集)的特性。LINDI的独特结构和功能使其特别适合在云环境中高效地访问和管理数据。
什么是LINDI文件?
LINDI文件是用于存储科学数据的云友好格式,旨在与HDF5和Zarr兼容,同时提供独特的优势。它有三种类型,它们是相同底层数据的表示:JSON/text格式(.lindi.json)、二进制格式(.lindi.tar)和目录格式(.lindi.d)。
在JSON格式中,分层组结构、属性和小型数据集存储在JSON结构中,而对较大数据块的外部文件的引用(灵感来自kerchunk)。这种格式可读性良好,易于检查和编辑。
二进制格式是一个包含JSON文件(lindi.json)以及由JSON文件引用的可选内部数据块(外部块)的.tar文件。此格式可用于创建新的NWB文件,该文件基于现有NWB文件而无需重复,并添加新的数据对象(见下文)。
目录格式与.tar格式类似,但将lindi.json和二进制块存储在目录中,而不是.tar文件中。
主要用例是什么?
LINDI文件在以下场景中特别有用:
在DANDI上的高效NWB文件表示:LINDI JSON文件可以表示存储在DANDI存档(或其他远程系统)上的NWB文件。通过下载一个压缩的JSON文件,可以一次性检索整个组结构,从而方便高效地加载NWB文件。例如,Neurosift利用预生成的LINDI JSON文件来简化从DANDI加载NWB文件的过程(示例)。
创建修订版NWB文件:LINDI允许创建修订版NWB文件,向现有NWB文件添加新的数据对象,而无需复制整个文件。这是通过生成一个引用原始NWB文件并包含作为内部数据块存储的附加数据对象的二进制或目录LINDI文件来实现的。这种方法通过减少冗余并建立NWB文件之间的依赖关系来节省存储空间。
为什么不使用Zarr?
当比较LINDI和Zarr时,应注意的是,LINDI文件实际上是有效的Zarr存档,可以通过Zarr API访问。事实上,LINDI文件是Zarr存储的特殊类型,允许对块进行外部链接(参见kerchunk)和用于表示NWB的HDF5功能的特殊约定,这些功能Zarr本身不支持。
传统的Zarr目录存储有一些局限性。首先,Zarr存档通常由数万个单独的文件组成,使得管理起来很麻烦。相比之下,LINDI采用类似于HDF5的单文件方法,提高了可管理性,同时保持了云友好性。另一个局限性(如前所述)是缺乏像LINDI那样的机制来引用外部数据集中的数据块。最后,Zarr本身不支持NWB使用的一些特性,如复合数据类型和引用。这些特性都由HDF5和LINDI支持。
为什么不使用HDF5?
HDF5不适合云环境,因为访问远程HDF5文件通常需要在下载更大的数据块之前,通过大量小请求来检索元数据。LINDI通过将整个组结构存储在单个JSON文件中来解决这个问题,该文件可以一次性下载。此外,HDF5缺乏内置的引用外部数据集中数据块的机制。此外,HDF5不支持Zarr和LINDI都有的自定义Python编解码器。
tar格式真的云友好吗?
使用LINDI时是的。有关详细信息,请参阅docs/tar.md。
安装
pip install --upgrade lindi
或从源安装
cd lindi
pip install -e .
使用方法
创建和读取LINDI文件
最简单的方法是像使用HDF5一样使用它。
import lindi
# Create a new lindi.json file
with lindi.LindiH5pyFile.from_lindi_file('example.lindi.json', mode='w') as f:
f.attrs['attr1'] = 'value1'
f.attrs['attr2'] = 7
ds = f.create_dataset('dataset1', shape=(10,), dtype='f')
ds[...] = 12
# Later read the file
with lindi.LindiH5pyFile.from_lindi_file('example.lindi.json', mode='r') as f:
print(f.attrs['attr1'])
print(f.attrs['attr2'])
print(f['dataset1'][...])
您可以通过查看example.lindi.json文件来了解数据是如何存储的。如果您熟悉内部Zarr格式,您将识别出.group和.zarray文件以及数据块的布局。这是一个示例,展示了表示存储在DANDI上的NWB文件的LINDI JSON文件。
由于上述数据集非常小,它可以合理地全部放入JSON文件中。对于存储更大的数组(通常情况),最好使用二进制或目录格式。
import numpy as np
import lindi
# Create a new lindi binary file
with lindi.LindiH5pyFile.from_lindi_file('example.lindi.tar', mode='w') as f:
f.attrs['attr1'] = 'value1'
f.attrs['attr2'] = 7
ds = f.create_dataset('dataset1', shape=(1000, 1000), dtype='f')
ds[...] = np.random.rand(1000, 1000)
# Later read the file
with lindi.LindiH5pyFile.from_lindi_file('example.lindi.tar', mode='r') as f:
print(f.attrs['attr1'])
print(f.attrs['attr2'])
print(f['dataset1'][...])
从DANDI加载远程NWB文件
使用LINDI,很容易从DANDI加载存储的NWB文件。以下示例演示了如何从DANDI加载NWB文件,使用pynwb库查看它,并将其保存为相对较小的.lindi.json文件。然后可以直接读取LINDI JSON文件以访问NWB文件。
import json
import pynwb
import lindi
# Define the URL for a remote NWB file
h5_url = "https://api.dandiarchive.org/api/assets/11f512ba-5bcf-4230-a8cb-dc8d36db38cb/download/"
# Load as LINDI and view using pynwb
f = lindi.LindiH5pyFile.from_hdf5_file(h5_url)
with pynwb.NWBHDF5IO(file=f, mode="r") as io:
nwbfile = io.read()
print('NWB via LINDI')
print(nwbfile)
print('Electrode group at shank0:')
print(nwbfile.electrode_groups["shank0"]) # type: ignore
print('Electrode group at index 0:')
print(nwbfile.electrodes.group[0]) # type: ignore
# Save as LINDI JSON
f.write_lindi_file('example.nwb.lindi.json')
f.close()
# Later, read directly from the LINDI JSON file
g = lindi.LindiH5pyFile.from_lindi_file('example.nwb.lindi.json')
with pynwb.NWBHDF5IO(file=g, mode="r") as io:
nwbfile = io.read()
print('')
print('NWB from LINDI JSON:')
print(nwbfile)
print('Electrode group at shank0:')
print(nwbfile.electrode_groups["shank0"]) # type: ignore
print('Electrode group at index 0:')
print(nwbfile.electrodes.group[0]) # type: ignore
修改NWB文件
LINDI的主要用途之一是创建修改后的NWB文件,该文件向现有NWB文件添加新的数据对象,而无需复制整个文件。这是通过生成一个引用原始NWB文件并包含作为内部数据块存储的附加数据对象的二进制或目录LINDI文件来实现的。
import numpy as np
import pynwb
from pynwb.file import TimeSeries
import lindi
# Load the remote NWB file from DANDI
h5_url = "https://api.dandiarchive.org/api/assets/11f512ba-5bcf-4230-a8cb-dc8d36db38cb/download/"
f = lindi.LindiH5pyFile.from_hdf5_file(h5_url)
# Write to a local .lindi.tar file
f.write_lindi_file('example.nwb.lindi.tar')
f.close()
# Open with pynwb and add new data
g = lindi.LindiH5pyFile.from_lindi_file('example.nwb.lindi.tar', mode='r+')
with pynwb.NWBHDF5IO(file=g, mode="a") as io:
nwbfile = io.read()
timeseries_test = TimeSeries(
name="test",
data=np.array([1, 2, 3, 4, 5, 4, 3, 2, 1]),
rate=1.,
unit='s'
)
ts = nwbfile.processing['behavior'].add(timeseries_test) # type: ignore
io.write(nwbfile) # type: ignore
# Later on, you can read the file again
h = lindi.LindiH5pyFile.from_lindi_file('example.nwb.lindi.tar')
with pynwb.NWBHDF5IO(file=h, mode="r") as io:
nwbfile = io.read()
test_timeseries = nwbfile.processing['behavior']['test'] # type: ignore
print(test_timeseries)
注意
对于开发者
许可证
请参阅LICENSE。
项目详情
下载文件
下载适用于您平台的文件。如果您不确定选择哪个,请了解更多关于安装包的信息。