Skip to content

Commit 09ee93e

Browse files
committed
COnvert to sphinx gallery.
1 parent 3a45c14 commit 09ee93e

File tree

183 files changed

+5402
-53
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

183 files changed

+5402
-53
lines changed

doc/how_to/handle_times.rst

Lines changed: 78 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,13 @@ How SpikeInterface handles time
44
Extracellular electrophysiology commonly involves synchronisation of events
55
across many timestreams. For example, an experiment may involve
66
displaying a stimuli to an animal and recording the stimuli-evoked
7-
neuronal responses. It is critical that timings is represented in
8-
a clear way across data streams so they may be properly synchronised during
7+
neuronal responses. It is critical that timings are represented
8+
accurately so they may be properly synchronised during
99
analysis.
1010

11-
Below, we will explore the ways that SpikeInterface represents time
11+
Below, we will explore the ways that SpikeInterface stores time
1212
information and how you can use it in your analysis to ensure the timing
13-
of your spike events is represented faithfully. The ways that will
14-
be explored are **providing no times**, **providing start times**
15-
and **providing the full time array**.
13+
of your spike events are accurate.
1614

1715
A familiarity with the terms used in digital sampling (e.g. sampling
1816
frequency) will be assumed below. If you are not familiar with these concepts,
@@ -56,22 +54,21 @@ An Overview of the possible Time representations in SpikeInterface
5654

5755
When you load a recording into SpikeInterface, it will be automatically
5856
associated with a time array. Depending on your data format, this might
59-
be loaded from metadata on your raw recording.
57+
be loaded from metadata on your raw recording. If there is no time metadata
58+
on your raw recording, the times will be generated based on your sampling
59+
rate and number of samples.
6060

61-
**[TODO: concrete example of this?]**
61+
**[TODO: concrete example of a datatype that loads time also on the neo side]**
6262

63-
If there is no time metadata on your raw recording, the times will be
64-
generated based on your sampling rate and number of samples.
65-
66-
You can use the `get_times()` method to inspect the time array associated
67-
with your recording.
63+
You can use the :meth:`get_times() <spikeinterface.core.BaseRecording.get_times>`
64+
method to inspect the time array associated with your recording.
6865

