try:
  import numpy
  import pipeline_display
  import pipeline_product
except ImportError:
  donothing=1


class Plot:

  def finalSetup(self, subplot, title, tooltip):
    subplot.grid(True)
    subplot.set_title(title, fontsize=8)
    subplot.tooltip = tooltip


class FlamesUvesSpectrum:
  def __init__(self, fits_low, fits_high,fib_id, 
               fits_low_err = None, fits_high_err = None):
    self.spec_low  = pipeline_product.PipelineProduct(fits_low[fib_id])
    self.spec_high = pipeline_product.PipelineProduct(fits_high[fib_id])
    self.spec_low_err = None
    if fits_low_err != None and fits_high_err != None :
      self.spec_low_err  = pipeline_product.PipelineProduct(fits_low_err[fib_id])
      self.spec_high_err = pipeline_product.PipelineProduct(fits_high_err[fib_id])
    self.loadFromFits()
    self.specdisp = pipeline_display.SpectrumDisplay()

  def loadFromFits(self) :
    self.spec_low.readSpectrum()
    self.spec_high.readSpectrum()
    if self.spec_low_err != None :
      self.spec_low_err.readSpectrum()
      self.spec_high_err.readSpectrum()
    #self.qc_ex_nord_low    = self.spec_low.readKeyword('ESO QC EX NORD', 0)
    #self.qc_ex_ysize_low   = self.spec_low.readKeyword('ESO QC EX YSIZE', 0)
    #self.qc_ex_nord_high   = self.spec_high.readKeyword('ESO QC EX NORD', 0)
    #self.qc_ex_ysize_high  = self.spec_high.readKeyword('ESO QC EX YSIZE', 0)

  def plot(self, subplot, title, tooltip):
    self.specdisp.setLabels(self.spec_low.type1,
                           '['+self.spec_low.bunit+']')
    if self.spec_low_err == None :
      self.specdisp.display(subplot, title, tooltip, 
                            self.spec_low.wave, self.spec_low.flux, 
                            autolimits=True)
      (flux_low_plotmin, flux_low_plotmax)   = self.specdisp.flux_lim
      self.specdisp.display(subplot, title, tooltip, 
                            self.spec_high.wave, self.spec_high.flux, 
                            autolimits=True)
      (flux_high_plotmin, flux_high_plotmax) = self.specdisp.flux_lim
    else :
      self.specdisp.display(subplot, title, tooltip, 
                           self.spec_low.wave, 
                           self.spec_low.flux, self.spec_low_err.flux, 
                           autolimits=True)
      (flux_low_plotmin, flux_low_plotmax)   = self.specdisp.flux_lim
      self.specdisp.display(subplot, title, tooltip, 
                           self.spec_high.wave, 
                           self.spec_high.flux, self.spec_high_err.flux, 
                           autolimits=True)
      (flux_high_plotmin, flux_high_plotmax) = self.specdisp.flux_lim
      
    subplot.set_xlim(min(self.spec_low.start_wave, self.spec_high.start_wave),
                     max(self.spec_low.end_wave, self.spec_high.end_wave))
    flux_plotmin           = min(flux_low_plotmin, flux_high_plotmin) 
    flux_plotmin           = min(flux_plotmin, 0) 
    flux_plotmax           = max(flux_low_plotmax, flux_high_plotmax)
    subplot.set_ylim(flux_plotmin,flux_plotmax)

class ScatterPlot(Plot):
  def __init__(self, fits):
    self.loadFromFits(fits)

  def scatterPlot(self, subplot, x, y, x_label, y_label, title, tooltip):
    self.scatterPlotScatter(subplot, x, y)
    self.setLabels(subplot, x_label, y_label,fontsize=8)
    self.scatterPlotLimits(subplot, x, y)
    self.finalSetup(subplot, title, tooltip)

  def scatterPlotScatter(self, subplot, x, y):
    subplot.scatter(x, y, s=1.4, color='blue')

  def scatterPlotScatterSmall(self, subplot, x, y, color_pt='blue'):
    subplot.scatter(x, y, s=0.5, color=color_pt)

  def setLabels(self, subplot, x_label, y_label, fontsize=8):
    subplot.set_xlabel(x_label,fontsize=fontsize)
    subplot.set_ylabel(y_label,fontsize=fontsize)

  def scatterPlotLimits(self, subplot, x, y):
    subplot.set_xlim(0., numpy.nanmax(x) + 1.)
    subplot.set_ylim(0., 1.05 * numpy.nanmax(y))

class PlotableOrderTable(ScatterPlot):
  def __init__(self, fits):
    self.table = pipeline_product.PipelineProduct(fits)
    self.loadFromFits(self.table)

  def loadFromFits(self, table) :
    self.order_raw      = table.all_hdu[1].data.field('Order')
    self.sn_raw         = table.all_hdu[1].data.field('ObjSnBlzCentre')
    self.fwhm_raw       = table.all_hdu[1].data.field('ObjFwhmAvg')
    self.pos_raw        = table.all_hdu[1].data.field('ObjPosOnSlit')
    self.ripple_raw     = table.all_hdu[1].data.field('Ripple')

  def maxOrder(self):
    return numpy.nanmax(self.order_raw)
  
  def maxSN(self):
    return numpy.nanmax(self.sn_raw)
  
  def minSN(self):
    return numpy.nanmin(self.sn_raw)
  
  def maxFWHM(self):
    return numpy.nanmax(self.fwhm_raw)
  
  def minFWHM(self):
    return numpy.nanmin(self.fwhm_raw)

  def maxRipple(self):
    return numpy.nanmax(self.ripple_raw)
  
  def minRipple(self):
    return numpy.nanmin(self.ripple_raw)
  
  def maxLinepos(self):
    return numpy.nanmax(self.pos_raw)
  
  def minLinepos(self):
    return numpy.nanmin(self.pos_raw)

class PlotableBlueOrderTable(PlotableOrderTable):
  def __init__(self, fits):
    self.table = pipeline_product.PipelineProduct(fits)
    self.loadFromFits(self.table)

  def plotSN(self, subplot, title, tooltip):
    self.scatterPlot(subplot, self.order_raw, self.sn_raw, 'Order', 'S/N', title, tooltip)

  def plotFWHM(self, subplot, title, tooltip):
    self.scatterPlot(subplot, self.order_raw, self.fwhm_raw, 'Order', 'FWHM (pix)', title, tooltip)

  def plotRipple(self, subplot, title, tooltip):
    self.setLabels(subplot, 'Order', 'Ripple')
    self.scatterPlotScatter(subplot, self.order_raw, self.ripple_raw)
    subplot.set_xlim(0., self.maxOrder() + 1.)
    self.finalSetup(subplot, title, tooltip)

  def plotLinepos(self, subplot, title, tooltip):
    self.scatterPlot(subplot, self.order_raw, self.pos_raw, 'Order', 'Slit Position (pix)', title, tooltip)
  
