input: Write a function to load a configuration file, libraries, and data, perform cubic spline interpolation on the data, apply a threshold to remove small values, and generate three plots: a histogram, an interpolated image, and a contour plot. The function should return the interpolated data. If the data file is not found, it should raise a FileNotFoundError.
  
  def generate_plots(config_path, lib_path, profileName, frameID, matrixID, save_dir):
      import os
      import sys
      import numpy as np
      import matplotlib.pyplot as plt
      import scipy.interpolate
      
      # Load configuration file before pyplot
      sys.path.append(config_path)
      import configuration as config
      
      # Library path
      sys.path.append(lib_path)
      import framemanager_python
      
      # Define custom colormaps
      cdict = {'red':   ((0.0, 80/256., 80/256.),
                         (0.2, 0.0, 0.0),
                         (0.4, 0.0, 0.0),
                         (0.6, 256/256., 256/256.),
                         (0.95, 256/256., 256/256.),
                         (1.0, 150/256., 150/256.)),
               'green': ((0.0, 0/256., 0/256.),
                         (0.2, 0/256., 0/256.),
                         (0.4, 130/256., 130/256.),
                         (0.6, 256/256., 256/256.),
                         (1.0, 0.0, 0.0)),
               'blue':  ((0.0, 80/256., 80/256.),
                         (0.2, 220/256., 220/256.),
                         (0.4, 0.0, 0.0),
                         (0.6, 20/256., 20/256.),
                         (1.0, 0.0, 0.0))}
  
      plt.register_cmap(name='bds_highcontrast', data=cdict) 
  
      cdict = {'red':   ((0.0, 0.9, 0.9),
                         (1.0, 0.9, 0.9)),
               'green': ((0.0, 0.9, 0.9),
                         (1.0, 0.0, 0.0)),
               'blue':  ((0.0, 0.0, 0.0),
                         (1.0, 0.0, 0.0))}
      plt.register_cmap(name='YELLOW_RED', data=cdict) 
  
      # Load profile
      if not os.path.exists(profileName):
          raise FileNotFoundError(f"File not found: {profileName}")
      
      frameManager = framemanager_python.FrameManagerWrapper()
      frameManager.load_profile(profileName)
  
      # Load single frame
      tsframe = np.copy(frameManager.get_tsframe(frameID, matrixID))
  
      cols = tsframe.shape[1]
      rows = tsframe.shape[0]
  
      # Add padding on border
      padding = 2
      v_padding = np.empty((padding, cols))
      v_padding.fill(-50)
      h_padding = np.empty((rows+2*padding, padding))
      h_padding.fill(-50)
      zs = np.vstack([v_padding, tsframe])
      zs = np.vstack([zs, v_padding])
      zs = np.hstack([h_padding, zs])
      zs = np.hstack([zs, h_padding])
  
      # Update matrix size with padding
      cols = zs.shape[1]
      rows = zs.shape[0]
  
      # Coordinates of sampled data points
      xs = np.arange(0, cols, 1)
      ys = np.arange(0, rows, 1)
  
      # Coordinates of interpolation points
      scaleFactor = 10
      xi = np.linspace(xs.min(), xs.max(), cols*scaleFactor)
      yi = np.linspace(ys.min(), ys.max(), rows*scaleFactor)
  
      # Interpolate with cubic splines
      spline = scipy.interpolate.RectBivariateSpline(ys, xs, zs, kx=3, ky=3, s=0)
  
      # Evaluate splines
      zi = spline(yi, xi)
  
      # Apply threshold to level out small values (interpolation ripples)
      min_threshold = 25
      zi[zi < min_threshold] = 0 
  
      # Plotting
      if not os.path.exists(save_dir):
          os.makedirs(save_dir)
  
      # Histogram
      plt.hist(zi.flatten(), 128, range=(min_threshold, zi.max()), fc='k', ec='k')
      plt.savefig(os.path.join(save_dir, "histogram.pdf"), format='pdf')
      plt.close()
  
      # Interpolated image
      fig, ax = plt.subplots()
      cmap = plt.get_cmap('bds_highcontrast')
      cax = ax.imshow(zi, cmap=cmap, vmin=zs.min(), vmax=zs.max(), origin='lower', extent=[xs.min(), xs.max(), ys.min(), ys.max()])
      cbar = fig.colorbar(cax)
      cbar.set_label('Raw sensor value', rotation=90)
      cbar.solids.set_edgecolor("face")
      ax.invert_yaxis()
      ax.xaxis.tick_top()
      plt.axis('off')
      plt.savefig(os.path.join(save_dir, "interpolation.pdf"), format='pdf')
      plt.close()
  
      # Contour
      fig, ax = plt.subplots()
      cax = ax.imshow(zs, interpolation='nearest', cmap=plt.get_cmap('gray'), vmin=zs.min(), vmax=zs.max(), origin='lower', extent=[xs.min(), xs.max(), ys.min(), ys.max()])
      countour_threshold = 50
      levels = np.linspace(countour_threshold, zs.max(), 10)
      contour = ax.contour(xi, yi, zi, levels, linewidths=1.0, colors=[(1.0, 0.0, 0.0)], origin='upper')
      cbar = fig.colorbar(cax)
      cbar.add_lines(contour)
      cbar.set_label('Raw sensor value', rotation=90)
      cbar.solids.set_edgecolor("face")
      ax.invert_yaxis()
      ax.xaxis.tick_top()
      plt.axis('off')
      plt.savefig(os.path.join(save_dir, "contour.pdf"), format='pdf')
      plt.close()
  
      return zi
  
  assert generate_plots('../matplotlib/', '../../lib', 'foam_ball_short.dsa', 230, 1, 'output_dir').shape == (890, 890)
  assert generate_plots('../matplotlib/', '../../lib', 'nonexistent.dsa', 230, 1, 'output_dir')
  assert generate_plots('../matplotlib/', '../../lib', 'foam_ball_short.dsa', 230, 1, 'output_dir').max() > 25
