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