Skip to main content

Yet another nd2 (Nikon NIS Elements) file reader

Project description

nd2

License PyPI Python Version Tests codecov

Yet another .nd2 (Nikon NIS Elements) file reader.

This reader provides a Cython wrapper for the official Nikon SDK. (The actual reading of image frames, however, uses a direct memmap approach, instead of the SDK, for performance reasons and to avoid occasional segfaults from the SDK.)

Features good metadata retrieval, and direct to_dask and to_xarray options for lazy and/or annotated arrays.

This library is tested against many nd2 files with the goal of maximizing compatibility and data extraction. (If you find an nd2 file that fails in some way, please open an issue with the file!)

install

pip install nd2

or from conda:

conda install -c conda-forge nd2

extras

Legacy nd2 (JPEG2000) files are also supported, but require imagecodecs. To install with support for these files use:

pip install nd2[legacy]

usage and API

import nd2
import numpy as np

my_array = nd2.imread('some_file.nd2')                          # read to numpy array
my_array = nd2.imread('some_file.nd2', dask=True)               # read to dask array
my_array = nd2.imread('some_file.nd2', xarray=True)             # read to xarray
my_array = nd2.imread('some_file.nd2', xarray=True, dask=True)  # read file to dask-xarray

# or open a file with nd2.ND2File
f = nd2.ND2File('some_file.nd2')

# (you can also use nd2.ND2File() as a context manager)
with nd2.ND2File('some_file.nd2') as ndfile:
    print(ndfile.metadata)
    ...


# ATTRIBUTES:   # example output
f.path          # 'some_file.nd2'
f.shape         # (10, 2, 256, 256)
f.ndim          # 4
f.dtype         # np.dtype('uint16')
f.size          # 1310720  (total voxel elements)
f.sizes         # {'T': 10, 'C': 2, 'Y': 256, 'X': 256}
f.is_rgb        # False (whether the file is rgb)
                # if the file is RGB, `f.sizes` will have
                # an additional {'S': 3} component

# ARRAY OUTPUTS
f.asarray()         # in-memory np.ndarray - or use np.asarray(f)
f.to_dask()         # delayed dask.array.Array
f.to_xarray()       # in-memory xarray.DataArray, with labeled axes/coords
f.to_xarray(delayed=True)   # delayed xarray.DataArray

                    # see below for examples of these structures
# METADATA          # returns instance of ...
f.attributes        # nd2.structures.Attributes
f.metadata          # nd2.structures.Metadata
f.frame_metadata(0) # nd2.structures.FrameMetadata (frame-specific meta)
f.experiment        # List[nd2.structures.ExpLoop]
f.rois              # Dict[int, nd2.structures.ROI]
f.voxel_size()      # VoxelSize(x=0.65, y=0.65, z=1.0)
f.text_info         # dict of misc info

f.binary_data       # any binary masks stored in the file.  See below.
f.custom_data       # bits of unstructured metadata that start with CustomData
f.recorded_data     # returns a dict of lists (passable to pandas.DataFrame) that
                    # the tabular "Recorded Data" view from in NIS Elements/Viewer
                    # with info for each frame in the experiment.

# allll the metadata we can find...
# no attempt made to standardize or parse it
# look in here if you're searching for metdata that isn't exposed in the above
f.unstructured_metadata()

f.close()           # don't forget to close when not using a contet manager!
f.closed            # boolean, whether the file is closed

Metadata structures

These follow the structure of the nikon SDK outputs (where relevant). Here are some example outputs

attributes
Attributes(
    bitsPerComponentInMemory=16,
    bitsPerComponentSignificant=16,
    componentCount=2,
    heightPx=32,
    pixelDataType='unsigned',
    sequenceCount=60,
    widthBytes=128,
    widthPx=32,
    compressionLevel=None,
    compressionType=None,
    tileHeightPx=None,
    tileWidthPx=None,
    channelCount=2
)
metadata

Note: the metadata for legacy (JPEG2000) files will be a plain unstructured dict.