output: 
  def generate_plots(config_path, lib_path, profileName, frameID, matrixID, save_dir):
      import os
      import sys
      import numpy as np
      import matplotlib.pyplot as plt
      import scipy.interpolate
      
      sys.path.append(config_path)
      import configuration as config
      
      sys.path.append(lib_path)
      import framemanager_python
      
      cdict = {'red':   ((0.0, 80/256., 80/256.),
                         (0.2, 0.0, 0.0),
                         (0.4, 0.0, 0.0),
                         (0.6, 256/256., 256/256.),
                         (0.95, 256/256., 256/256.),
                         (1.0, 150/256., 150/256.)),
               'green': ((0.0, 0/256., 0/256.),
                         (0.2, 0/256., 0/256.),
                         (0.4, 130/256., 130/256.),
                         (0.6, 256/256., 256/256.),
                         (1.0, 0.0, 0.0)),
               'blue':  ((0.0, 80/256., 80/256.),
                         (0.2, 220/256., 220/256.),
                         (0.4, 0.0, 0.0),
                         (0.6, 20/256., 20/256.),
                         (1.0, 0.0, 0.0))}
  
      plt.register_cmap(name='bds_highcontrast', data=cdict) 
  
      cdict = {'red':   ((0.0, 0.9, 0.9),
                         (1.0, 0.9, 0.9)),
               'green': ((0.0, 0.9, 0.9),
                         (1.0, 0.0, 0.0)),
               'blue':  ((0.0, 0.0, 0.0),
                         (1.0, 0.0, 0.0))}
      plt.register_cmap(name='YELLOW_RED', data=cdict) 
  
      if not os.path.exists(profileName):
          raise FileNotFoundError(f"File not found: {profileName}")
      
      frameManager = framemanager_python.FrameManagerWrapper()
      frameManager.load_profile(profileName)
  
      tsframe = np.copy(frameManager.get_tsframe(frameID, matrixID))
  
      cols = tsframe.shape[1]
      rows = tsframe.shape[0]
  
      padding = 2
      v_padding = np.empty((padding, cols))
      v_padding.fill(-50)
      h_padding = np.empty((rows+2*padding, padding))
      h_padding.fill(-50)
      zs = np.vstack([v_padding, tsframe])
      zs = np.vstack([zs, v_padding])
      zs = np.hstack([h_padding, zs])
      zs = np.hstack([zs, h_padding])
  
      cols = zs.shape[1]
      rows = zs.shape[0]
  
      xs = np.arange(0, cols, 1)
      ys = np.arange(0, rows, 1)
  
      scaleFactor = 10
      xi = np.linspace(xs.min(), xs.max(), cols*scaleFactor)
      yi = np.linspace(ys.min(), ys.max(), rows*scaleFactor)
  
      spline = scipy.interpolate.RectBivariateSpline(ys, xs, zs, kx=3, ky=3, s=0)
  
      zi = spline(yi, xi)
  
      min_threshold = 25
      zi[zi < min_threshold] = 0 
  
      if not os.path.exists(save_dir):
          os.makedirs(save_dir)
  
      plt.hist(zi.flatten(), 128, range=(min_threshold, zi.max()), fc='k', ec='k')
      plt.savefig(os.path.join(save_dir, "histogram.pdf"), format='pdf')
      plt.close()
  
      fig, ax = plt.subplots()
      cmap = plt.get_cmap('bds_highcontrast')
      cax = ax.imshow(zi, cmap=cmap, vmin=zs.min(), vmax=zs.max(), origin='lower', extent=[xs.min(), xs.max(), ys.min(), ys.max()])
      cbar = fig.colorbar(cax)
      cbar.set_label('Raw sensor value', rotation=90)
      cbar.solids.set_edgecolor("face")
      ax.invert_yaxis()
      ax.xaxis.tick_top()
      plt.axis('off')
      plt.savefig(os.path.join(save_dir, "interpolation.pdf"), format='pdf')
      plt.close()
  
      fig, ax = plt.subplots()
      cax = ax.imshow(zs, interpolation='nearest', cmap=plt.get_cmap('gray'), vmin=zs.min(), vmax=zs.max(), origin='lower', extent=[xs.min(), xs.max(), ys.min(), ys.max()])
      countour_threshold = 50
      levels = np.linspace(countour_threshold, zs.max(), 10)
      contour = ax.contour(xi, yi, zi, levels, linewidths=1.0, colors=[(1.0, 0.0, 0.0)], origin='upper')
      cbar = fig.colorbar(cax)
      cbar.add_lines(contour)
      cbar.set_label('Raw sensor value', rotation=90)
      cbar.solids.set_edgecolor("face")
      ax.invert_yaxis()
      ax.xaxis.tick_top()
      plt.axis('off')
      plt.savefig(os.path.join(save_dir, "contour.pdf"), format='pdf')
      plt.close()
  
      return zi
  