docs: def get_peaks(self, method="slope", peak_amp_thresh=0.00005,
                    valley_thresh=0.00003, intervals=None, lookahead=20,
                    avg_interval=100):
          """
          This function expects SMOOTHED histogram. If you run it on a raw histogram,
          there is a high chance that it returns no peaks.
  
          method can be interval/slope/hybrid.
              The interval-based method simply steps through the whole histogram
              and pick up the local maxima in each interval, from which irrelevant
              peaks are filtered out by looking at the proportion of points on 
              either side of the detected peak in each interval, and by applying
              peal_amp_thresh and valley_thresh bounds.
          
              Slope approach uses, of course slope information, to find peaks, 
              which are then filtered by applying peal_amp_thresh and 
              valley_thresh bounds. 
              
              Hybrid approach combines the peaks obtained using slope method and
              interval-based approach. It retains the peaks/valleys from slope method
              if there should be a peak around the same region from each of the methods.
          
          peak_amp_thresh is the minimum amplitude/height that a peak should have
          in a normalized smoothed histogram, to be qualified as a peak. 
          valley_thresh is viceversa for valleys!
  
          If the method is interval/hybrid, then the intervals argument must be passed
          and it should be an instance of Intervals class.
  
          If the method is slope/hybrid, then the lookahead and avg_window
          arguments should be changed based on the application. 
          They have some default values though.
  
          The method stores peaks in self.peaks in the following format:
          {"peaks":[[peak positions], [peak amplitudes]],
          "valleys": [[valley positions], [valley amplitudes]]}
          """
  
          peaks = {}
          slope_peaks = {}
          #Oh dear future me, please don't get confused with a lot of mess around
          # indices around here. All indices (eg: left_index etc) refer to indices
          # of x or y (of histogram).
          if method == "slope" or method == "hybrid":
  
              #step 1: get the peaks
              result = slope.peaks(self.x, self.y, lookahead=lookahead,
                                   delta=valley_thresh)
  
              #step 2: find left and right valley points for each peak
              peak_data = result["peaks"]
              valley_data = result["valleys"]
  
              for i in xrange(len(peak_data[0])):
                  nearest_index = slope.find_nearest_index(valley_data[0],
                                                           peak_data[0][i])
                  if valley_data[0][nearest_index] < peak_data[0][i]:
                      left_index = slope.find_nearest_index(
                          self.x, valley_data[0][nearest_index])
                      if len(valley_data[0][nearest_index + 1:]) == 0:
                          right_index = slope.find_nearest_index(
                              self.x, peak_data[0][i] + avg_interval / 2)
                      else:
                          offset = nearest_index + 1
                          nearest_index = offset + slope.find_nearest_index(
                              valley_data[0][offset:], peak_data[0][i])
                          right_index = slope.find_nearest_index(
                              self.x, valley_data[0][nearest_index])
                  else:
                      right_index = slope.find_nearest_index(
                          self.x, valley_data[0][nearest_index])
                      if len(valley_data[0][:nearest_index]) == 0:
                          left_index = slope.find_nearest_index(
                              self.x, peak_data[0][i] - avg_interval / 2)
                      else:
                          nearest_index = slope.find_nearest_index(
                              valley_data[0][:nearest_index], peak_data[0][i])
                          left_index = slope.find_nearest_index(
                              self.x, valley_data[0][nearest_index])
  
                  pos = slope.find_nearest_index(self.x, peak_data[0][i])
                  slope_peaks[pos] = [peak_data[1][i], left_index, right_index]
  
          if method == "slope":
              peaks = slope_peaks
  
          interval_peaks = {}
          if method == "interval" or method == "hybrid":
              if intervals is None:
                  raise ValueError('The interval argument is not passed.')
              #step 1: get the average size of the interval, first and last
              # probable centers of peaks
              avg_interval = np.average(intervals.intervals[1:] - intervals.intervals[:-1])
              value = (min(self.x) + 1.5 * avg_interval) / avg_interval * avg_interval
              first_center = intervals.nearest_interval(value)
              value = (max(self.x) - avg_interval) / avg_interval * avg_interval
              last_center = intervals.nearest_interval(value)
              if first_center < intervals.intervals[0]:
                  first_center = intervals.intervals[0]
                  warn("In the interval based approach, the first center was seen\
                      to be too low and is set to " + str(first_center))
              if last_center > intervals.intervals[-1]:
                  last_center = intervals.intervals[-1]
                  warn("In the interval based approach, the last center was seen\
                       to be too high and is set to " + str(last_center))
  
              #step 2: find the peak position, and set the left and right bounds
              # which are equivalent in sense to the valley points
              interval = first_center
              while interval <= last_center:
                  prev_interval = intervals.prev_interval(interval)
                  next_interval = intervals.next_interval(interval)
                  left_index = slope.find_nearest_index(
                      self.x, (interval + prev_interval) / 2)
                  right_index = slope.find_nearest_index(
                      self.x, (interval + next_interval) / 2)
                  peak_pos = np.argmax(self.y[left_index:right_index])
                  # add left_index to peak_pos to get the correct position in x/y
                  peak_amp = self.y[left_index + peak_pos]
                  interval_peaks[left_index + peak_pos] = [peak_amp, left_index,
                                                           right_index]
                  interval = next_interval
  
          if method == "interval":
              peaks = interval_peaks
  
          # If its is a hybrid method merge the results. If we find same
          # peak position in both results, we prefer valleys of slope-based peaks
          if method == "hybrid":
              p1 = slope_peaks.keys()
              p2 = interval_peaks.keys()
              all_peaks = {}
              for p in p1:
                  near_index = slope.find_nearest_index(p2, p)
                  if abs(p - p2[near_index]) < avg_interval / 2:
                      p2.pop(near_index)
              for p in p1:
                  all_peaks[p] = slope_peaks[p]
              for p in p2:
                  all_peaks[p] = interval_peaks[p]
              peaks = all_peaks
  
          # Finally, filter the peaks and retain eligible peaks, also get
          # their valley points.
  
          # check 1: peak_amp_thresh
          for pos in peaks.keys():
              # pos is an index in x/y. DOES NOT refer to a cent value.
              if peaks[pos][0] < peak_amp_thresh:
                  peaks.pop(pos)
  
          # check 2, 3: valley_thresh, proportion of size of left and right lobes
          valleys = {}
          for pos in peaks.keys():
              # remember that peaks[pos][1] is left_index and
              # peaks[pos][2] is the right_index
              left_lobe = self.y[peaks[pos][1]:pos]
              right_lobe = self.y[pos:peaks[pos][2]]
              if len(left_lobe) == 0 or len(right_lobe) == 0:
                  peaks.pop(pos)
                  continue
              if len(left_lobe) / len(right_lobe) < 0.15 or len(right_lobe) / len(left_lobe) < 0.15:
                  peaks.pop(pos)
                  continue
              left_valley_pos = np.argmin(left_lobe)
              right_valley_pos = np.argmin(right_lobe)
              if (abs(left_lobe[left_valley_pos] - self.y[pos]) < valley_thresh and
                  abs(right_lobe[right_valley_pos] - self.y[pos]) < valley_thresh):
                  peaks.pop(pos)
              else:
                  valleys[peaks[pos][1] + left_valley_pos] = left_lobe[left_valley_pos]
                  valleys[pos + right_valley_pos] = right_lobe[right_valley_pos]
  
          if len(peaks) > 0:
              peak_amps = np.array(peaks.values())
              peak_amps = peak_amps[:, 0]
              # hello again future me, it is given that you'll pause here
              # wondering why the heck we index x with peaks.keys() and
              # valleys.keys(). Just recall that pos refers to indices and
              # not value corresponding to the histogram bin. If i is pos,
              # x[i] is the bin value. Tada!!
              self.peaks = {'peaks': [self.x[peaks.keys()], peak_amps], 'valleys': [self.x[valleys.keys()], valleys.values()]}
          else:
              self.peaks = {'peaks': [[], []], 'valleys': [[], []]}