Metadata(
    contents=Contents(channelCount=2, frameCount=60),
    channels=[
        Channel(
            channel=ChannelMeta(name='Widefield Green', index=0, colorRGB=65371, emissionLambdaNm=535.0, excitationLambdaNm=None),
            loops=LoopIndices(NETimeLoop=None, TimeLoop=0, XYPosLoop=1, ZStackLoop=2),
            microscope=Microscope(
                objectiveMagnification=10.0,
                objectiveName='Plan Fluor 10x Ph1 DLL',
                objectiveNumericalAperture=0.3,
                zoomMagnification=1.0,
                immersionRefractiveIndex=1.0,
                projectiveMagnification=None,
                pinholeDiameterUm=None,
                modalityFlags=['fluorescence']
            ),
            volume=Volume(
                axesCalibrated=[True, True, True],
                axesCalibration=[0.652452890023035, 0.652452890023035, 1.0],
                axesInterpretation=(
                    <AxisInterpretation.distance: 'distance'>,
                    <AxisInterpretation.distance: 'distance'>,
                    <AxisInterpretation.distance: 'distance'>
                ),
                bitsPerComponentInMemory=16,
                bitsPerComponentSignificant=16,
                cameraTransformationMatrix=[-0.9998932296054086, -0.014612644841559427, 0.014612644841559427, -0.9998932296054086],
                componentCount=1,
                componentDataType='unsigned',
                voxelCount=[32, 32, 5],
                componentMaxima=[0.0],
                componentMinima=[0.0],
                pixelToStageTransformationMatrix=None
            )
        ),
        Channel(
            channel=ChannelMeta(name='Widefield Red', index=1, colorRGB=22015, emissionLambdaNm=620.0, excitationLambdaNm=None),
            loops=LoopIndices(NETimeLoop=None, TimeLoop=0, XYPosLoop=1, ZStackLoop=2),
            microscope=Microscope(
                objectiveMagnification=10.0,
                objectiveName='Plan Fluor 10x Ph1 DLL',
                objectiveNumericalAperture=0.3,
                zoomMagnification=1.0,
                immersionRefractiveIndex=1.0,
                projectiveMagnification=None,
                pinholeDiameterUm=None,
                modalityFlags=['fluorescence']
            ),
            volume=Volume(
                axesCalibrated=[True, True, True],
                axesCalibration=[0.652452890023035, 0.652452890023035, 1.0],
                axesInterpretation=(
                    <AxisInterpretation.distance: 'distance'>,
                    <AxisInterpretation.distance: 'distance'>,
                    <AxisInterpretation.distance: 'distance'>
                ),
                bitsPerComponentInMemory=16,
                bitsPerComponentSignificant=16,
                cameraTransformationMatrix=[-0.9998932296054086, -0.014612644841559427, 0.014612644841559427, -0.9998932296054086],
                componentCount=1,
                componentDataType='unsigned',
                voxelCount=[32, 32, 5],
                componentMaxima=[0.0],
                componentMinima=[0.0],
                pixelToStageTransformationMatrix=None
            )
        )
    ]
)
experiment
[
    TimeLoop(
        count=3,
        nestingLevel=0,
        parameters=TimeLoopParams(
            startMs=0.0,
            periodMs=1.0,
            durationMs=0.0,
            periodDiff=PeriodDiff(avg=16278.339965820312, max=16411.849853515625, min=16144.830078125)
        ),
        type='TimeLoop'
    ),
    XYPosLoop(
        count=4,
        nestingLevel=1,
        parameters=XYPosLoopParams(
            isSettingZ=True,
            points=[
                Position(stagePositionUm=[26950.2, -1801.6000000000001, 498.46000000000004], pfsOffset=None, name=None),
                Position(stagePositionUm=[31452.2, -1801.6000000000001, 670.7], pfsOffset=None, name=None),
                Position(stagePositionUm=[35234.3, 2116.4, 664.08], pfsOffset=None, name=None),
                Position(stagePositionUm=[40642.9, -3585.1000000000004, 555.12], pfsOffset=None, name=None)
            ]
        ),
        type='XYPosLoop'
    ),
    ZStackLoop(count=5, nestingLevel=2, parameters=ZStackLoopParams(homeIndex=2, stepUm=1.0, bottomToTop=True, deviceName='Ti2 ZDrive'), type='ZStackLoop')
]
rois

ROIs found in the metadata are available at ND2File.rois, which is a dict of nd2.structures.ROI objects, keyed by the ROI ID:

{
    1: ROI(
        id=1,
        info=RoiInfo(
            shapeType=<RoiShapeType.Rectangle: 3>,
            interpType=<InterpType.StimulationROI: 4>,
            cookie=1,
            color=255,
            label='',
            stimulationGroup=0,
            scope=1,
            appData=0,
            multiFrame=False,
            locked=False,
            compCount=2,
            bpc=16,
            autodetected=False,
            gradientStimulation=False,
            gradientStimulationBitDepth=0,
            gradientStimulationLo=0.0,
            gradientStimulationHi=0.0
        ),
        guid='{87190352-9B32-46E4-8297-C46621C1E1EF}',
        animParams=[
            AnimParam(
                timeMs=0.0,
                enabled=1,
                centerX=-0.4228425369685782,
                centerY=-0.5194951478743071,
                centerZ=0.0,
                rotationZ=0.0,
                boxShape=BoxShape(
                    sizeX=0.21256931608133062,
                    sizeY=0.21441774491682075,
                    sizeZ=0.0
                ),
                extrudedShape=ExtrudedShape(sizeZ=0, basePoints=[])
            )
        ]
    ),
    ...
}
text_info
{
    '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',
    'date': '9/28/2021  9:41:27 AM',
    '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',
    'optics': 'Plan Fluor 10x Ph1 DLL'
}
custom_data

No attempt is made to parse this data. It will vary from file to file, but you may find something useful here:

