text: import numpy as np
  import scipy.interpolate as spinterp
  
  from . import fitfuns
  from .kernel import Kernel1D
  
  
  class TemporalFilter(object):
      def __init__(self):
          self.t_support = []
          self.kernel_data = None
  
      def imshow(self, t_range=None, threshold=0, reverse=False, rescale=False, **kwargs):
          return self.get_kernel(t_range, threshold, reverse, rescale).imshow(**kwargs)
          
      def to_dict(self):
          return {'class': (__name__, self.__class__.__name__)}
  
      def get_default_t_grid(self):
          raise NotImplementedError()
  
      def get_kernel(self, t_range=None, threshold=0, reverse=False, rescale=False):
          if t_range is None:
              t_range = self.get_default_t_grid() 
          
          if len(self.t_support) == 1:
              k = Kernel1D(self.t_support, self.kernel_data, threshold=threshold, reverse=reverse)
  
          else:
              interpolation_function = spinterp.interp1d(self.t_support, self.kernel_data, fill_value=0,
                                                         bounds_error=False, assume_sorted=True)
              k = Kernel1D(t_range, interpolation_function(t_range), threshold=threshold, reverse=reverse)
  
          if rescale:
              k.rescale()
              assert(np.abs(np.abs(k.kernel.sum()) - 1) < 1e-14)
          
          return k
  
  
  class ArrayTemporalFilter(TemporalFilter):
      def __init__(self, mask, t_support):
          super(ArrayTemporalFilter, self).__init__()
          self.mask = mask
          self.t_support = t_support
          assert(len(self.mask) == len(self.t_support))
          self.nkt = 600
          self.kernel_data = self.mask
  
      def get_default_t_grid(self):
          return np.arange(self.nkt)*0.001
  
  
  class TemporalFilterCosineBump(TemporalFilter):
      def __init__(self, weights, kpeaks, delays):
          """Creates a time-based filter function by combining two cosine-based peaks into a function for convoluting
          the input with.
  
          :param weights: (float, float)the magntiude of both peaks, first weight must be positive
          :param kpeaks: (float, float) the spread of each peak, first peak (0) must be sharper
          :param delays: (float, float) the delay of both peaks, peak 0 must be positive occur first.
          """
  
          assert(len(kpeaks) == 2)
          assert(kpeaks[0] < kpeaks[1])
          assert(weights[0] > 0)
          assert(delays[0] <= delays[1])
  
          super(TemporalFilterCosineBump, self).__init__()
          self.ncos = len(weights)
  
          # Not likely to change defaults:
          self.neye = 0
          self.b = .3
          self.nkt = 600
  
          # Parameters
          self.weights = np.array([weights]).T
          self.kpeaks = kpeaks
          self.delays = np.array([delays]).astype(int)
  
          # Create two peak arrays (arr0 and arr1) using makeBasisStimKernel. Then merge them using dot product
          # w0*arr0 + w1*arr1.
          kbasprs = {
              'neye': self.neye,
              'ncos': self.ncos,
              'kpeaks': self.kpeaks,
              'b': self.b,
              'delays': self.delays
          }
          nkt = self.nkt
          self.kernel_data = np.dot(fitfuns.makeBasis_StimKernel(kbasprs, nkt), self.weights)[::-1].T[0]
  
          self.t_support = np.arange(0, len(self.kernel_data)*.001, .001)
          self.kbasprs = kbasprs
          assert len(self.t_support) == len(self.kernel_data)
          
      def __call__(self, t):
          return self.interpolation_function(t)
          
      def get_default_t_grid(self):
          return np.arange(self.nkt)*.001
      
      def to_dict(self):
          param_dict = super(TemporalFilterCosineBump, self).to_dict()
          param_dict.update({'weights': self.weights.tolist(), 'kpeaks': self.kpeaks})
          return param_dict
  