class PlotableRedOrderTable(PlotableOrderTable):
  def __init__(self, fits_low, fits_high):
    self.order_low         = PlotableOrderTable(fits_low)
    self.order_high        = PlotableOrderTable(fits_high)
    self.order_high_shift  = self.order_high.order_raw + self.order_low.maxOrder()
    self.max_total_order   = numpy.nanmax(self.order_high_shift)

  def plotSN(self, subplot, title, tooltip):
    self.plotLowHiTextBottom(subplot)
    self.setLabels(subplot, 'Order', 'S/N')
    self.scatterPlotScatter(subplot, self.order_low.order_raw, self.order_low.sn_raw)
    self.scatterPlotScatter(subplot, self.order_high_shift,    self.order_high.sn_raw)
    subplot.set_xlim(0., self.max_total_order + 1.)
    subplot.set_ylim(0., 1.05 * max(self.order_low.maxSN(), self.order_high.maxSN()))
    self.plotLowHiSepLine(subplot)
    self.finalSetup(subplot, title, tooltip)

  def plotFWHM(self, subplot, title, tooltip):
    self.plotLowHiTextBottom(subplot)
    self.setLabels(subplot, 'Order', 'FWHM (pix)')
    self.scatterPlotScatter(subplot, self.order_low.order_raw, self.order_low.fwhm_raw)
    self.scatterPlotScatter(subplot, self.order_high_shift,    self.order_high.fwhm_raw)
    subplot.set_xlim(0., self.max_total_order + 1.)
    subplot.set_ylim(0., 1.05 * max(self.order_low.maxFWHM(), self.order_high.maxFWHM()))
    self.plotLowHiSepLine(subplot)
    self.finalSetup(subplot, title, tooltip)

  def plotRipple(self, subplot, title, tooltip):
    self.plotLowHiTextBottom(subplot)
    self.setLabels(subplot, 'Order', 'Ripple')
    self.scatterPlotScatter(subplot, self.order_low.order_raw, self.order_low.ripple_raw)
    self.scatterPlotScatter(subplot, self.order_high_shift,    self.order_high.ripple_raw)
    subplot.set_xlim(0., self.max_total_order + 1.)
    self.plotLowHiSepLine(subplot)
    self.finalSetup(subplot, title, tooltip)

  def plotLinepos(self, subplot, title, tooltip):
    self.plotLowHiTextBottom(subplot)
    self.setLabels(subplot, 'Order', 'Slit Position (pix)')
    self.scatterPlotScatter(subplot, self.order_low.order_raw, self.order_low.pos_raw)
    self.scatterPlotScatter(subplot, self.order_high_shift,    self.order_high.pos_raw)
    subplot.set_xlim(0., self.max_total_order + 1.)
    self.plotLowHiSepLine(subplot)
    self.finalSetup(subplot, title, tooltip)

  def plotLowHiSepLine(self, subplot):
    subplot.axvline(linewidth=1.5, color='black', x=self.order_low.maxOrder() + 0.5)

  def plotLowHiTextBottom(self, subplot):
    subplot.text(0.1, 0.1, "RedLo", transform = subplot.transAxes,
                 ha="left",size=13,bbox=dict(boxstyle="round",alpha=0.2))
    subplot.text(0.9, 0.1, "RedHi", transform = subplot.transAxes,
                 ha="right",size=13,bbox=dict(boxstyle="round",alpha=0.2))
    
  def maxSN(self):
    return max(self.order_low.maxSN(), self.order_high.maxSN())
  
  def minSN(self):
    return min(self.order_low.minSN(), self.order_high.minSN())
  
  def maxFWHM(self):
    return max(self.order_low.maxFWHM(), self.order_high.maxFWHM())
  
  def minFWHM(self):
    return min(self.order_low.minFWHM(), self.order_high.minFWHM())

  def maxRipple(self):
    return max(self.order_low.maxRipple(), self.order_high.maxRipple())
  
  def minRipple(self):
    return min(self.order_low.minRipple(), self.order_high.minRipple())
  
  def maxLinepos(self):
    return max(self.order_low.maxLinepos(), self.order_high.maxLinepos())
  
  def minLinepos(self):
    return min(self.order_low.minLinepos(), self.order_high.minLinepos())
  
class PlotableLineGuessTable(ScatterPlot):
  def __init__(self, fits):
    self.table = pipeline_product.PipelineProduct(fits)
    self.loadFromFits(self.table)
  
  def loadFromFits(self, table) :
    self.xdif_raw    = table.all_hdu[1].data.field('XDIF')
    self.ydif_raw    = table.all_hdu[1].data.field('YDIF')
    self.x_raw       = table.all_hdu[1].data.field('X')
    self.ynew_raw    = table.all_hdu[1].data.field('YNEW')
    self.select_raw  = table.all_hdu[1].data.field('SELPLOT')
    self.det_nx      = table.all_hdu[0].header['ESO DET OUT1 NX']
    self.det_ny      = table.all_hdu[0].header['ESO DET OUT1 NY']
    self.xdif_sel    = self.xdif_raw[self.select_raw == 1]
    self.x_sel       = self.x_raw[self.select_raw == 1]
    self.ydif_sel    = self.ydif_raw[self.select_raw == 1]
    self.ynew_sel    = self.ynew_raw[self.select_raw == 1]
    self.min_x       = numpy.nanmin(self.x_raw)
    self.max_x       = numpy.nanmax(self.x_raw)
    self.min_ynew    = numpy.nanmin(self.ynew_raw)
    self.max_ynew    = numpy.nanmax(self.ynew_raw)
    self.median_xdif = numpy.median(self.xdif_sel)
    self.mean_xdif   = numpy.mean(self.xdif_sel)
    self.std_xdif    = numpy.std(self.xdif_sel)
    self.median_ydif = numpy.median(self.ydif_sel)
    self.mean_ydif   = numpy.mean(self.ydif_sel)
    self.std_ydif    = numpy.std(self.ydif_sel)

