diff --git a/CHANGELOG.md b/CHANGELOG.md index e63b60538..ebc08a94a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ * Added a function to generate ogen timestamps and data from onset times and parameters to `tools.optogenetics`. [PR #832](https://github.com/catalystneuro/neuroconv/pull/832) * Added `configure_and_write_nwbfile` and optimized imports in `tools.nwb_helpers` module. [PR #848](https://github.com/catalystneuro/neuroconv/pull/848) * `configure_backend` may now apply a `BackendConfiguration` to equivalent in-memory `pynwb.NWBFile` objects that have different address in RAM. [PR #848](https://github.com/catalystneuro/neuroconv/pull/848) +* Add support for doubled ragged arrays in `add_units_table` [PR #879](https://github.com/catalystneuro/neuroconv/pull/879) ### Bug fixes * Remove JSON Schema `definitions` from the `properties` field. [PR #818](https://github.com/catalystneuro/neuroconv/pull/818) diff --git a/src/neuroconv/tools/spikeinterface/spikeinterface.py b/src/neuroconv/tools/spikeinterface/spikeinterface.py index b927d91b7..8f2596f1c 100644 --- a/src/neuroconv/tools/spikeinterface/spikeinterface.py +++ b/src/neuroconv/tools/spikeinterface/spikeinterface.py @@ -1064,6 +1064,9 @@ def add_units_table( if isinstance(data[0], (bool, np.bool_)): data = data.astype(str) index = isinstance(data[0], (list, np.ndarray, tuple)) + if index and isinstance(data[0], np.ndarray): + index = data[0].ndim + description = property_descriptions.get(property, "No description.") data_to_add[property].update(description=description, data=data, index=index) if property in ["max_channel", "max_electrode"] and nwbfile.electrodes is not None: diff --git a/tests/test_ecephys/test_tools_spikeinterface.py b/tests/test_ecephys/test_tools_spikeinterface.py index 3f65db278..1caf97b35 100644 --- a/tests/test_ecephys/test_tools_spikeinterface.py +++ b/tests/test_ecephys/test_tools_spikeinterface.py @@ -1144,8 +1144,47 @@ def test_adding_ragged_array_properties(self): written_values = self.nwbfile.units.to_dataframe()["ragged_property2"].to_list() number_of_rows_added_before = sorting1.get_num_units() - valuees_appended_to_table = [[] for _ in range(number_of_rows_added_before)] - expected_values = valuees_appended_to_table + second_ragged_array_values + values_appended_to_table = [[] for _ in range(number_of_rows_added_before)] + expected_values = values_appended_to_table + second_ragged_array_values + + # We need a for loop because this is a non-homogenous ragged array + for i, value in enumerate(written_values): + np.testing.assert_array_equal(value, expected_values[i]) + + def test_adding_doubled_ragged_arrays(self): + + sorting1 = generate_sorting(num_units=4) + sorting1 = sorting1.rename_units(new_unit_ids=["a", "b", "c", "d"]) + sorting2 = generate_sorting(num_units=4) + sorting2 = sorting2.rename_units(new_unit_ids=["e", "f", "g", "h"]) + + doubled_nested_array = [[[1, 2], [3, 4]], [[5, 6], [7, 8]], [[9, 10], [11, 12]], [[13, 14], [15, 16]]] + sorting1.set_property(key="double_ragged_property", values=doubled_nested_array) + add_units_table(sorting=sorting1, nwbfile=self.nwbfile) + + written_values = self.nwbfile.units.to_dataframe()["double_ragged_property"].to_list() + np.testing.assert_array_equal(written_values, doubled_nested_array) + + # Add a new recording that contains more properties for the ragged array + doubled_nested_array2 = [[[17, 18], [19, 20]], [[21, 22], [23, 24]], [[25, 26], [27, 28]], [[29, 30], [31, 32]]] + sorting2.set_property(key="double_ragged_property", values=doubled_nested_array2) + second_doubled_nested_array = [ + [["a", "b", "c"], ["d", "e", "f"]], + [["g", "h", "i"], ["j", "k", "l"]], + [["m", "n", "o"], ["p", "q", "r"]], + [["s", "t", "u"], ["v", "w", "x"]], + ] + sorting2.set_property(key="double_ragged_property2", values=second_doubled_nested_array) + add_units_table(sorting=sorting2, nwbfile=self.nwbfile) + + written_values = self.nwbfile.units.to_dataframe()["double_ragged_property"].to_list() + expected_values = doubled_nested_array + doubled_nested_array2 + np.testing.assert_array_equal(written_values, expected_values) + + written_values = self.nwbfile.units.to_dataframe()["double_ragged_property2"].to_list() + number_of_rows_added_before = sorting1.get_num_units() + values_appended_to_table = [[] for _ in range(number_of_rows_added_before)] + expected_values = values_appended_to_table + second_doubled_nested_array # We need a for loop because this is a non-homogenous ragged array for i, value in enumerate(written_values):