|
249 | 249 | ) |
250 | 250 | ecephys_module.add(lfp) |
251 | 251 |
|
252 | | -#################### |
| 252 | +####################### |
| 253 | +# If the derived data is filtered but not downsampled, you can store the data in an |
| 254 | +# :py:class:`~pynwb.ecephys.ElectricalSeries` object in a :py:class:`~pynwb.ecephys.FilteredEphys` object |
| 255 | +# instead of a :py:class:`~pynwb.ecephys.LFP` object. |
| 256 | + |
| 257 | +from pynwb.ecephys import FilteredEphys |
| 258 | + |
| 259 | +filtered_data = np.random.randn(50, 12) |
| 260 | +filtered_electrical_series = ElectricalSeries( |
| 261 | + name="FilteredElectricalSeries", |
| 262 | + description="Filtered data", |
| 263 | + data=filtered_data, |
| 264 | + electrodes=all_table_region, |
| 265 | + starting_time=0.0, |
| 266 | + rate=200.0, |
| 267 | +) |
| 268 | + |
| 269 | +filtered_ephys = FilteredEphys(electrical_series=filtered_electrical_series) |
| 270 | +ecephys_module.add(filtered_ephys) |
| 271 | + |
| 272 | +################################ |
253 | 273 | # In some cases, you may want to further process the LFP data and decompose the signal into different frequency bands |
254 | 274 | # to use for other downstream analyses. You can store the processed data from these spectral analyses using a |
255 | 275 | # :py:class:`~pynwb.misc.DecompositionSeries` object. This object allows you to include metadata about the frequency |
|
266 | 286 | gamma=(30.0, 80.0)) # in Hz |
267 | 287 | phase_data = np.random.randn(50, 12, len(bands)) # 50 samples, 12 channels, 3 frequency bands |
268 | 288 |
|
269 | | -decomp_series = DecompositionSeries(name="theta", |
270 | | - description="phase of bandpass filtered LFP data", |
271 | | - data=phase_data, |
272 | | - metric='phase', |
273 | | - rate=200.0, |
274 | | - source_channels=all_table_region, |
275 | | - source_timeseries=lfp_electrical_series) |
| 289 | +decomp_series = DecompositionSeries( |
| 290 | + name="theta", |
| 291 | + description="phase of bandpass filtered LFP data", |
| 292 | + data=phase_data, |
| 293 | + metric='phase', |
| 294 | + rate=200.0, |
| 295 | + source_channels=all_table_region, |
| 296 | + source_timeseries=lfp_electrical_series, |
| 297 | +) |
276 | 298 |
|
277 | 299 | for band_name, band_limits in bands.items(): |
278 | | - decomp_series.add_band(band_name=band_name, band_limits=band_limits, band_mean=np.nan, band_stdev=np.nan) |
| 300 | + decomp_series.add_band( |
| 301 | + band_name=band_name, |
| 302 | + band_limits=band_limits, |
| 303 | + band_mean=np.nan, |
| 304 | + band_stdev=np.nan, |
| 305 | + ) |
279 | 306 |
|
280 | 307 | ecephys_module.add(decomp_series) |
281 | 308 |
|
|
312 | 339 |
|
313 | 340 | ####################### |
314 | 341 | # The :py:class:`~pynwb.misc.Units` table can also be converted to a pandas :py:class:`~pandas.DataFrame`. |
| 342 | +# |
| 343 | +# The :py:class:`~pynwb.misc.Units` table can contain simply the spike times of sorted units, or you can also include |
| 344 | +# individual and mean waveform information in some of the optional, predefined :py:class:`~pynwb.misc.Units` table |
| 345 | +# columns: ``waveform_mean``, ``waveform_sd``, or ``waveforms``. |
315 | 346 |
|
316 | 347 | nwbfile.units.to_dataframe() |
317 | 348 |
|
|
330 | 361 | description="shank0", |
331 | 362 | ) |
332 | 363 |
|
333 | | - |
334 | | -spike_events = SpikeEventSeries(name='SpikeEvents_Shank0', |
335 | | - description="events detected with 100uV threshold", |
336 | | - data=spike_snippets, |
337 | | - timestamps=np.arange(20), |
338 | | - electrodes=shank0) |
| 364 | +spike_events = SpikeEventSeries( |
| 365 | + name='SpikeEvents_Shank0', |
| 366 | + description="events detected with 100uV threshold", |
| 367 | + data=spike_snippets, |
| 368 | + timestamps=np.arange(20), |
| 369 | + electrodes=shank0, |
| 370 | +) |
339 | 371 | nwbfile.add_acquisition(spike_events) |
340 | 372 |
|
341 | | -####################### |
342 | | -# Designating electrophysiology data |
343 | | -# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
344 | | -# |
345 | | -# As mentioned above, :py:class:`~pynwb.ecephys.ElectricalSeries` objects |
346 | | -# are meant for storing specific types of extracellular recordings. In addition to this |
347 | | -# :py:class:`~pynwb.base.TimeSeries` class, NWB provides some :ref:`modules_overview` |
348 | | -# for designating the type of data you are storing. We will briefly discuss them here, and refer the reader to |
349 | | -# :py:mod:`API documentation <pynwb.ecephys>` and :ref:`basics` for more details on |
350 | | -# using these objects. |
351 | | -# |
352 | | -# For storing unsorted spiking data, there are two options. Which one you choose depends on what data you |
353 | | -# have available. If you need to store the complete, continuous raw voltage traces, you should store the traces with |
354 | | -# :py:class:`~pynwb.ecephys.ElectricalSeries` objects as :ref:`acquisition <basic_timeseries>` data, and use |
355 | | -# the :py:class:`~pynwb.ecephys.EventDetection` class for identifying the spike events in your raw traces. |
| 373 | +############################################ |
| 374 | +# If you need to store the complete, continuous raw voltage traces, along with unsorted spike times, you should store |
| 375 | +# the traces with :py:class:`~pynwb.ecephys.ElectricalSeries` objects as :ref:`acquisition <basic_timeseries>` data, |
| 376 | +# and use the :py:class:`~pynwb.ecephys.EventDetection` class to identify the spike events in your raw traces. |
| 377 | + |
| 378 | +from pynwb.ecephys import EventDetection |
| 379 | + |
| 380 | +event_detection = EventDetection( |
| 381 | + name="threshold_events", |
| 382 | + detection_method="thresholding, 1.5 * std", |
| 383 | + source_electricalseries=raw_electrical_series, |
| 384 | + source_idx=[1000, 2000, 3000], |
| 385 | + times=[.033, .066, .099], |
| 386 | +) |
| 387 | + |
| 388 | +ecephys_module.add(event_detection) |
| 389 | + |
| 390 | +###################################### |
356 | 391 | # If you do not want to store the raw voltage traces and only the waveform 'snippets' surrounding spike events, |
357 | 392 | # you should store the snippets with :py:class:`~pynwb.ecephys.SpikeEventSeries` objects. |
358 | 393 | # |
359 | | -# The results of spike sorting (or clustering) should be stored in the top-level :py:class:`~pynwb.misc.Units` table. |
360 | | -# The :py:class:`~pynwb.misc.Units` table can contain simply the spike times of sorted units, or you can also include |
361 | | -# individual and mean waveform information in some of the optional, predefined :py:class:`~pynwb.misc.Units` table |
362 | | -# columns: ``waveform_mean``, ``waveform_sd``, or ``waveforms``. |
363 | | -# |
364 | | -# For local field potential data, there are two options. Again, which one you choose depends on what data you |
365 | | -# have available. With both options, you should store your traces with :py:class:`~pynwb.ecephys.ElectricalSeries` |
366 | | -# objects. If you are storing unfiltered local field potential data, you should store |
367 | | -# the :py:class:`~pynwb.ecephys.ElectricalSeries` objects in :py:class:`~pynwb.ecephys.LFP` data interface object(s). |
368 | | -# If you have filtered LFP data, you should store the :py:class:`~pynwb.ecephys.ElectricalSeries` objects in |
369 | | -# :py:class:`~pynwb.ecephys.FilteredEphys` data interface object(s). |
| 394 | +# NWB also provides a way to store features of spikes, such as principal components, using the |
| 395 | +# :py:class:`~pynwb.ecephys.FeatureExtraction` class. |
| 396 | + |
| 397 | +from pynwb.ecephys import FeatureExtraction |
| 398 | + |
| 399 | +feature_extraction = FeatureExtraction( |
| 400 | + name="PCA_features", |
| 401 | + electrodes=all_table_region, |
| 402 | + description=["PC1", "PC2", "PC3", "PC4"], |
| 403 | + times=[.033, .066, .099], |
| 404 | + features=np.random.rand(3, 12, 4), # time, channel, feature |
| 405 | +) |
370 | 406 |
|
| 407 | +ecephys_module.add(feature_extraction) |
371 | 408 |
|
372 | 409 | #################### |
373 | 410 | # .. _ecephys_writing: |
|
0 commit comments