{
    'StreamDataV1_0': {
        'Vector_StreamAnalogIn': '',
        'Vector_StreamDigitalIn': '',
        'Vector_AnalogIn': '',
        'Vector_DigitalIn': '',
        'Vector_Other': '',
        'Vector_StreamAnalogOut': '',
        'Vector_StreamDigitalOut': '',
        'Vector_AnalogOut': '',
        'Vector_DigitalOut': ''
    },
    'NDControlV1_0': {
        'NDControl': {
            'LoopState': {'no_name': [529, 529, 529, 529, 529]},
            'PlayFPS': {'no_name': [20.0, 20.0, 0.0, 20.0, 0.0]},
            'LoopSize': {'no_name': [3, 4, 0, 5, 0]},
            'LoopPosition': {'no_name': [2, 3, 0, 4, 0]},
            'LoopSelection': {'no_name': [b'AAAA', b'AAAAAA==', b'', b'AAAAAAA=', b'']},
            'LoopRangeSelection': {'no_name': [b'AQEB', b'AQEBAQ==', b'', b'AQEBAQE=', b'']},
            'LoopEventSelection': {'no_name': [b'AAAA', b'AAAAAA==', b'', b'AAAAAAA=', b'']},
            'FramesInRange': '',
            'LoopStep': {'no_name': [0, 0, 0, 0, 0]},
            'UserEventType': 2,
            'SelectionStyle': 0,
            'FramesBefore': 2,
            'FramesAfter': 1,
            'TimeBefore': 1.0,
            'TimeAfter': 1.0
        }
    },
    'LUTDataV1_0': {
        'ViewLut': True,
        'LutParam': {
            'Gradient': 0,
            'GradientBrightField': 0,
            'MinSrc': 0,
            'MaxSrc': 65535,
            'GammaSrc': 1.0,
            'MinDst': 0,
            'MaxDst': 65535,
            'ColorSpace': 4,
            'Representation': 0,
            'LutComponentCount': 2,
            'GroupCount': 1,
            'CompLutParam': {
                '00': {'MinSrc': [82, 0.0], 'MaxSrc': [113, 1.0], 'GammaSrc': 1.0, 'MinDst': 0, 'MaxDst': 65535, 'Group': 0},
                '01': {'MinSrc': [82, 0.0], 'MaxSrc': [114, 1.0], 'GammaSrc': 1.0, 'MinDst': 0, 'MaxDst': 65535, 'Group': 0},
                '02': {'MinSrc': [0, 0.0], 'MaxSrc': [65535, 1.0], 'GammaSrc': 1.0, 'MinDst': 0, 'MaxDst': 65535, 'Group': 0}
            },
            'LutDataSpectral': {
                'GainTrueColor': 1.0,
                'OffsetTrueColor': 0.0,
                'GainGrayScale': 1.0,
                'OffsetGrayScal': 0.0,
                'SpectralColorMode': 0,
                'Group00': {
                    'ColorGroup': 16711680,
                    'ColorCustom': 16711680,
                    'GainCustom': 1.0,
                    'OffsetCustom': 0.0,
                    'GainGrouped': 1.0,
                    'OffsetGrouped': 0.0
                }
            }
        },
        'EnableAutoContrast': True,
        'EnableAutoWhite': True,
        'AutoWhiteColor': 16777215,
        'RatioDesc': {
            'Numer': 0,
            'Denom': 1,
            'NumOffset': 0,
            'DenOffset': 0,
            'Min': 0.0,
            'Max': 2.0,
            'BkgndSize': 0,
            'Calibrated': True,
            'Cal.dKd': 224.0,
            'Cal.dVisc': 1.0,
            'Cal.dFmin': 255.0,
            'Cal.dFmax': 1.0,
            'Cal.dRmin': 0.0,
            'Cal.dRmax': 2.0,
            'Cal.dTMeasCalMin': 0.0,
            'Cal.dTMeasCalMax': 0.0,
            'PickFromGraph': True,
            'RatioViewEnabled': True
        },
        'GraphSelected': -1,
        'GraphVerticalSplit': True,
        'GrayGraph': True,
        'ShowAllComp': True,
        'ShowSpectralGraph': True,
        'GraphScale': 0,
        'GraphZoom00': 1.0,
        'GraphOffset00': 0.0,
        'GraphZoom01': 1.0,
        'GraphOffset01': 0.0,
        'GraphZoom02': 1.0,
        'GraphOffset02': 0.0
    },
    'GrabberCameraSettingsV1_0': {
        'GrabberCameraSettings': {
            'CameraUniqueName': 'Hamamatsu C11440-22C SN:101412',
            'CameraUserName': 'Flash4.0, SN:101412',
            'CameraFamilyName': 'ecmC11440_22C',
            'OverloadedUniqueName': '',
            'ModifiedAtJDN': 2459486.07103009,
            'FormatFast': {
                'Desc': {
                    'UniqueName': 'FMT 1x1 16',
                    'Interpretation': 1,
                    'FQModeUsage': 15,
                    'CanExecAsyncSampleGet': True,
                    'Fps': 30.00300030003,
                    'Sensitivity': 1.0,
                    'SensorPixels': {'cx': 2048, 'cy': 2044},
                    'SensorMicrons': {'cx': 13312, 'cy': 13286},
                    'SensorMin': {'cx': 4, 'cy': 4},
                    'SensorStep': {'cx': 2, 'cy': 2},
                    'BinningX': 1.0,
                    'BinningY': 1.0,
                    'SensorSource': {'left': 0, 'top': 0, 'right': 2048, 'bottom': 2044},
                    'FormatText': '16-bit - No Binning',
                    'FormatDesc': '16-bit - No Binning (30.0 FPS)',
                    'CamCorrReq': True,
                    'Comp': 1,
                    'Bpc': 16,
                    'UsageFlags': 1
                },
                'SensorUser': {'left': 512, 'top': 512, 'right': 544, 'bottom': 544}
            },
            'FormatQuality': {
                'Desc': {
                    'UniqueName': 'FMT 1x1 16',
                    'Interpretation': 1,
                    'FQModeUsage': 15,
                    'CanExecAsyncSampleGet': True,
                    'Fps': 30.00300030003,
                    'Sensitivity': 1.0,
                    'SensorPixels': {'cx': 2048, 'cy': 2044},
                    'SensorMicrons': {'cx': 13312, 'cy': 13286},
                    'SensorMin': {'cx': 4, 'cy': 4},
                    'SensorStep': {'cx': 2, 'cy': 2},
                    'BinningX': 1.0,
                    'BinningY': 1.0,
                    'SensorSource': {'left': 0, 'top': 0, 'right': 2048, 'bottom': 2044},
                    'FormatText': '16-bit - No Binning',
                    'FormatDesc': '16-bit - No Binning (30.0 FPS)',
                    'CamCorrReq': True,
                    'Comp': 1,
                    'Bpc': 16,
                    'UsageFlags': 1
                },
                'SensorUser': {'left': 512, 'top': 512, 'right': 544, 'bottom': 544}
            },
            'PropertiesFast': {
                'Exposure': 100.0,
                'LiveSpeedUp': 1,
                'CaptureQuality': 75,
                'CaptureMaxExposure': 10000.0,
                'QuantilRelative': True,
                'QuantilPromile': 0.1,
                'QuantilPixels': 100,
                'EnableAutoExposure': True,
                'ScanMode': 2,
                'Average': 1,
                'Integrate': 1,
                'AverageToQuality': 0.0,
                'AverageCH': '',
                'IntegrateCH': '',
                'AverageToQualityCH': '',
                'IntegrateToQualityCH': '',
                'FlexibleHeight': -1,
                'Negate': 0,
                'MultiExcitation': ''
            },
            'PropertiesFast_Extra': {'PropGroupCount': 0, 'PropGroupUsageArray': {}, 'PropGroupNameArray': {}},
            'PropertiesQuality': {
                'Exposure': 100.0,
                'LiveSpeedUp': 1,
                'CaptureQuality': 75,
                'CaptureMaxExposure': 10000.0,
                'QuantilRelative': True,
                'QuantilPromile': 0.1,
                'QuantilPixels': 100,
                'EnableAutoExposure': True,
                'ScanMode': 2,
                'Average': 1,
                'Integrate': 1,
                'AverageToQuality': 0.0,
                'AverageCH': '',
                'IntegrateCH': '',
                'AverageToQualityCH': '',
                'IntegrateToQualityCH': '',
                'FlexibleHeight': -1,
                'Negate': 0,
                'MultiExcitation': ''
            },
            'PropertiesQuality_Extra': {
                'PropGroupCount': 1,
                'PropGroupUsageArray': {'0': 0},
                'PropGroupNameArray': {'0': 'Use Stored ROI'}
            },
            'Metadata': {
                'Key': 'MV=0,TA=0,CH=1',
                'ChannelCount': 1,
                'Channels': {
                    'Channel_0': {
                        'Color': 22015,
                        'Name': 'Widefield Red',
                        'EmWavelength': 620.0,
                        'ChannelIsActive': True,
                        'ExWavelength': 540.5,
                        'MaxSaturatedValue': 4294967295
                    }
                }
            },
            'LightPath': {
                'TypeID': 0,
                'ExcitationSourceKey': 'LIGHT-EPI',
                'ExcitationSourceName': '',
                'EPIAdditionalFilterKey': '',
                'EPIAdditionalFilterName': '',
                'DIAAdditionalFilterKey': '',
                'DIAAdditionalFilterName': '',
                'LastEmissionFilterKey1': 'Turret-Lo',
                'LastEmissionFilterName1': 'Nikon Ti2, FilterChanger(Turret-Lo)',
                'SetColorManually': True,
                'MultiViewEnabled': True,
                'UpdateLPAutomatically': True
            },
            'ROI': {'Left': 512, 'Top': 512, 'Right': 544, 'Bottom': 544}
        },
        'GrabberCameraSettingsFQMode': 1
    },
    'CustomDataV2_0': {
        'CustomTagDescription_v1.0': {
            'Tag0': {'ID': 'Camera_ExposureTime1', 'Type': 3, 'Group': 2, 'Size': 60, 'Desc': 'Exposure Time', 'Unit': 'ms'},
            'Tag1': {'ID': 'PFS_OFFSET', 'Type': 2, 'Group': 1, 'Size': 60, 'Desc': 'PFS Offset', 'Unit': ''},
            'Tag2': {'ID': 'PFS_STATUS', 'Type': 2, 'Group': 1, 'Size': 60, 'Desc': 'PFS Status', 'Unit': ''},
            'Tag3': {'ID': 'X', 'Type': 3, 'Group': 1, 'Size': 60, 'Desc': 'X Coord', 'Unit': 'µm'},
            'Tag4': {'ID': 'Y', 'Type': 3, 'Group': 1, 'Size': 60, 'Desc': 'Y Coord', 'Unit': 'µm'},
            'Tag5': {'ID': 'Z', 'Type': 3, 'Group': 1, 'Size': 60, 'Desc': 'Z Coord', 'Unit': 'µm'},
            'Tag6': {'ID': 'Z1', 'Type': 3, 'Group': 1, 'Size': 60, 'Desc': 'Ti2 ZDrive', 'Unit': 'µm'}
        }
    },
    'AppInfo_V1_0': {
        'SWNameString': 'NIS-Elements AR',
        'GrabberString': 'Hamamatsu',
        'VersionString': '5.20.02 (Build 1453)',
        'CopyrightString': 'Copyright © 1991-2019  Laboratory Imaging,  http://www.lim.cz',
        'CompanyString': 'NIKON Corporation',
        'NFRString': ''
    },
    'AcqTimeV1_0': 2459486.07044662
}
recorded_data