6966
.. code-block:: python
7067
7168
import spikeinterface.full as si
7269
7370
# Generate a recording for this example
74-
recording, _ = si.generate_ground_truth_recording(durations=[10])
71+
recording, sorting = si.generate_ground_truth_recording(durations=[10])
7572
7673
print(f"number of samples: {recording.get_num_samples()}")
7774
print(f"sampling frequency: {recording.get_sampling_frequency()}"
@@ -80,22 +77,25 @@ with your recording.
8077
recording.get_times()
8178
)
8279
83-
Here, we see that as no time metadata was associated with the loaded recording,
84-
the time array starts at 0 seconds and continues until 10 seconds
85-
(`10 * sampling_frequency`) in steps of sampling step (`1 / sampling_frequency`).
80+
Here, we see that as no time metadata is associated with the loaded recording,
81+
a default time array is generated from the number of samples and sampling frequency.
82+
The times starts at :math:`0` seconds and continues until :math:`10` seconds
83+
(:math:`10 \cdot \text{sampling frequency}` samples) in steps of sampling step size,
84+
:math:`\frac{1}{\text{sampling frequency}}`.
8685
87-
If timings were loaded from metadata, you may find that the first timepoint is
88-
not zero, or the times may not be separated by exactly `1/sampling_frequency` but
89-
may be irregular due to small drifts in sampling rate during acquisition.
86+
If timings are obtained from metadata during file loading, you may find that the first timepoint is
87+
not zero, or the times may not be separated by exactly :math:`\frac{1}{\text{sampling frequency}}`
88+
but may be irregular due to small drifts in sampling rate during acquisition (so called 'clock drift').
9089
9190
^^^^^^^^^^^^^^^^^^^^^^^
9291
Shifting the start time
9392
^^^^^^^^^^^^^^^^^^^^^^^
9493
9594
Having loaded your recording object and inspected the associated
96-
time vector, you may want to change the start time of your recording.
95+
times, you may want to change the start time of your recording.
96+
9797
For example, your recording may not have metadata attached and you
98-
want to shift the default time vector (with zero start time) to the
98+
want to shift the default times to start at the
9999
true (real world) start time of the recording, or relative to some
100100
other event (e.g. behavioural trial start time).
101101
@@ -117,19 +117,52 @@ the start time.
117117
118118
print(recording.get_times()) # time now start at 50 seconds
119119
120+
**TODO: link to new function and test when other PR is merged**
121+
122+
123+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
124+
Setting time vector changes spike times
125+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
126+
127+
If we sort out recording, the spike times will reflect the times
128+
set on the recording. In our case, because we already have the
129+
sorting object based on the default times, we will set the new
130+
recording object on the sorting.
131+
132+
.. code-block:: python
133+
134+
unit_id_to_show = sorting.unid_ids[0]
135+
136+
spike_times_orig = sorting.get_unit_spike_train(unit_id_to_show, return_times=True)
137+
138+
sorting.register_recording(recording)
139+
140+
spike_times_new = sorting.get_unit_spike_train(unit_id_to_show, return_times=True)
141+
120142
121143
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
122144
Manually setting a time vector
123145
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
124146
125-
Less commonly, you may want to manually set the time vector on a recording.
126-
For example, maybe you have a known time vector with non-regularly spaced
127-
samples due to sampling drift, and you want to associate it with your recording.
147+
It is also possible to manualyl set an entire time vector on your recording.
148+
This might be useful in case you have the true sample timestamps of your
149+
recording but these were not automatically loaded from metadata.
128150
129151
You can associate any time vector with your recording (as long as it contains
130-
as many samples as the recording itself) using `recording.set_times()`.
152+
as many samples as the recording itself) using
153+
:meth:`set_times() <spikeinterface.core.BaseRecording.set_times>`
131154
132-
[TODO - an example?]
155+
.. code-block:: python
156+
157+
times = np.linspace(0, 10, recording.get_num_samples()))
158+
offset = np.cumsum(
159+
np.linspace(0, 0.1, recording.get_num_samples())
160+
)
161+
true_times = times + offset
162+
163+
recording.set_times(true_times)
164+
165+
recording.get_times()
133166
134167
.. warning::
135168
@@ -142,8 +175,12 @@ as many samples as the recording itself) using `recording.set_times()`.
142175
Retrieving timepoints from sample index
143176
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
144177
145-
SpikeInterface provides two convenience methods for obtaining the timepoint in seconds
146-
given an index of the time array:
178+
SpikeInterface provides two convenience methods for obtaining the
179+
timepoint in seconds given an index of the time array.
180+
181+
Use
182+
:meth:`time_to_sample_index() <spikeinterface.core.BaseRecording.time_to_sample_index>`
183+
to go from time to the sample index:
147184
148185
.. code-block:: python
149186
@@ -152,7 +189,9 @@ given an index of the time array:
152189
print(sample_index)
153190
154191
155-
Similarly, you can retrieve the time array index given a timepoint:
192+
and
193+
:meth:`sample_index_to_to_time() <spikeinterface.core.BaseRecording.sample_index_to_to_time>`
194+
to can retrieve the index given a timepoint:
156195
157196
158197
.. code-block:: python
@@ -166,9 +205,12 @@ Aligning events across timestreams
166205
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
167206
168207
The alignment of electrophysiology recording time to other data streams (e.g. behaviour)
169-
is an important step in ephys analysis. To acheive this,it is common to collect
170-
a synconrisation ('sync') pulse on an additional channel. At present SpikeInterface does not include
171-
features for time-alignment, but some useful articles can be found on the following pages,
172-
`SpikeGLX <https://github.com/billkarsh/SpikeGLX/blob/master/Markdown/UserManual.md#procedure-to-calibrate-sample-rates>`_,
173-
`OpenEphys <https://open-ephys.github.io/gui-docs/Tutorials/Data-Synchronization.html>`_,
174-
`NWB <https://neuroconv.readthedocs.io/en/main/user_guide/temporal_alignment.html>`_
208+
is an important step in electrophysiology analysis. To achieve this,it is common to acquire
209+
a synchronisation ('sync') pulse on an additional channel.
210+
211+
At present SpikeInterface does not include features for time-alignment,
212+
but some useful articles on how to approach this can be found on the following pages:
213+
214+
* `SpikeGLX <https://github.com/billkarsh/SpikeGLX/blob/master/Markdown/UserManual.md#procedure-to-calibrate-sample-rates>`_,
215+
* `OpenEphys <https://open-ephys.github.io/gui-docs/Tutorials/Data-Synchronization.html>`_,
216+
* `NWB <https://neuroconv.readthedocs.io/en/main/user_guide/temporal_alignment.html>`_