class PlotableBlueLineGuessTable(PlotableLineGuessTable):

  def plotXDIFvsX(self, subplot, title, tooltip) :
    self.setLabels(subplot, 'X [pix]', 'XDIF [pix]')
    self.scatterPlotScatterSmall(subplot, self.x_sel, self.xdif_sel)
    subplot.set_xlim(self.min_x, self.max_x)
    subplot.axhline(y=self.median_xdif, color='black', lw=1.2)
    subplot.axhline(y=self.median_xdif+self.std_xdif, color='black', ls='-.', lw=1.2)
    subplot.axhline(y=self.median_xdif-self.std_xdif, color='black', ls='-.', lw=1.2)
    self.finalSetup(subplot, title, tooltip)

  def plotYDIFvsX(self, subplot, title, tooltip) :
    self.setLabels(subplot, 'X [pix]', 'YDIF [pix]')
    self.scatterPlotScatterSmall(subplot, self.x_sel, self.ydif_sel)
    subplot.set_xlim(self.min_x, self.max_x)
    subplot.axhline(y=self.median_ydif, color='black', lw=1.2)
    subplot.axhline(y=self.median_ydif+self.std_ydif, color='black', ls='-.', lw=1.2)
    subplot.axhline(y=self.median_ydif-self.std_ydif, color='black', ls='-.', lw=1.2)
    self.finalSetup(subplot, title, tooltip)

  def plotXDIFvsY(self, subplot, title, tooltip) :
    self.setLabels(subplot,'Y [pix]', 'XDIF [pix]')
    self.scatterPlotScatterSmall(subplot, self.ynew_sel, self.xdif_sel)
    subplot.set_xlim(self.min_ynew, self.max_ynew)
    subplot.axhline(y=self.median_xdif, color='black', lw=1.2)
    subplot.axhline(y=self.median_xdif+self.std_xdif, color='black', ls='-.', lw=1.2)
    subplot.axhline(y=self.median_xdif-self.std_xdif, color='black', ls='-.', lw=1.2)
    self.finalSetup(subplot, title, tooltip)

  def plotYDIFvsY(self, subplot, title, tooltip) :
    self.setLabels(subplot,'Y [pix]', 'YDIF [pix]')
    self.scatterPlotScatterSmall(subplot, self.ynew_sel, self.ydif_sel)
    subplot.set_xlim(self.min_ynew, self.max_ynew)
    subplot.axhline(y=self.median_ydif, color='black', lw=1.2)
    subplot.axhline(y=self.median_ydif+self.std_ydif, color='black', ls='-.', lw=1.2)
    subplot.axhline(y=self.median_ydif-self.std_ydif, color='black', ls='-.', lw=1.2)
    self.finalSetup(subplot, title, tooltip)

  def plotYDIFvsXDIF(self, subplot, title, tooltip) :
    self.setLabels(subplot,'XDIF [pix]', 'YDIF [pix]')
    self.scatterPlotScatterSmall(subplot, self.xdif_sel, self.ydif_sel)
    subplot.axhline(y=self.median_ydif, color='black', lw=1.2)
    subplot.axvline(x=self.median_xdif, color='black', lw=1.2)
    self.finalSetup(subplot, title, tooltip)

  def plotYvsX(self, subplot, title, tooltip) :
    self.setLabels(subplot,'X [pix]', 'Y [pix]')
    self.scatterPlotScatterSmall(subplot, self.x_raw, self.ynew_raw, 'red')
    self.scatterPlotScatterSmall(subplot, self.x_sel, self.ynew_sel)
    subplot.set_xlim(0., self.det_ny)
    subplot.set_ylim(0., self.det_nx)
    self.finalSetup(subplot, title, tooltip)
 
class PlotableRedLineGuessTable(ScatterPlot):
  def __init__(self, fits_low, fits_high):
    self.tab_low = PlotableLineGuessTable(fits_low)
    self.tab_high = PlotableLineGuessTable(fits_high)
    self.x_sel_shift     = self.tab_high.x_sel + self.tab_low.det_ny
    self.x_raw_shift     = self.tab_high.x_raw + self.tab_low.det_ny
    self.y_sel_shift     = self.tab_high.ynew_sel + self.tab_low.det_nx
    self.y_raw_shift     = self.tab_high.ynew_raw + self.tab_low.det_nx
    self.ynew_sel_shift  = self.tab_high.ynew_sel + self.tab_low.det_nx
    self.median_all_xdif = numpy.median(numpy.concatenate((self.tab_low.xdif_sel, self.tab_high.xdif_sel)))
    self.mean_all_xdif   = numpy.mean(numpy.concatenate((self.tab_low.xdif_sel, self.tab_high.xdif_sel)))
    self.std_all_xdif    = numpy.std(numpy.concatenate((self.tab_low.xdif_sel, self.tab_high.xdif_sel)))
    self.median_all_ydif = numpy.median(numpy.concatenate((self.tab_low.ydif_sel, self.tab_high.ydif_sel)))
    self.mean_all_ydif   = numpy.mean(numpy.concatenate((self.tab_low.ydif_sel, self.tab_high.ydif_sel)))
    self.std_all_ydif    = numpy.std(numpy.concatenate((self.tab_low.ydif_sel, self.tab_high.ydif_sel)))

  def plotGridLowHiTextRight(self, grid):
    grid[1].text(0.9, 0.1, "RedLo", transform = grid[1].transAxes,
                 ha="right",size=13,bbox=dict(boxstyle="round",alpha=0.2))
    grid[0].text(0.9, 0.9, "RedHi", transform = grid[0].transAxes,
                 ha="right",va="top",size=13,bbox=dict(boxstyle="round",alpha=0.2))

  def plotLowHiTextBottom(self, subplot):
    subplot.text(0.1, 0.1, "RedLo", transform = subplot.transAxes,
                 ha="left",size=13,bbox=dict(boxstyle="round",alpha=0.2))
    subplot.text(0.9, 0.1, "RedHi", transform = subplot.transAxes,
                 ha="right",size=13,bbox=dict(boxstyle="round",alpha=0.2))

  def plotLowHiTextRight(self, subplot):
    subplot.text(0.9, 0.1, "RedLo", transform = subplot.transAxes,
                 ha="right",size=13,bbox=dict(boxstyle="round",alpha=0.2))
    subplot.text(0.9, 0.9, "RedHi", transform = subplot.transAxes,
                 ha="right",va="top",size=13,bbox=dict(boxstyle="round",alpha=0.2))

  def plotGridXDIFvsX(self, grid, title, tooltip) :
    self.plotGridLowHiTextRight(grid)
    self.setLabels(grid[0], 'X [pix]', 'XDIF [pix]')
    self.scatterPlotScatterSmall(grid[0], self.tab_high.x_sel, self.tab_high.xdif_sel)
    self.setLabels(grid[1], 'X [pix]', 'XDIF [pix]')
    self.scatterPlotScatterSmall(grid[1], self.tab_low.x_sel, self.tab_low.xdif_sel)
    grid[0].set_xlim(min(self.tab_low.min_x, self.tab_high.min_x), max(self.tab_low.max_x, self.tab_high.max_x))
    grid[1].set_xlim(min(self.tab_low.min_x, self.tab_high.min_x), max(self.tab_low.max_x, self.tab_high.max_x))