This property returns a dict of equal-length sequences. It matches the tabular data reported in the Image Properties > Recorded Data tab of the NIS Viewer.

(There will be a column for each tag in the CustomDataV2_0 section of custom_data above.)

{
    'Time [s]': array([ 1.32686654,  1.69089657,  2.04194662,  2.38194662,  2.63795663,
        8.7022286 ,  9.03626864,  9.33031869,  9.63934872,  9.90636874,
       11.48143856, 11.7964786 , 12.0894786 , 12.37153866, 12.66546859]),
    'Z-Series': array([-2., -1.,  0.,  1.,  2., -2., -1.,  0.,  1.,  2., -2., -1.,  0.,
        1.,  2.]),
    'Exposure Time [ms]': array([100., 100., 100., 100., 100., 100., 100., 100., 100., 100., 100.,
       100., 100., 100., 100.]),
    'PFS Offset []': array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], dtype=int32),
    'PFS Status []': array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], dtype=int32),
    'X Coord [µm]': array([31452.2, 31452.2, 31452.2, 31452.2, 31452.2, 31452.2, 31452.2,
       31452.2, 31452.2, 31452.2, 31452.2, 31452.2, 31452.2, 31452.2,
       31452.2]),
    'Y Coord [µm]': array([-1801.6, -1801.6, -1801.6, -1801.6, -1801.6, -1801.6, -1801.6,
       -1801.6, -1801.6, -1801.6, -1801.6, -1801.6, -1801.6, -1801.6,
       -1801.6]),
    'Z Coord [µm]': array([552.74, 553.74, 554.74, 555.74, 556.74, 552.7 , 553.7 , 554.68,
       555.7 , 556.64, 552.68, 553.68, 554.68, 555.68, 556.68]),
    'Ti2 ZDrive [µm]': array([552.74, 553.74, 554.74, 555.74, 556.74, 552.7 , 553.7 , 554.68,
       555.7 , 556.64, 552.68, 553.68, 554.68, 555.68, 556.68])
}

