code: def distort_matrix_X(Z, X, f, new_xmin, new_xmax, subsample=3):
      
  
      Z = _n.array(Z)
      X = _n.array(X)
      points = len(Z)*subsample
  
  
      # define a function for searching
      def zero_me(new_x): return f(new_x)-target_old_x
  
      # do a simple search to find the new_x that gives old_x = min(X)
      target_old_x = min(X)
      new_xmin = find_zero_bisect(zero_me, new_xmin, new_xmax, _n.abs(new_xmax-new_xmin)*0.0001)
      target_old_x = max(X)
      new_xmax = find_zero_bisect(zero_me, new_xmin, new_xmax, _n.abs(new_xmax-new_xmin)*0.0001)
  
      # now loop over all the new x values
      new_X = []
      new_Z = []
      bin_width = float(new_xmax-new_xmin)/(points)
      for new_x in frange(new_xmin, new_xmax, bin_width):
  
          # make sure we're in the range of X
          if f(new_x) <= max(X) and f(new_x) >= min(X):
  
              # add this guy to the array
              new_X.append(new_x)
  
              # get the interpolated column
              new_Z.append( interpolate(X,Z,f(new_x)) )
  
      return _n.array(new_Z), _n.array(new_X)
docs: Applies a distortion (remapping) to the matrix Z (and x-values X) using function f.
      returns new_Z, new_X
  
      f is an INVERSE function old_x(new_x)
  
      Z is a matrix. X is an array where X[n] is the x-value associated with the array Z[n].
  
      new_xmin, new_xmax is the possible range of the distorted x-variable for generating Z
  
      points is how many elements the stretched Z should have. "auto" means use the same number of bins