#    Should we plot here the median of that chip or the median of all the values?
    grid[0].axhline(y=self.tab_high.median_xdif, color='black', lw=1.2)
    grid[1].axhline(y=self.tab_low.median_xdif, color='black', lw=1.2)
    grid[0].axhline(y=self.tab_high.median_xdif+self.tab_high.std_xdif, color='black', ls='-.', lw=1.2)
    grid[1].axhline(y=self.tab_low.median_xdif+self.tab_low.std_xdif, color='black', ls='-.', lw=1.2)
    grid[0].axhline(y=self.tab_high.median_xdif-self.tab_high.std_xdif, color='black', ls='-.', lw=1.2)
    grid[1].axhline(y=self.tab_low.median_xdif-self.tab_low.std_xdif, color='black', ls='-.', lw=1.2)
    self.finalSetup(grid[0], title, tooltip)
    self.finalSetup(grid[1], "", tooltip)

  def plotXDIFvsX(self, subplot, title, tooltip) :
    self.plotLowHiTextBottom(subplot)
    self.setLabels(subplot, 'X [pix]', 'XDIF [pix]')
    self.scatterPlotScatterSmall(subplot, self.x_sel_shift, self.tab_high.xdif_sel)
    self.scatterPlotScatterSmall(subplot, self.tab_low.x_sel, self.tab_low.xdif_sel)
    subplot.set_xlim(min(self.tab_low.min_x, self.tab_high.min_x + self.tab_low.det_ny), max(self.tab_low.max_x, self.tab_high.max_x + self.tab_low.det_ny))
    subplot.axhline(y=self.median_all_xdif, color='black', lw=1.2)
    subplot.axhline(y=self.median_all_xdif+self.std_all_xdif, color='black', ls='-.', lw=1.2)
    subplot.axhline(y=self.median_all_xdif-self.std_all_xdif, color='black', ls='-.', lw=1.2)
    subplot.axvline(linewidth=1.5, color='black', x=self.tab_low.det_ny)
    self.finalSetup(subplot, title, tooltip)

  def plotGridYDIFvsX(self, grid, title, tooltip) :
    self.plotGridLowHiTextRight(grid)
    self.setLabels(grid[0], 'X [pix]', 'YDIF [pix]')
    self.scatterPlotScatterSmall(grid[0], self.tab_high.x_sel, self.tab_high.ydif_sel)
    self.setLabels(grid[1], 'X [pix]', 'YDIF [pix]')
    self.scatterPlotScatterSmall(grid[1], self.tab_low.x_sel, self.tab_low.ydif_sel)
    grid[0].set_xlim(min(self.tab_low.min_x, self.tab_high.min_x), max(self.tab_low.max_x, self.tab_high.max_x))
    grid[1].set_xlim(min(self.tab_low.min_x, self.tab_high.min_x), max(self.tab_low.max_x, self.tab_high.max_x))
#    Should we plot here the median of that chip or the median of all the values?
    grid[0].axhline(y=self.tab_high.median_ydif, color='black', lw=1.2)
    grid[1].axhline(y=self.tab_low.median_ydif, color='black', lw=1.2)
    grid[0].axhline(y=self.tab_high.median_ydif+self.tab_high.std_ydif, color='black', ls='-.', lw=1.2)
    grid[1].axhline(y=self.tab_low.median_ydif+self.tab_low.std_ydif, color='black', ls='-.', lw=1.2)
    grid[0].axhline(y=self.tab_high.median_ydif-self.tab_high.std_ydif, color='black', ls='-.', lw=1.2)
    grid[1].axhline(y=self.tab_low.median_ydif-self.tab_low.std_ydif, color='black', ls='-.', lw=1.2)
    self.finalSetup(grid[0], title, tooltip)
    self.finalSetup(grid[1], "", tooltip)

  def plotYDIFvsX(self, subplot, title, tooltip) :
    self.plotLowHiTextBottom(subplot)
    self.setLabels(subplot, 'X [pix]', 'YDIF [pix]')
    self.scatterPlotScatterSmall(subplot, self.x_sel_shift, self.tab_high.ydif_sel)
    self.scatterPlotScatterSmall(subplot, self.tab_low.x_sel, self.tab_low.ydif_sel)
    subplot.set_xlim(min(self.tab_low.min_x, self.tab_high.min_x + self.tab_low.det_ny), max(self.tab_low.max_x, self.tab_high.max_x + self.tab_low.det_ny))
    subplot.axhline(y=self.median_all_ydif, color='black', lw=1.2)
    subplot.axhline(y=self.median_all_ydif+self.std_all_ydif, color='black', ls='-.', lw=1.2)
    subplot.axhline(y=self.median_all_ydif-self.std_all_ydif, color='black', ls='-.', lw=1.2)
    subplot.axvline(linewidth=1.5, color='black', x=self.tab_low.det_ny)
    self.finalSetup(subplot, title, tooltip)

  def plotGridXDIFvsY(self, grid, title, tooltip) :
    self.plotGridLowHiTextRight(grid)
    self.setLabels(grid[0], 'Y [pix]', 'XDIF [pix]')
    self.scatterPlotScatterSmall(grid[0], self.tab_high.ynew_sel, self.tab_high.xdif_sel)
    self.setLabels(grid[1], 'Y [pix]', 'XDIF [pix]')
    self.scatterPlotScatterSmall(grid[1], self.tab_low.ynew_sel, self.tab_low.xdif_sel)
    grid[0].set_xlim(min(self.tab_low.min_ynew, self.tab_high.min_ynew), max(self.tab_low.max_ynew, self.tab_high.max_ynew))
    grid[1].set_xlim(min(self.tab_low.min_ynew, self.tab_high.min_ynew), max(self.tab_low.max_ynew, self.tab_high.max_ynew))
