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.1.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.1-cp311-cp311-win_amd64.whl (769.3 kB view details)

Uploaded CPython 3.11Windows x86-64

nd2-0.5.1-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.1-cp311-cp311-macosx_11_0_arm64.whl (1.1 MB view details)

Uploaded CPython 3.11macOS 11.0+ ARM64

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

Uploaded CPython 3.11macOS 10.9+ x86-64

nd2-0.5.1-cp310-cp310-win_amd64.whl (770.8 kB view details)

Uploaded CPython 3.10Windows x86-64

nd2-0.5.1-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.1-cp310-cp310-macosx_11_0_arm64.whl (1.1 MB view details)

Uploaded CPython 3.10macOS 11.0+ ARM64

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

Uploaded CPython 3.10macOS 10.9+ x86-64

nd2-0.5.1-cp39-cp39-win_amd64.whl (771.7 kB view details)

Uploaded CPython 3.9Windows x86-64

nd2-0.5.1-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.1-cp39-cp39-macosx_11_0_arm64.whl (1.1 MB view details)

Uploaded CPython 3.9macOS 11.0+ ARM64

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

Uploaded CPython 3.9macOS 10.9+ x86-64

nd2-0.5.1-cp38-cp38-win_amd64.whl (772.1 kB view details)

Uploaded CPython 3.8Windows x86-64

nd2-0.5.1-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.1-cp38-cp38-macosx_11_0_arm64.whl (1.1 MB view details)

Uploaded CPython 3.8macOS 11.0+ ARM64

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

Uploaded CPython 3.8macOS 10.9+ x86-64

nd2-0.5.1-cp37-cp37m-win_amd64.whl (770.6 kB view details)

Uploaded CPython 3.7mWindows x86-64

nd2-0.5.1-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.1-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.1.tar.gz.

File metadata

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

File hashes

Hashes for nd2-0.5.1.tar.gz
Algorithm Hash digest
SHA256 f9908301586d68cd304d4e144107d462042c43ea02a811ed87f07664e750dbb1
MD5 07427416ae4c2f9b6a65ca23564a32f4
BLAKE2b-256 2a2bb712850cda0bd11db1814b31ce7163f0d4768de0c71ed405156fbb20ff08

See more details on using hashes here.

File details

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

File metadata

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

File hashes

Hashes for nd2-0.5.1-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 67b2df9109e22742a2e360339b83eb646ec7e35ec0f92be6af04d8d39f4285a0
MD5 5a5c60e4697154c449c44c86bc08d05a
BLAKE2b-256 bc77087cb7d2060ca0f0fae7919572cf5aff3466d2c37cc19e81ed65f8c7f8bd

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for nd2-0.5.1-cp311-cp311-manylinux_2_24_x86_64.whl
Algorithm Hash digest
SHA256 8de326dd46d4dff46b5d5d6bed2a0da0d5fbed987211e571b80cd9b48524b2f1
MD5 4ffb69cbc2d69a365c94362f9fc76e41
BLAKE2b-256 0d055574cffc8a36175c47d0ef06f73cc9abff348c426b9f055e959423517df1

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for nd2-0.5.1-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 a24a3ce32c8d4eb59ec2c0b93f330c907140597cf8c3d0db830873093e6b367d
MD5 9e81a464cb960ed0e8b71bdf7bd05ed1
BLAKE2b-256 8270c1c1e488e37502dead68b842edc23f827683216659a7c1fdb20502a76ebd

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for nd2-0.5.1-cp311-cp311-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 ffa05489468e1ee104155e4abf978e779d2d3e5a2be45837241ab78cb050dcd4
MD5 1ad162da2613ca09d97d4ad76842dc53
BLAKE2b-256 68ba656b1a86a82c63d68a45b8b48be156132f18050d061887ec2250d7416036

See more details on using hashes here.

File details

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

File metadata

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

File hashes

Hashes for nd2-0.5.1-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 bcf137597266894117804760ac8286df75349584bc4084c2a3812edbcaa5571f
MD5 3dcc2c2d6113a150a327a4ca72782ebf
BLAKE2b-256 b149a5820d66c232f97bacc064ba04ec55d70de29932c53a48a7699469a093e3

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for nd2-0.5.1-cp310-cp310-manylinux_2_24_x86_64.whl
Algorithm Hash digest
SHA256 eaa6376d1ece7d319781faef369e6b2398a2e81a99e7924144ab91da3787f50c
MD5 2214af00a6639c7239607008fddba527
BLAKE2b-256 98c0be3678d29edf9c14bc8badaee3b92ad22b1b4a9dd6fb8a5220bf756abf7e

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for nd2-0.5.1-cp310-cp310-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 c756766302511116ca59b7aa40ac2c29940fe2643f8842396864b958f6bec06d
MD5 b88e0160b2983b434fb0d5f0ec5c887f
BLAKE2b-256 28f9b0ebd96e0f31c10aa48e9269572876bbf0a3ea0995df36ddf97d801dc1b1

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for nd2-0.5.1-cp310-cp310-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 56cfbf2753447ae2481e1aea17164d00a0412633c58e4d1ee126167de1ea5ee1
MD5 655d2d2bdc7451cb2b2bee53fab28d25
BLAKE2b-256 0915ea6f7bcc55972b8e403972d2b5c2f56f8ce56c3a37904d35efeaf38d38df

See more details on using hashes here.

File details

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

File metadata

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

File hashes

