Source code for pynapple.io.misc

#!/usr/bin/env python

"""
Various io functions

"""
import warnings
from pathlib import Path
from xml.dom import minidom

import numpy as np
from pynwb import NWBHDF5IO
from pynwb.ecephys import LFP, ElectricalSeries

from .. import core as nap
from .cnmfe import CNMF_E, InscopixCNMFE, Minian
from .folder import Folder
from .interface_npz import NPZFile
from .interface_nwb import NWBFile
from .loader import BaseLoader
from .neurosuite import NeuroSuite
from .phy import Phy
from .suite2p import Suite2P


[docs] def load_file(path, lazy_loading=None): """Load file. Current format supported is (npz,nwb,) .npz -> If the file is compatible with a pynapple format, the function will return a pynapple object. Otherwise, the function will return the output of numpy.load .nwb -> Return the pynapple.io.NWBFile class wrapping the NWBFile Parameters ---------- path : str Path to the file lazy_loading : bool, optional default True Lazy loading of the data. If not specified, the function will use the defaults True. Works only with NWB files. Returns ------- (Tsd, TsdFrame, Ts, IntervalSet, TsGroup, pynapple.io.NWBFile) One of the 5 pynapple objects or pynapple.io.NWBFile Raises ------ FileNotFoundError If file is missing """ path = Path(path) if not path.exists(): raise FileNotFoundError(f"File {path} does not exist") if path.suffix == ".npz": if lazy_loading: warnings.warn("Lazy loading is not supported for NPZ files") return NPZFile(path).load() elif path.suffix == ".nwb": # preserves class init default: kwargs_for_lazyloading = ( {} if lazy_loading is None else {"lazy_loading": lazy_loading} ) return NWBFile(path, **kwargs_for_lazyloading) else: raise RuntimeError("File format not supported")
[docs] def load_folder(path): """Load folder containing files or other folder. Pynapple will walk throught the subfolders to detect compatible npz files or nwb files. Parameters ---------- path : str Path to the folder Returns ------- Folder A dictionary-like class containing all the sub-folders and compatible files (i.e. npz, nwb) Raises ------ RuntimeError If folder is missing """ path = Path(path) if not path.exists(): raise FileNotFoundError(f"Folder {path} does not exist") return Folder(path)
[docs] def load_session(path, session_type=None): """ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % WARNING : THIS FUNCTION IS DEPRECATED % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% General Loader for - Neurosuite\n - Phy\n - Minian\n - Inscopix-cnmfe\n - Matlab-cnmfe\n - Suite2p - None for default session. Parameters ---------- path : str, optional The path to load the data session_type : str, optional Can be 'neurosuite', 'phy', 'minian', 'inscopix-cnmfe', 'cnmfe-matlab', 'suite2p' or None for default loader. Returns ------- Session A class holding all the data from the session. """ path = Path(path) assert path.exists(), f"Folder {path} does not exist" if isinstance(session_type, str): session_type = session_type.lower() if session_type == "neurosuite": return NeuroSuite(path) elif session_type == "phy": return Phy(path) elif session_type == "inscopix-cnmfe": return InscopixCNMFE(path) elif session_type == "minian": return Minian(path) elif session_type == "cnmfe-matlab": return CNMF_E(path) elif session_type == "suite2p": return Suite2P(path) else: return BaseLoader(path)
[docs] def load_eeg( filepath, channel=None, n_channels=None, frequency=None, precision="int16", bytes_size=2, ): """ Standalone function to load eeg/lfp/dat file in binary format. Parameters ---------- filepath : str The path to the eeg file channel : int or list of int, optional The channel(s) to load. If None return a memory map of the dat file to avoid memory error n_channels : int, optional Number of channels frequency : float, optional Sampling rate of the file precision : str, optional The precision of the binary file bytes_size : int, optional Bytes size of the binary file Raises ------ RuntimeError If can't find the lfp/eeg/dat file Returns ------- Tsd or TsdFrame The lfp in a time series format Deleted Parameters ------------------ extension : str, optional The file extenstion (.eeg, .dat, .lfp). Make sure the frequency match """ # Need to check if a xml file exists filepath = Path(filepath) path = filepath.parent basename = filepath.name.split(".")[0] listdir = list(path.glob("*")) if frequency is None or n_channels is None: if basename + ".xml" in listdir: xmlpath = path / (basename + ".xml") xmldoc = minidom.parse(xmlpath) else: raise RuntimeError( "Can't find xml file; please specify sampling frequency or number of channels" ) if frequency is None: if filepath.endswith(".dat"): fs_dat = int( xmldoc.getElementsByTagName("acquisitionSystem")[0] .getElementsByTagName("samplingRate")[0] .firstChild.data ) frequency = fs_dat elif filepath.endswith((".lfp", ".eeg")): fs_eeg = int( xmldoc.getElementsByTagName("fieldPotentials")[0] .getElementsByTagName("lfpSamplingRate")[0] .firstChild.data ) frequency = fs_eeg if n_channels is None: n_channels = int( xmldoc.getElementsByTagName("acquisitionSystem")[0] .getElementsByTagName("nChannels")[0] .firstChild.data ) f = open(filepath, "rb") startoffile = f.seek(0, 0) endoffile = f.seek(0, 2) bytes_size = 2 n_samples = int((endoffile - startoffile) / n_channels / bytes_size) duration = n_samples / frequency f.close() fp = np.memmap(filepath, np.int16, "r", shape=(n_samples, n_channels)) timestep = np.arange(0, n_samples) / frequency time_support = nap.IntervalSet(start=0, end=duration, time_units="s") if channel is None: return fp elif type(channel) is int: return nap.Tsd( t=timestep, d=fp[:, channel], time_units="s", time_support=time_support ) elif type(channel) is list: return nap.TsdFrame( t=timestep, d=fp[:, channel], time_units="s", time_support=time_support, columns=channel, )
[docs] def append_NWB_LFP(path, lfp, channel=None): """Standalone function for adding lfp/eeg to already existing nwb files. Parameters ---------- path : str The path to the data. The function will looks for a nwb file in path or in path/pynapplenwb. lfp : Tsd or TsdFrame Description channel : None, optional channel number in int ff lfp is a Tsd Raises ------ RuntimeError If can't find the nwb file \n If no channel is specify when passing a Tsd """ path = Path(path) new_path = path / "pynapplenwb" nwb_path = "" try: nwb_path = next(new_path.glob("*.nwb")) except StopIteration: raise RuntimeError("Can't find nwb file in {}".format(path)) if isinstance(lfp, nap.TsdFrame): channels = list(lfp.columns.values) elif isinstance(lfp, nap.Tsd): if isinstance(channel, int): channels = [channel] else: raise RuntimeError("Please specify which channel it is.") io = NWBHDF5IO(nwb_path, "r+") nwbfile = io.read() all_table_region = nwbfile.create_electrode_table_region( region=channels, description="", name="electrodes" ) lfp_electrical_series = ElectricalSeries( name="ElectricalSeries", data=lfp.values, timestamps=lfp.index.values, electrodes=all_table_region, ) lfp = LFP(electrical_series=lfp_electrical_series) ecephys_module = nwbfile.create_processing_module( name="ecephys", description="processed extracellular electrophysiology data" ) ecephys_module.add(lfp) io.write(nwbfile) io.close() return