#    Should we plot here the median of that chip or the median of all the values?
    grid[0].axhline(y=self.tab_high.median_xdif, color='black', lw=1.2)
    grid[1].axhline(y=self.tab_low.median_xdif, color='black', lw=1.2)
    grid[0].axhline(y=self.tab_high.median_xdif+self.tab_high.std_xdif, color='black', ls='-.', lw=1.2)
    grid[1].axhline(y=self.tab_low.median_xdif+self.tab_low.std_xdif, color='black', ls='-.', lw=1.2)
    grid[0].axhline(y=self.tab_high.median_xdif-self.tab_high.std_xdif, color='black', ls='-.', lw=1.2)
    grid[1].axhline(y=self.tab_low.median_xdif-self.tab_low.std_xdif, color='black', ls='-.', lw=1.2)
    self.finalSetup(grid[0], title, tooltip)
    self.finalSetup(grid[1], "", tooltip)

  def plotXDIFvsY(self, subplot, title, tooltip) :
    self.plotLowHiTextBottom(subplot)
    self.scatterPlotScatterSmall(subplot, self.ynew_sel_shift, self.tab_high.xdif_sel)
    self.scatterPlotScatterSmall(subplot, self.tab_low.ynew_sel, self.tab_low.xdif_sel)
    self.setLabels(subplot, 'Y [pix]', 'XDIF [pix]')
    subplot.set_xlim(min(self.tab_low.min_ynew, self.tab_high.min_ynew + self.tab_low.det_nx), max(self.tab_low.max_ynew, self.tab_high.max_ynew + self.tab_low.det_nx))
    subplot.axhline(y=self.median_all_xdif, color='black', lw=1.2)
    subplot.axhline(y=self.median_all_xdif+self.std_all_xdif, color='black', ls='-.', lw=1.2)
    subplot.axhline(y=self.median_all_xdif-self.std_all_xdif, color='black', ls='-.', lw=1.2)
    subplot.axvline(linewidth=1.5, color='black', x=self.tab_low.det_nx)
    self.finalSetup(subplot, title, tooltip)

  def plotGridYDIFvsY(self, grid, title, tooltip) :
    self.plotGridLowHiTextRight(grid)
    self.setLabels(grid[0], 'Y [pix]', 'YDIF [pix]')
    self.scatterPlotScatterSmall(grid[0], self.tab_high.ynew_sel, self.tab_high.ydif_sel)
    self.setLabels(grid[1], 'Y [pix]', 'YDIF [pix]')
    self.scatterPlotScatterSmall(grid[1], self.tab_low.ynew_sel, self.tab_low.ydif_sel)
    grid[0].set_xlim(min(self.tab_low.min_ynew, self.tab_high.min_ynew), max(self.tab_low.max_ynew, self.tab_high.max_ynew))
    grid[1].set_xlim(min(self.tab_low.min_ynew, self.tab_high.min_ynew), max(self.tab_low.max_ynew, self.tab_high.max_ynew))
#    Should we plot here the median of that chip or the median of all the values?
    grid[0].axhline(y=self.tab_high.median_ydif, color='black', lw=1.2)
    grid[1].axhline(y=self.tab_low.median_ydif, color='black', lw=1.2)
    grid[0].axhline(y=self.tab_high.median_ydif+self.tab_high.std_ydif, color='black', ls='-.', lw=1.2)
    grid[1].axhline(y=self.tab_low.median_ydif+self.tab_low.std_ydif, color='black', ls='-.', lw=1.2)
    grid[0].axhline(y=self.tab_high.median_ydif-self.tab_high.std_ydif, color='black', ls='-.', lw=1.2)
    grid[1].axhline(y=self.tab_low.median_ydif-self.tab_low.std_ydif, color='black', ls='-.', lw=1.2)
    self.finalSetup(grid[0], title, tooltip)
    self.finalSetup(grid[1], "", tooltip)

  def plotYDIFvsY(self, subplot, title, tooltip) :
    self.plotLowHiTextBottom(subplot)
    self.setLabels(subplot, 'Y [pix]', 'YDIF [pix]')
    self.scatterPlotScatterSmall(subplot, self.ynew_sel_shift, self.tab_high.ydif_sel)
    self.scatterPlotScatterSmall(subplot, self.tab_low.ynew_sel, self.tab_low.ydif_sel)
    subplot.set_xlim(min(self.tab_low.min_ynew, self.tab_high.min_ynew + self.tab_low.det_nx), max(self.tab_low.max_ynew, self.tab_high.max_ynew + self.tab_low.det_nx))
    subplot.axhline(y=self.median_all_ydif, color='black', lw=1.2)
    subplot.axhline(y=self.median_all_ydif+self.std_all_ydif, color='black', ls='-.', lw=1.2)
    subplot.axhline(y=self.median_all_ydif-self.std_all_ydif, color='black', ls='-.', lw=1.2)
    subplot.axvline(linewidth=1.5, color='black', x=self.tab_low.det_nx)
    self.finalSetup(subplot, title, tooltip)

  def plotYDIFvsXDIF(self, subplot, title, tooltip) :
    self.setLabels(subplot, 'XDIF [pix]', 'YDIF [pix]')
    self.scatterPlotScatterSmall(subplot, self.tab_high.xdif_sel, self.tab_high.ydif_sel)
    self.scatterPlotScatterSmall(subplot, self.tab_low.xdif_sel, self.tab_low.ydif_sel)
    subplot.axhline(y=self.median_all_ydif, color='black', lw=1.2)
    subplot.axvline(x=self.median_all_xdif, color='black', lw=1.2)
    self.finalSetup(subplot, title, tooltip)

  def plotGridYvsX(self, grid, title, tooltip) :
    self.plotGridLowHiTextRight(grid)
    self.setLabels(grid[0], 'X [pix]', 'Y [pix]')
    self.scatterPlotScatterSmall(grid[0], self.tab_high.x_raw, self.tab_high.ynew_raw, color_pt='red')
    self.scatterPlotScatterSmall(grid[0], self.tab_high.x_sel, self.tab_high.ynew_sel, color_pt='blue')
    self.setLabels(grid[1], 'X [pix]', 'Y [pix]')
    self.scatterPlotScatterSmall(grid[1], self.tab_low.x_raw, self.tab_low.ynew_raw, color_pt='red')
    self.scatterPlotScatterSmall(grid[1], self.tab_low.x_sel, self.tab_low.ynew_sel, color_pt='blue')
    grid[0].set_xlim(0, self.tab_high.det_ny)
    grid[0].set_ylim(0, self.tab_high.det_nx)
    grid[1].set_xlim(0, self.tab_low.det_ny)
    grid[1].set_ylim(0, self.tab_low.det_nx)
    self.finalSetup(grid[0], title, tooltip)
    self.finalSetup(grid[1], "", tooltip)

  def plotYvsX(self, subplot, title, tooltip) :
    self.plotLowHiTextRight(subplot)
    self.setLabels(subplot, 'X [pix]', 'Y [pix]')
    self.scatterPlotScatterSmall(subplot, self.tab_high.x_raw, self.y_raw_shift, color_pt='red')
    self.scatterPlotScatterSmall(subplot, self.tab_high.x_sel, self.y_sel_shift, color_pt='blue')
    self.scatterPlotScatterSmall(subplot, self.tab_low.x_raw, self.tab_low.ynew_raw, color_pt='red')
    self.scatterPlotScatterSmall(subplot, self.tab_low.x_sel, self.tab_low.ynew_sel, color_pt='blue')
    subplot.set_xlim(0, self.tab_low.det_ny)
    subplot.set_ylim(0, self.tab_high.det_nx + self.tab_low.det_nx)
    subplot.axhline(linewidth=1.5, color='black', y=self.tab_low.det_nx)
    self.finalSetup(subplot, title, tooltip)

