pynapple icon indicating copy to clipboard operation
pynapple copied to clipboard

New desired functions for IntervalSets - expand, contract, is_in

Open ckemere opened this issue 1 year ago • 2 comments

Just starting to play around with Pynapple, and I find a few expected IntervalSet functions missing. I'd love to be able to

slightly_larger_interval = intervals.expand(0.1)
slightly_smaller_interval = intervals.contract(0.1)

Though note that here, expanding should cause automerging of nearby intervals (so the number might decrease), and contracting should autodrop zero-duration intervals (so the number might decrease).

Also, I'd love to be able to do:

if intervals.is_in(t_interesting):
    do something cool

ckemere avatar Jun 24 '24 15:06 ckemere

Maybe expand() and contract() can take a tuple to include/exclude timepoints before and after. Similar to numpy.pad. Also something I think might be useful is to shift the interval as a whole. This would be handy when playing with different response latency to compute tuning curves. For is_in(), would intersect() be a good enough exiting solution?

qian-chu avatar Jun 26 '24 08:06 qian-chu

For is_in(), there is already the function in_interval of IntervalSet. For example

ep = nap.IntervalSet(start=[0, 40], end=[10, 50])
tsd = nap.Tsd(t=np.arange(100), d=np.random.randn(100))
idx = ep.in_interval(tsd)

and idx is

>>> idx
array([ 0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0., nan, nan,
       nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,
       nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,
       nan,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1., nan,
       nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,
       nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,
       nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan,
       nan, nan, nan, nan, nan, nan, nan, nan, nan])

then you can do np.any(~np.isnan(ep.in_interval(tsd))) or np.all(~np.isnan(ep.in_interval(tsd)))

~ Expand and contract might be interesting although it is quite fast to do it manually. If you have ep like

>>> ep
            start    end
       0        0     10
       1       40     50
shape: (2, 2), time unit: sec.

I can add 1 second by recreating a new object:

nap.IntervalSet(ep.start, ep.end+1.0)

If the start is after the next end, IntervalSet will automatically merge them during initialization.

~ Shifting can be a good idea. For the moment adding any scalar to the IntervalSet will return a numpy array. Shifting everything together is mostly about writing the __array__ function of IntervalSet to support arithmetical operations so not too complicated.

Maybe expand() and contract() can take a tuple to include/exclude timepoints before and after. I am not sure I understand this part.

~ Overall I don't think any of those functions are too complicated to implement and could be nice additions. I will let this issue open until it's added. Feel free to open PRs.

gviejo avatar Jul 01 '24 16:07 gviejo