You can pass the output of recorded_data to pandas.DataFrame:

In [13]: pd.DataFrame(nd2file.recorded_data)
Out[13]:
     Time [s]  Z-Series  Exposure Time [ms]  PFS Offset []  PFS Status []  X Coord [µm]  Y Coord [µm]  Z Coord [µm]  Ti2 ZDrive [µm]
0    1.326867      -2.0               100.0              0              0       31452.2       -1801.6        552.74           552.74
1    1.690897      -1.0               100.0              0              0       31452.2       -1801.6        553.74           553.74
2    2.041947       0.0               100.0              0              0       31452.2       -1801.6        554.74           554.74
3    2.381947       1.0               100.0              0              0       31452.2       -1801.6        555.74           555.74
4    2.637957       2.0               100.0              0              0       31452.2       -1801.6        556.74           556.74
5    8.702229      -2.0               100.0              0              0       31452.2       -1801.6        552.70           552.70
6    9.036269      -1.0               100.0              0              0       31452.2       -1801.6        553.70           553.70
7    9.330319       0.0               100.0              0              0       31452.2       -1801.6        554.68           554.68
8    9.639349       1.0               100.0              0              0       31452.2       -1801.6        555.70           555.70
9    9.906369       2.0               100.0              0              0       31452.2       -1801.6        556.64           556.64
10  11.481439      -2.0               100.0              0              0       31452.2       -1801.6        552.68           552.68
11  11.796479      -1.0               100.0              0              0       31452.2       -1801.6        553.68           553.68
12  12.089479       0.0               100.0              0              0       31452.2       -1801.6        554.68           554.68
13  12.371539       1.0               100.0              0              0       31452.2       -1801.6        555.68           555.68
14  12.665469       2.0               100.0              0              0       31452.2       -1801.6        556.68           556.68
binary_data

This property returns an nd2.BinaryLayers object representing all of the binary masks in the nd2 file.

A nd2.BinaryLayers object is a sequence of individual nd2.BinaryLayer objects (one for each binary layer found in the file). Each BinaryLayer in the sequence is a named tuple that has, among other things, a name attribute, and a data attribute that is list of numpy arrays (one for each frame in the experiment) or None if the binary layer had no data in that frame.

The most common use case will be to cast either the entire BinaryLayers object or an individual BinaryLayer to a numpy.ndarray:

>>> import nd2
>>> nd2file = nd2.ND2File('path/to/file.nd2')
>>> binary_layers = nd2file.binary_data

# The output array will have shape
# (n_binary_layers, *coord_shape, *frame_shape).
>>> np.asarray(binary_layers)

For example, if the data in the nd2 file has shape (nT, nZ, nC, nY, nX), and there are 4 binary layers, then the output of np.asarray(nd2file.binary_data) will have shape (4, nT, nZ, nY, nX). (Note that the nC dimension is not present in the output array, and the binary layers are always in the first axis).

You can also cast an individual BinaryLayer to a numpy array:

>>> binary_layer = binary_layers[0]
>>> np.asarray(binary_layer)

Contributing / Development

To test locally and contribute. Clone this repo, then:

pip install -e .[dev]

To download sample data:

pip install requests
python scripts/download_samples.py

then run tests:

pytest