class PlotableLineTable(ScatterPlot):
  def __init__(self, fits,fib_id):
    self.table = pipeline_product.PipelineProduct(fits)
    self.loadFromFits(self.table,fib_id+1)
  
  def loadFromFits(self, table,fib_id) :
    n_win                = (table.all_hdu.__len__() - 1 )//3
    id_win               = (n_win+1)//2
    ext_id               = 3 * (id_win -1 ) + 1
    #print 'ext_id=',ext_id,'w_win=',n_win
    self.x_raw           = table.all_hdu[ext_id].data.field('X')
    self.ynew_raw        = table.all_hdu[ext_id].data.field('Ynew')
    self.residual_raw    = table.all_hdu[ext_id].data.field('Residual')
    self.order_raw       = table.all_hdu[ext_id].data.field('Y')
    self.xwidth_raw      = table.all_hdu[ext_id].data.field('Xwidth')
    self.wavec_raw       = table.all_hdu[ext_id].data.field('WaveC')
    self.select_raw      = table.all_hdu[ext_id].data.field('NLinSol')
    self.det_nx          = table.all_hdu[0].header['ESO DET OUT1 NX']
    self.det_ny          = table.all_hdu[0].header['ESO DET OUT1 NY']
    self.nlintot = 0
    self.nlinsel = 0
    self.nlinsol = 0
    #self.nlintot         = table.all_hdu[0].header['ESO QC FIB%d NLINTOT' % fib_id]
    #self.nlinsel         = table.all_hdu[0].header['ESO QC FIB%d NLINSEL' % fib_id]
    #self.nlinsol         = table.all_hdu[0].header['ESO QC FIB%d NLINSOL' % fib_id] 
    self.fwhm            = self.xwidth_raw * 2.35
    self.fwhm_sel        = self.fwhm[self.select_raw == 1]
    self.fwhm_clean      = self.fwhm_sel[numpy.isfinite(self.fwhm_sel)]
    self.x_sel           = self.x_raw[self.select_raw == 1]
    self.ynew_sel        = self.ynew_raw[self.select_raw == 1]
    self.wavec_sel       = self.wavec_raw[self.select_raw == 1]
    self.residual_sel    = self.residual_raw[self.select_raw == 1]
    self.order_sel       = self.order_raw[self.select_raw == 1]
    self.min_wavec       = numpy.nanmin(self.wavec_raw)
    self.max_wavec       = numpy.nanmax(self.wavec_raw)
    self.mean_residual   = numpy.mean(self.residual_sel)
    self.median_residual = numpy.median(self.residual_sel)
    self.std_residual    = numpy.std(self.residual_sel)
    self.max_order       = numpy.nanmax(self.order_raw)
    self.max_fwhm        = numpy.nanmax(self.fwhm)
    self.mean_fwhm       = numpy.mean(self.fwhm_clean)
    self.median_fwhm     = numpy.median(self.fwhm_clean)
    self.std_fwhm        = numpy.std(self.fwhm_clean)

