You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Clarification request: ImageSeries.num_samples is persisted for internal (non-external) data
I'd like to understand the intended behavior of num_samples on ImageSeries, because the inherited in-memory TimeSeries.num_samples property interacts with the schema-defined num_samples dataset (added in #2194) in a way that seems inconsistent with the field's documented meaning. I'm raising this as a question rather than a bug report — I may be misreading the intent.
Background
TimeSeries.num_samples is a computed property that returns len(data) (falling back to len(timestamps)).
ImageSeries overrides this property, and Add num_samples to ImageSeries #2194 also added num_samples as an actual schema dataset (nwb.image.yaml), documented as:
Total number of frames across all external files. This is required when format='external' and timing is described using starting_time and rate, since data is empty and its first dimension cannot be used to determine the number of frames. When timestamps is provided, len(timestamps) already serves this purpose.
The doc frames num_samples as an external-file concept: a way to recover a frame count that cannot otherwise be derived. The _check_num_samples warning is likewise gated on external_file is not None and rate is not None and num_samples is None.
Observed behavior
For an internalImageSeries (data stored in the file, no external file), the user never sets num_samples, but:
The overridden property falls through to TimeSeries.num_samples and returns len(data).
There is no custom IO mapper, so the default ObjectMapper persists whatever the property returns — so num_samples gets written to disk even though data.shape[0] already carries that information.
importnumpyasnpfrompynwb.imageimportImageSeriesimg=ImageSeries(name="img", data=np.zeros((10, 5, 5)), unit="n.a.", rate=1.0)
print(img._num_samples) # None -- user never set itprint(img.num_samples) # 10 -- inherited TimeSeries property returns len(data)# on write -> acquisition/img/num_samples == 10 is persisted to the file
So the persisted num_samples value on an internal ImageSeries doesn't correspond to the documented meaning of the field ("total number of frames across all external files") — there are no external files. The value is numerically correct, but it's a redundant write of a field the schema doc describes as external-only.
Questions
Is persisting num_samples for internal (non-external) ImageSeries intended, or should the dataset only be written in the external-file case it was designed for?
If it's not intended, would the preferred fix be to decouple the in-memory convenience property from persistence (e.g. only write the dataset when external_file is set / data is empty), so that ImageSeries.num_samples can still return the frame count in Python without writing a redundant/misapplied dataset?
Should the schema doc be broadened to also describe the internal-data meaning, if persisting it there is in fact intended?
Clarification request:
ImageSeries.num_samplesis persisted for internal (non-external) dataI'd like to understand the intended behavior of
num_samplesonImageSeries, because the inherited in-memoryTimeSeries.num_samplesproperty interacts with the schema-definednum_samplesdataset (added in #2194) in a way that seems inconsistent with the field's documented meaning. I'm raising this as a question rather than a bug report — I may be misreading the intent.Background
TimeSeries.num_samplesis a computed property that returnslen(data)(falling back tolen(timestamps)).ImageSeriesoverrides this property, and Add num_samples to ImageSeries #2194 also addednum_samplesas an actual schema dataset (nwb.image.yaml), documented as:The doc frames
num_samplesas an external-file concept: a way to recover a frame count that cannot otherwise be derived. The_check_num_sampleswarning is likewise gated onexternal_file is not None and rate is not None and num_samples is None.Observed behavior
For an internal
ImageSeries(data stored in the file, no external file), the user never setsnum_samples, but:TimeSeries.num_samplesand returnslen(data).ObjectMapperpersists whatever the property returns — sonum_samplesgets written to disk even thoughdata.shape[0]already carries that information.So the persisted
num_samplesvalue on an internalImageSeriesdoesn't correspond to the documented meaning of the field ("total number of frames across all external files") — there are no external files. The value is numerically correct, but it's a redundant write of a field the schema doc describes as external-only.Questions
num_samplesfor internal (non-external)ImageSeriesintended, or should the dataset only be written in the external-file case it was designed for?external_fileis set /datais empty), so thatImageSeries.num_samplescan still return the frame count in Python without writing a redundant/misapplied dataset?Environment
🤖 Generated with Claude Code