12345678910111213141516171819202122232425262728293031323334353637383940 |
- from collections import namedtuple
- import numpy as np
- import sliding1d as sliding
- def interpolate(vec, min_size=10):
- valid = ~np.isnan(vec)
- if np.count_nonzero(valid) < min_size:
- return np.empty(vec.size) * np.nan
- t = np.arange(vec.size)
- return np.interp(t, t[valid], vec[valid])
- def whisker(trial, side="left", radius_sample=10, smooth=True):
- return Envelope.whisker(trial, side=side, radius_sample=radius_sample, smooth=smooth)
- class Envelope(namedtuple("_Envelope", ("time", "raw", "bottom", "top"))):
- @classmethod
- def whisker(cls, trial, side="left", radius_sample=10, smooth=True):
- vec = interpolate(trial.tracking[f"{side}_whisker_angle_deg"])
- vec = (vec - vec.min()) / (vec.max() - vec.min())
- time = np.array(trial.tracking["time"])
- return cls.compute(time, vec, radius_sample=radius_sample, smooth=smooth)
-
- @classmethod
- def compute(cls, time, vec, radius_sample=10, smooth=True):
- bottom = sliding.nanmin(vec, radius_sample)
- top = sliding.nanmax(vec, radius_sample)
- if smooth == True:
- bottom = sliding.nanmean(bottom, radius_sample)
- top = sliding.nanmean(top, radius_sample)
- return cls(time, vec, bottom, top)
-
- @property
- def amplitude(self):
- return self.top - self.bottom
-
- def with_range(self, rng):
- return self.__class__(self.time[rng],
- self.raw[rng],
- self.bottom[rng],
- self.top[rng])
|