(and feel free to open an issue if that doesn't work!)

alternatives

  • pims_nd2 - pims-based reader. ctypes wrapper around the v9.00 (2015) SDK
  • nd2reader - pims-based reader, using reverse-engineered file headers. mostly tested on NIS Elements 4.30.02
  • nd2file - another pure-python, chunk map reader, unmaintained?
  • pyND2SDK - windows-only cython wrapper around the v9.00 (2015) SDK. not on PyPI

The motivating factors for this library were:

  • support for as many nd2 files as possible, with a large test suite
  • pims-independent delayed reader based on dask
  • axis-associated metadata via xarray
  • combined approach of SDK and direct binary reads

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nd2-0.5.2.tar.gz (6.8 MB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

nd2-0.5.2-cp311-cp311-win_amd64.whl (769.4 kB view details)

Uploaded CPython 3.11Windows x86-64

nd2-0.5.2-cp311-cp311-manylinux_2_24_x86_64.whl (1.6 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.24+ x86-64

nd2-0.5.2-cp311-cp311-macosx_11_0_arm64.whl (1.1 MB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

nd2-0.5.2-cp311-cp311-macosx_10_9_x86_64.whl (1.2 MB view details)

Uploaded CPython 3.11macOS 10.9+ x86-64

nd2-0.5.2-cp310-cp310-win_amd64.whl (770.9 kB view details)

Uploaded CPython 3.10Windows x86-64

nd2-0.5.2-cp310-cp310-manylinux_2_24_x86_64.whl (1.6 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.24+ x86-64

nd2-0.5.2-cp310-cp310-macosx_11_0_arm64.whl (1.1 MB view details)

Uploaded CPython 3.10macOS 11.0+ ARM64

nd2-0.5.2-cp310-cp310-macosx_10_9_x86_64.whl (1.2 MB view details)

Uploaded CPython 3.10macOS 10.9+ x86-64

nd2-0.5.2-cp39-cp39-win_amd64.whl (771.9 kB view details)

Uploaded CPython 3.9Windows x86-64

nd2-0.5.2-cp39-cp39-manylinux_2_24_x86_64.whl (1.6 MB view details)

Uploaded CPython 3.9manylinux: glibc 2.24+ x86-64

nd2-0.5.2-cp39-cp39-macosx_11_0_arm64.whl (1.1 MB view details)

Uploaded CPython 3.9macOS 11.0+ ARM64

nd2-0.5.2-cp39-cp39-macosx_10_9_x86_64.whl (1.2 MB view details)

Uploaded CPython 3.9macOS 10.9+ x86-64

nd2-0.5.2-cp38-cp38-win_amd64.whl (772.2 kB view details)

Uploaded CPython 3.8Windows x86-64

nd2-0.5.2-cp38-cp38-manylinux_2_24_x86_64.whl (1.6 MB view details)

Uploaded CPython 3.8manylinux: glibc 2.24+ x86-64

nd2-0.5.2-cp38-cp38-macosx_11_0_arm64.whl (1.1 MB view details)

Uploaded CPython 3.8macOS 11.0+ ARM64

nd2-0.5.2-cp38-cp38-macosx_10_9_x86_64.whl (1.2 MB view details)

Uploaded CPython 3.8macOS 10.9+ x86-64

nd2-0.5.2-cp37-cp37m-win_amd64.whl (770.7 kB view details)

Uploaded CPython 3.7mWindows x86-64

nd2-0.5.2-cp37-cp37m-manylinux_2_24_x86_64.whl (1.6 MB view details)

Uploaded CPython 3.7mmanylinux: glibc 2.24+ x86-64

nd2-0.5.2-cp37-cp37m-macosx_10_9_x86_64.whl (1.2 MB view details)

Uploaded CPython 3.7mmacOS 10.9+ x86-64

File details

Details for the file nd2-0.5.2.tar.gz.

File metadata

  • Download URL: nd2-0.5.2.tar.gz
  • Upload date:
  • Size: 6.8 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.11.0

File hashes

Hashes for nd2-0.5.2.tar.gz
Algorithm Hash digest
SHA256 e5fcac3243ce85613811704432bf13df4d0003ff4ef9a7c05308c6930cc04642
MD5 7de6311fe8d1b8dbea838390b84e6a29
BLAKE2b-256 1dccf370ef5417fdbb26c3566f9a67a6f52ccdcd141205ff8f01518475ca52cd

See more details on using hashes here.

File details

Details for the file nd2-0.5.2-cp311-cp311-win_amd64.whl.

File metadata

  • Download URL: nd2-0.5.2-cp311-cp311-win_amd64.whl
  • Upload date:
  • Size: 769.4 kB
  • Tags: CPython 3.11, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.11.0

File hashes

Hashes for nd2-0.5.2-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 0c0eb077f5605de499318d58acfbaef6cd83b3f2ff39204f1bd2e73abc776664
MD5 f26f274ef77301216f4a0bc68b8703b4
BLAKE2b-256 0cf631567e00564186920da55e4371ae4522f3b7e770e9044be38c96e7f1c3f2

See more details on using hashes here.

File details

Details for the file nd2-0.5.2-cp311-cp311-manylinux_2_24_x86_64.whl.

File metadata

File hashes

Hashes for nd2-0.5.2-cp311-cp311-manylinux_2_24_x86_64.whl
Algorithm Hash digest
SHA256 7c6acf8560412b3c754f9252ad2aa3df64a25eaf2a15bccd5e906ee7bf1899f8
MD5 2204fc7c5b6f2ef07222af5331e56ca5
BLAKE2b-256 3fc74800407003d1345069e9c0b650b967b1682178267fa3f50ccf4149ecd1ce

See more details on using hashes here.

File details

Details for the file nd2-0.5.2-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for nd2-0.5.2-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 8f42c9b12de3da993c8696605698ed0a5a3f1b419a51144a01d8bd62b276e6ac
MD5 25519f34e23e646187a941bd976ad1b1
BLAKE2b-256 8703005419bd91ebd0a01ba2be99011e7ce95e6e7e969ae55a7d47cb9ffa6202

See more details on using hashes here.

File details

Details for the file nd2-0.5.2-cp311-cp311-macosx_10_9_x86_64.whl.

File metadata

File hashes

Hashes for nd2-0.5.2-cp311-cp311-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 a019d9415809fded158b95330c331c9c4a5cc942086ef9fdc9c1bb25f7e547a5
MD5 a8134ae493dcda0b0f9fefd58eb8c8c5
BLAKE2b-256 8020627d5a863ae09aaccfee607b39520b262d1f7953376f10fd997dd45fd525

See more details on using hashes here.

File details

Details for the file nd2-0.5.2-cp310-cp310-win_amd64.whl.

File metadata

  • Download URL: nd2-0.5.2-cp310-cp310-win_amd64.whl
  • Upload date:
  • Size: 770.9 kB
  • Tags: CPython 3.10, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.11.0

File hashes

Hashes for nd2-0.5.2-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 e672da588ca6e3dc58a1ce5fb90b3235638a1c7b0ffdef60ee3dedc6e03fce31
MD5 3ba7277516837dfb5aba33a38e987df5
BLAKE2b-256 7fcb7078970ee006f7683d1db6e99fee2ac5fa73ab8b5b9e896c6c8b54a66318

See more details on using hashes here.

File details

Details for the file nd2-0.5.2-cp310-cp310-manylinux_2_24_x86_64.whl.

File metadata

File hashes

Hashes for nd2-0.5.2-cp310-cp310-manylinux_2_24_x86_64.whl
Algorithm Hash digest
SHA256 dc99f7f26ae7c0f0918c8920e959b9a46989829b3aa4105076f58d151889e18b
MD5 bae09605b9ab1e5d02a9b75387ff3f41
BLAKE2b-256 dfdccfcd1aba7a59db06bb7e9cf96db6e8ac65cc62bd7947acadfd1d0a965063

See more details on using hashes here.

File details

Details for the file nd2-0.5.2-cp310-cp310-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for nd2-0.5.2-cp310-cp310-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 2c1b8f8f9d55702c947ebc258408d77d5fd5febbcf98d5700130631970222599
MD5 c7ceb35135022f13bb80354464b72942
BLAKE2b-256 bf053f0ef1788936a429576307b2a2127f308a63b42e8a90d7252d4fef180679

See more details on using hashes here.

File details

Details for the file nd2-0.5.2-cp310-cp310-macosx_10_9_x86_64.whl.

File metadata

File hashes

Hashes for nd2-0.5.2-cp310-cp310-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 7f8f11b9a207cc2d45188595bca1812f247e431beb18c9815e353f32ab29f6fe
MD5 176667ce0900c90b1ed0d6dbb8ee4c81
BLAKE2b-256 5579942e5655dde123fe264417f4af3aaf2ea44b2362c239ced1ac50c3dc391f

See more details on using hashes here.

File details

Details for the file nd2-0.5.2-cp39-cp39-win_amd64.whl.

File metadata

  • Download URL: nd2-0.5.2-cp39-cp39-win_amd64.whl
  • Upload date:
  • Size: 771.9 kB
  • Tags: CPython 3.9, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.11.0

File hashes

Hashes for nd2-0.5.2-cp39-cp39-win_amd64.whl
Algorithm Hash digest
SHA256 a0a0e8eea84e7d9c9865c343f45b9652c7aa5b814184db8b1fd94ec1f8c19c71
MD5 c5d1095e57ee77a8f34a92469fd788b2
BLAKE2b-256 5d263d7987ea895f97890fee966fb191289c0d76bd92ebe7c1fcc84e46cca15f

See more details on using hashes here.

File details

Details for the file nd2-0.5.2-cp39-cp39-manylinux_2_24_x86_64.whl.

File metadata

  • Download URL: nd2-0.5.2-cp39-cp39-manylinux_2_24_x86_64.whl
  • Upload date:
  • Size: 1.6 MB
  • Tags: CPython 3.9, manylinux: glibc 2.24+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.11.0

File hashes

Hashes for nd2-0.5.2-cp39-cp39-manylinux_2_24_x86_64.whl
Algorithm Hash digest
SHA256 24b666cde350fd7da293489a9e8cc1c36abbd8395b8cba393c8ef4160f39a0da
MD5 0d220b66a2c3fec2493459ab6db2031c
BLAKE2b-256 2d90277f334b9109f7d441787ea9a5108a427218dfe89b1b364bfc3fbe54744f

See more details on using hashes here.

File details

Details for the file nd2-0.5.2-cp39-cp39-macosx_11_0_arm64.whl.

File metadata

  • Download URL: nd2-0.5.2-cp39-cp39-macosx_11_0_arm64.whl
  • Upload date:
  • Size: 1.1 MB
  • Tags: CPython 3.9, macOS 11.0+ ARM64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.11.0

File hashes

Hashes for nd2-0.5.2-cp39-cp39-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 9bf14a40b49c9bcb4ac157bb10fc7d1c96af5f2cbb1ee16e048fbc318a6a4df4
MD5 c38f9a17fdf4d38edc3e306ad0cdc797
BLAKE2b-256 a9ef5afc28048edce3d1dbd17825c143491cc2284345ff6091d92c601528ac27

See more details on using hashes here.

File details

Details for the file nd2-0.5.2-cp39-cp39-macosx_10_9_x86_64.whl.

File metadata

  • Download URL: nd2-0.5.2-cp39-cp39-macosx_10_9_x86_64.whl
  • Upload date:
  • Size: 1.2 MB
  • Tags: CPython 3.9, macOS 10.9+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.11.0

File hashes

Hashes for nd2-0.5.2-cp39-cp39-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 2cbad03a76e78b16775756d3205e43118091433b00edf5dd98eb1398083d6572
MD5 43c7ac82214e2d6197f2a3fb5f62326c
BLAKE2b-256 9b56cb178a93a4c060ecaf85b3a5e5d06730e76cae1aa8ca89bc7ab1e5b3e353

See more details on using hashes here.

File details

Details for the file nd2-0.5.2-cp38-cp38-win_amd64.whl.

File metadata

  • Download URL: nd2-0.5.2-cp38-cp38-win_amd64.whl
  • Upload date:
  • Size: 772.2 kB
  • Tags: CPython 3.8, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.11.0

File hashes

Hashes for nd2-0.5.2-cp38-cp38-win_amd64.whl
Algorithm Hash digest
SHA256 a4d47d1aa22e08958344611f8aef397eede68c309859df20d38249a4695815ae
MD5 26ba032813854df73cea6d6648982d6c
BLAKE2b-256 cb79a4826455cebfef42ae46be3358f9d667f3bf28cc687168c322aba2392b95

See more details on using hashes here.

File details

Details for the file nd2-0.5.2-cp38-cp38-manylinux_2_24_x86_64.whl.

File metadata

  • Download URL: nd2-0.5.2-cp38-cp38-manylinux_2_24_x86_64.whl
  • Upload date:
  • Size: 1.6 MB
  • Tags: CPython 3.8, manylinux: glibc 2.24+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.11.0

File hashes

Hashes for nd2-0.5.2-cp38-cp38-manylinux_2_24_x86_64.whl
Algorithm Hash digest
SHA256 9a5cb82a0705b09c329db9a530c6e3a329300e5f106dc97e2576f11ac9641e43
MD5 232b050c3b46616bdaf94abff69482b5
BLAKE2b-256 681a2985a97d864fc8f98aaf6bae8cd34b52fba9d4e3a6463655e0a0431b7cc2

See more details on using hashes here.

File details

Details for the file nd2-0.5.2-cp38-cp38-macosx_11_0_arm64.whl.

File metadata

  • Download URL: nd2-0.5.2-cp38-cp38-macosx_11_0_arm64.whl
  • Upload date:
  • Size: 1.1 MB
  • Tags: CPython 3.8, macOS 11.0+ ARM64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.11.0

File hashes

Hashes for nd2-0.5.2-cp38-cp38-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 94059c4fa7459f50f19223b19b9cefe82db3f12bcd5379614205cdebf96697e3
MD5 30922c9145946850ac7da0b6d89888a8
BLAKE2b-256 213b986553c515b451bb47f6900cdf03915c1ba2f71b108d34f628f82fed23ad

See more details on using hashes here.

File details

Details for the file nd2-0.5.2-cp38-cp38-macosx_10_9_x86_64.whl.

File metadata

  • Download URL: nd2-0.5.2-cp38-cp38-macosx_10_9_x86_64.whl
  • Upload date:
  • Size: 1.2 MB
  • Tags: CPython 3.8, macOS 10.9+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.11.0

File hashes

Hashes for nd2-0.5.2-cp38-cp38-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 f86b19696a1e82c5d5a7e3fb0670af562bb22d33fe9651b9e935061d92cfcb23
MD5 4a4e253c06d8122d1e8cbd46c007a59b
BLAKE2b-256 053c1c071141325db7bf50732d580ef382d7aa46ff0f1b60c8917d4a72945461

See more details on using hashes here.

File details

Details for the file nd2-0.5.2-cp37-cp37m-win_amd64.whl.

File metadata

  • Download URL: nd2-0.5.2-cp37-cp37m-win_amd64.whl
  • Upload date:
  • Size: 770.7 kB
  • Tags: CPython 3.7m, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.11.0

File hashes

Hashes for nd2-0.5.2-cp37-cp37m-win_amd64.whl
Algorithm Hash digest
SHA256 8ce1fcdd310f1fa55d6d2d898d36b3fcad5a2adb979cfc29cf2e2c58794de29c
MD5 71a8fdd2e16a50428df6e82846a53e07
BLAKE2b-256 c99d9c63993287ab447813c8418e5380e6cc231b7806bf67430304a67871d224

See more details on using hashes here.

File details

Details for the file nd2-0.5.2-cp37-cp37m-manylinux_2_24_x86_64.whl.

File metadata

File hashes

Hashes for nd2-0.5.2-cp37-cp37m-manylinux_2_24_x86_64.whl
Algorithm Hash digest
SHA256 119ba2ec63278bb039b509a08cfb95f06b3d69c62fba74ef8a74aa863a872a9f
MD5 20614a629d5a7eab7734c0cd995936da
BLAKE2b-256 ad75f4ad772e8178c2d674c781e0e5d8640c6d334ae2352abe2053d3f3c20822

See more details on using hashes here.

File details

Details for the file nd2-0.5.2-cp37-cp37m-macosx_10_9_x86_64.whl.

File metadata

  • Download URL: nd2-0.5.2-cp37-cp37m-macosx_10_9_x86_64.whl
  • Upload date:
  • Size: 1.2 MB
  • Tags: CPython 3.7m, macOS 10.9+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.11.0

File hashes

Hashes for nd2-0.5.2-cp37-cp37m-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 033c0e8712f3c8ecda07621624397e35718ba44fb722758d70f9454d1db12698
MD5 2e68e8f92d1951cc2e6ee39af61fe164
BLAKE2b-256 19c3d5b94668400189603a9a4f4c6eabc5c19db4f6a3a4c796d8d7cd32d0eeaf

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page