tlambert03 / nd2

Full-featured nd2 (Nikon NIS Elements) file reader for python. Outputs to numpy, dask, and xarray. Exhaustive metadata extraction
https://tlambert03.github.io/nd2
BSD 3-Clause "New" or "Revised" License
54 stars 15 forks source link

Difference between NETimeLoop and TimeLoop? #121

Closed gatoniel closed 1 year ago

gatoniel commented 1 year ago

Hi, this is not a bug report as I think it is actually related to the information that NIS Elements itself saves to the nd2 files. However, I have pretty much the same experimental files but from two different microscopes running with the same settings (I haven't checked the concrete NIS Elements versions yet, though). For all experiments I can extract the timestamps. They are also correct for the experiments from the first microscope. But for the experiments of the second microscope, the timestamps do not change over time. When I investigated differences between the nd2-files, I found that in the ones where the timestamps are correct there is a NETimeLoop present, while in those were the timestamps are incorrect a TimeLoop is present. I suspect that difference is responsible for the incorrect timestamps. However, I do not understand how this could happen, and whether I can somehow recover the correct timestamps for these experiments. Maybe, you can help me with this?

When importing the files with OME in Fiji, the timestamps are also incorrect. So it is really, saved wrongly in the nd2-file from the very beginning. But I would like to find out how I can resolve that problem.

tlambert03 commented 1 year ago

Hey @gatoniel ... this is indeed a big bummer of a limitation in the way that NIS Elements stores time information. I've definitely come across this as well (with, for example, all channels in a timepoint sharing the same timestamp, even though they were acquired at different times, and other similar cases).

I can't say that I am completely versed on when it is and isn't possible to glean the accurate time stamps, but I can share your frustration :) However, If you can share them, I would be curious however to see the difference between those two files (along with the version of Elements you used to capture them)

gatoniel commented 1 year ago

Can't access the exact microscopes at the moment. But I tried on a different one with NIS Elements 4.51.01 (Build 1146). Here I can at least "control" whether there is a NETimeLoop or a TimeLoop. If there is only one phase in the Times tab one-phase I get a TimeLoop. For multiple phases that are present but not selected several-phases I get a NETimeLoop.

However, the timestamps are correct for all different timepoints.

Currently, I am just using this small function to test the timestamps. If they are all similar, I just add the time periods of the timeloops that are saved in the nd2-file.

def test_nd2_timestamps(times, nd2_file):
    if np.all(np.diff(times, axis=0) == 0.0):
        print("made afjustment")
        period_time = nd2_file._rdr.experiment()[0].parameters.periodMs / 1000
        in_julian = period_time / (24 * 3600)

        add_time = np.arange(times.shape[0]) * in_julian

        return times + add_time[:, np.newaxis, np.newaxis]
    return times

where I get the times array with the following function: https://github.com/gatoniel/napari-nd2-folder-viewer/blob/e0cafea7bbc45357ca6f6d061e937bc97fc44b44/src/napari_nd2_folder_viewer/_widget.py#L160

gatoniel commented 1 year ago

Those files where the timestamps are incorrect have this nd2_file._rdr.experiment()[0] description:

TimeLoop(count=37, nestingLevel=0, parameters=TimeLoopParams(startMs=0.0, periodMs=3600000.0, durationMs=-1.0,
periodDiff=PeriodDiff(avg=0.0, max=0.0, min=0.0)), type='TimeLoop')

with that very weird part: PeriodDiff(avg=0.0, max=0.0, min=0.0)

tlambert03 commented 1 year ago

yeah, from the info in their header:

https://github.com/tlambert03/nd2/blob/fc3d667d92d9f6f36ee11512ce0149776291eddc/src/sdk/Windows/x86_64/include/Nd2ReadSdk.h#L508-L517

it looks like NETimeLoop is a multi-phase timeloop ... but as to why some scopes write it correctly and others don't, I'm still not sure, but I would first wonder about versions. most of our scopes are ~5.20 now, but I'd be curious to hear if your other scope is on an older version.


Side note: I see you're using the private ._rdr quite a bit in your plugin... is there any reason you're unable to use the public api? There is definitely no guarantee that any of that stuff in _rdr will remain in future versions

gatoniel commented 1 year ago

So the version is 4.51.01 (build 1146) for all microscopes. The specific NIS Elements version seems not to be the problem.

Side note: I see you're using the private ._rdr quite a bit in your plugin... is there any reason you're unable to use the public api? There is definitely no guarantee that any of that stuff in _rdr will remain in future versions

No, there is no reason. When I started to use your module the public API was unclear to me, so I just searched for workarounds. I will rewrite with the public API step by step.

tlambert03 commented 1 year ago

a heads up, with #135, the _rdr has probably changed a lot (and will be released soon) ... but nothing in the public api documented in the readme has changed: https://github.com/tlambert03/nd2#usage-and-api

tlambert03 commented 1 year ago

hey @gatoniel just checking in on this issue. Are there still any remaining problems in your pipeline with regards to extracting time stamps?

There is one feature that might make this all easier for you now, and that is the events() output: https://www.talleylambert.com/nd2/API/nd2/#nd2.nd2file.ND2File.events

It will give you a list of dicts with info for each frame (pandas dataframe compatible format). It has a "Time [s]" column that may or may not do a better job than what you were previously using to get time info.

Let me know if you still have any questions or if this can be closed

gatoniel commented 1 year ago

Hey, thanks a lot! Currently I have no problems. When they occur again, I will first try out your new events() output.