From 2457ad3efb4e8ce81a7948c8b8fafefaf7a678a7 Mon Sep 17 00:00:00 2001 From: Steph Prince <40640337+stephprince@users.noreply.github.com> Date: Wed, 13 Dec 2023 09:35:33 -0800 Subject: [PATCH 01/12] add stimulus template column option to IntracellularRecordingsTable --- src/pynwb/icephys.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/pynwb/icephys.py b/src/pynwb/icephys.py index 04382abbc..d3a52d12c 100644 --- a/src/pynwb/icephys.py +++ b/src/pynwb/icephys.py @@ -415,6 +415,12 @@ class IntracellularStimuliTable(DynamicTable): 'index': False, 'table': False, 'class': TimeSeriesReferenceVectorData}, + {'name': 'stimulus_template', + 'description': 'Column storing the reference to the stimulus template for the recording (rows)', + 'required': False, + 'index': False, + 'table': False, + 'class': TimeSeriesReferenceVectorData}, ) @docval(*get_docval(DynamicTable.__init__, 'id', 'columns', 'colnames')) @@ -518,6 +524,13 @@ def __init__(self, **kwargs): {'name': 'stimulus', 'type': TimeSeries, 'doc': 'The TimeSeries (usually a PatchClampSeries) with the stimulus', 'default': None}, + {'name': 'stimulus_template_start_index', 'type': int, 'doc': 'Start index of the stimulus template', + 'default': None}, + {'name': 'stimulus_template_index_count', 'type': int, 'doc': 'Stop index of the stimulus template', + 'default': None}, + {'name': 'stimulus_template', 'type': TimeSeries, + 'doc': 'The TimeSeries (usually a PatchClampSeries) with the stimulus template waveforms', + 'default': None}, {'name': 'response_start_index', 'type': int, 'doc': 'Start index of the response', 'default': None}, {'name': 'response_index_count', 'type': int, 'doc': 'Stop index of the response', 'default': None}, {'name': 'response', 'type': TimeSeries, @@ -553,6 +566,11 @@ def add_recording(self, **kwargs): 'response', kwargs) electrode = popargs('electrode', kwargs) + stimulus_template_start_index, stimulus_template_index_count, stimulus_template = popargs( + 'stimulus_template_start_index', + 'stimulus_template_index_count', + 'stimulus_template', + kwargs) # if electrode is not provided, take from stimulus or response object if electrode is None: @@ -572,6 +590,15 @@ def add_recording(self, **kwargs): response_start_index, response_index_count = self.__compute_index(response_start_index, response_index_count, response, 'response') + stimulus_template_start_index, stimulus_template_index_count = self.__compute_index( + stimulus_template_start_index, + stimulus_template_index_count, + stimulus_template, 'stimulus_template') + + # if stimulus template is already a column in the stimuli table, but stimulus_template was None + if 'stimulus_template' in self.category_tables['stimuli'].colnames and stimulus_template is None: + stimulus_template = stimulus if stimulus is not None else response # set to stimulus if it was provided + # If either stimulus or response are None, then set them to the same TimeSeries to keep the I/O happy response = response if response is not None else stimulus stimulus_provided_is_not_none = stimulus is not None # Store if stimulus is None for error checks later @@ -612,6 +639,9 @@ def add_recording(self, **kwargs): stimuli = {} stimuli['stimulus'] = TimeSeriesReferenceVectorData.TIME_SERIES_REFERENCE_TUPLE( stimulus_start_index, stimulus_index_count, stimulus) + if stimulus_template is not None: + stimuli['stimulus_template'] = TimeSeriesReferenceVectorData.TIME_SERIES_REFERENCE_TUPLE( + stimulus_template_start_index, stimulus_template_index_count, stimulus_template) # Compile the responses table data responses = copy(popargs('response_metadata', kwargs)) From fb60a07258004df7df1228922471b99264d69fc9 Mon Sep 17 00:00:00 2001 From: Steph Prince <40640337+stephprince@users.noreply.github.com> Date: Mon, 8 Jan 2024 16:01:32 -0800 Subject: [PATCH 02/12] add tests for stimulus template column --- tests/unit/test_icephys_metadata_tables.py | 62 ++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/tests/unit/test_icephys_metadata_tables.py b/tests/unit/test_icephys_metadata_tables.py index 34531d6a4..b31ee9215 100644 --- a/tests/unit/test_icephys_metadata_tables.py +++ b/tests/unit/test_icephys_metadata_tables.py @@ -419,6 +419,15 @@ def test_add_row_index_out_of_range(self): response=self.response, id=np.int64(10) ) + with self.assertRaises(IndexError): + ir = IntracellularRecordingsTable() + ir.add_recording( + electrode=self.electrode, + stimulus_template=self.stimulus, + stimulus_template_start_index=10, + response=self.response, + id=np.int64(10) + ) # Stimulus/Response index count too large with self.assertRaises(IndexError): ir = IntracellularRecordingsTable() @@ -438,6 +447,15 @@ def test_add_row_index_out_of_range(self): response=self.response, id=np.int64(10) ) + with self.assertRaises(IndexError): + ir = IntracellularRecordingsTable() + ir.add_recording( + electrode=self.electrode, + stimulus_template=self.stimulus, + stimulus_template_index_count=10, + response=self.response, + id=np.int64(10) + ) # Stimulus/Response start+count combination too large with self.assertRaises(IndexError): ir = IntracellularRecordingsTable() @@ -459,6 +477,16 @@ def test_add_row_index_out_of_range(self): response=self.response, id=np.int64(10) ) + with self.assertRaises(IndexError): + ir = IntracellularRecordingsTable() + ir.add_recording( + electrode=self.electrode, + stimulus_template=self.stimulus, + stimulus_template_start_index=3, + stimulus_template_index_count=4, + response=self.response, + id=np.int64(10) + ) def test_add_row_no_stimulus_and_response(self): with self.assertRaises(ValueError): @@ -469,6 +497,40 @@ def test_add_row_no_stimulus_and_response(self): response=None ) + def test_add_row_with_stimulus_template(self): + ir = IntracellularRecordingsTable() + ir.add_recording( + electrode=self.electrode, + stimulus=self.stimulus, + stimulus_template=self.stimulus, + response=self.response, + id=np.int64(10) + ) + + def test_add_stimulus_template_column(self): + ir = IntracellularRecordingsTable() + ir.add_column(name='stimulus_template', + description='test column', + category='stimuli', + col_cls=TimeSeriesReferenceVectorData) + + def test_add_row_with_no_stimulus_template_when_stimulus_template_column_exists(self): + ir = IntracellularRecordingsTable() + ir.add_recording(electrode=self.electrode, + stimulus=self.stimulus, + response=self.response, + stimulus_template=self.stimulus, + id=np.int64(10)) + + # add row with only stimulus when stimulus template column already exists + ir.add_recording(electrode=self.electrode, + stimulus=self.stimulus, + id=np.int64(20)) + # add row with only response when stimulus template column already exists + ir.add_recording(electrode=self.electrode, + response=self.stimulus, + id=np.int64(30)) + def test_add_column(self): ir = IntracellularRecordingsTable() ir.add_recording( From 5512a7a21ece8e78b17c14da1347fc4c444df095 Mon Sep 17 00:00:00 2001 From: Steph Prince <40640337+stephprince@users.noreply.github.com> Date: Mon, 8 Jan 2024 16:02:05 -0800 Subject: [PATCH 03/12] add example in tutorial for adding stimulus template data --- docs/gallery/domain/plot_icephys.py | 33 +++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/docs/gallery/domain/plot_icephys.py b/docs/gallery/domain/plot_icephys.py index 109ec5fcc..3f1ebbd5b 100644 --- a/docs/gallery/domain/plot_icephys.py +++ b/docs/gallery/domain/plot_icephys.py @@ -97,6 +97,7 @@ # Import additional core datatypes used in the example from pynwb.core import DynamicTable, VectorData +from pynwb.base import TimeSeriesReferenceVectorData # Import icephys TimeSeries types used from pynwb.icephys import VoltageClampSeries, VoltageClampStimulusSeries @@ -457,6 +458,38 @@ category="electrodes", ) +##################################################################### +# One predefined subcategory column is the stimulus template column in the stimuli table. This column can be used to +# store stimulus template waveforms that were generated by the recording software. Similar to the stimulus and response +# columns, we can specify a relevant time range. + +nwbfile.intracellular_recordings.add_column( + name="stimulus_template", + data=[(0, 5, stimulus), # (start_index, index_count, stimulus_template) can be specified as a tuple + (1, 3, stimulus), + (-1, -1, stimulus)], + description="Column storing the reference to the stimulus template for the recording (rows).", + category="stimuli", + col_cls=TimeSeriesReferenceVectorData +) + +# we can also add stimulus template data as follows +rowindex = nwbfile.add_intracellular_recording( + electrode=electrode, + stimulus=stimulus, + stimulus_template=stimulus, # the full time range of the stimulus template will be used unless specified + recording_tag='A4', + recording_lab_data={'location': 'Isengard'}, + electrode_metadata={'voltage_threshold': 0.14}, + id=13, +) + +##################################################################### +# .. note:: If a stimulus template column exists but there is no stimulus template data for that recording, then the +# stimulus template will be internally set to the provided stimulus or response TimeSeries and the start_index +# and index_count for the missing parameter are set to -1. The missing values will be represented via masked +# numpy arrays. + ##################################################################### # Add a simultaneous recording # --------------------------------- From 0f6912a9381998be79d01b3d45958cf800429515 Mon Sep 17 00:00:00 2001 From: Steph Prince <40640337+stephprince@users.noreply.github.com> Date: Mon, 8 Jan 2024 16:02:30 -0800 Subject: [PATCH 04/12] link to nwb-schema PR with stimulus template change --- src/pynwb/nwb-schema | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pynwb/nwb-schema b/src/pynwb/nwb-schema index b4f8838cb..de18d1289 160000 --- a/src/pynwb/nwb-schema +++ b/src/pynwb/nwb-schema @@ -1 +1 @@ -Subproject commit b4f8838cbfbb7f8a117bd7e0aad19133d26868b4 +Subproject commit de18d1289a3b4bfd64222984d862524eb1e8c933 From efae4802a8f7cd8b586d27db97f690ff898b6fe3 Mon Sep 17 00:00:00 2001 From: Steph Prince <40640337+stephprince@users.noreply.github.com> Date: Tue, 9 Jan 2024 16:01:34 -0800 Subject: [PATCH 05/12] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c5cfa5a9e..d9e9b6ac5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ - Expose `starting_time` in `mock_ElectricalSeries`. @h-mayorquin [#1805](https://github.com/NeurodataWithoutBorders/pynwb/pull/1805) - Enhance `get_data_in_units()` to work with objects that have a `channel_conversion` attribute like the `ElectricalSeries`. @h-mayorquin [#1806](https://github.com/NeurodataWithoutBorders/pynwb/pull/1806) - Refactor validation CLI tests to use `{sys.executable} -m coverage` to use the same Python version and run correctly on Debian systems. @yarikoptic [#1811](https://github.com/NeurodataWithoutBorders/pynwb/pull/1811) +- Support `stimulus_template` as optional predefined column in `IntracellularStimuliTable` @stephprince [#1815](https://github.com/NeurodataWithoutBorders/pynwb/pull/1815) ### Bug fixes - Fix bug where namespaces were loaded in "w-" mode. @h-mayorquin [#1795](https://github.com/NeurodataWithoutBorders/pynwb/pull/1795) From adfaf2e59a2bea24ac743cd76640485cc9cd309f Mon Sep 17 00:00:00 2001 From: Steph Prince <40640337+stephprince@users.noreply.github.com> Date: Wed, 10 Jan 2024 13:21:20 -0800 Subject: [PATCH 06/12] add empty TimeSeriesReference method --- docs/gallery/domain/plot_icephys.py | 8 ++++---- src/pynwb/base.py | 19 +++++++++++++++++++ tests/unit/test_base.py | 11 +++++++++++ 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/docs/gallery/domain/plot_icephys.py b/docs/gallery/domain/plot_icephys.py index 3f1ebbd5b..9e5da899d 100644 --- a/docs/gallery/domain/plot_icephys.py +++ b/docs/gallery/domain/plot_icephys.py @@ -97,7 +97,7 @@ # Import additional core datatypes used in the example from pynwb.core import DynamicTable, VectorData -from pynwb.base import TimeSeriesReferenceVectorData +from pynwb.base import TimeSeriesReference, TimeSeriesReferenceVectorData # Import icephys TimeSeries types used from pynwb.icephys import VoltageClampSeries, VoltageClampStimulusSeries @@ -465,9 +465,9 @@ nwbfile.intracellular_recordings.add_column( name="stimulus_template", - data=[(0, 5, stimulus), # (start_index, index_count, stimulus_template) can be specified as a tuple - (1, 3, stimulus), - (-1, -1, stimulus)], + data=[TimeSeriesReference(0, 5, stimulus), # (start_index, index_count, stimulus_template) + TimeSeriesReference(1, 3, stimulus), + TimeSeriesReference.empty(stimulus)], # if there was no data for that recording, use an empty reference description="Column storing the reference to the stimulus template for the recording (rows).", category="stimuli", col_cls=TimeSeriesReferenceVectorData diff --git a/src/pynwb/base.py b/src/pynwb/base.py index 42f7b7ff3..044a2c840 100644 --- a/src/pynwb/base.py +++ b/src/pynwb/base.py @@ -497,6 +497,25 @@ def data(self): # load the data from the timeseries return self.timeseries.data[self.idx_start: (self.idx_start + self.count)] + @classmethod + @docval({'name': 'timeseries', 'type': TimeSeries, 'doc': 'the timeseries object to reference.'}) + def empty(cls, timeseries): + """ + Creates an empty TimeSeriesReference class to represent missing data. + + When missing data needs to be represented, NWB defines ``None`` for the complex data type ``(idx_start, + count, TimeSeries)`` as (-1, -1, TimeSeries) for storage. The exact timeseries object will technically not + matter since the empty reference is a way of indicating a NaN value. In practice, this may be used in the + :py:class:`~pynwb.icephys.IntracellularRecordingsTable` where only one of stimulus or response data was + recorded. In such cases, the timeseries object for the empty stimulus TimeSeriesReference could be set to the + response series or vice versa (the timeseries object for the empty response TimeSeriesReference could be set + to the stimulus) + + :returns: Returns :py:class:`~pynwb.base.TimeSeriesReference` + """ + + return cls(-1, -1, timeseries) + @register_class('TimeSeriesReferenceVectorData', CORE_NAMESPACE) class TimeSeriesReferenceVectorData(VectorData): diff --git a/tests/unit/test_base.py b/tests/unit/test_base.py index ad4ce6739..4ad813d03 100644 --- a/tests/unit/test_base.py +++ b/tests/unit/test_base.py @@ -877,3 +877,14 @@ def test_data_property_bad_reference(self): IndexError, "'idx_start + count' out of range for timeseries 'test'" ): tsr.data + + def test_empty_reference_creation(self): + tsr = TimeSeriesReference.empty(self._create_time_series_with_rate()) + self.assertFalse(tsr.isvalid()) + self.assertIsNone(tsr.data) + self.assertIsNone(tsr.timestamps) + + def test_empty_reference_creation_invalid_type(self): + tsr = TimeSeriesReference.empty(None) + with self.assertRaisesWith(TypeError, "timeseries must be of type TimeSeries. "): + tsr.check_types() From 85e399a3938d46fa7d603bb2c9b3d7c77e4d8f47 Mon Sep 17 00:00:00 2001 From: Steph Prince <40640337+stephprince@users.noreply.github.com> Date: Wed, 10 Jan 2024 14:38:19 -0800 Subject: [PATCH 07/12] point to updated nwb-schema PR --- src/pynwb/nwb-schema | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pynwb/nwb-schema b/src/pynwb/nwb-schema index de18d1289..aacef3eb1 160000 --- a/src/pynwb/nwb-schema +++ b/src/pynwb/nwb-schema @@ -1 +1 @@ -Subproject commit de18d1289a3b4bfd64222984d862524eb1e8c933 +Subproject commit aacef3eb1965df5eec72a9a586ef4dd4da9e9e83 From 728d3d0ac559c1063795d9f37ddad5066f60da88 Mon Sep 17 00:00:00 2001 From: Steph Prince <40640337+stephprince@users.noreply.github.com> Date: Wed, 10 Jan 2024 14:57:59 -0800 Subject: [PATCH 08/12] remove test caught by docval argument checking --- tests/unit/test_base.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/unit/test_base.py b/tests/unit/test_base.py index 4ad813d03..b079464d1 100644 --- a/tests/unit/test_base.py +++ b/tests/unit/test_base.py @@ -883,8 +883,3 @@ def test_empty_reference_creation(self): self.assertFalse(tsr.isvalid()) self.assertIsNone(tsr.data) self.assertIsNone(tsr.timestamps) - - def test_empty_reference_creation_invalid_type(self): - tsr = TimeSeriesReference.empty(None) - with self.assertRaisesWith(TypeError, "timeseries must be of type TimeSeries. "): - tsr.check_types() From 93a2c630824fc4b524d604f28928c22a3d3d5680 Mon Sep 17 00:00:00 2001 From: Steph Prince <40640337+stephprince@users.noreply.github.com> Date: Wed, 10 Jan 2024 16:46:24 -0800 Subject: [PATCH 09/12] Apply suggestions from code review Co-authored-by: Oliver Ruebel --- docs/gallery/domain/plot_icephys.py | 7 ++++--- src/pynwb/base.py | 12 +++++++----- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/docs/gallery/domain/plot_icephys.py b/docs/gallery/domain/plot_icephys.py index 9e5da899d..162714845 100644 --- a/docs/gallery/domain/plot_icephys.py +++ b/docs/gallery/domain/plot_icephys.py @@ -459,9 +459,10 @@ ) ##################################################################### -# One predefined subcategory column is the stimulus template column in the stimuli table. This column can be used to -# store stimulus template waveforms that were generated by the recording software. Similar to the stimulus and response -# columns, we can specify a relevant time range. +# One predefined subcategory column is the ``stimulus_template`` column in the stimuli table. This column is +# used to store template waveforms of stimuli in addition to the actual recorded stimulus that is stored in the +# ``stimulus`` column. Similar to the ``stimulus`` and ``response`` columns, we can specify a relevant +# time range. nwbfile.intracellular_recordings.add_column( name="stimulus_template", diff --git a/src/pynwb/base.py b/src/pynwb/base.py index 044a2c840..f47414328 100644 --- a/src/pynwb/base.py +++ b/src/pynwb/base.py @@ -505,11 +505,13 @@ def empty(cls, timeseries): When missing data needs to be represented, NWB defines ``None`` for the complex data type ``(idx_start, count, TimeSeries)`` as (-1, -1, TimeSeries) for storage. The exact timeseries object will technically not - matter since the empty reference is a way of indicating a NaN value. In practice, this may be used in the - :py:class:`~pynwb.icephys.IntracellularRecordingsTable` where only one of stimulus or response data was - recorded. In such cases, the timeseries object for the empty stimulus TimeSeriesReference could be set to the - response series or vice versa (the timeseries object for the empty response TimeSeriesReference could be set - to the stimulus) + matter since the empty reference is a way of indicating a NaN value. in a + :py:class:`~pynwb.base.TimeSeriesReferenceVectorData` column. + + An example, where this functionality is used is :py:class:`~pynwb.icephys.IntracellularRecordingsTable` + where only one of stimulus or response data was recorded. In such cases, the timeseries object for the + empty stimulus :py:class:`~pynwb.base.TimeSeriesReference` could be set to the response series, or + vice versa. :returns: Returns :py:class:`~pynwb.base.TimeSeriesReference` """ From 554e78d96a9813d6f68dd5d5bc6d49d4f26f0f7f Mon Sep 17 00:00:00 2001 From: Steph Prince <40640337+stephprince@users.noreply.github.com> Date: Thu, 11 Jan 2024 13:44:36 -0800 Subject: [PATCH 10/12] update tutorial and documentation --- docs/gallery/domain/plot_icephys.py | 40 +++++++++++++++++++++-------- src/pynwb/base.py | 13 +++++----- 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/docs/gallery/domain/plot_icephys.py b/docs/gallery/domain/plot_icephys.py index 162714845..2e7f51a23 100644 --- a/docs/gallery/domain/plot_icephys.py +++ b/docs/gallery/domain/plot_icephys.py @@ -459,16 +459,31 @@ ) ##################################################################### +# Adding stimulus templates +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# # One predefined subcategory column is the ``stimulus_template`` column in the stimuli table. This column is # used to store template waveforms of stimuli in addition to the actual recorded stimulus that is stored in the -# ``stimulus`` column. Similar to the ``stimulus`` and ``response`` columns, we can specify a relevant -# time range. +# ``stimulus`` column. The ``stimulus_template`` column contains an idealized version of the template waveform used as +# the stimulus. This can be useful as a noiseless version of the stimulus for data analysis or to validate that the +# recorded stimulus matches the expected waveform of the template. Similar to the ``stimulus`` and ``response`` +# columns, we can specify a relevant time range. + +stimulus_template = VoltageClampStimulusSeries( + name="ccst", + data=[0, 1, 2, 3, 4], + starting_time=0.0, + rate=10e3, + electrode=electrode, + gain=0.02, +) +nwbfile.add_stimulus_template(stimulus_template) nwbfile.intracellular_recordings.add_column( name="stimulus_template", - data=[TimeSeriesReference(0, 5, stimulus), # (start_index, index_count, stimulus_template) - TimeSeriesReference(1, 3, stimulus), - TimeSeriesReference.empty(stimulus)], # if there was no data for that recording, use an empty reference + data=[TimeSeriesReference(0, 5, stimulus_template), # (start_index, index_count, stimulus_template) + TimeSeriesReference(1, 3, stimulus_template), + TimeSeriesReference.empty(stimulus_template)], # if there was no data for that recording, use empty reference description="Column storing the reference to the stimulus template for the recording (rows).", category="stimuli", col_cls=TimeSeriesReferenceVectorData @@ -478,7 +493,7 @@ rowindex = nwbfile.add_intracellular_recording( electrode=electrode, stimulus=stimulus, - stimulus_template=stimulus, # the full time range of the stimulus template will be used unless specified + stimulus_template=stimulus_template, # the full time range of the stimulus template will be used unless specified recording_tag='A4', recording_lab_data={'location': 'Isengard'}, electrode_metadata={'voltage_threshold': 0.14}, @@ -486,10 +501,15 @@ ) ##################################################################### -# .. note:: If a stimulus template column exists but there is no stimulus template data for that recording, then the -# stimulus template will be internally set to the provided stimulus or response TimeSeries and the start_index -# and index_count for the missing parameter are set to -1. The missing values will be represented via masked -# numpy arrays. +# .. note:: If a stimulus template column exists but there is no stimulus template data for that recording, then +# :py:meth:`~pynwb.file.NWBFile.add_intracellular_recording` will internally set the stimulus template to the +# provided stimulus or response TimeSeries and the start_index and index_count for the missing parameter are +# set to -1. The missing values will be represented via masked numpy arrays. + +##################################################################### +# .. note:: Since stimulus templates are often reused across many recordings, the timestamps in the templates are not +# usually aligned with the recording nor with the reference time of the file. The timestamps often start +# at 0 and are relative to the time of the application of the stimulus. ##################################################################### # Add a simultaneous recording diff --git a/src/pynwb/base.py b/src/pynwb/base.py index f47414328..d1ca74a2f 100644 --- a/src/pynwb/base.py +++ b/src/pynwb/base.py @@ -505,13 +505,12 @@ def empty(cls, timeseries): When missing data needs to be represented, NWB defines ``None`` for the complex data type ``(idx_start, count, TimeSeries)`` as (-1, -1, TimeSeries) for storage. The exact timeseries object will technically not - matter since the empty reference is a way of indicating a NaN value. in a - :py:class:`~pynwb.base.TimeSeriesReferenceVectorData` column. - - An example, where this functionality is used is :py:class:`~pynwb.icephys.IntracellularRecordingsTable` - where only one of stimulus or response data was recorded. In such cases, the timeseries object for the - empty stimulus :py:class:`~pynwb.base.TimeSeriesReference` could be set to the response series, or - vice versa. + matter since the empty reference is a way of indicating a NaN value in a + :py:class:`~pynwb.base.TimeSeriesReferenceVectorData` column. + + An example where this functionality is used is :py:class:`~pynwb.icephys.IntracellularRecordingsTable` + where only one of stimulus or response data was recorded. In such cases, the timeseries object for the + empty stimulus :py:class:`~pynwb.base.TimeSeriesReference` could be set to the response series, or vice versa. :returns: Returns :py:class:`~pynwb.base.TimeSeriesReference` """ From f54b7284f5359cbee5264e7c81f42fa848408b1d Mon Sep 17 00:00:00 2001 From: Steph Prince <40640337+stephprince@users.noreply.github.com> Date: Thu, 11 Jan 2024 14:26:28 -0800 Subject: [PATCH 11/12] Update src/pynwb/base.py Co-authored-by: Ryan Ly --- src/pynwb/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pynwb/base.py b/src/pynwb/base.py index d1ca74a2f..02d2e3c0f 100644 --- a/src/pynwb/base.py +++ b/src/pynwb/base.py @@ -501,7 +501,7 @@ def data(self): @docval({'name': 'timeseries', 'type': TimeSeries, 'doc': 'the timeseries object to reference.'}) def empty(cls, timeseries): """ - Creates an empty TimeSeriesReference class to represent missing data. + Creates an empty TimeSeriesReference object to represent missing data. When missing data needs to be represented, NWB defines ``None`` for the complex data type ``(idx_start, count, TimeSeries)`` as (-1, -1, TimeSeries) for storage. The exact timeseries object will technically not From a5bffdb89ef50f06d047cc4c39f4da442646f6ff Mon Sep 17 00:00:00 2001 From: Ryan Ly Date: Thu, 11 Jan 2024 14:52:02 -0800 Subject: [PATCH 12/12] Update CHANGELOG.md --- CHANGELOG.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0834094a1..e52448d53 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ ### Enhancements and minor changes - Added support for NWB schema 2.7.0. - - ... + - Support `stimulus_template` as optional predefined column in `IntracellularStimuliTable`. @stephprince [#1815](https://github.com/NeurodataWithoutBorders/pynwb/pull/1815) - ... - ... - ... @@ -16,7 +16,6 @@ - Expose `starting_time` in `mock_ElectricalSeries`. @h-mayorquin [#1805](https://github.com/NeurodataWithoutBorders/pynwb/pull/1805) - Enhance `get_data_in_units()` to work with objects that have a `channel_conversion` attribute like the `ElectricalSeries`. @h-mayorquin [#1806](https://github.com/NeurodataWithoutBorders/pynwb/pull/1806) - Refactor validation CLI tests to use `{sys.executable} -m coverage` to use the same Python version and run correctly on Debian systems. @yarikoptic [#1811](https://github.com/NeurodataWithoutBorders/pynwb/pull/1811) -- Support `stimulus_template` as optional predefined column in `IntracellularStimuliTable` @stephprince [#1815](https://github.com/NeurodataWithoutBorders/pynwb/pull/1815) ### Bug fixes - Fix bug where namespaces were loaded in "w-" mode. @h-mayorquin [#1795](https://github.com/NeurodataWithoutBorders/pynwb/pull/1795)