class PlotableBlueLineTable(PlotableLineTable):
  def plotRESvsWAVE(self, subplot, title, tooltip) :
    self.scatterPlotScatterSmall(subplot, self.wavec_raw, self.residual_raw, color_pt='red')
    self.scatterPlotScatterSmall(subplot, self.wavec_sel, self.residual_sel)
    self.setLabels(subplot, 'Wavelength [Ang]', 'Wavelength Residual  [Ang]',fontsize=8)

    subplot.set_xlim(self.min_wavec, self.max_wavec)
    subplot.axhline(y=self.median_residual, color='black', lw=1.2)
    subplot.axhline(y=self.median_residual+self.std_residual, color='black', ls='-.', lw=1.2)
    subplot.axhline(y=self.median_residual-self.std_residual, color='black', ls='-.', lw=1.2)
    self.finalSetup(subplot, title, tooltip)
    
  def plotRESvsORDER(self, subplot, title, tooltip) :
    self.setLabels(subplot, 'Order', 'Wavelength Residual [Ang]')
    self.scatterPlotScatterSmall(subplot, self.order_raw, self.residual_raw, color_pt='red')
    self.scatterPlotScatterSmall(subplot, self.order_sel, self.residual_sel)
    subplot.set_xlim(0., self.max_order + 1.)
    subplot.axhline(y=self.median_residual, color='black', lw=1.2)
    subplot.axhline(y=self.median_residual+self.std_residual, color='black', ls='-.', lw=1.2)
    subplot.axhline(y=self.median_residual-self.std_residual, color='black', ls='-.', lw=1.2)
    self.finalSetup(subplot, title, tooltip)
    
  def plotFWHMvsWAVE(self, subplot, title, tooltip) :
    self.setLabels(subplot, 'Wavelength [Ang]', 'Line FWHM [pix]')
    self.scatterPlotScatterSmall(subplot, self.wavec_raw, self.fwhm, color_pt='red')
    self.scatterPlotScatterSmall(subplot, self.wavec_sel, self.fwhm_sel)
    subplot.set_xlim(self.min_wavec, self.max_wavec)
    subplot.set_ylim(0., self.max_fwhm * 1.05)
    subplot.axhline(y=self.median_fwhm, color='black', lw=1.2)
    subplot.axhline(y=self.median_fwhm+self.std_fwhm, color='black', ls='-.', lw=1.2)
    subplot.axhline(y=self.median_fwhm-self.std_fwhm, color='black', ls='-.', lw=1.2)
    self.finalSetup(subplot, title, tooltip)

  def plotYvsX(self, subplot, title, tooltip) :
    self.setLabels(subplot,'X [pix]', 'Y [pix]')
    self.scatterPlotScatterSmall(subplot, self.x_raw, self.ynew_raw, 'red')
    self.scatterPlotScatterSmall(subplot, self.x_sel, self.ynew_sel)
    subplot.set_xlim(0., self.det_ny)
    subplot.set_ylim(0., self.det_nx)
    self.finalSetup(subplot, title, tooltip)

  def plotLinesText(self, subplot) :
     subplot.set_axis_off()
     text1 = 'No. of detected lines = %g'%self.nlintot 
     subplot.text(0.05, 0.80, text1, color='#11557c', fontsize=15, ha='left', va='center', alpha=1.0)
     text2 = 'Initial no. of fitted lines = %g'%self.nlinsel
     subplot.text(0.05, 0.65, text2, color='#11557c', fontsize=15, ha='left', va='center', alpha=1.0)
     text3 = 'Final no. of fitted lines = %g'%self.nlinsol 
     subplot.text(0.05, 0.50, text3, color='#11557c', fontsize=15, ha='left', va='center', alpha=1.0)
     subplot.tooltip='Lines info'