doc/sg_execution_times.rst

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
Computation times
88
=================
9-
**00:02.107** total execution time for 15 files **from all galleries**:
9+
**00:01.439** total execution time for 17 files **from all galleries**:
1010

1111
.. container::
1212

@@ -32,48 +32,54 @@ Computation times
3232
* - Example
3333
- Time
3434
- Mem (MB)
35-
* - :ref:`sphx_glr_tutorials_core_plot_4_sorting_analyzer.py` (``../examples/tutorials/core/plot_4_sorting_analyzer.py``)
36-
- 00:02.107
35+
* - :ref:`sphx_glr_tutorials_core_plot_4_sorting_analyzer.py` (``..\examples\tutorials\core\plot_4_sorting_analyzer.py``)
36+
- 00:01.425
3737
- 0.0
38-
* - :ref:`sphx_glr_tutorials_comparison_plot_5_comparison_sorter_weaknesses.py` (``../examples/tutorials/comparison/plot_5_comparison_sorter_weaknesses.py``)
38+
* - :ref:`sphx_glr_tutorials_core_plot_7_handle_times_new.py` (``..\examples\tutorials\core\plot_7_handle_times_new.py``)
39+
- 00:00.013
40+
- 0.0
41+
* - :ref:`sphx_glr_tutorials_comparison_generate_erroneous_sorting.py` (``..\examples\tutorials\comparison\generate_erroneous_sorting.py``)
42+
- 00:00.000
43+
- 0.0
44+
* - :ref:`sphx_glr_tutorials_comparison_plot_5_comparison_sorter_weaknesses.py` (``..\examples\tutorials\comparison\plot_5_comparison_sorter_weaknesses.py``)
3945
- 00:00.000
4046
- 0.0
41-
* - :ref:`sphx_glr_tutorials_core_plot_1_recording_extractor.py` (``../examples/tutorials/core/plot_1_recording_extractor.py``)
47+
* - :ref:`sphx_glr_tutorials_core_plot_1_recording_extractor.py` (``..\examples\tutorials\core\plot_1_recording_extractor.py``)
4248
- 00:00.000
4349
- 0.0
44-
* - :ref:`sphx_glr_tutorials_core_plot_2_sorting_extractor.py` (``../examples/tutorials/core/plot_2_sorting_extractor.py``)
50+
* - :ref:`sphx_glr_tutorials_core_plot_2_sorting_extractor.py` (``..\examples\tutorials\core\plot_2_sorting_extractor.py``)
4551
- 00:00.000
4652
- 0.0
47-
* - :ref:`sphx_glr_tutorials_core_plot_3_handle_probe_info.py` (``../examples/tutorials/core/plot_3_handle_probe_info.py``)
53+
* - :ref:`sphx_glr_tutorials_core_plot_3_handle_probe_info.py` (``..\examples\tutorials\core\plot_3_handle_probe_info.py``)
4854
- 00:00.000
4955
- 0.0
50-
* - :ref:`sphx_glr_tutorials_core_plot_5_append_concatenate_segments.py` (``../examples/tutorials/core/plot_5_append_concatenate_segments.py``)
56+
* - :ref:`sphx_glr_tutorials_core_plot_5_append_concatenate_segments.py` (``..\examples\tutorials\core\plot_5_append_concatenate_segments.py``)
5157
- 00:00.000
5258
- 0.0
53-
* - :ref:`sphx_glr_tutorials_core_plot_6_handle_times.py` (``../examples/tutorials/core/plot_6_handle_times.py``)
59+
* - :ref:`sphx_glr_tutorials_core_plot_6_handle_times.py` (``..\examples\tutorials\core\plot_6_handle_times.py``)
5460
- 00:00.000
5561
- 0.0
56-
* - :ref:`sphx_glr_tutorials_extractors_plot_1_read_various_formats.py` (``../examples/tutorials/extractors/plot_1_read_various_formats.py``)
62+
* - :ref:`sphx_glr_tutorials_extractors_plot_1_read_various_formats.py` (``..\examples\tutorials\extractors\plot_1_read_various_formats.py``)
5763
- 00:00.000
5864
- 0.0
59-
* - :ref:`sphx_glr_tutorials_extractors_plot_2_working_with_unscaled_traces.py` (``../examples/tutorials/extractors/plot_2_working_with_unscaled_traces.py``)
65+
* - :ref:`sphx_glr_tutorials_extractors_plot_2_working_with_unscaled_traces.py` (``..\examples\tutorials\extractors\plot_2_working_with_unscaled_traces.py``)
6066
- 00:00.000
6167
- 0.0
62-
* - :ref:`sphx_glr_tutorials_qualitymetrics_plot_3_quality_mertics.py` (``../examples/tutorials/qualitymetrics/plot_3_quality_mertics.py``)
68+
* - :ref:`sphx_glr_tutorials_qualitymetrics_plot_3_quality_mertics.py` (``..\examples\tutorials\qualitymetrics\plot_3_quality_mertics.py``)
6369
- 00:00.000
6470
- 0.0
65-
* - :ref:`sphx_glr_tutorials_qualitymetrics_plot_4_curation.py` (``../examples/tutorials/qualitymetrics/plot_4_curation.py``)
71+
* - :ref:`sphx_glr_tutorials_qualitymetrics_plot_4_curation.py` (``..\examples\tutorials\qualitymetrics\plot_4_curation.py``)
6672
- 00:00.000
6773
- 0.0
68-
* - :ref:`sphx_glr_tutorials_widgets_plot_1_rec_gallery.py` (``../examples/tutorials/widgets/plot_1_rec_gallery.py``)
74+
* - :ref:`sphx_glr_tutorials_widgets_plot_1_rec_gallery.py` (``..\examples\tutorials\widgets\plot_1_rec_gallery.py``)
6975
- 00:00.000
7076
- 0.0
71-
* - :ref:`sphx_glr_tutorials_widgets_plot_2_sort_gallery.py` (``../examples/tutorials/widgets/plot_2_sort_gallery.py``)
77+
* - :ref:`sphx_glr_tutorials_widgets_plot_2_sort_gallery.py` (``..\examples\tutorials\widgets\plot_2_sort_gallery.py``)
7278
- 00:00.000
7379
- 0.0
74-
* - :ref:`sphx_glr_tutorials_widgets_plot_3_waveforms_gallery.py` (``../examples/tutorials/widgets/plot_3_waveforms_gallery.py``)
80+
* - :ref:`sphx_glr_tutorials_widgets_plot_3_waveforms_gallery.py` (``..\examples\tutorials\widgets\plot_3_waveforms_gallery.py``)
7581
- 00:00.000
7682
- 0.0
77-
* - :ref:`sphx_glr_tutorials_widgets_plot_4_peaks_gallery.py` (``../examples/tutorials/widgets/plot_4_peaks_gallery.py``)
83+
* - :ref:`sphx_glr_tutorials_widgets_plot_4_peaks_gallery.py` (``..\examples\tutorials\widgets\plot_4_peaks_gallery.py``)
7884
- 00:00.000
7985
- 0.0
25.4 KB
Loading

0 commit comments

Comments
 (0)