{"id":15576828,"url":"https://github.com/tlambert03/nd2","last_synced_at":"2026-01-08T06:10:26.412Z","repository":{"id":36958268,"uuid":"409575609","full_name":"tlambert03/nd2","owner":"tlambert03","description":"Full-featured nd2 (Nikon NIS Elements) file reader for python. Outputs to numpy, dask, and xarray. Exhaustive metadata extraction","archived":false,"fork":false,"pushed_at":"2025-03-05T15:00:51.000Z","size":8693,"stargazers_count":62,"open_issues_count":10,"forks_count":17,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-04-02T02:57:47.768Z","etag":null,"topics":["microscopy","nd2","nikon","nis-elements"],"latest_commit_sha":null,"homepage":"http://tlambert03.github.io/nd2","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tlambert03.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-09-23T12:08:28.000Z","updated_at":"2025-03-31T11:21:35.000Z","dependencies_parsed_at":"2023-10-03T17:58:44.348Z","dependency_job_id":"864adf08-a0a3-4c4a-8077-92c5f6eaa987","html_url":"https://github.com/tlambert03/nd2","commit_stats":{"total_commits":207,"total_committers":7,"mean_commits":"29.571428571428573","dds":"0.18357487922705318","last_synced_commit":"ba78c7a2aae10b6096d4bfd96ee8a48342b08cc7"},"previous_names":[],"tags_count":45,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tlambert03%2Fnd2","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tlambert03%2Fnd2/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tlambert03%2Fnd2/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tlambert03%2Fnd2/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tlambert03","download_url":"https://codeload.github.com/tlambert03/nd2/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246746932,"owners_count":20827061,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["microscopy","nd2","nikon","nis-elements"],"created_at":"2024-10-02T18:59:05.224Z","updated_at":"2026-01-08T06:10:26.357Z","avatar_url":"https://github.com/tlambert03.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# nd2\n\n[![License](https://img.shields.io/pypi/l/nd2.svg?color=green)](https://github.com/tlambert03/nd2/raw/main/LICENSE)\n[![PyPI](https://img.shields.io/pypi/v/nd2.svg?color=green)](https://pypi.org/project/nd2)\n[![Python Version](https://img.shields.io/pypi/pyversions/nd2.svg?color=green)](https://python.org)\n[![Tests](https://github.com/tlambert03/nd2/actions/workflows/ci.yml/badge.svg)](https://github.com/tlambert03/nd2/actions/workflows/ci.yml)\n[![codecov](https://codecov.io/gh/tlambert03/nd2/branch/main/graph/badge.svg)](https://codecov.io/gh/tlambert03/nd2)\n[![Benchmarks](https://img.shields.io/badge/⏱-codspeed-%23FF7B53)](https://codspeed.io/tlambert03/nd2)\n\n`.nd2` (Nikon NIS Elements) file reader.\n\nThis reader provides a pure python implementation of the Nikon ND2 SDK.\n\n\u003e It _used_ to wrap the official SDK with Cython, but has since been completely\n\u003e rewritten to be pure python (for performance, ease of distribution, and\n\u003e maintenance) while retaining complete API parity with the official SDK.\n\u003e\n\u003e **Note:** This library is not affiliated with Nikon in any way, but we are\n\u003e grateful for assistance from the SDK developers at Laboratory Imaging.\n\nFeatures good metadata retrieval, direct `to_dask` and `to_xarray` options\nfor lazy and/or annotated arrays, and output to OME-TIFF.\n\nThis library is tested against many nd2 files with the goal of maximizing\ncompatibility and data extraction. (If you find an nd2 file that fails in some\nway, please [open an issue](https://github.com/tlambert03/nd2/issues/new) with\nthe file!)\n\n### :book: [Documentation](https://tlambert03.github.io/nd2)\n\n## install\n\n```sh\npip install nd2\n```\n\nor from conda:\n\n```sh\nconda install -c conda-forge nd2\n```\n\n### Legacy nd2 file support\n\nLegacy nd2 (JPEG2000) files are also supported, but require `imagecodecs`. To\ninstall with support for these files use the `legacy` extra:\n\n```sh\npip install nd2[legacy]\n```\n\n### Faster XML parsing\n\nMuch of the metadata in the file stored as XML. If found in the environment,\n`nd2` will use [`lxml`](https://pypi.org/project/lxml/) which is much faster\nthan the built-in `xml` module. To install with support for `lxml` use:\n\n```sh\npip install nd2 lxml\n```\n\n## Usage and API\n\nFull API documentation is available at\n[https://tlambert03.github.io/nd2](https://tlambert03.github.io/nd2)\n\nQuick summary below:\n\n```python\nimport nd2\nimport numpy as np\n\nmy_array = nd2.imread('some_file.nd2')                          # read to numpy array\nmy_array = nd2.imread('some_file.nd2', dask=True)               # read to dask array\nmy_array = nd2.imread('some_file.nd2', xarray=True)             # read to xarray\nmy_array = nd2.imread('some_file.nd2', xarray=True, dask=True)  # read to dask-xarray\n\n# or open a file with nd2.ND2File\nf = nd2.ND2File('some_file.nd2')\n\n# (you can also use nd2.ND2File() as a context manager)\nwith nd2.ND2File('some_file.nd2') as ndfile:\n    print(ndfile.metadata)\n    ...\n\n\n# ATTRIBUTES:   # example output\nf.path          # 'some_file.nd2'\nf.shape         # (10, 2, 256, 256)\nf.ndim          # 4\nf.dtype         # np.dtype('uint16')\nf.size          # 1310720  (total voxel elements)\nf.sizes         # {'T': 10, 'C': 2, 'Y': 256, 'X': 256}\nf.is_rgb        # False (whether the file is rgb)\n                # if the file is RGB, `f.sizes` will have\n                # an additional {'S': 3} component\n\n# ARRAY OUTPUTS\nf.asarray()         # in-memory np.ndarray - or use np.asarray(f)\nf.to_dask()         # delayed dask.array.Array\nf.to_xarray()       # in-memory xarray.DataArray, with labeled axes/coords\nf.to_xarray(delayed=True)   # delayed xarray.DataArray\n\n# OME-TIFF OUTPUT (new in v0.10.0)\nf.write_tiff('output.ome.tif')  # write to ome-tiff file\n\n                    # see below for examples of these structures\n# METADATA          # returns instance of ...\nf.attributes        # nd2.structures.Attributes\nf.metadata          # nd2.structures.Metadata\nf.frame_metadata(0) # nd2.structures.FrameMetadata (frame-specific meta)\nf.experiment        # List[nd2.structures.ExpLoop]\nf.text_info         # dict of misc info\nf.voxel_size()      # VoxelSize(x=0.65, y=0.65, z=1.0)\n\nf.rois              # Dict[int, nd2.structures.ROI]\nf.binary_data       # any binary masks stored in the file.  See below.\nf.events()          # returns tabular \"Recorded Data\" view from in NIS Elements/Viewer\n                    # with info for each frame in the experiment.\n                    # output is passabled to pandas.DataFrame\n\nf.ome_metadata()    # returns metadata as an ome_types.OME object\n                    # (requires ome-types package)\n\n# allll the metadata we can find...\n# no attempt made to standardize or parse it\n# look in here if you're searching for metadata that isn't exposed in the above\n# but try not to rely on it, as it's not guaranteed to be stable\nf.unstructured_metadata()\n\nf.close()           # don't forget to close when not using a context manager!\nf.closed            # boolean, whether the file is closed\n```\n\n## Metadata structures\n\nThese follow the structure of the nikon SDK outputs (where relevant).\nHere are some example outputs\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003ccode\u003eattributes\u003c/code\u003e\u003c/summary\u003e\n\n```python\nAttributes(\n    bitsPerComponentInMemory=16,\n    bitsPerComponentSignificant=16,\n    componentCount=2,\n    heightPx=32,\n    pixelDataType='unsigned',\n    sequenceCount=60,\n    widthBytes=128,\n    widthPx=32,\n    compressionLevel=None,\n    compressionType=None,\n    tileHeightPx=None,\n    tileWidthPx=None,\n    channelCount=2\n)\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003ccode\u003emetadata\u003c/code\u003e\u003c/summary\u003e\n\n_Note: the `metadata` for legacy (JPEG2000) files will be a plain unstructured dict._\n\n```python\nMetadata(\n    contents=Contents(channelCount=2, frameCount=60),\n    channels=[\n        Channel(\n            channel=ChannelMeta(\n                name='Widefield Green',\n                index=0,\n                color=Color(r=91, g=255, b=0, a=1.0),\n                emissionLambdaNm=535.0,\n                excitationLambdaNm=None\n            ),\n            loops=LoopIndices(NETimeLoop=None, TimeLoop=0, XYPosLoop=1, ZStackLoop=2),\n            microscope=Microscope(\n                objectiveMagnification=10.0,\n                objectiveName='Plan Fluor 10x Ph1 DLL',\n                objectiveNumericalAperture=0.3,\n                zoomMagnification=1.0,\n                immersionRefractiveIndex=1.0,\n                projectiveMagnification=None,\n                pinholeDiameterUm=None,\n                modalityFlags=['fluorescence']\n            ),\n            volume=Volume(\n                axesCalibrated=[True, True, True],\n                axesCalibration=[0.652452890023035, 0.652452890023035, 1.0],\n                axesInterpretation=(\n                    \u003cAxisInterpretation.distance: 'distance'\u003e,\n                    \u003cAxisInterpretation.distance: 'distance'\u003e,\n                    \u003cAxisInterpretation.distance: 'distance'\u003e\n                ),\n                bitsPerComponentInMemory=16,\n                bitsPerComponentSignificant=16,\n                cameraTransformationMatrix=[-0.9998932296054086, -0.014612644841559427, 0.014612644841559427, -0.9998932296054086],\n                componentCount=1,\n                componentDataType='unsigned',\n                voxelCount=[32, 32, 5],\n                componentMaxima=[0.0],\n                componentMinima=[0.0],\n                pixelToStageTransformationMatrix=None\n            )\n        ),\n        Channel(\n            channel=ChannelMeta(\n                name='Widefield Red',\n                index=1,\n                color=Color(r=255, g=85, b=0, a=1.0),\n                emissionLambdaNm=620.0,\n                excitationLambdaNm=None\n            ),\n            loops=LoopIndices(NETimeLoop=None, TimeLoop=0, XYPosLoop=1, ZStackLoop=2),\n            microscope=Microscope(\n                objectiveMagnification=10.0,\n                objectiveName='Plan Fluor 10x Ph1 DLL',\n                objectiveNumericalAperture=0.3,\n                zoomMagnification=1.0,\n                immersionRefractiveIndex=1.0,\n                projectiveMagnification=None,\n                pinholeDiameterUm=None,\n                modalityFlags=['fluorescence']\n            ),\n            volume=Volume(\n                axesCalibrated=[True, True, True],\n                axesCalibration=[0.652452890023035, 0.652452890023035, 1.0],\n                axesInterpretation=(\n                    \u003cAxisInterpretation.distance: 'distance'\u003e,\n                    \u003cAxisInterpretation.distance: 'distance'\u003e,\n                    \u003cAxisInterpretation.distance: 'distance'\u003e\n                ),\n                bitsPerComponentInMemory=16,\n                bitsPerComponentSignificant=16,\n                cameraTransformationMatrix=[-0.9998932296054086, -0.014612644841559427, 0.014612644841559427, -0.9998932296054086],\n                componentCount=1,\n                componentDataType='unsigned',\n                voxelCount=[32, 32, 5],\n                componentMaxima=[0.0],\n                componentMinima=[0.0],\n                pixelToStageTransformationMatrix=None\n            )\n        )\n    ]\n)\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003ccode\u003eexperiment\u003c/code\u003e\u003c/summary\u003e\n\n```python\n[\n    TimeLoop(\n        count=3,\n        nestingLevel=0,\n        parameters=TimeLoopParams(\n            startMs=0.0,\n            periodMs=1.0,\n            durationMs=0.0,\n            periodDiff=PeriodDiff(avg=16278.339965820312, max=16411.849853515625, min=16144.830078125)\n        ),\n        type='TimeLoop'\n    ),\n    XYPosLoop(\n        count=4,\n        nestingLevel=1,\n        parameters=XYPosLoopParams(\n            isSettingZ=True,\n            points=[\n                Position(stagePositionUm=[26950.2, -1801.6000000000001, 498.46000000000004], pfsOffset=None, name=None),\n                Position(stagePositionUm=[31452.2, -1801.6000000000001, 670.7], pfsOffset=None, name=None),\n                Position(stagePositionUm=[35234.3, 2116.4, 664.08], pfsOffset=None, name=None),\n                Position(stagePositionUm=[40642.9, -3585.1000000000004, 555.12], pfsOffset=None, name=None)\n            ]\n        ),\n        type='XYPosLoop'\n    ),\n    ZStackLoop(count=5, nestingLevel=2, parameters=ZStackLoopParams(homeIndex=2, stepUm=1.0, bottomToTop=True, deviceName='Ti2 ZDrive'), type='ZStackLoop')\n]\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003ccode\u003erois\u003c/code\u003e\u003c/summary\u003e\n\nROIs found in the metadata are available at `ND2File.rois`, which is a\n`dict` of `nd2.structures.ROI` objects, keyed by the ROI ID:\n\n```python\n{\n    1: ROI(\n        id=1,\n        info=RoiInfo(\n            shapeType=\u003cRoiShapeType.Rectangle: 3\u003e,\n            interpType=\u003cInterpType.StimulationROI: 4\u003e,\n            cookie=1,\n            color=255,\n            label='',\n            stimulationGroup=0,\n            scope=1,\n            appData=0,\n            multiFrame=False,\n            locked=False,\n            compCount=2,\n            bpc=16,\n            autodetected=False,\n            gradientStimulation=False,\n            gradientStimulationBitDepth=0,\n            gradientStimulationLo=0.0,\n            gradientStimulationHi=0.0\n        ),\n        guid='{87190352-9B32-46E4-8297-C46621C1E1EF}',\n        animParams=[\n            AnimParam(\n                timeMs=0.0,\n                enabled=1,\n                centerX=-0.4228425369685782,\n                centerY=-0.5194951478743071,\n                centerZ=0.0,\n                rotationZ=0.0,\n                boxShape=BoxShape(\n                    sizeX=0.21256931608133062,\n                    sizeY=0.21441774491682075,\n                    sizeZ=0.0\n                ),\n                extrudedShape=ExtrudedShape(sizeZ=0, basePoints=[])\n            )\n        ]\n    ),\n    ...\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003ccode\u003etext_info\u003c/code\u003e\u003c/summary\u003e\n\n```python\n{\n    'capturing': 'Flash4.0, SN:101412\\r\\nSample 1:\\r\\n  Exposure: 100 ms\\r\\n  Binning: 1x1\\r\\n  Scan Mode: Fast\\r\\nSample 2:\\r\\n  Exposure: 100 ms\\r\\n  Binning: 1x1\\r\\n  Scan Mode: Fast',\n    'date': '9/28/2021  9:41:27 AM',\n    'description': 'Metadata:\\r\\nDimensions: T(3) x XY(4) x λ(2) x Z(5)\\r\\nCamera Name: Flash4.0, SN:101412\\r\\nNumerical Aperture: 0.3\\r\\nRefractive Index: 1\\r\\nNumber of Picture Planes: 2\\r\\nPlane #1:\\r\\n Name: Widefield Green\\r\\n Component Count: 1\\r\\n Modality: Widefield Fluorescence\\r\\n Camera Settings:   Exposure: 100 ms\\r\\n  Binning: 1x1\\r\\n  Scan Mode: Fast\\r\\n Microscope Settings:   Nikon Ti2, FilterChanger(Turret-Lo): 3 (FITC)\\r\\n  Nikon Ti2, Shutter(FL-Lo): Open\\r\\n  Nikon Ti2, Shutter(DIA LED): Closed\\r\\n  Nikon Ti2, Illuminator(DIA): Off\\r\\n  Nikon Ti2, Illuminator(DIA) Iris intensity: 3.0\\r\\n  Analyzer Slider: Extracted\\r\\n  Analyzer Cube: Extracted\\r\\n  Condenser: 1 (Shutter)\\r\\n  PFS, state: On\\r\\n  PFS, offset: 7959\\r\\n  PFS, mirror: Inserted\\r\\n  PFS, Dish Type: Glass\\r\\n  Zoom: 1.00x\\r\\n  Sola, Shutter(Sola): Active\\r\\n  Sola, Illuminator(Sola) Voltage: 100.0\\r\\nPlane #2:\\r\\n Name: Widefield Red\\r\\n Component Count: 1\\r\\n Modality: Widefield Fluorescence\\r\\n Camera Settings:   Exposure: 100 ms\\r\\n  Binning: 1x1\\r\\n  Scan Mode: Fast\\r\\n Microscope Settings:   Nikon Ti2, FilterChanger(Turret-Lo): 4 (TRITC)\\r\\n  Nikon Ti2, Shutter(FL-Lo): Open\\r\\n  Nikon Ti2, Shutter(DIA LED): Closed\\r\\n  Nikon Ti2, Illuminator(DIA): Off\\r\\n  Nikon Ti2, Illuminator(DIA) Iris intensity: 1.5\\r\\n  Analyzer Slider: Extracted\\r\\n  Analyzer Cube: Extracted\\r\\n  Condenser: 1 (Shutter)\\r\\n  PFS, state: On\\r\\n  PFS, offset: 7959\\r\\n  PFS, mirror: Inserted\\r\\n  PFS, Dish Type: Glass\\r\\n  Zoom: 1.00x\\r\\n  Sola, Shutter(Sola): Active\\r\\n  Sola, Illuminator(Sola) Voltage: 100.0\\r\\nTime Loop: 3\\r\\n- Equidistant (Period 1 ms)\\r\\nZ Stack Loop: 5\\r\\n- Step: 1 µm\\r\\n- Device: Ti2 ZDrive',\n    'optics': 'Plan Fluor 10x Ph1 DLL'\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003ccode\u003ebinary_data\u003c/code\u003e\u003c/summary\u003e\n\nThis property returns an `nd2.BinaryLayers` object representing all of the\nbinary masks in the nd2 file.\n\nA `nd2.BinaryLayers` object is a sequence of individual `nd2.BinaryLayer`\nobjects (one for each binary layer found in the file). Each `BinaryLayer` in\nthe sequence is a named tuple that has, among other things, a `name` attribute,\nand a `data` attribute that is list of numpy arrays (one for each frame in the\nexperiment) or `None` if the binary layer had no data in that frame.\n\nThe most common use case will be to cast either the entire `BinaryLayers` object\nor an individual `BinaryLayer` to a `numpy.ndarray`:\n\n```python\n\u003e\u003e\u003e import nd2\n\u003e\u003e\u003e nd2file = nd2.ND2File('path/to/file.nd2')\n\u003e\u003e\u003e binary_layers = nd2file.binary_data\n\n# The output array will have shape\n# (n_binary_layers, *coord_shape, *frame_shape).\n\u003e\u003e\u003e np.asarray(binary_layers)\n```\n\nFor example, if the data in the nd2 file has shape `(nT, nZ, nC, nY, nX)`, and\nthere are 4 binary layers, then the output of `np.asarray(nd2file.binary_data)` will\nhave shape `(4, nT, nZ, nY, nX)`. (Note that the `nC` dimension is not present\nin the output array, and the binary layers are always in the first axis).\n\nYou can also cast an individual `BinaryLayer` to a numpy array:\n\n```python\n\u003e\u003e\u003e binary_layer = binary_layers[0]\n\u003e\u003e\u003e np.asarray(binary_layer)\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003ccode\u003eevents()\u003c/code\u003e\u003c/summary\u003e\n\nThis property returns the tabular data reported in the `Image Properties \u003e\nRecorded Data` tab of the NIS Viewer.\n\n(There will be a column for each tag in the `CustomDataV2_0` section of\n`custom_data` above, as well as any additional events found in the metadata)\n\nThe format of the return type data is controlled by the `orient` argument:\n\n- `'records'` : list of dicts - `[{column -\u003e value}, ...]` (default)\n- `'dict'` : dict of dicts - `{column -\u003e {index -\u003e value}, ...}`\n- `'list'` : dict of lists - `{column -\u003e [value, ...]}`\n\nNot every column header appears in every event, so when `orient` is either\n`'dict'` or `'list'`, `float('nan')` will be inserted to maintain a consistent\nlength for each column.\n\n```python\n\n# with `orient='records'` (DEFAULT)\n[\n    {\n        'Time [s]': 1.32686654,\n        'Z-Series': -2.0,\n        'Exposure Time [ms]': 100.0,\n        'PFS Offset': 0,\n        'PFS Status': 0,\n        'X Coord [µm]': 31452.2,\n        'Y Coord [µm]': -1801.6,\n        'Z Coord [µm]': 552.74,\n        'Ti2 ZDrive [µm]': 552.74\n    },\n    {\n        'Time [s]': 1.69089657,\n        'Z-Series': -1.0,\n        'Exposure Time [ms]': 100.0,\n        'PFS Offset': 0,\n        'PFS Status': 0,\n        'X Coord [µm]': 31452.2,\n        'Y Coord [µm]': -1801.6,\n        'Z Coord [µm]': 553.74,\n        'Ti2 ZDrive [µm]': 553.74\n    },\n    {\n        'Time [s]': 2.04194662,\n        'Z-Series': 0.0,\n        'Exposure Time [ms]': 100.0,\n        'PFS Offset': 0,\n        'PFS Status': 0,\n        'X Coord [µm]': 31452.2,\n        'Y Coord [µm]': -1801.6,\n        'Z Coord [µm]': 554.74,\n        'Ti2 ZDrive [µm]': 554.74\n    },\n    {\n        'Time [s]': 2.38194662,\n        'Z-Series': 1.0,\n        'Exposure Time [ms]': 100.0,\n        'PFS Offset': 0,\n        'PFS Status': 0,\n        'X Coord [µm]': 31452.2,\n        'Y Coord [µm]': -1801.6,\n        'Z Coord [µm]': 555.74,\n        'Ti2 ZDrive [µm]': 555.74\n    },\n    {\n        'Time [s]': 2.63795663,\n        'Z-Series': 2.0,\n        'Exposure Time [ms]': 100.0,\n        'PFS Offset': 0,\n        'PFS Status': 0,\n        'X Coord [µm]': 31452.2,\n        'Y Coord [µm]': -1801.6,\n        'Z Coord [µm]': 556.74,\n        'Ti2 ZDrive [µm]': 556.74\n    }\n]\n\n# with `orient='list'`\n{\n    'Time [s]': array([1.32686654, 1.69089657, 2.04194662, 2.38194662, 2.63795663]),\n    'Z-Series': array([-2., -1.,  0.,  1.,  2.]),\n    'Exposure Time [ms]': array([100., 100., 100., 100., 100.]),\n    'PFS Offset': array([0, 0, 0, 0, 0], dtype=int32),\n    'PFS Status': array([0, 0, 0, 0, 0], dtype=int32),\n    'X Coord [µm]': array([31452.2, 31452.2, 31452.2, 31452.2, 31452.2]),\n    'Y Coord [µm]': array([-1801.6, -1801.6, -1801.6, -1801.6, -1801.6]),\n    'Z Coord [µm]': array([552.74, 553.74, 554.74, 555.74, 556.74]),\n    'Ti2 ZDrive [µm]': array([552.74, 553.74, 554.74, 555.74, 556.74])\n}\n\n# with `orient='dict'`\n{\n    'Time [s]': {0: 1.32686654, 1: 1.69089657, 2: 2.04194662, 3: 2.38194662, 4: 2.63795663},\n    'Z-Series': {0: -2.0, 1: -1.0, 2: 0.0, 3: 1.0, 4: 2.0},\n    'Exposure Time [ms]': {0: 100.0, 1: 100.0, 2: 100.0, 3: 100.0, 4: 100.0},\n    'PFS Offset []': {0: 0, 1: 0, 2: 0, 3: 0, 4: 0},\n    'PFS Status []': {0: 0, 1: 0, 2: 0, 3: 0, 4: 0},\n    'X Coord [µm]': {0: 31452.2, 1: 31452.2, 2: 31452.2, 3: 31452.2, 4: 31452.2},\n    'Y Coord [µm]': {0: -1801.6, 1: -1801.6, 2: -1801.6, 3: -1801.6, 4: -1801.6},\n    'Z Coord [µm]': {0: 552.74, 1: 553.74, 2: 554.74, 3: 555.74, 4: 556.74},\n    'Ti2 ZDrive [µm]': {0: 552.74, 1: 553.74, 2: 554.74, 3: 555.74, 4: 556.74}\n}\n\n\n```\n\nYou can pass the output of `events()` to `pandas.DataFrame`:\n\n```python\nIn [1]: pd.DataFrame(nd2file.events())\nOut[1]:\n     Time [s]  Z-Series  Exposure Time [ms]  PFS Offset  PFS Status []  X Coord [µm]  Y Coord [µm]  Z Coord [µm]  Ti2 ZDrive [µm]\n0    1.326867      -2.0               100.0              0              0       31452.2       -1801.6        552.74           552.74\n1    1.690897      -1.0               100.0              0              0       31452.2       -1801.6        553.74           553.74\n2    2.041947       0.0               100.0              0              0       31452.2       -1801.6        554.74           554.74\n3    2.381947       1.0               100.0              0              0       31452.2       -1801.6        555.74           555.74\n4    2.637957       2.0               100.0              0              0       31452.2       -1801.6        556.74           556.74\n5    8.702229      -2.0               100.0              0              0       31452.2       -1801.6        552.70           552.70\n6    9.036269      -1.0               100.0              0              0       31452.2       -1801.6        553.70           553.70\n7    9.330319       0.0               100.0              0              0       31452.2       -1801.6        554.68           554.68\n8    9.639349       1.0               100.0              0              0       31452.2       -1801.6        555.70           555.70\n9    9.906369       2.0               100.0              0              0       31452.2       -1801.6        556.64           556.64\n10  11.481439      -2.0               100.0              0              0       31452.2       -1801.6        552.68           552.68\n11  11.796479      -1.0               100.0              0              0       31452.2       -1801.6        553.68           553.68\n12  12.089479       0.0               100.0              0              0       31452.2       -1801.6        554.68           554.68\n13  12.371539       1.0               100.0              0              0       31452.2       -1801.6        555.68           555.68\n14  12.665469       2.0               100.0              0              0       31452.2       -1801.6        556.68           556.68\n\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\n\u003csummary\u003e\u003ccode\u003eome_metadata()\u003c/code\u003e\u003c/summary\u003e\n\nSee the [ome-types documentation](https://ome-types.readthedocs.io/) for details on\nthe `OME` type returned by this method.\n\n```python\nIn [1]: ome = nd2file.ome_metadata()\n\nIn [2]: print(ome)\nOME(\n    instruments=[\u003c1 Instrument\u003e],\n    images=[\u003c1 Image\u003e],\n    creator='nd2 v0.7.1'\n)\n\nIn [3]: print(ome.to_xml())\n\u003cOME xmlns=\"http://www.openmicroscopy.org/Schemas/OME/2016-06\"\n     xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n     xsi:schemaLocation=\"http://www.openmicroscopy.org/Schemas/OME/2016-06 http://www.openmicroscopy.org/Schemas/OME/2016-06/ome.xsd\"\n     Creator=\"nd2 v0.7.1.dev2+g4ea166e.d20230709\"\u003e\n  \u003cInstrument ID=\"Instrument:0\"\u003e\n    \u003cDetector Model=\"Hamamatsu Dual C14440-20UP\" SerialNumber=\"Hamamatsu Dual C14440-20UP\" ID=\"Detector:0\"/\u003e\n  \u003c/Instrument\u003e\n  \u003cImage ID=\"Image:0\" Name=\"test39\"\u003e\n    \u003cAcquisitionDate\u003e2023-07-08T09:30:55\u003c/AcquisitionDate\u003e\n    ...\n```\n\n\u003c/details\u003e\n\n## Contributing / Development\n\nTo test locally and contribute. Clone this repo, then:\n\n```\npip install -e .[dev]\n```\n\nTo download sample data:\n\n```\npip install requests\npython scripts/download_samples.py\n```\n\nthen run tests:\n\n```\npytest\n```\n\n(and feel free to open an issue if that doesn't work!)\n\n## alternatives\n\nHere are some other nd2 readers that I know of, though many\nof them are unmaintained:\n\n- [pims_nd2](https://github.com/soft-matter/pims_nd2) - _pims-based reader.\n  ctypes wrapper around the v9.00 (2015) SDK_\n- [nd2reader](https://github.com/rbnvrw/nd2reader) - _pims-based reader, using\n  reverse-engineered file headers. mostly tested on files from NIS Elements\n  4.30.02_\n- [nd2file](https://github.com/csachs/nd2file) - _another pure-python, chunk map\n  reader, unmaintained?_\n- [pyND2SDK](https://github.com/aarpon/pyND2SDK) - _windows-only cython wrapper\n  around the v9.00 (2015) SDK. not on PyPI_\n\nThe motivating factors for this library were:\n\n- support for as many nd2 files as possible, with a large test suite\n  an and emphasis on correctness\n- pims-independent delayed reader based on dask\n- axis-associated metadata via xarray\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftlambert03%2Fnd2","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftlambert03%2Fnd2","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftlambert03%2Fnd2/lists"}