class PlotableMosLineTable(ScatterPlot):
  def __init__(self, fits_low, fits_high,fib_id = None):
    self.tab_low              = PlotableLineTable(fits_low,fib_id)
    self.tab_high             = PlotableLineTable(fits_high,fib_id)
    self.min_wavec            = min(self.tab_low.min_wavec, self.tab_high.min_wavec)
    self.max_wavec            = max(self.tab_low.max_wavec, self.tab_high.max_wavec)
    self.median_all_residual  = numpy.median(numpy.concatenate((self.tab_low.residual_sel, self.tab_high.residual_sel)))
    self.mean_all_residual    = numpy.mean(numpy.concatenate((self.tab_low.residual_sel, self.tab_high.residual_sel)))
    self.std_all_residual     = numpy.std(numpy.concatenate((self.tab_low.residual_sel, self.tab_high.residual_sel)))
    self.median_all_fwhm      = numpy.median(numpy.concatenate((self.tab_low.fwhm_sel, self.tab_high.fwhm_sel)))
    self.mean_all_fwhm        = numpy.mean(numpy.concatenate((self.tab_low.fwhm_sel, self.tab_high.fwhm_sel)))
    self.std_all_fwhm         = numpy.std(numpy.concatenate((self.tab_low.fwhm_sel, self.tab_high.fwhm_sel)))
    self.order_high_shift     = self.tab_high.order_raw + self.tab_low.max_order
    self.order_high_shift_sel = self.order_high_shift[self.tab_high.select_raw == 1]
    self.max_total_order      = numpy.nanmax(self.order_high_shift)
    self.max_fwhm             = max(self.tab_low.max_fwhm, self.tab_high.max_fwhm)
    self.x_sel_shift          = self.tab_high.x_sel + self.tab_low.det_ny
    self.x_raw_shift          = self.tab_high.x_raw + self.tab_low.det_ny
    self.y_sel_shift          = self.tab_high.ynew_sel + self.tab_low.det_nx
    self.y_raw_shift          = self.tab_high.ynew_raw + self.tab_low.det_nx

  def plotGridLowHiTextRight(self, grid):
    grid[0].text(0.9, 0.9, "RedHi", transform = grid[0].transAxes,
                 ha="right",va="top",size=13,bbox=dict(boxstyle="round",alpha=0.2))
    grid[1].text(0.9, 0.1, "RedLo", transform = grid[1].transAxes,
                 ha="right",size=13,bbox=dict(boxstyle="round",alpha=0.2))

  def plotLowHiTextBottom(self, subplot):
    subplot.text(0.9, 0.1, "RedHi", transform = subplot.transAxes,
                 ha="right", size=13,bbox=dict(boxstyle="round",alpha=0.2))
    subplot.text(0.1, 0.1, "RedLo", transform = subplot.transAxes,
                 ha="left",size=13,bbox=dict(boxstyle="round",alpha=0.2))

  def plotLowHiTextTop(self, subplot):
    subplot.text(0.9, 0.8, "RedHi", transform = subplot.transAxes,
                 ha="right", size=13,bbox=dict(boxstyle="round",alpha=0.2))
    subplot.text(0.1, 0.8, "RedLo", transform = subplot.transAxes,
                 ha="left",size=13,bbox=dict(boxstyle="round",alpha=0.2))

  def plotLowHiTextRight(self, subplot):
    subplot.text(0.9, 0.1, "RedLo", transform = subplot.transAxes,
                 ha="right",size=13,bbox=dict(boxstyle="round",alpha=0.2))
    subplot.text(0.9, 0.9, "RedHi", transform = subplot.transAxes,
                 ha="right",va="top",size=13,bbox=dict(boxstyle="round",alpha=0.2))

  def plotRESvsWAVE(self, subplot, title, tooltip) :
    self.plotLowHiTextTop(subplot)
    self.setLabels(subplot, 'Wavelength [Ang]', 'Wave Resid [Ang]')
    self.scatterPlotScatterSmall(subplot, self.tab_low.wavec_raw, self.tab_low.residual_raw, color_pt='red')
    self.scatterPlotScatterSmall(subplot, self.tab_low.wavec_sel, self.tab_low.residual_sel)
    self.scatterPlotScatterSmall(subplot, self.tab_high.wavec_raw, self.tab_high.residual_raw, color_pt='red')
    self.scatterPlotScatterSmall(subplot, self.tab_high.wavec_sel, self.tab_high.residual_sel)
    subplot.set_xlim(self.min_wavec, self.max_wavec)
    subplot.axhline(y=self.median_all_residual, color='black', lw=1.2)
    subplot.axhline(y=self.median_all_residual+self.std_all_residual, color='black', ls='-.', lw=1.2)
    subplot.axhline(y=self.median_all_residual-self.std_all_residual, color='black', ls='-.', lw=1.2)
    subplot.axvline(linewidth=1.5, color='black', x=(self.tab_low.max_wavec + self.tab_high.min_wavec)/2.)
    self.finalSetup(subplot, title, tooltip)

  def plotRESvsORDER(self, subplot, title, tooltip) :
    self.plotLowHiTextTop(subplot)
    self.setLabels(subplot, 'Order', 'Wave Resid [Ang]')
    self.scatterPlotScatterSmall(subplot, self.tab_low.order_raw, self.tab_low.residual_raw, color_pt='red')
    self.scatterPlotScatterSmall(subplot, self.tab_low.order_sel, self.tab_low.residual_sel)
    self.scatterPlotScatterSmall(subplot, self.order_high_shift, self.tab_high.residual_raw, color_pt='red')
    self.scatterPlotScatterSmall(subplot, self.order_high_shift_sel, self.tab_high.residual_sel)
    subplot.set_xlim(0., self.max_total_order + 1.)
    subplot.axhline(y=self.median_all_residual, color='black', lw=1.2)
    subplot.axhline(y=self.median_all_residual+self.std_all_residual, color='black', ls='-.', lw=1.2)
    subplot.axhline(y=self.median_all_residual-self.std_all_residual, color='black', ls='-.', lw=1.2)
    subplot.axvline(linewidth=1.5, color='black', x=self.tab_low.max_order + 0.5)
    self.finalSetup(subplot, title, tooltip)

  def plotFWHMvsWAVE(self, subplot, title, tooltip) :
    self.plotLowHiTextTop(subplot)
    self.setLabels(subplot, 'Wavelength [Ang]', 'Line FWHM [pix]')
    self.scatterPlotScatterSmall(subplot, self.tab_low.wavec_raw, self.tab_low.fwhm, color_pt='red')
    self.scatterPlotScatterSmall(subplot, self.tab_low.wavec_sel, self.tab_low.fwhm_sel)
    self.scatterPlotScatterSmall(subplot, self.tab_high.wavec_raw, self.tab_high.fwhm, color_pt='red')
    self.scatterPlotScatterSmall(subplot, self.tab_high.wavec_sel, self.tab_high.fwhm_sel)
    subplot.set_xlim(self.min_wavec, self.max_wavec)
    subplot.set_ylim(0., self.max_fwhm * 1.05)
    subplot.axhline(y=self.median_all_fwhm, color='black', lw=1.2)
    subplot.axhline(y=self.median_all_fwhm+self.std_all_fwhm, color='black', ls='-.', lw=1.2)
    subplot.axhline(y=self.median_all_fwhm-self.std_all_fwhm, color='black', ls='-.', lw=1.2)
    subplot.axvline(linewidth=1.5, color='black', x=(self.tab_low.max_wavec + self.tab_high.min_wavec)/2.)
    self.finalSetup(subplot, title, tooltip)

  def plotGridYvsX(self, grid, title, tooltip) :
    self.plotLowHiTextRight(grid)
    self.setLabels(grid[0], 'X [pix]', 'Y [pix]')
    self.scatterPlotScatterSmall(grid[0], self.tab_high.x_raw, self.tab_high.ynew_raw, color_pt='red')
    self.scatterPlotScatterSmall(grid[0], self.tab_high.x_sel, self.tab_high.ynew_sel, color_pt='blue')
    self.setLabels(grid[1], 'X [pix]', 'Y [pix]')
    self.scatterPlotScatterSmall(grid[1], self.tab_low.x_raw, self.tab_low.ynew_raw, color_pt='red')
    self.scatterPlotScatterSmall(grid[1], self.tab_low.x_sel, self.tab_low.ynew_sel, color_pt='blue')
    grid[0].set_xlim(0, self.tab_high.det_ny)
    grid[0].set_ylim(0, self.tab_high.det_nx)
    grid[1].set_xlim(0, self.tab_low.det_ny)
    grid[1].set_ylim(0, self.tab_low.det_nx)
    self.finalSetup(grid[0], title, tooltip)
    self.finalSetup(grid[1], "", tooltip)

  def plotYvsX(self, subplot, title, tooltip) :
    self.plotLowHiTextRight(subplot)
    self.setLabels(subplot, 'X [pix]', 'Y [pix]')
    self.scatterPlotScatterSmall(subplot, self.tab_high.x_raw, self.y_raw_shift, color_pt='red')
    self.scatterPlotScatterSmall(subplot, self.tab_high.x_sel, self.y_sel_shift, color_pt='blue')
    self.scatterPlotScatterSmall(subplot, self.tab_low.x_raw, self.tab_low.ynew_raw, color_pt='red')
    self.scatterPlotScatterSmall(subplot, self.tab_low.x_sel, self.tab_low.ynew_sel, color_pt='blue')
    subplot.set_xlim(0, self.tab_low.det_ny)
    subplot.set_ylim(0, self.tab_high.det_nx + self.tab_low.det_nx)
    subplot.axhline(linewidth=1.5, color='black', y=self.tab_low.det_nx)
    self.finalSetup(subplot, title, tooltip)

  def plotLinesText(self, subplot) :
     subplot.set_axis_off()
     text1 = 'No. of detected lines = %g'%(self.tab_low.nlintot + self.tab_high.nlintot)  
     subplot.text(0.05, 0.80, text1, color='#11557c', fontsize=15, ha='left', va='center', alpha=1.0)
     text2 = 'Initial no. of fitted lines = %g'%(self.tab_low.nlinsel + self.tab_high.nlinsel)
     subplot.text(0.05, 0.65, text2, color='#11557c', fontsize=15, ha='left', va='center', alpha=1.0)
     text3 = 'Final no. of fitted lines = %g'%(self.tab_low.nlinsol + self.tab_high.nlinsol) 
     subplot.text(0.05, 0.50, text3, color='#11557c', fontsize=15, ha='left', va='center', alpha=1.0)
     subplot.tooltip='Lines info'

