Skip to content

Commit

Permalink
simplify the loading of input files in the io module #minor (#335)
Browse files Browse the repository at this point in the history
* simplify the loading of ascii file in the io module

* add annotations for earlier python versions

* simplify load_neo_file's logic
  • Loading branch information
anilbey authored Dec 11, 2023
1 parent ada9b43 commit 1d898c8
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 544 deletions.
121 changes: 24 additions & 97 deletions efel/io.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from __future__ import annotations
"""IO handler for eFEL"""

"""
Expand All @@ -18,89 +19,22 @@
along with this library; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""
from pathlib import Path
import neo
import numpy as np

import os

# pylint:disable=E0611, F0401
import urllib.parse as up
import urllib.request as ur
def load_ascii_input(
file_path: Path | str, delimiter: str = " "
) -> tuple[np.ndarray, np.ndarray]:
"""Loads electrophysiology data from an ASCII file.
# pylint:enable=E0611,F0401

import mimetypes


def windows_compatible(func):
"""Decorator allowing to use urlparse with windows."""

def inner(fragment_url):
"""Change windows path part to url."""
# if system is windows
if os.name == "nt":
fragment_url.replace("\\", "/")

parsed_url = func(fragment_url)

return parsed_url

return inner


def load_fragment(fragment_url, mime_type=None):
"""Load fragment
Load a fragment (e.g. time series data) from a given URL
Returns: A tuple containing two numpy arrays, one for time and one for voltage.
"""
parsed_url = windows_compatible(up.urlparse)(fragment_url)

scheme = parsed_url.scheme
server_loc = parsed_url.netloc
path = parsed_url.path
fragment_string = parsed_url.fragment

# reform path for windows files
if scheme == "file" and os.name == "nt":
path = ur.url2pathname(r"\\" + server_loc + path)

if mime_type is None:
mimetypes.init()
mime_type, _ = mimetypes.guess_type(path)
if mime_type is None:
raise TypeError(
'load_fragment: impossible to guess MIME type from url, '
'please specify the type manually as argument: %s' % path)

if scheme == 'file' and os.name == 'nt':
file_handle = open(path, 'r')
elif scheme == 'file':
file_handle = open(os.path.join(server_loc, path), 'r')

if 'text/' in mime_type:
import numpy

if fragment_string == '':
cols = None
else:
import re

match = re.match("col=([0-9]+)", fragment_string)
if match is None or len(match.groups()) != 1:
raise TypeError(
"load_fragment: don't understand url fragment %s" %
fragment_string)
else:
cols = int(match.groups()[0]) - 1

# Unfortunately we need this if statement
# Setting usecols to None throws an error in the loadtxt call
if cols is not None:
fragment_content = numpy.loadtxt(file_handle, usecols=[cols])
else:
fragment_content = numpy.loadtxt(file_handle)

return fragment_content
else:
raise TypeError('load_fragment: unknown mime type %s' % mime_type)
file_path = Path(file_path)
data = np.loadtxt(file_path, delimiter=delimiter)
time, voltage = data[:, 0], data[:, 1]
return time, voltage


def extract_stim_times_from_neo_data(blocks, stim_start, stim_end):
Expand Down Expand Up @@ -242,37 +176,30 @@ def load_neo_file(file_name, stim_start=None, stim_end=None, **kwargs):
returned object : [Segments_1, Segments_2, ..., Segments_n]
Segments_1 = [Traces_1, Traces_2, ..., Traces_n]
"""

import neo

reader = neo.io.get_io(file_name)
blocks = reader.read(**kwargs)

stim_start, stim_end = extract_stim_times_from_neo_data(
blocks, stim_start, stim_end)
if stim_start is None or stim_end is None:
raise ValueError(
'No stim_start or stim_end has been found inside epochs or events.'
' You can directly specify their value as argument "stim_start"'
' and "stim_end"')
'No stim_start or stim_end found in epochs or events. '
'Please specify "stim_start" and "stim_end" arguments.')

# this part of the code transforms the data format.
# Convert data for eFEL
efel_blocks = []
for bl in blocks:
efel_segments = []
for seg in bl.segments:
traces = []
count_traces = 0
analogsignals = seg.analogsignals

for sig in analogsignals:
traces.append({})
traces[count_traces]['T'] = sig.times.rescale('ms').magnitude
traces[count_traces]['V'] = sig.rescale('mV').magnitude
traces[count_traces]['stim_start'] = [stim_start]
traces[count_traces]['stim_end'] = [stim_end]
count_traces += 1

for sig in seg.analogsignals:
trace = {
'T': sig.times.rescale('ms').magnitude,
'V': sig.rescale('mV').magnitude,
'stim_start': [stim_start],
'stim_end': [stim_end]
}
traces.append(trace)
efel_segments.append(traces)
efel_blocks.append(efel_segments)

Expand Down
3 changes: 1 addition & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,7 @@
name="efel",
version=versioneer.get_version(),
cmdclass=versioneer.get_cmdclass(),
install_requires=['numpy>=1.6'],
extras_require={'neo': ['neo[neomatlabio]>=0.5.1']},
install_requires=['numpy>=1.6', 'neo>=0.5.2'],
packages=['efel', 'efel.pyfeatures', 'efel.units'],
author="BlueBrain Project, EPFL",
maintainer="Werner Van Geit",
Expand Down
Loading

0 comments on commit 1d898c8

Please sign in to comment.