Hashes for nd2-0.5.1-cp39-cp39-win_amd64.whl
Algorithm Hash digest
SHA256 20df2f329ffae587195c54e39d63d9a42ab5c787ad3c94a719b0399059e68d28
MD5 471af1916aac266590edfc2ce03562af
BLAKE2b-256 e75fa66b9816f442772710afda47cf6617c614436875070bbc1fb1865563a472

See more details on using hashes here.

File details

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

File metadata

  • Download URL: nd2-0.5.1-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.9.15

File hashes

Hashes for nd2-0.5.1-cp39-cp39-manylinux_2_24_x86_64.whl
Algorithm Hash digest
SHA256 a24d013ba1f5516022a482ef76e3f0e627f62d19ce84e6b17a09b9db67d65ad6
MD5 a7b0a5350abc0bde6921207d5f847ae5
BLAKE2b-256 c4d381f7ee9ecf38a896f1a47474dc3d106ee7224a607cf1e6bb370524bc445d

See more details on using hashes here.

File details

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

File metadata

  • Download URL: nd2-0.5.1-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.9.15

File hashes

Hashes for nd2-0.5.1-cp39-cp39-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 f85bf9962ffd939fc3fbed5198f2220975106e1c58957910eaae20d8359196ca
MD5 20965718d8de74bfd1dbfe46a7752f43
BLAKE2b-256 39815da64b40033cfa0396140de12b7cd0c3c576b80cf6c2ba3158ee8af56f2a

See more details on using hashes here.

File details

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

File metadata

  • Download URL: nd2-0.5.1-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.9.15

File hashes

Hashes for nd2-0.5.1-cp39-cp39-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 998a9d6738829660ce8baa87d90c768c5c34031723b40ca235db99f1c1a8350b
MD5 5b81a41ea2dbeb2286e683a8358bcd45
BLAKE2b-256 a9c48d1eccd65815dbf2d2f38fce82e43fa6c9d252366cc68767f59bfec9537a

See more details on using hashes here.

File details

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

File metadata

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

File hashes

Hashes for nd2-0.5.1-cp38-cp38-win_amd64.whl
Algorithm Hash digest
SHA256 8fde749dbe8973f76cbbea64a182a9d8291982d761272b08931d6d17464353b7
MD5 8a91c1a55bf89c4dcaec9aa032b8c2ca
BLAKE2b-256 c8b4fea749cb03ca727582b9f5183461e82567571ac89615b1ff27838e1a790a

See more details on using hashes here.

File details

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

File metadata

  • Download URL: nd2-0.5.1-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.9.15

File hashes

Hashes for nd2-0.5.1-cp38-cp38-manylinux_2_24_x86_64.whl
Algorithm Hash digest
SHA256 ab707110dc60742145f8551aea50ccab45b498ceebfd447096bac4afcdf683e2
MD5 3a41538681b78613215db6558ca50aa4
BLAKE2b-256 4a44874aec96cb9b7143dbe56733116136103bc7dc2e0cadd15fa6b8b3e2a5a6

See more details on using hashes here.

File details

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

File metadata

  • Download URL: nd2-0.5.1-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.9.15

File hashes

Hashes for nd2-0.5.1-cp38-cp38-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 11b44e486567414e6b32c6e2172db30c93958afcebdc8f10f0415fa5805ef23f
MD5 734f4967bf73a1d454042e3b555723e0
BLAKE2b-256 c1f11864ea0fcb0c97634452571722fab10864c9fc36574d5b077a8c19f2d882

See more details on using hashes here.

File details

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

File metadata

  • Download URL: nd2-0.5.1-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.9.15

File hashes

Hashes for nd2-0.5.1-cp38-cp38-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 b4366eac63c29d9478d7295451ef61b1858158989e87784249d80f9bcb97f3ad
MD5 8b2beabc30b54f6be3216ffa6f588c2c
BLAKE2b-256 6610f9c23cdc2c23c1d01f7b69adda937e7627acfe22df35eb55ccf7bc00a632

See more details on using hashes here.

File details

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

File metadata

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

File hashes

Hashes for nd2-0.5.1-cp37-cp37m-win_amd64.whl
Algorithm Hash digest
SHA256 a4481b03c74ee940f71fa67fdf0710d2400ff3731e4e8759b55b241cdcccef4c
MD5 661afd7c26adb5a85184ce99cd7051db
BLAKE2b-256 e8a460cf66293769e6227efe1a0e6f898ef8081d7d4d1ed94d5fa2a1083bc846

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for nd2-0.5.1-cp37-cp37m-manylinux_2_24_x86_64.whl
Algorithm Hash digest
SHA256 3c52f403104d389340d465f98d0bd6b6fdfec4656ef8936ca99287a3e5e486b3
MD5 c42bc37b1415eab6a87ae29780c85074
BLAKE2b-256 b0450f83e030137d0708de4377d85e82e9d3c9e92ec29c9430c7c774ee636bd9

See more details on using hashes here.

File details

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

File metadata

  • Download URL: nd2-0.5.1-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.9.15

File hashes

Hashes for nd2-0.5.1-cp37-cp37m-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 bac8d355ccbdb3a93e363c88c537bf1822440f463783b287c557d5c875df9aac
MD5 d15dbd2e4326a3f4819cbbde86d2416b
BLAKE2b-256 8558c21df992c58ab345b286584bb6681282964e913838fc693e23b3966f96b2

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