Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[New Check]: Spike times are increasing #405

Open
wants to merge 11 commits into
base: dev
Choose a base branch
from
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Upcoming

### New Checks

* Added `check_ascending_spike_times` for ensuring spike times are sorted in ascending order. [#394](https://github.com/NeurodataWithoutBorders/nwbinspector/issues/394)

# v0.4.30

### Fixes
Expand Down
11 changes: 11 additions & 0 deletions docs/best_practices/ecephys.rst
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,14 @@ Observation Intervals
The ``obs_intervals`` field of the :ref:`nwb-schema:sec-units-src` table is used to indicate periods of time where the underlying electrical signal(s) were not observed. This can happen if the recording site moves away from the unit, or if the recording is stopped. Since the channel is not observed, it is not determinable whether a spike occurred during this time. Therefore, there should not be any identified spike times for units matched to those electrical signal(s) occurring outside of the defined ``obs_intervals``. If this variable is not set, it is assumed that all time is observed.

Check function: :py:meth:`~nwbinspector.checks.ecephys.check_spike_times_not_in_unobserved_interval`



.. _best_practice_ascending_spike_times:

Ascending Spike Times
~~~~~~~~~~~~~~~~~~~~~

All spike times should be sorted in ascending order. If they reset to zero, this can be a sign that spikes are not properly aligned with the ``timestamps_reference_time`` of the :ref:`nwb-schema:sec-NWBFile`.

Check function: :py:meth:`~nwbinspector.checks.ecephys.check_ascending_spike_times`
10 changes: 10 additions & 0 deletions src/nwbinspector/checks/ecephys.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,13 @@ def check_spike_times_not_in_unobserved_interval(units_table: Units, nunits: int
"observed intervals."
)
)


@register_check(importance=Importance.BEST_PRACTICE_VIOLATION, neurodata_type=Units)
def check_ascending_spike_times(units_table: Units):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are still testing the performance of this, since it's the first data heavy check to be added without options to control how much data is loaded

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alessandratrapani Can you add a nelems option here to mirror other table tests?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"""Check that the values in the timestamps array are strictly increasing."""
if "spike_times" not in units_table:
return
for spike_times_per_unit in units_table["spike_times"]:
if not np.all(spike_times_per_unit[:-1] <= spike_times_per_unit[1:]):
return InspectorMessage(message=("This Units table contains spike times that are not ascending."))
34 changes: 34 additions & 0 deletions tests/unit_tests/test_ecephys.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
check_electrical_series_dims,
check_electrical_series_reference_electrodes_table,
check_spike_times_not_in_unobserved_interval,
check_ascending_spike_times,
)


Expand Down Expand Up @@ -215,3 +216,36 @@ def test_check_spike_times_not_in_unobserved_interval_multiple_units():
object_name="TestUnits",
location="/",
)


def test_check_ascending_spike_times_pass():
units_table = Units()
units_table.add_unit(spike_times=[0.0, 0.1])
units_table.add_unit(spike_times=[1.0, 2.0])
assert check_ascending_spike_times(units_table=units_table) is None


def test_check_ascending_spike_times_w_missing_spike_times_pass():
units_table = Units()
units_table.add_unit(spike_times=[0.0, 0.1])
units_table.add_unit(spike_times=[])
CodyCBakerPhD marked this conversation as resolved.
Show resolved Hide resolved
assert check_ascending_spike_times(units_table=units_table) is None


def test_check_ascending_spike_times_missing_column_skip():
units_table = Units()
assert check_ascending_spike_times(units_table=units_table) is None


def test_check_ascending_spike_times_fail():
units_table = Units(name="TestUnits")
units_table.add_unit(spike_times=[0.0, 0.1])
units_table.add_unit(spike_times=[2.0, 1.0])
assert check_ascending_spike_times(units_table=units_table) == InspectorMessage(
message=("This Units table contains spike times that are not ascending."),
importance=Importance.BEST_PRACTICE_VIOLATION,
check_function_name="check_ascending_spike_times",
object_type="Units",
object_name="TestUnits",
location="/",
)
Loading