class SlotViewWindow(QtGui.QMainWindow): """Main application window.""" def __init__(self, struct, pid, tflux, cflux, ratio, time, phottype, sleep, tx, ty, cx, cy, r, br1, br2, naxis1, naxis2, sigdet, contpix, driftlimit): """Default constructor.""" maxcolumn = 7 self.struct = struct self.infile = struct._HDUList__file.name self.name = self.struct[0].header['OBJECT'] self.pid = pid self.dtime = time.copy() self.tflux = tflux self.cflux = cflux self.ratio = ratio self.min_xlim = 10 self.radius = r['comparison'] self.r = r self.br1 = br1 self.br2 = br2 self.tx = tx self.ty = ty self.cx = cx self.cy = cy self.phottype = phottype self.naxis1 = naxis1 self.naxis2 = naxis2 self.sigdet = sigdet self.contpix = contpix self.driftlimit = driftlimit self.niter = 5 self.sigback = 5 self.fft = False self.stopplay = False self.sleep = sleep self.zbox = [] self.npoint = 4 self.id = 0 self.nframes = len(self.struct) self.header = self.struct[int(self.pid[self.id])].header self.goodframes = self.dtime * 0 + 1 if self.phottype == 'circular': self.npoint = 24 # Setup widget QtGui.QMainWindow.__init__(self) # Set main widget self.main = QtGui.QWidget(self) # Set window title self.setWindowTitle("SlotView %s" % self.infile) #set up the different pages self.slotPage = QtGui.QWidget() #set up the differen panels self.set_optionpanel() self.set_imagepanel() self.set_controlpanel() self.set_plotpanel() self.set_infopanel() # Set up the layout slotLayout = QtGui.QVBoxLayout(self.slotPage) slotLayout.addWidget(self.plotpanel) slotLayout.addWidget(self.optipanel) slotLayout.addWidget(self.imdisplay) slotLayout.addWidget(self.contpanel) slotLayout.addWidget(self.infopanel) #create the tabs #self.tabWidget=QtGui.QTabWidget() #self.tabWidget.addTab(self.slotPage, 'Slot') #layout the widgets mainLayout = QtGui.QVBoxLayout(self.main) mainLayout.addWidget(self.slotPage) #mainLayout.addWidget(self.tabWidget) #self.setLayout(mainLayout) # Set focus to main widget self.main.setFocus() # Set the main widget as the central widget self.setCentralWidget(self.main) # Destroy widget on close self.setAttribute(QtCore.Qt.WA_DeleteOnClose) # Close when config dialog is closed self.connect(self.main, QtCore.SIGNAL('keyPressEvent'), self.keyPressEvent) #self.connect(self.conf, QtCore.SIGNAL('destroyed()'), self, QtCore.SLOT('close()')) #self.connect(self.tabWidget, QtCore.SIGNAL('currentChanged(int)'), self.currentChanged) #self.connect(self.imagePage, QtCore.SIGNAL('regionChange(int,int)'), self.regionChange) #self.connect(self.imagePage, QtCore.SIGNAL('runauto(int, int, int)'), self.runauto) def keyPressEvent(self, event): #print "Key Pressed:", event.key() self.keyEvents(str(event.text())) def keyEvents(self, key, x=None, y=None): if key == '?': self.help() if key == 'q': self.close() if key == 'd': self.goodframes[self.id] = 0 self.updatepage() if key == 'u': self.goodframes[self.id] = 1 if key == 'p': self.redophot(self.id) self.updatedataplot() if key == 'P': self.thread = QtCore.QThread() self.thread.run = self.newphot self.thread.start() if key == 't' and x is not None and y is not None: tr = self.radius imarr = self.struct[int(self.pid[self.id])].data timage, tx, ty = st.calcdrift(imarr, x, y, tr, self.naxis1, self.naxis2) if tx >= 0 and ty >= 0: self.tx[self.id] = tx self.ty[self.id] = ty self.updatepage() if key == 'c' and x is not None and y is not None: r = self.radius imarr = self.struct[int(self.pid[self.id])].data cimage, cx, cy = st.calcdrift(imarr, x, y, r, self.naxis1, self.naxis2) if cx >= 0 and cy >= 0: self.cx[self.id] = cx self.cy[self.id] = cy self.updatepage() def onKeyPress(self, event): self.keyEvents(event.key, event.xdata, event.ydata) def onButtonPress(self, event): if event.button == 2: self.lcpickframe(event) def currentChanged(self, event): #print event pass def redophot(self, i): """Redo the photometry for a single frame""" self.id = i x = {} y = {} x['target'] = self.tx[self.id] y['target'] = self.ty[self.id] x['comparison'] = self.cx[self.id] y['comparison'] = self.cy[self.id] image = self.struct[int(self.pid[self.id])].data #these will need to be changed gain = 1 rdnoise = 1 verbose = False try: tflux, tflux_err, cflux, cflux_err, ratio, ratio_err = \ st.dophot(self. phottype, image, x, y, self.r, self.br1, self.br2, \ gain, rdnoise, self.naxis1, self.naxis2) except: msg = "SLOTVIEW--ERROR: Could not measure photometry in frame %i" % i raise SaltError(msg) self.tflux[self.id] = tflux self.cflux[self.id] = cflux self.ratio[self.id] = ratio def newphot(self): self.redophot(self.id) i = self.id + 1 self.stopplay = True while i < self.nframes - 1 and self.stopplay: self.id = i imarr = self.struct[int(self.pid[self.id])].data carray, fx,fy = st.finddrift(imarr, self.cx[self.id-1], self.cy[self.id-1], self.radius, \ self.naxis1, self.naxis2, self.sigdet, self.contpix, self.sigback, self.driftlimit, self.niter) if 0 <= fx < self.naxis1 and 0 <= fy < self.naxis2: dx = self.cx[i - 1] - fx dy = self.cy[i - 1] - fy self.cx[i] = fx self.cy[i] = fy self.tx[i] = self.tx[i - 1] - dx self.ty[i] = self.ty[i - 1] - dy self.redophot(i) i = i + 1 print 'Stopped at', i self.updatepage() def changefluxplot(self, event): self.fluxplot = event self.updatedataplot(save_zoom=False) def changetstarplot(self, event): self.tstarplot = event self.updatedataplot(save_zoom=False) def changecstarplot(self, event): self.cstarplot = event self.updatedataplot(save_zoom=False) def plotlightcurve(self): """Plot the light curve""" #cut the data self.make_lcdata() #make the figure self.light_plot = self.lccanvas.figure.add_axes( [0.10, 0.15, 0.8, 0.80], autoscale_on=False, adjustable='datalim') self.light_plot.hold(True) #plot the curve self.lightcurve, = self.light_plot.plot(self.tarr, self.rarr, linewidth=0.5, linestyle='-', marker='', color='b') if self.fluxplot: self.lightcurve.set_visible(True) else: self.lightcurve.set_visible(False) #plot the flux curve for star 1 self.tstarcurve, = self.light_plot.plot(self.tarr, self.tfarr, linewidth=0.5, linestyle='-', marker='', color='y') if self.tstarplot: self.tstarcurve.set_visible(True) else: self.tstarcurve.set_visible(False) #plot the flux curve for star 1 self.cstarcurve, = self.light_plot.plot(self.tarr, self.cfarr, linewidth=0.5, linestyle='-', marker='', color='g') if self.cstarplot: self.cstarcurve.set_visible(True) else: self.cstarcurve.set_visible(False) #plot a point which matches the time self.ptime = self.dtime[self.id] self.pratio = self.ratio[self.id] self.light_point, = self.light_plot.plot(np.asarray([self.ptime]), np.asarray([self.pratio]), linestyle='', marker='o', mec='#FF0000', mfc='#FF0000') self.find_lclimits() ylabel = 'Star1/Star2' self.light_plot.set_ylabel(ylabel) self.light_plot.set_xlabel('Time (s)') def make_lcdata(self): #cut the data mask = (self.goodframes > 0) self.tarr = np.compress(mask, self.dtime) self.rarr = np.compress(mask, self.ratio) self.tfarr = np.compress(mask, self.tflux) self.cfarr = np.compress(mask, self.cflux) def find_lclimits(self, save_zoom=False): """Find the limits on the Light Curve plot""" if save_zoom: return self.lcx1 = self.tarr.min() self.lcx2 = self.tarr.max() self.light_plot.set_xlim(self.lcx1, self.lcx2) #determine the minimum y value based on what plots are turned on if self.fluxplot: self.lcy1 = self.rarr.min() self.lcy2 = self.rarr.max() if self.tstarplot: self.lcy1 = self.tfarr.min() self.lcy2 = self.tfarr.max() if self.cstarplot: self.lcy1 = self.cfarr.min() self.lcy2 = self.cfarr.max() if self.fluxplot and self.tstarplot and self.cstarplot: self.lcy1 = min(self.rarr.min(), self.tfarr.min(), self.cfarr.min()) self.lcy2 = max(self.rarr.max(), self.tfarr.max(), self.cfarr.max()) if self.tstarplot and self.cstarplot and not self.fluxplot: self.lcy1 = min(self.tfarr.min(), self.cfarr.min()) self.lcy2 = max(self.tfarr.max(), self.cfarr.max()) if self.tstarplot and not self.cstarplot and self.fluxplot: self.lcy1 = min(self.tfarr.min(), self.rarr.min()) self.lcy2 = max(self.tfarr.max(), self.rarr.max()) if not self.tstarplot and self.cstarplot and self.fluxplot: self.lcy1 = min(self.rarr.min(), self.cfarr.min()) self.lcy2 = max(self.rarr.max(), self.cfarr.max()) self.light_plot.set_ylim(self.lcy1, self.lcy2) def lcpickframe(self, event): self.set_id(event.xdata) self.updatepage() def set_id(self, t): """Given a time, set the object id""" self.id = np.abs(self.dtime - t).argmin() def set_plotpanel(self, hmin=250): #set up the control panel self.plotpanel = QtGui.QWidget() self.lccanvas = MplCanvas() self.plotlightcurve() #add the actions self.lccanvas.mpl_connect('button_press_event', self.onButtonPress) # Add navigation toolbars for each widget to enable zooming self.toolbar = NavigationToolbar2QT(self.lccanvas, self) # Set up the layout plotLayout = QtGui.QVBoxLayout(self.plotpanel) plotLayout.addWidget(self.lccanvas) plotLayout.addWidget(self.toolbar) def set_optionpanel(self): #set up the control panel self.optipanel = QtGui.QWidget() #set up the options self.fluxplot = True self.tstarplot = False self.cstarplot = False self.fluxButton = QtGui.QCheckBox("Flux Ratio") self.fluxButton.setChecked(self.fluxplot) self.fluxButton.clicked.connect(self.changefluxplot) self.tstarButton = QtGui.QCheckBox("Target") self.tstarButton.clicked.connect(self.changetstarplot) self.cstarButton = QtGui.QCheckBox("Comparison") self.cstarButton.clicked.connect(self.changecstarplot) # Set up the layout optiLayout = QtGui.QGridLayout(self.optipanel) optiLayout.addWidget(self.fluxButton, 0, 0, 1, 1) optiLayout.addWidget(self.tstarButton, 0, 1, 1, 1) optiLayout.addWidget(self.cstarButton, 0, 2, 1, 1) #optiLayout.addWidget(self.imagtoolbar) def set_imagepanel(self, name=None, cmap='gray', scale='zscale', contrast=0.1): """set up the Image Panel""" hmin = 150 wmin = 400 #set up the control panel self.imagpanel = QtGui.QWidget() #hmin=wmin*self.naxis2/self.naxis1 #print self.naxis1, self.naxis2, wmin, hmin # Add FITS display widget with mouse interaction and overplotting self.imdisplay = ImageDisplay() #self.imdisplay.setMinimumWidth(wmin) # Set colormap self.imdisplay.setColormap(cmap) # Set scale mode for dynamic range imarr = self.struct[int(self.pid[self.id])].data self.imdisplay.scale = scale self.imdisplay.contrast = contrast self.imdisplay.aspect = 'auto' self.imdisplay.loadImage(imarr) #self.imdisplay.drawImage() hmin = self.imdisplay.width() * self.naxis2 / self.naxis1 self.imdisplay.setMaximumHeight(hmin) self.imdisplay.setMinimumHeight(hmin) #add the rectangles self.add_mark(self.tx[self.id], self.ty[self.id], 'target', color='b', lw=2) self.add_mark(self.cx[self.id], self.cy[self.id], 'comparison', color='g', lw=2) self.imdisplay.redraw_canvas() self.imdisplay.axes.set_xticklabels([]) self.imdisplay.axes.set_yticklabels([]) self.imdisplay.connectMatplotlibMouseMotion() self.imdisplay.mpl_connect('button_press_event', self.onButtonPress) self.imdisplay.mpl_connect('key_press_event', self.onKeyPress) # Add navigation toolbars for each widget to enable zooming self.imagtoolbar = NavigationToolbar2QT(self.imdisplay, self) # Set up the layout imagLayout = QtGui.QVBoxLayout(self.imagpanel) #imagLayout.addWidget(self.imdisplay) imagLayout.addWidget(MplCanvas()) imagLayout.addWidget(self.imagtoolbar) def add_mark(self, x1, y1, label, color='g', lw=2): """Add the rectangle for the object""" self.imdisplay.removePatch(label) r1 = self.r[label] rect = self.imdisplay.addSquare(label, x1, y1, r1, color=color, lw=lw) def set_controlpanel(self): """set up the Control Panel""" #set up the control panel self.contpanel = QtGui.QWidget() #set up the buttons self.frevButton = QtGui.QPushButton("<<") self.frevButton.clicked.connect(self.freverse) self.revButton = QtGui.QPushButton("<") self.revButton.clicked.connect(self.reverse) self.rev1Button = QtGui.QPushButton("-") self.rev1Button.clicked.connect(self.revone) self.stopButton = QtGui.QPushButton("Stop") self.stopButton.clicked.connect(self.stop) self.play1Button = QtGui.QPushButton("+") self.play1Button.clicked.connect(self.playone) self.playButton = QtGui.QPushButton(">") self.playButton.clicked.connect(self.play) self.fplayButton = QtGui.QPushButton(">>") self.fplayButton.clicked.connect(self.fplay) #set up the info panel layout contLayout = QtGui.QGridLayout(self.contpanel) #contLayout.addWidget(self.frevButton, 0, 0, 1, 1) #contLayout.addWidget(self.revButton, 0, 1, 1, 1) contLayout.addWidget(self.rev1Button, 0, 2, 1, 1) contLayout.addWidget(self.stopButton, 0, 3, 1, 1) contLayout.addWidget(self.play1Button, 0, 4, 1, 1) #contLayout.addWidget(self.playButton, 0, 5, 1, 1) #contLayout.addWidget(self.fplayButton,0, 6, 1, 1) def set_infopanel(self): """Set up the information panel""" #set up the information panel self.infopanel = QtGui.QWidget() #add the name of the file self.IDValueLabel = QtGui.QLabel("%i" % self.pid[self.id]) self.IDValueLabel.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Sunken) self.NameValueLabel = QtGui.QLabel("%s" % self.name) self.NameValueLabel.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Sunken) self.timeValueLabel = QtGui.QLabel("%s" % self.get_time()) self.timeValueLabel.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Sunken) #set up the info panel layout infoLayout = QtGui.QGridLayout(self.infopanel) infoLayout.addWidget(self.IDValueLabel, 0, 0, 1, 1) infoLayout.addWidget(self.NameValueLabel, 0, 1, 1, 1) infoLayout.addWidget(self.timeValueLabel, 0, 2, 1, 1) def get_time(self): #set the time try: utime = self.struct[int(self.pid[self.id])].header['UTC-OBS'] except: utime = '' return utime def help(self): """Print the help message and the key-bindings available to the user""" helpmessage = """ The following commands are available to the user: ? - Print this information q - quit the viewer n - Move to the next image b - move back an image D - Delete this image u - undelete this image p - Perform photometry on this image P - Perform photometry starting at this image stop button-Stop photometry or display reset button-Reset the light curve plot Middle Click-Display image corresponding to this time """ print helpmessage return def stop(self): self.stopplay = False print self.stopplay def playone(self): stopid = self.nframes - 2 if self.id < (stopid): self.id = self.id + 1 self.updatepage() def play(self): self.stopplay = True stopid = self.nframes - 2 while self.stopplay and self.id < stopid: self.id = self.id + 1 time.sleep(self.sleep) self.updatepage() def fplay(self): self.stopplay = True stopid = self.nframes - 2 while self.stopplay and self.id < stopid: self.id = self.id + 1 self.updatepage() def revone(self): if self.id > 0: self.id = self.id - 1 self.updatepage() def reverse(self): self.stopplay = True while self.stopplay and self.id > 0: self.id = self.id - 1 time.sleep(self.sleep) self.updatepage() def freverse(self): self.stopplay = True while self.stopplay and self.id > 0: self.id = self.id - 1 self.updatepage() def updatepage(self): """Update all the values on the page that need updating""" self.IDValueLabel.setText("%i" % self.pid[self.id]) self.timeValueLabel.setText("%s" % self.get_time()) #update the image imarr = self.struct[int(self.pid[self.id])].data self.imdisplay.loadImage(imarr) #update the boxes self.add_mark(self.tx[self.id], self.ty[self.id], 'target', color='b', lw=2) self.add_mark(self.cx[self.id], self.cy[self.id], 'comparison', color='g', lw=2) self.imdisplay.redraw_canvas() self.imdisplay.axes.set_xticklabels([]) self.imdisplay.axes.set_yticklabels([]) self.updatedataplot() def updatedataplot(self, save_zoom=True): """Update the data plot for changes in the options """ #redraw the lines self.make_lcdata() self.lightcurve.set_xdata(self.tarr) self.lightcurve.set_ydata(self.rarr) self.tstarcurve.set_xdata(self.tarr) self.tstarcurve.set_ydata(self.tfarr) self.cstarcurve.set_xdata(self.tarr) self.cstarcurve.set_ydata(self.cfarr) #move the point self.light_point.set_xdata([self.dtime[self.id]]) self.light_point.set_ydata([self.ratio[self.id]]) if self.fluxplot: self.lightcurve.set_visible(True) else: self.lightcurve.set_visible(False) #plot the flux curve for star 1 if self.tstarplot: self.tstarcurve.set_visible(True) else: self.tstarcurve.set_visible(False) #plot the flux curve for star 1 if self.cstarplot: self.cstarcurve.set_visible(True) else: self.cstarcurve.set_visible(False) self.find_lclimits(save_zoom=save_zoom) self.lccanvas.draw()
class FpRingWidget (QtGui.QWidget): def __init__(self,filenumber,flatnumber,parent=None): super(FpRingWidget,self).__init__(parent) self.filenumber=filenumber self.flatnumber=flatnumber #set up the ring plot self.ringplot=MplCanvas() self.axes=self.ringplot.figure.add_subplot(211) self.erraxes=self.ringplot.figure.add_subplot(212) self.ringplot.setMinimumHeight(500) # self.ringplot.setMinimumHeight(500) self.loadfpring() self.plotRing() # self.redraw_canvas() #set up the information panel self.infopanel=QtGui.QWidget() # add a label: self.NameLabel = QtGui.QLabel("File number:") #add the name of the file self.NameValueLabel = QtGui.QLineEdit(str(self.filenumber)) # and a button to process the new ring self.ringButton = QtGui.QPushButton('Load new ring') self.ringButton.clicked.connect(self.redrawRing) # add a label for the flat field: self.flatLabel = QtGui.QLabel("Flat file number:") #add the name of the file self.flatValueLabel = QtGui.QLineEdit(str(self.flatnumber)) #set up info panel layout infoLayout=QtGui.QGridLayout(self.infopanel) infoLayout.addWidget(self.NameLabel,0,0,1,1) infoLayout.addWidget(self.NameValueLabel,0,1,1,1) infoLayout.addWidget(self.ringButton,0,2,2,1) infoLayout.addWidget(self.flatLabel,0,3,1,1) infoLayout.addWidget(self.flatValueLabel,0,4,1,1) # fitLayout=QtGui.QGridLayout(self.infopanel) # add a panel to display the fit results self.fitpanel=QtGui.QWidget() self.fitLabel = QtGui.QLabel("Fit Results:") fitXresult="X:" + str(self.etalon_x) fitYresult="Y:" + str(self.etalon_y) fitZresult="Z:" + str(self.etalon_z) fitRresult="R: %.1f" % float(self.pars['R'][0]) fitAmpresult="Amplitude: %.1f" % float(self.pars['Amplitude'][0]) fitRmsresult="RMS: %.1f" % float(self.rms) fitGammaresult="Gamma: %.1f" % float(self.pars['Gamma'][0]) fitFWHMresult="FWHM: %.1f" % float(self.pars['FWHM'][0]) #add the text to the fit results panel self.fitX = QtGui.QLabel(fitXresult) self.fitY = QtGui.QLabel(fitYresult) self.fitZ = QtGui.QLabel(fitZresult) self.fitR = QtGui.QLabel(fitRresult) self.fitAmp = QtGui.QLabel(fitAmpresult) self.fitRms = QtGui.QLabel(fitRmsresult) self.fitGamma = QtGui.QLabel(fitGammaresult) self.fitFWHM = QtGui.QLabel(fitFWHMresult) # lay them out nicely... fitLayout=QtGui.QGridLayout(self.fitpanel) fitLayout.addWidget(self.fitLabel,0,0,1,1) fitLayout.addWidget(self.fitX,0,1,1,1) fitLayout.addWidget(self.fitY,0,2,1,1) fitLayout.addWidget(self.fitZ,0,3,1,1) fitLayout.addWidget(self.fitR,0,4,1,1) fitLayout.addWidget(self.fitAmp,0,5,1,2) fitLayout.addWidget(self.fitRms,0,7,1,1) fitLayout.addWidget(self.fitGamma,0,8,1,1) fitLayout.addWidget(self.fitFWHM,0,9,1,1) # Set up the main layout mainLayout = QtGui.QVBoxLayout() mainLayout.addWidget(self.infopanel) mainLayout.addWidget(self.ringplot) mainLayout.addWidget(self.fitpanel) self.setLayout(mainLayout) def loadfpring(self): date = os.getcwd().split('/')[-1] self.getFitsHeader() fits = "mbxpP%s%04d.fits" % (date, self.filenumber) if self.flatnumber != 0: flat = "mbxpP%s%04d.fits" % (date, self.flatnumber) else: flat="/home/ccd/erc/FP_utils/DefaultNeFlat.fits" ffits='f'+fits fpfile='p'+ffits maskedfile='m'+fpfile if (not os.path.isfile(maskedfile)): saltflat(fits,ffits,'',flat, clobber='yes',verbose='no') saltfpprep(ffits,fpfile,'',clobber='yes',verbose='no') saltfpmask(fpfile,maskedfile,'',axc=798*4/self.xbin,ayc=503*4/self.ybin,arad=450*4/self.xbin,clobber='yes', verbose='no') self.good, self.rsq, self.prof, self.fit, self.pars = fit_rings(maskedfile) self.resid = self.prof - self.fit self.rms = self.resid.std() self.saveFitToFile() return def plotRing(self): #set up the plots.... self.axes.plot(self.rsq, self.prof, label="Profile") self.axes.plot(self.rsq, self.fit, label="Fit") self.axes.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=3, ncol=2, mode="expand", borderaxespad=0.) self.erraxes.plot(self.rsq, self.resid, label="Profile - Fit") self.erraxes.legend(loc=1) self.show() return def redrawRing(self): # read the new filenumber from the input box self.filenumber=int(self.NameValueLabel.text()) # recalculate and re-draw self.loadfpring() self.axes.clear() self.erraxes.clear() self.plotRing() #Force a redraw!!! self.ringplot.draw() def getFitsHeader(self): date = os.getcwd().split('/')[-1] fits = "mbxpP%s%04d.fits" % (date, self.filenumber) hdu = pyfits.open(fits) (data, header) = (hdu[0].data, hdu[0].header) etalon = int(header['ET-STATE'].split()[3]) hetalon_x = "ET%dX" % etalon hetalon_y = "ET%dY" % etalon hetalon_z = "ET%dZ" % etalon self.etalon_x=int(header[hetalon_x]) self.etalon_y=int(header[hetalon_y]) self.etalon_z=int(header[hetalon_z]) self.xbin=int(header['CCDSUM'].split()[0]) self.ybin=int(header['CCDSUM'].split()[1]) print self.xbin,self.ybin return def saveFitToFile(self): pars=self.pars self.getFitsHeader() if os.path.isfile('outparams'): try: outparams=open('outparams','a') except IOError, e: print 'Failed to open the ring file' else:
class ArcDisplay(QtGui.QWidget): """Class for displaying Arc Spectra using matplotlib and embedded in a Qt 4 GUI. """ def __init__(self, xarr, farr, slines, sfluxes, ws, xp=[], wp=[], xdiff=20, res=2.0, dres=0.1, sigma=5, niter=5): """Default constructor.""" QtGui.QWidget.__init__(self) # Initialize base class self.arcfigure = MplCanvas() self.errfigure = MplCanvas() # Add central axes instance self.axes = self.arcfigure.figure.add_subplot(111) self.erraxes = self.errfigure.figure.add_subplot(111) # Connect mouse events self.arcfigure.connectMatplotlibMouseMotion() self.arcfigure.mpl_connect('button_press_event', self.onButtonPress) self.arcfigure.mpl_connect('key_press_event', self.onKeyPress) self.errfigure.connectMatplotlibMouseMotion() self.errfigure.mpl_connect('button_press_event', self.onButtonPress) self.errfigure.mpl_connect('key_press_event', self.onKeyPress) # load the data self.xarr = xarr self.farr = farr self.slines = slines self.sfluxes = sfluxes self.ws = ws self.xdiff = xdiff self.sigma = sigma self.niter = niter self.res = res self.dres = dres self.xp = xp self.wp = wp # set up the artificial spectra self.spectrum = Spectrum.Spectrum(self.slines, self.sfluxes, dw=self.dres, stype='line', sigma=self.res) self.swarr = self.spectrum.wavelength self.sfarr = self.spectrum.flux * self.farr.max( ) / self.spectrum.flux.max() # set up the wavelength solution if self.ws.function == 'line': self.ws.set_xarr(self.xarr) self.ws.farr = self.farr self.ws.spectrum = self.spectrum # set up the list of deleted points self.dxp = [] self.dwp = [] # set up other variables self.isArt = False self.isFeature = False # Set display parameters self.xmin = self.xarr.min() self.xmax = self.xarr.max() self.ymin = self.farr.min() self.ymax = self.farr.max() def onKeyPress(self, event): """Emit signal on key press""" if event.key == '?': # return the help file print('?:', event.key) elif event.key == 'c': # return the centroid if event.xdata: cx = st.mcentroid(self.xarr, self.farr, xc=event.xdata, xdiff=self.xdiff) self.emit(QtCore.SIGNAL("updatex(float)"), cx) elif event.key == 'x': # return the x position if event.xdata: self.emit(QtCore.SIGNAL("updatex(float)"), event.xdata) elif event.key == 'f': # find the fit self.findfit() self.emit(QtCore.SIGNAL("fitUpdate()")) elif event.key == 'b': # auto-idenitfy features self.findfeatures() elif event.key == 'z': # Assume the solution is correct and find the zeropoint # that best matches it from cross correllation self.findzp() elif event.key == 'e': # find closest feature from existing fit and line list # and match it pass elif event.key == 'l': # plot the features from existing list self.plotFeatures() self.redraw_canvas() elif event.key == 'i': # reset identified features pass elif event.key == 'r': # redraw graph self.redraw_canvas() elif event.key == 'a': # draw artificial spectrum self.isArt = not self.isArt self.redraw_canvas() elif event.key == 'd': # Delete feature save = False if event.canvas == self.errfigure: save = True self.deletepoints(event.xdata, save=save) self.redraw_canvas(keepzoom=True) elif event.key: self.emit(QtCore.SIGNAL("keyPressEvent(string)"), event.key) def onButtonPress(self, event): """Emit signal on selecting valid image position.""" if event.xdata and event.ydata: print(event.xdata, event.ydata, event.canvas, event.name) self.emit(QtCore.SIGNAL("positionSelected(float, float)"), float(event.xdata), float(event.ydata)) def plotArc(self): """Draw image to canvas.""" # plot the spectra self.spcurve, = self.axes.plot(self.xarr, self.farr, linewidth=0.5, linestyle='-', marker=None, color='b') def plotArt(self): """Plot the artificial spectrum""" self.isArt = True warr = self.ws.value(self.xarr) asfarr = st.interpolate(warr, self.swarr, self.sfarr, left=0.0, right=0.0) self.fpcurve, = self.axes.plot(self.xarr, asfarr, linewidth=0.5, linestyle='-', marker=None, color='r') def plotFeatures(self): """Plot features identified in the line list""" self.isFeature = True fl = np.array(self.xp) * 0.0 + 0.25 * self.farr.max() self.splines = self.axes.plot(self.xp, fl, ls='', marker='|', ms=20, color='#00FF00') # set up the text position tsize = 0.83 self.ymin, self.ymax = self.axes.get_ylim() ppp = (self.ymax - self.ymin) / (self.arcfigure.figure.get_figheight() * self.arcfigure.figure.get_dpi()) f = self.ymax - 10 * tsize * ppp for x, w in zip(self.xp, self.wp): w = '%6.2f' % float(w) self.axes.text(x, f, w, size='small', rotation='vertical', color='#00FF00') def plotErr(self): """Draw image to canvas.""" if self.xp and self.wp: # plot the spectra w = self.ws.value(self.xp) self.errcurve, = self.erraxes.plot(self.xp, self.wp - w, linewidth=0.5, linestyle='', marker='o', color='b') if self.dxp and self.dwp: # plot the spectra dw = self.ws.value(self.dxp) self.delerrcurve, = self.erraxes.plot(self.dxp, self.dwp - dw, linewidth=0.5, linestyle='', marker='x', color='b') def findfeatures(self): """Given a set of features, find other features that might correspond to those features """ xp, wp = st.findfeatures(self.xarr, self.farr, self.slines, self.sfluxes, self.ws, sigma=self.sigma, niter=self.niter) for x, w in zip(xp, wp): if w not in self.wp and w > -1: self.xp.append(x) self.wp.append(w) self.plotFeatures() self.redraw_canvas() def findzp(self): """Find the zeropoint for the source and plot of the new value """ self.ws = st.findzeropoint(self.xarr, self.farr, self.swarr, self.sfarr, self.ws, dc=10, nstep=20, inttype='interp') self.plotArt() self.redraw_canvas() def findfit(self): print(self.xp) print(self.wp) self.ws = st.findfit(self.xp, self.wp, function=self.ws.function, order=self.ws.order) self.err_redraw_canvas() def addpoints(self, x, w): """Add points to the line list """ if isinstance(x, list) and isinstance(w, list): self.xp.extend(x) self.wp.extend(w) else: self.xp.append(x) self.wp.append(w) print(self.xp) def deletepoints(self, x, save=False): """ Delete points from the line list """ in_minw = np.abs(np.array(self.xp) - x).argmin() if save: self.dxp.append(self.xp[in_minw]) self.dwp.append(self.wp[in_minw]) self.xp.__delitem__(in_minw) self.wp.__delitem__(in_minw) def redraw_canvas(self, keepzoom=False): if keepzoom: # Store current zoom level xmin, xmax = self.axes.get_xlim() ymin, ymax = self.axes.get_ylim() # Clear plot self.axes.clear() # Draw image self.plotArc() # if necessary, redraw the features if self.isFeature: self.plotFeatures() # if necessary, draw the artificial spectrum if self.isArt: self.plotArt() # Restore zoom level if keepzoom: self.axes.set_xlim((self.xmin, self.xmax)) self.axes.set_ylim((self.ymin, self.ymax)) # Force redraw self.arcfigure.draw() self.err_redraw_canvas() def err_redraw_canvas(self, keepzoom=False): if keepzoom: # Store current zoom level xmin, xmax = self.erraxes.get_xlim() ymin, ymax = self.erraxes.get_ylim() else: self.xmin, self.xmax = self.axes.get_xlim() # Clear plot self.erraxes.clear() # Draw image self.plotErr() # Restore zoom level if keepzoom: self.erraxes.set_xlim((xmin, xmax)) self.erraxes.set_ylim((ymin, ymax)) else: self.erraxes.set_xlim((self.xmin, self.xmax)) self.errfigure.draw() self.emit(QtCore.SIGNAL("fitUpdate()"))
class ArcDisplay(QtGui.QWidget): """Class for displaying Arc Spectra using matplotlib and embedded in a Qt 4 GUI. """ def __init__(self, xarr, farr, slines, sfluxes, ws, xp=[], wp=[], xdiff=20, res=2.0, dres=0.1, sigma=5, niter=5): """Default constructor.""" QtGui.QWidget.__init__(self) # Initialize base class self.arcfigure = MplCanvas() self.errfigure = MplCanvas() # Add central axes instance self.axes = self.arcfigure.figure.add_subplot(111) self.erraxes = self.errfigure.figure.add_subplot(111) # Connect mouse events self.arcfigure.connectMatplotlibMouseMotion() self.arcfigure.mpl_connect('button_press_event', self.onButtonPress) self.arcfigure.mpl_connect('key_press_event', self.onKeyPress) self.errfigure.connectMatplotlibMouseMotion() self.errfigure.mpl_connect('button_press_event', self.onButtonPress) self.errfigure.mpl_connect('key_press_event', self.onKeyPress) # load the data self.xarr = xarr self.farr = farr self.slines = slines self.sfluxes = sfluxes self.ws = ws self.xdiff = xdiff self.sigma = sigma self.niter = niter self.res = res self.dres = dres self.xp = xp self.wp = wp # set up the artificial spectra self.spectrum = Spectrum.Spectrum(self.slines, self.sfluxes, dw=self.dres, stype='line', sigma=self.res) self.swarr = self.spectrum.wavelength self.sfarr = self.spectrum.flux * self.farr.max() / self.spectrum.flux.max() # set up the wavelength solution if self.ws.function == 'line': self.ws.set_xarr(self.xarr) self.ws.farr = self.farr self.ws.spectrum = self.spectrum # set up the list of deleted points self.dxp = [] self.dwp = [] # set up other variables self.isArt = False self.isFeature = False # Set display parameters self.xmin = self.xarr.min() self.xmax = self.xarr.max() self.ymin = self.farr.min() self.ymax = self.farr.max() def onKeyPress(self, event): """Emit signal on key press""" if event.key == '?': # return the help file print '?:', event.key elif event.key == 'c': # return the centroid if event.xdata: cx = st.mcentroid(self.xarr, self.farr, xc=event.xdata, xdiff=self.xdiff) self.emit(QtCore.SIGNAL("updatex(float)"), cx) elif event.key == 'x': # return the x position if event.xdata: self.emit(QtCore.SIGNAL("updatex(float)"), event.xdata) elif event.key == 'f': # find the fit self.findfit() self.emit(QtCore.SIGNAL("fitUpdate()")) elif event.key == 'b': # auto-idenitfy features self.findfeatures() elif event.key == 'z': # Assume the solution is correct and find the zeropoint # that best matches it from cross correllation self.findzp() elif event.key == 'e': # find closest feature from existing fit and line list # and match it pass elif event.key == 'l': # plot the features from existing list self.plotFeatures() self.redraw_canvas() elif event.key == 'i': # reset identified features pass elif event.key == 'r': # redraw graph self.redraw_canvas() elif event.key == 'a': # draw artificial spectrum self.isArt = not self.isArt self.redraw_canvas() elif event.key == 'd': # Delete feature save = False if event.canvas == self.errfigure: save = True self.deletepoints(event.xdata, save=save) self.redraw_canvas(keepzoom=True) elif event.key: self.emit(QtCore.SIGNAL("keyPressEvent(string)"), event.key) def onButtonPress(self, event): """Emit signal on selecting valid image position.""" if event.xdata and event.ydata: print event.xdata, event.ydata, event.canvas, event.name self.emit(QtCore.SIGNAL("positionSelected(float, float)"), float(event.xdata), float(event.ydata)) def plotArc(self): """Draw image to canvas.""" # plot the spectra self.spcurve, = self.axes.plot(self.xarr, self.farr, linewidth=0.5, linestyle='-', marker=None, color='b') def plotArt(self): """Plot the artificial spectrum""" self.isArt = True warr = self.ws.value(self.xarr) asfarr = st.interpolate(warr, self.swarr, self.sfarr, left=0.0, right=0.0) self.fpcurve, = self.axes.plot(self.xarr, asfarr, linewidth=0.5, linestyle='-', marker=None, color='r') def plotFeatures(self): """Plot features identified in the line list""" self.isFeature = True fl = np.array(self.xp) * 0.0 + 0.25 * self.farr.max() self.splines = self.axes.plot(self.xp, fl, ls='', marker='|', ms=20, color='#00FF00') # set up the text position tsize = 0.83 self.ymin, self.ymax = self.axes.get_ylim() ppp = (self.ymax - self.ymin) / (self.arcfigure.figure.get_figheight() * self.arcfigure.figure.get_dpi()) f = self.ymax - 10 * tsize * ppp for x, w in zip(self.xp, self.wp): w = '%6.2f' % float(w) self.axes.text(x, f, w, size='small', rotation='vertical', color='#00FF00') def plotErr(self): """Draw image to canvas.""" if self.xp and self.wp: # plot the spectra w = self.ws.value(self.xp) self.errcurve, = self.erraxes.plot(self.xp, self.wp - w, linewidth=0.5, linestyle='', marker='o', color='b') if self.dxp and self.dwp: # plot the spectra dw = self.ws.value(self.dxp) self.delerrcurve, = self.erraxes.plot( self.dxp, self.dwp - dw, linewidth=0.5, linestyle='', marker='x', color='b') def findfeatures(self): """Given a set of features, find other features that might correspond to those features """ xp, wp = st.findfeatures(self.xarr, self.farr, self.slines, self.sfluxes, self.ws, sigma=self.sigma, niter=self.niter) for x, w in zip(xp, wp): if w not in self.wp and w > -1: self.xp.append(x) self.wp.append(w) self.plotFeatures() self.redraw_canvas() def findzp(self): """Find the zeropoint for the source and plot of the new value """ self.ws = st.findzeropoint(self.xarr, self.farr, self.swarr, self.sfarr, self.ws, dc=10, nstep=20, inttype='interp') self.plotArt() self.redraw_canvas() def findfit(self): print self.xp print self.wp self.ws = st.findfit(self.xp, self.wp, function=self.ws.function, order=self.ws.order) self.err_redraw_canvas() def addpoints(self, x, w): """Add points to the line list """ if isinstance(x, list) and isinstance(w, list): self.xp.extend(x) self.wp.extend(w) else: self.xp.append(x) self.wp.append(w) print self.xp def deletepoints(self, x, save=False): """ Delete points from the line list """ in_minw = np.abs(np.array(self.xp) - x).argmin() if save: self.dxp.append(self.xp[in_minw]) self.dwp.append(self.wp[in_minw]) self.xp.__delitem__(in_minw) self.wp.__delitem__(in_minw) def redraw_canvas(self, keepzoom=False): if keepzoom: # Store current zoom level xmin, xmax = self.axes.get_xlim() ymin, ymax = self.axes.get_ylim() # Clear plot self.axes.clear() # Draw image self.plotArc() # if necessary, redraw the features if self.isFeature: self.plotFeatures() # if necessary, draw the artificial spectrum if self.isArt: self.plotArt() # Restore zoom level if keepzoom: self.axes.set_xlim((self.xmin, self.xmax)) self.axes.set_ylim((self.ymin, self.ymax)) # Force redraw self.arcfigure.draw() self.err_redraw_canvas() def err_redraw_canvas(self, keepzoom=False): if keepzoom: # Store current zoom level xmin, xmax = self.erraxes.get_xlim() ymin, ymax = self.erraxes.get_ylim() else: self.xmin, self.xmax = self.axes.get_xlim() # Clear plot self.erraxes.clear() # Draw image self.plotErr() # Restore zoom level if keepzoom: self.erraxes.set_xlim((xmin, xmax)) self.erraxes.set_ylim((ymin, ymax)) else: self.erraxes.set_xlim((self.xmin, self.xmax)) self.errfigure.draw() self.emit(QtCore.SIGNAL("fitUpdate()"))
class FpParallWidget (QtGui.QWidget): def __init__(self,parent=None): super(FpParallWidget,self).__init__(parent) #Load up the data: self.loadOutparams() #set up the file range panel self.rangepanel=QtGui.QWidget() # add a label: self.FromLabel = QtGui.QLabel("From file number:") self.ToLabel = QtGui.QLabel("To file number:") #add the name of the file self.FromValueLabel = QtGui.QLineEdit(str(min(self.outparams[:,0]))) self.ToValueLabel = QtGui.QLineEdit(str(max(self.outparams[:,0]))) # and a button to process the new range self.refreshButton = QtGui.QPushButton('Refresh') self.refreshButton.clicked.connect(self.plotOutparams) #set up file range panel layout rangeLayout=QtGui.QGridLayout(self.rangepanel) rangeLayout.addWidget(self.FromLabel,0,0,1,1) rangeLayout.addWidget(self.FromValueLabel,0,1,1,1) rangeLayout.addWidget(self.refreshButton,0,2,2,1) rangeLayout.addWidget(self.ToLabel,0,3,1,1) rangeLayout.addWidget(self.ToValueLabel,0,4,1,1) #add the radio buttons for the choice of x axis... self.radioFilenumber= QtGui.QRadioButton("Plot vs Filenumber") self.radioX= QtGui.QRadioButton("Plot vs etalon X") self.radioY= QtGui.QRadioButton("Plot vs etalon Y") #create a gropu for them: self.radioGroupX=QtGui.QButtonGroup() self.radioGroupX.addButton(self.radioFilenumber) self.radioGroupX.addButton(self.radioX) self.radioGroupX.addButton(self.radioY) #make sure the filenumber is the default self.radioFilenumber.setChecked(True) #create radio buttons for the choice of y axis: self.radioFWHM=QtGui.QRadioButton("Plots vs FWHM") self.radioAmp=QtGui.QRadioButton("Plots vs Amplitude") #add a group for the y axis: self.radioGroupY=QtGui.QButtonGroup() self.radioGroupY.addButton(self.radioFWHM) self.radioGroupY.addButton(self.radioAmp) #add a default: self.radioFWHM.setChecked(True) # display best fit in range: self.fitpanel=QtGui.QWidget() self.fitLabel = QtGui.QLabel("Lowest FWHM in file range:") self.cleanOutparams() self.getBestparams() fitFileresult="File number: %i" %int(self.bestparams[0]) fitXresult="X: %i" % int(self.bestparams[1]) fitYresult="Y: %i" % int(self.bestparams[2]) fitZresult="Z: %i " % int(self.bestparams[3]) fitRresult="R: %.1f" % float(self.bestparams[4]) fitAmpresult="Amplitude: %.1f" % float(self.bestparams[5]) fitRmsresult="RMS: %.3f" % float(self.bestparams[6]) fitGammaresult="Gamma: %.2f" % float(self.bestparams[7]) fitFWHMresult="FWHM: %.3f" % float(self.bestparams[8]) #add the text to the fit results panel self.fitFile = QtGui.QLabel(fitFileresult) self.fitX = QtGui.QLabel(fitXresult) self.fitY = QtGui.QLabel(fitYresult) self.fitZ = QtGui.QLabel(fitZresult) self.fitR = QtGui.QLabel(fitRresult) self.fitAmp = QtGui.QLabel(fitAmpresult) self.fitRms = QtGui.QLabel(fitRmsresult) self.fitGamma = QtGui.QLabel(fitGammaresult) self.fitFWHM = QtGui.QLabel(fitFWHMresult) # lay them out nicely... fitLayout=QtGui.QGridLayout(self.fitpanel) fitLayout.addWidget(self.fitLabel,0,0,1,4) fitLayout.addWidget(self.fitFile,3,0,1,1) fitLayout.addWidget(self.fitX,3,1,1,1) fitLayout.addWidget(self.fitY,3,2,1,1) fitLayout.addWidget(self.fitZ,3,3,1,1) fitLayout.addWidget(self.fitR,3,4,1,1) fitLayout.addWidget(self.fitAmp,3,5,1,1) fitLayout.addWidget(self.fitRms,3,6,1,1) fitLayout.addWidget(self.fitGamma,3,7,1,1) fitLayout.addWidget(self.fitFWHM,3,8,1,1) #set up the fwhm plot self.fwhmplot=MplCanvas() self.fwhmaxes=self.fwhmplot.figure.add_subplot(111) #connect mouse clicks self.fwhmplot.mpl_connect('button_press_event',self.onClick) #and now we know what the X and Y axis should be, make the fwhm/amp plot self.plotOutparams() # and check for radio button event signals! self.radioGroupX.buttonClicked.connect(self.plotOutparams) self.radioGroupY.buttonClicked.connect(self.plotOutparams) #Add the X radio buttons to a horizontal layout self.radiopanel= QtGui.QWidget() radioLayout=QtGui.QHBoxLayout(self.radiopanel) radioLayout.addWidget(self.radioFilenumber) radioLayout.addWidget(self.radioX) radioLayout.addWidget(self.radioY) #Add the Y radio buttons to a vertical layout self.radioYpanel=QtGui.QWidget() radioYLayout=QtGui.QVBoxLayout(self.radioYpanel) radioYLayout.addWidget(self.radioFWHM) radioYLayout.addWidget(self.radioAmp) # Set up the main layout mainLayout = QtGui.QGridLayout() mainLayout.addWidget(self.rangepanel,0,0,1,9) mainLayout.addWidget(self.fitpanel,1,0,1,9) mainLayout.addWidget(self.fwhmplot,2,0,1,4) mainLayout.addWidget(self.radioYpanel,2,5,1,1) mainLayout.addWidget(self.radiopanel,3,1,1,1) self.setLayout(mainLayout) def loadOutparams(self): self.outparams=np.genfromtxt('outparams', skip_header=1) return def cleanOutparams(self): minFile=float(self.FromValueLabel.text()) maxFile=float(self.ToValueLabel.text()) # print "reloading from %i to %i" % (minFile, maxFile) self.cleanarr=[] mask = (minFile <= self.outparams[:,0]) * (self.outparams[:,0] <= maxFile) self.cleanarr = self.outparams[mask] # print self.cleanarr[:,0] return def plotOutparams(self): #reload outparams self.loadOutparams() #set up the plot.... self.cleanOutparams() self.fwhmaxes.clear() if self.radioFilenumber.isChecked(): x=self.cleanarr[:,0] elif self.radioX.isChecked(): x=self.cleanarr[:,1] elif self.radioY.isChecked(): x=self.cleanarr[:,2] # Work out the Y axis: if self.radioFWHM.isChecked(): y=self.cleanarr[:,8] elif self.radioAmp.isChecked(): y=self.cleanarr[:,5] self.fwhmaxes.plot(x, y, 'bo') # self.show() # don't forget to force a redraw! self.fwhmplot.draw() #ummmm we forgot to update the best fit.. self.getBestparams() self.fitFile.setText("File number: %i" %int(self.bestparams[0])) self.fitX.setText("X: %i" % int(self.bestparams[1])) self.fitX.setText("X: %i" % int(self.bestparams[1])) self.fitY.setText("Y %i:" % int(self.bestparams[2])) self.fitZ.setText("Z: %i " % int(self.bestparams[3])) self.fitR.setText("R: %.1f" % float(self.bestparams[4])) self.fitAmp.setText("Amplitude: %.1f" % float(self.bestparams[5])) self.fitRms.setText("RMS: %.2f" % float(self.bestparams[6])) self.fitGamma.setText("Gamma: %.2f" % float(self.bestparams[7])) self.fitFWHM.setText("FWHM: %.3f" % float(self.bestparams[8])) # self.fitpanel.show() return def onClick(self,event): # What's on the X axis? if self.radioFilenumber.isChecked(): mask = (self.cleanarr[:,0]==round(event.xdata)) elif self.radioX.isChecked(): mask = (self.cleanarr[:,1]==round(event.xdata)) elif self.radioY.isChecked(): mask = (self.cleanarr[:,2]==round(event.xdata)) # get from the array the first row that matches the X value) datapoint = self.cleanarr[mask][0] #format it ready for the tooltip: text="FileNumber: %i, \nX: %i, \nY: %i, \nZ:%i, \nAmp: %.2f, \nRMS: %.2f, \nGamma: %.2f, \nFWHM: %.3f" % (int(datapoint[0]), int(datapoint[1]),int(datapoint[2]),int(datapoint[3]),datapoint[5],datapoint[6],datapoint[7],datapoint[8]) #and plonk it on! :) QtGui.QToolTip.showText(QtCore.QPoint(338,314),text) return def getBestparams(self): if self.radioFWHM.isChecked(): self.fitLabel.setText("Lowest FWHM in file range:") mask = (self.cleanarr[:,8]==min(self.cleanarr[:,8])) self.bestparams = self.cleanarr[mask][0] elif self.radioAmp.isChecked(): self.fitLabel.setText("Highest Amplitude in file range:") mask = (self.cleanarr[:,5]==max(self.cleanarr[:,5])) self.bestparams = self.cleanarr[mask][0] return
class SpectraViewWidget(QtGui.QWidget): def __init__(self, warr, farr, snarr, name='', y1=1010, y2=1030, hmin=150, wmin=400, smooth=5, parent=None): super(SpectraViewWidget, self).__init__(parent) self.y1 = y1 self.y2 = y2 self.smooth = smooth self.name = name #set up the arc display self.arcfigure = MplCanvas() # Add central axes instance self.axes = self.arcfigure.figure.add_subplot(111) #set up the variables self.loaddata(warr, farr, snarr, name) #force a re-draw self.redraw_canvas() # Add navigation toolbars for each widget to enable zooming self.toolbar = NavigationToolbar2QTAgg(self.arcfigure, self) #set up the information panel self.infopanel = QtGui.QWidget() #add the name of the file self.NameLabel = QtGui.QLabel("Filename:") self.NameLabel.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Raised) self.NameValueLabel = QtGui.QLabel(self.name) self.NameValueLabel.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Sunken) #add extraction window self.y1Label = QtGui.QLabel("y1:") self.y1Label.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Raised) self.y1ValueLabel = QtGui.QLineEdit(str(self.y1)) self.y2Label = QtGui.QLabel("y2:") self.y2Label.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Raised) self.y2ValueLabel = QtGui.QLineEdit(str(self.y2)) self.apButton = QtGui.QPushButton('Extract') self.apButton.clicked.connect(self.extractspectra) #add default button self.defaultBox = QtGui.QCheckBox('Use values as default') self.defaultBox.stateChanged.connect(self.updatedefaults) #add smoothing self.smoothLabel = QtGui.QLabel("Smooth") self.smoothLabel.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Raised) self.smoothValueLabel = QtGui.QLineEdit(str(self.smooth)) self.smoothValueLabel.textChanged.connect(self.updatesmooth) #set up the info panel layout infoLayout = QtGui.QGridLayout(self.infopanel) infoLayout.addWidget(self.NameLabel, 0, 0, 1, 1) infoLayout.addWidget(self.NameValueLabel, 0, 1, 1, 5) infoLayout.addWidget(self.y1Label, 1, 0, 1, 1) infoLayout.addWidget(self.y1ValueLabel, 1, 1, 1, 1) infoLayout.addWidget(self.y2Label, 1, 2, 1, 1) infoLayout.addWidget(self.y2ValueLabel, 1, 3, 1, 1) infoLayout.addWidget(self.apButton, 1, 4, 1, 1) infoLayout.addWidget(self.defaultBox, 2, 0, 1, 2) infoLayout.addWidget(self.smoothLabel, 2, 2, 1, 1) infoLayout.addWidget(self.smoothValueLabel, 2, 3, 1, 1) # Set up the layout mainLayout = QtGui.QVBoxLayout() mainLayout.addWidget(self.arcfigure) mainLayout.addWidget(self.toolbar) mainLayout.addWidget(self.infopanel) self.setLayout(mainLayout) def updatedefaults(self): print self.defaultBox.checkState() return def updatesmooth(self): try: self.smooth = int(self.smoothValueLabel.text()) except ValueError: return print self.smooth self.redraw_canvas() def updatename(self, name): self.name = name self.NameValueLabel.setText(self.name) print self.name def updaterange(self, y1, y2): self.y1 = y1 self.y2 = y2 self.y1ValueLabel.setText(str(self.y1)) self.y2ValueLabel.setText(str(self.y2)) def extractspectra(self): y1 = int(self.y1ValueLabel.text()) y2 = int(self.y2ValueLabel.text()) print self.name self.emit(QtCore.SIGNAL("updateextract(int, int)"), y1, y2) def loaddata(self, warr, farr, snarr, name=''): print "Loading data" self.warr = warr self.farr = farr self.snarr = snarr self.name = name return def plotSpectra(self): if self.smooth > 0 and self.farr is not None: farr = np.convolve(self.farr, np.ones(self.smooth), mode='same') / self.smooth else: farr = self.farr self.splot = self.axes.plot(self.warr, farr, linewidth=0.5, linestyle='-', marker='None', color='b') def redraw_canvas(self, keepzoom=False): if keepzoom: # Store current zoom level xmin, xmax = self.axes.get_xlim() ymin, ymax = self.axes.get_ylim() # Clear plot self.axes.clear() # Draw image self.plotSpectra() # Restore zoom level if keepzoom: self.axes.set_xlim((self.xmin, self.xmax)) self.axes.set_ylim((self.ymin, self.ymax)) # Force redraw self.arcfigure.draw()
class SlotViewWindow(QtGui.QMainWindow): """Main application window.""" def __init__(self, struct, pid, tflux, cflux, ratio, time, phottype, sleep, tx, ty, cx, cy, r, br1, br2, naxis1, naxis2, sigdet, contpix, driftlimit): """Default constructor.""" maxcolumn=7 self.struct = struct self.infile=struct._HDUList__file.name self.name=self.struct[0].header['OBJECT'] self.pid=pid self.dtime=time.copy() self.tflux=tflux self.cflux=cflux self.ratio=ratio self.min_xlim=10 self.radius=r['comparison'] self.r=r self.br1=br1 self.br2=br2 self.tx=tx self.ty=ty self.cx=cx self.cy=cy self.phottype=phottype self.naxis1=naxis1 self.naxis2=naxis2 self.sigdet=sigdet self.contpix=contpix self.driftlimit=driftlimit self.niter=5 self.sigback=5 self.fft=False self.stopplay=False self.sleep=sleep self.zbox=[] self.npoint=4 self.id=0 self.nframes=len(self.struct) self.header=self.struct[int(self.pid[self.id])].header self.goodframes=self.dtime*0+1 if self.phottype=='circular': self.npoint=24 # Setup widget QtGui.QMainWindow.__init__(self) # Set main widget self.main = QtGui.QWidget(self) # Set window title self.setWindowTitle("SlotView %s" % self.infile) #set up the different pages self.slotPage=QtGui.QWidget() #set up the differen panels self.set_optionpanel() self.set_imagepanel() self.set_controlpanel() self.set_plotpanel() self.set_infopanel() # Set up the layout slotLayout = QtGui.QVBoxLayout(self.slotPage) slotLayout.addWidget(self.plotpanel) slotLayout.addWidget(self.optipanel) slotLayout.addWidget(self.imdisplay) slotLayout.addWidget(self.contpanel) slotLayout.addWidget(self.infopanel) #create the tabs #self.tabWidget=QtGui.QTabWidget() #self.tabWidget.addTab(self.slotPage, 'Slot') #layout the widgets mainLayout = QtGui.QVBoxLayout(self.main) mainLayout.addWidget(self.slotPage) #mainLayout.addWidget(self.tabWidget) #self.setLayout(mainLayout) # Set focus to main widget self.main.setFocus() # Set the main widget as the central widget self.setCentralWidget(self.main) # Destroy widget on close self.setAttribute(QtCore.Qt.WA_DeleteOnClose) # Close when config dialog is closed self.connect(self.main, QtCore.SIGNAL('keyPressEvent'), self.keyPressEvent) #self.connect(self.conf, QtCore.SIGNAL('destroyed()'), self, QtCore.SLOT('close()')) #self.connect(self.tabWidget, QtCore.SIGNAL('currentChanged(int)'), self.currentChanged) #self.connect(self.imagePage, QtCore.SIGNAL('regionChange(int,int)'), self.regionChange) #self.connect(self.imagePage, QtCore.SIGNAL('runauto(int, int, int)'), self.runauto) def keyPressEvent(self, event): #print "Key Pressed:", event.key() self.keyEvents(str(event.text())) def keyEvents(self, key, x=None, y=None): if key=='?': self.help() if key=='q': self.close() if key=='d': self.goodframes[self.id] = 0 self.updatepage() if key=='u': self.goodframes[self.id] = 1 if key=='p': self.redophot(self.id) self.updatedataplot() if key=='P': self.thread=QtCore.QThread() self.thread.run=self.newphot self.thread.start() if key=='t' and x is not None and y is not None: tr=self.radius imarr=self.struct[int(self.pid[self.id])].data timage, tx, ty = st.calcdrift(imarr, x, y, tr, self.naxis1, self.naxis2) if tx >= 0 and ty >= 0: self.tx[self.id]=tx self.ty[self.id]=ty self.updatepage() if key=='c' and x is not None and y is not None: r=self.radius imarr=self.struct[int(self.pid[self.id])].data cimage, cx, cy = st.calcdrift(imarr, x, y, r, self.naxis1, self.naxis2) if cx >= 0 and cy >= 0: self.cx[self.id]=cx self.cy[self.id]=cy self.updatepage() def onKeyPress(self, event): self.keyEvents(event.key, event.xdata, event.ydata) def onButtonPress(self, event): if event.button==2: self.lcpickframe(event) def currentChanged(self, event): #print event pass def redophot(self, i): """Redo the photometry for a single frame""" self.id=i x={} y={} x['target']=self.tx[self.id] y['target']=self.ty[self.id] x['comparison']=self.cx[self.id] y['comparison']=self.cy[self.id] image=self.struct[int(self.pid[self.id])].data #these will need to be changed gain=1 rdnoise=1 verbose=False try: tflux, tflux_err, cflux, cflux_err, ratio, ratio_err = \ st.dophot(self. phottype, image, x, y, self.r, self.br1, self.br2, \ gain, rdnoise, self.naxis1, self.naxis2) except: msg="SLOTVIEW--ERROR: Could not measure photometry in frame %i" % i raise SaltError(msg) self.tflux[self.id]=tflux self.cflux[self.id]=cflux self.ratio[self.id]=ratio def newphot(self): self.redophot(self.id) i=self.id+1 self.stopplay=True while i < self.nframes-1 and self.stopplay: self.id=i imarr=self.struct[int(self.pid[self.id])].data carray, fx,fy = st.finddrift(imarr, self.cx[self.id-1], self.cy[self.id-1], self.radius, \ self.naxis1, self.naxis2, self.sigdet, self.contpix, self.sigback, self.driftlimit, self.niter) if 0 <= fx < self.naxis1 and 0 <= fy < self.naxis2: dx=self.cx[i-1]-fx dy=self.cy[i-1]-fy self.cx[i]=fx self.cy[i]=fy self.tx[i]=self.tx[i-1]-dx self.ty[i]=self.ty[i-1]-dy self.redophot(i) i = i+1 print('Stopped at', i) self.updatepage() def changefluxplot(self, event): self.fluxplot=event self.updatedataplot(save_zoom=False) def changetstarplot(self, event): self.tstarplot=event self.updatedataplot(save_zoom=False) def changecstarplot(self, event): self.cstarplot=event self.updatedataplot(save_zoom=False) def plotlightcurve(self): """Plot the light curve""" #cut the data self.make_lcdata() #make the figure self.light_plot=self.lccanvas.figure.add_axes([0.10,0.15,0.8,0.80], autoscale_on=False, adjustable='datalim' ) self.light_plot.hold(True) #plot the curve self.lightcurve,=self.light_plot.plot(self.tarr,self.rarr,linewidth=0.5,linestyle='-',marker='',color='b') if self.fluxplot: self.lightcurve.set_visible(True) else: self.lightcurve.set_visible(False) #plot the flux curve for star 1 self.tstarcurve,=self.light_plot.plot(self.tarr,self.tfarr,linewidth=0.5,linestyle='-',marker='',color='y') if self.tstarplot: self.tstarcurve.set_visible(True) else: self.tstarcurve.set_visible(False) #plot the flux curve for star 1 self.cstarcurve,=self.light_plot.plot(self.tarr,self.cfarr,linewidth=0.5,linestyle='-',marker='',color='g') if self.cstarplot: self.cstarcurve.set_visible(True) else: self.cstarcurve.set_visible(False) #plot a point which matches the time self.ptime=self.dtime[self.id] self.pratio=self.ratio[self.id] self.light_point,=self.light_plot.plot(np.asarray([self.ptime]), np.asarray([self.pratio]), linestyle='', marker='o', mec='#FF0000', mfc='#FF0000') self.find_lclimits() ylabel='Star1/Star2' self.light_plot.set_ylabel(ylabel) self.light_plot.set_xlabel('Time (s)') def make_lcdata(self): #cut the data mask = (self.goodframes>0) self.tarr=np.compress(mask,self.dtime) self.rarr=np.compress(mask,self.ratio) self.tfarr=np.compress(mask,self.tflux) self.cfarr=np.compress(mask,self.cflux) def find_lclimits(self, save_zoom=False): """Find the limits on the Light Curve plot""" if save_zoom: return self.lcx1=self.tarr.min() self.lcx2=self.tarr.max() self.light_plot.set_xlim(self.lcx1, self.lcx2) #determine the minimum y value based on what plots are turned on if self.fluxplot: self.lcy1=self.rarr.min() self.lcy2=self.rarr.max() if self.tstarplot: self.lcy1=self.tfarr.min() self.lcy2=self.tfarr.max() if self.cstarplot: self.lcy1=self.cfarr.min() self.lcy2=self.cfarr.max() if self.fluxplot and self.tstarplot and self.cstarplot: self.lcy1=min(self.rarr.min(), self.tfarr.min(), self.cfarr.min()) self.lcy2=max(self.rarr.max(), self.tfarr.max(), self.cfarr.max()) if self.tstarplot and self.cstarplot and not self.fluxplot: self.lcy1=min(self.tfarr.min(), self.cfarr.min()) self.lcy2=max(self.tfarr.max(), self.cfarr.max()) if self.tstarplot and not self.cstarplot and self.fluxplot: self.lcy1=min(self.tfarr.min(), self.rarr.min()) self.lcy2=max(self.tfarr.max(), self.rarr.max()) if not self.tstarplot and self.cstarplot and self.fluxplot: self.lcy1=min(self.rarr.min(), self.cfarr.min()) self.lcy2=max(self.rarr.max(), self.cfarr.max()) self.light_plot.set_ylim(self.lcy1, self.lcy2) def lcpickframe(self, event): self.set_id(event.xdata) self.updatepage() def set_id(self, t): """Given a time, set the object id""" self.id=np.abs(self.dtime-t).argmin() def set_plotpanel(self, hmin=250): #set up the control panel self.plotpanel=QtGui.QWidget() self.lccanvas=MplCanvas() #self.lccanvas=FigureCanvasQTAgg(self.lcfigure) self.plotlightcurve() #add the actions self.lccanvas.mpl_connect('button_press_event',self.onButtonPress) # Add navigation toolbars for each widget to enable zooming self.toolbar=NavigationToolbar2QTAgg(self.lccanvas,self) # Set up the layout plotLayout = QtGui.QVBoxLayout(self.plotpanel) plotLayout.addWidget(self.lccanvas) plotLayout.addWidget(self.toolbar) def set_optionpanel(self): #set up the control panel self.optipanel=QtGui.QWidget() #set up the options self.fluxplot=True self.tstarplot=False self.cstarplot=False self.fluxButton = QtGui.QCheckBox("Flux Ratio") self.fluxButton.setChecked(self.fluxplot) self.fluxButton.clicked.connect(self.changefluxplot) self.tstarButton = QtGui.QCheckBox("Target") self.tstarButton.clicked.connect(self.changetstarplot) self.cstarButton = QtGui.QCheckBox("Comparison") self.cstarButton.clicked.connect(self.changecstarplot) # Set up the layout optiLayout=QtGui.QGridLayout(self.optipanel) optiLayout.addWidget(self.fluxButton, 0, 0, 1,1) optiLayout.addWidget(self.tstarButton, 0, 1, 1,1) optiLayout.addWidget(self.cstarButton, 0, 2, 1,1) #optiLayout.addWidget(self.imagtoolbar) def set_imagepanel(self, name=None, cmap='gray', scale='zscale', contrast=0.1): """set up the Image Panel""" hmin=150 wmin=400 #set up the control panel self.imagpanel=QtGui.QWidget() #hmin=wmin*self.naxis2/self.naxis1 #print self.naxis1, self.naxis2, wmin, hmin # Add FITS display widget with mouse interaction and overplotting self.imdisplay = ImageDisplay() #self.imdisplay.setMinimumWidth(wmin) # Set colormap self.imdisplay.setColormap(cmap) # Set scale mode for dynamic range imarr=self.struct[int(self.pid[self.id])].data self.imdisplay.scale=scale self.imdisplay.contrast=contrast self.imdisplay.aspect='auto' self.imdisplay.loadImage(imarr) #self.imdisplay.drawImage() hmin=self.imdisplay.width()*self.naxis2/self.naxis1 self.imdisplay.setMaximumHeight(hmin) self.imdisplay.setMinimumHeight(hmin) #add the rectangles self.add_mark(self.tx[self.id], self.ty[self.id], 'target',color='b', lw=2) self.add_mark(self.cx[self.id], self.cy[self.id], 'comparison',color='g', lw=2) self.imdisplay.redraw_canvas() self.imdisplay.axes.set_xticklabels([]) self.imdisplay.axes.set_yticklabels([]) self.imdisplay.connectMatplotlibMouseMotion() self.imdisplay.mpl_connect('button_press_event', self.onButtonPress) self.imdisplay.mpl_connect('key_press_event', self.onKeyPress) # Add navigation toolbars for each widget to enable zooming self.imagtoolbar=NavigationToolbar2QTAgg(self.imdisplay,self) # Set up the layout imagLayout = QtGui.QVBoxLayout(self.imagpanel) #imagLayout.addWidget(self.imdisplay) imagLayout.addWidget(MplCanvas()) imagLayout.addWidget(self.imagtoolbar) def add_mark(self, x1, y1, label, color='g', lw=2): """Add the rectangle for the object""" self.imdisplay.removePatch(label) r1=self.r[label] rect=self.imdisplay.addSquare(label, x1, y1, r1, color=color, lw=lw) def set_controlpanel(self): """set up the Control Panel""" #set up the control panel self.contpanel=QtGui.QWidget() #set up the buttons self.frevButton = QtGui.QPushButton("<<") self.frevButton.clicked.connect(self.freverse) self.revButton = QtGui.QPushButton("<") self.revButton.clicked.connect(self.reverse) self.rev1Button = QtGui.QPushButton("-") self.rev1Button.clicked.connect(self.revone) self.stopButton = QtGui.QPushButton("Stop") self.stopButton.clicked.connect(self.stop) self.play1Button = QtGui.QPushButton("+") self.play1Button.clicked.connect(self.playone) self.playButton = QtGui.QPushButton(">") self.playButton.clicked.connect(self.play) self.fplayButton = QtGui.QPushButton(">>") self.fplayButton.clicked.connect(self.fplay) #set up the info panel layout contLayout=QtGui.QGridLayout(self.contpanel) #contLayout.addWidget(self.frevButton, 0, 0, 1, 1) #contLayout.addWidget(self.revButton, 0, 1, 1, 1) contLayout.addWidget(self.rev1Button, 0, 2, 1, 1) contLayout.addWidget(self.stopButton, 0, 3, 1, 1) contLayout.addWidget(self.play1Button,0, 4, 1, 1) #contLayout.addWidget(self.playButton, 0, 5, 1, 1) #contLayout.addWidget(self.fplayButton,0, 6, 1, 1) def set_infopanel(self): """Set up the information panel""" #set up the information panel self.infopanel=QtGui.QWidget() #add the name of the file self.IDValueLabel = QtGui.QLabel("%i" % self.pid[self.id]) self.IDValueLabel.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Sunken ) self.NameValueLabel = QtGui.QLabel("%s" % self.name) self.NameValueLabel.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Sunken ) self.timeValueLabel = QtGui.QLabel("%s" % self.get_time()) self.timeValueLabel.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Sunken ) #set up the info panel layout infoLayout=QtGui.QGridLayout(self.infopanel) infoLayout.addWidget(self.IDValueLabel, 0, 0, 1, 1) infoLayout.addWidget(self.NameValueLabel, 0, 1, 1, 1) infoLayout.addWidget(self.timeValueLabel, 0, 2, 1, 1) def get_time(self): #set the time try: utime=self.struct[int(self.pid[self.id])].header['UTC-OBS'] except: utime='' return utime def help(self): """Print the help message and the key-bindings available to the user""" helpmessage=""" The following commands are available to the user: ? - Print this information q - quit the viewer n - Move to the next image b - move back an image D - Delete this image u - undelete this image p - Perform photometry on this image P - Perform photometry starting at this image stop button-Stop photometry or display reset button-Reset the light curve plot Middle Click-Display image corresponding to this time """ print(helpmessage) return def stop(self): self.stopplay=False print(self.stopplay) def playone(self): stopid = self.nframes-2 if self.id < (stopid): self.id=self.id+1 self.updatepage() def play(self): self.stopplay=True stopid = self.nframes-2 while self.stopplay and self.id < stopid: self.id = self.id+1 time.sleep(self.sleep) self.updatepage() def fplay(self): self.stopplay=True stopid = self.nframes-2 while self.stopplay and self.id < stopid: self.id = self.id+1 self.updatepage() def revone(self): if self.id > 0: self.id=self.id-1 self.updatepage() def reverse(self): self.stopplay=True while self.stopplay and self.id > 0: self.id = self.id-1 time.sleep(self.sleep) self.updatepage() def freverse(self): self.stopplay=True while self.stopplay and self.id > 0: self.id = self.id-1 self.updatepage() def updatepage(self): """Update all the values on the page that need updating""" self.IDValueLabel.setText("%i" % self.pid[self.id]) self.timeValueLabel.setText("%s" % self.get_time()) #update the image imarr=self.struct[int(self.pid[self.id])].data self.imdisplay.loadImage(imarr) #update the boxes self.add_mark(self.tx[self.id], self.ty[self.id], 'target',color='b', lw=2) self.add_mark(self.cx[self.id], self.cy[self.id], 'comparison',color='g', lw=2) self.imdisplay.redraw_canvas() self.imdisplay.axes.set_xticklabels([]) self.imdisplay.axes.set_yticklabels([]) self.updatedataplot() def updatedataplot(self, save_zoom=True): """Update the data plot for changes in the options """ #redraw the lines self.make_lcdata() self.lightcurve.set_xdata(self.tarr) self.lightcurve.set_ydata(self.rarr) self.tstarcurve.set_xdata(self.tarr) self.tstarcurve.set_ydata(self.tfarr) self.cstarcurve.set_xdata(self.tarr) self.cstarcurve.set_ydata(self.cfarr) #move the point self.light_point.set_xdata([self.dtime[self.id]]) self.light_point.set_ydata([self.ratio[self.id]]) if self.fluxplot: self.lightcurve.set_visible(True) else: self.lightcurve.set_visible(False) #plot the flux curve for star 1 if self.tstarplot: self.tstarcurve.set_visible(True) else: self.tstarcurve.set_visible(False) #plot the flux curve for star 1 if self.cstarplot: self.cstarcurve.set_visible(True) else: self.cstarcurve.set_visible(False) self.find_lclimits(save_zoom=save_zoom) self.lccanvas.draw()
class ArcDisplay(QtGui.QWidget): """Class for displaying Arc Spectra using matplotlib and embedded in a Qt 4 GUI. """ def __init__(self, xarr, farr, slines, sfluxes, ws, xp=[], wp=[], mdiff=20, specarr=None, res=2.0, dres=0.1, dc=20, ndstep=20, sigma=5, smooth=0, niter=5, method='MatchZero', textcolor='green', log=None, verbose=True): """Default constructor.""" QtGui.QWidget.__init__(self) # Initialize base class self.arcfigure = MplCanvas() self.errfigure = MplCanvas() # Add central axes instance self.axes = self.arcfigure.figure.add_subplot(111) self.erraxes = self.errfigure.figure.add_subplot(111) # Connect mouse events self.arcfigure.connectMatplotlibMouseMotion() self.arcfigure.mpl_connect('button_press_event', self.onButtonPress) self.arcfigure.mpl_connect('key_press_event', self.onKeyPress) self.errfigure.connectMatplotlibMouseMotion() self.errfigure.mpl_connect('button_press_event', self.onButtonPress) self.errfigure.mpl_connect('key_press_event', self.onKeyPress) # load the data self.xarr = xarr self.farr = farr self.slines = slines self.sfluxes = sfluxes self.ws = ws self.orig_ws = copy.deepcopy(ws) self.specarr = specarr self.mdiff = mdiff self.sigma = sigma self.niter = int(niter) self.smooth = int(smooth) self.res = res self.dres = dres self.dc = dc self.sections = 6 self.ndstep = ndstep self.method = method self.textcolor = textcolor self.log = log self.verbose = True # if asked, smooth the data if self.smooth > 0: self.farr = st.smooth_spectra( self.xarr, self.farr, sigma=self.smooth) self.xp = xp self.wp = wp self.rms = res # set up the artificial spectra self.spectrum = Spectrum.Spectrum( self.slines, self.sfluxes, dw=self.dres, stype='line', sigma=self.res) self.swarr = self.spectrum.wavelength self.sfarr = self.spectrum.flux * \ self.farr.max() / self.spectrum.flux.max() # set up the wavelength solution if self.ws.function == 'line': self.ws.set_xarr(self.xarr) self.ws.farr = self.farr self.ws.spectrum = self.spectrum # set up the list of deleted points self.dxp = [] self.dwp = [] # set up other variables self.isArt = False self.isFeature = False # Set display parameters self.xmin = self.xarr.min() self.xmax = self.xarr.max() self.ymin = self.farr.min() self.ymax = self.farr.max() def help(self): helpoutput = """ ? - Print this file q - Quit the program c - centroid on line x - print the current position a - Display spectrum l - display features b - identify features f - fit solution p - print features P - print solution z - zeropoint fit Z - find zeropoint and dispersion r - redraw spectrum R - reset values e - add closest line L - show detected peaks d - delete feature u - undelete feature X - fit full X-cor """ print helpoutput def onKeyPress(self, event): """Emit signal on key press""" if event.key == '?': # return the help file self.help() elif event.key == 'q': # exit the task self.emit(QtCore.SIGNAL("quit()")) elif event.key == 'c': # return the centroid if event.xdata: self.log.message(str(event.xdata), with_header=False) cx = st.mcentroid( self.xarr, self.farr, xc=event.xdata, xdiff=self.mdiff) self.emit(QtCore.SIGNAL("updatex(float)"), cx) elif event.key == 'x': # return the x position if event.xdata: self.log.message(str(event.xdata), with_header=False) self.emit(QtCore.SIGNAL("updatex(float)"), event.xdata) elif event.key == 'R': # reset the fit self.reset() elif event.key == 'f': # find the fit self.findfit() self.emit(QtCore.SIGNAL("fitUpdate()")) elif event.key == 'b': # auto-idenitfy features self.isFeature = True self.findfeatures() elif event.key == 'z': # Assume the solution is correct and find the zeropoint # that best matches it from cross correllation self.findzp() elif event.key == 'Z': # Assume the solution is correct and find the zeropoint # that best matches it from cross correllation self.findzpd() elif event.key == 'X': # Assume the solution is almost correct # Fit the full solution using the cross correlation coefficient self.findxcorfit() elif event.key == 'e': # find closest feature from existing fit and line list # and match it self.addclosestline(event.xdata) elif event.key == 'i': # reset identified features pass elif event.key == 't': # reset identified features self.isFeature = True self.testfeatures() elif event.key == 'l': # plot the features from existing list if self.isFeature: self.isFeature = False self.redraw_canvas() else: self.isFeature = True self.plotFeatures() self.redraw_canvas() elif event.key == 'L': # plot the sources that are detected self.plotDetections() elif event.key == 'p': # print information about features for i in range(len(self.xp)): print self.xp[i], self.wp[i] elif event.key == 'P': # print information about features print self.ws.coef elif event.key == 'r': # redraw graph self.redraw_canvas() elif event.key == 'a': # draw artificial spectrum self.isArt = not self.isArt self.redraw_canvas() elif event.key == 'd': # Delete feature save = False y = None if event.canvas == self.errfigure: y = event.ydata save = True self.deletepoints(event.xdata, y=y, save=save) self.redraw_canvas(keepzoom=True) elif event.key == 'u': # undelete self.undeletepoints(event.xdata, y=event.ydata) self.redraw_canvas(keepzoom=True) elif event.key: self.emit(QtCore.SIGNAL("keyPressEvent(string)"), event.key) def onButtonPress(self, event): """Emit signal on selecting valid image position.""" if event.xdata and event.ydata: self.emit(QtCore.SIGNAL("positionSelected(float, float)"), float(event.xdata), float(event.ydata)) def plotArc(self): """Draw image to canvas.""" # plot the spectra self.spcurve, = self.axes.plot( self.xarr, self.farr, linewidth=0.5, linestyle='-', marker='None', color='b') def plotArt(self): """Plot the artificial spectrum""" self.isArt = True warr = self.ws.value(self.xarr) asfarr = st.interpolate( warr, self.swarr, self.sfarr, left=0.0, right=0.0) asfarr = asfarr * self.farr.max() / asfarr.max() self.fpcurve, = self.axes.plot(self.xarr, asfarr, linewidth=0.5, linestyle='-', marker='None', color='r') def plotDetections(self): """Plot the lines that are detected""" xp, xf = st.findpoints( self.xarr, self.farr, self.sigma, self.niter, sections=self.sections) print xp self.axes.plot(xp, xf, ls='', marker='|', ms=20, color='#000000') def plotFeatures(self): """Plot features identified in the line list""" fl = np.array(self.xp) * 0.0 + 0.25 * self.farr.max() self.splines = self.axes.plot( self.xp, fl, ls='', marker='|', ms=20, color=self.textcolor) # set up the text position tsize = 0.83 self.ymin, self.ymax = self.axes.get_ylim() ppp = (self.ymax - self.ymin) / (self.arcfigure.figure.get_figheight() * self.arcfigure.figure.get_dpi()) f = self.ymax - 10 * tsize * ppp for x, w in zip(self.xp, self.wp): w = '%6.2f' % float(w) self.axes.text( x, f, w, size='small', rotation='vertical', color=self.textcolor) def plotErr(self): """Draw image to canvas.""" if self.xp and self.wp: # plot the spectra w = self.ws.value(np.array(self.xp)) self.errcurve, = self.erraxes.plot( self.xp, self.wp - w, linewidth=0.5, linestyle='', marker='o', color='b') if self.dxp and self.dwp: # plot the spectra dw = self.ws.value(np.array(self.dxp)) self.delerrcurve, = self.erraxes.plot( self.dxp, self.dwp - dw, linewidth=0.5, linestyle='', marker='x', color='b') def set_wdiff(self): """Derive a value for wdiff""" try: self.wdiff = self.mdiff * self.ws.coef[1] except: self.wdiff = self.mdiff def testfeatures(self): """Run the test matching algorithm""" self.set_wdiff() res = max(self.res * 0.25, 2) xp, wp = st.crosslinematch(self.xarr, self.farr, self.slines, self.sfluxes, self.ws, res=res, mdiff=self.mdiff, wdiff=20, sigma=self.sigma, niter=self.niter, sections=self.sections) for x, w in zip(xp, wp): if w not in self.wp and w > -1: self.xp.append(x) self.wp.append(w) self.plotFeatures() self.redraw_canvas() def findfeatures(self): """Given a set of features, find other features that might correspond to those features """ self.set_wdiff() # xp, wp=st.findfeatures(self.xarr, self.farr, self.slines, self.sfluxes, # self.ws, mdiff=self.mdiff, wdiff=self.wdiff, sigma=self.sigma, # niter=self.niter, sections=3) xp, wp = st.crosslinematch(self.xarr, self.farr, self.slines, self.sfluxes, self.ws, res=self.res, mdiff=self.mdiff, wdiff=20, sections=self.sections, sigma=self.sigma, niter=self.niter) for x, w in zip(xp, wp): if w not in self.wp and w > -1: self.xp.append(x) self.wp.append(w) # for i in range(len(self.xp)): print self.xp[i], self.wp[i] # print self.plotFeatures() self.redraw_canvas() def addclosestline(self, x): """Find the closes line to the centroided position and add it """ cx = st.mcentroid(self.xarr, self.farr, xc=x, xdiff=self.mdiff) w = self.ws.value(cx) d = abs(self.slines - w) w = self.slines[d.argmin()] self.xp.append(x) self.wp.append(w) self.plotFeatures() self.redraw_canvas() def findzp(self): """Find the zeropoint for the source and plot of the new value """ dc = 0.5 * self.rms * self.ndstep self.ws = st.findzeropoint(self.xarr, self.farr, self.swarr, self.sfarr, self.ws, dc=dc, ndstep=self.ndstep, inttype='interp') self.plotArt() self.redraw_canvas() def findzpd(self): """Find the zeropoint and dispersion for the source and plot of the new value """ dc = 0.5 * self.rms * self.ndstep # fixed at 0.1 of the dispersion dd = 0.1 * self.ws.coef[1] # set upt he docef values dcoef = self.ws.coef * 0.0 dcoef[0] = dc dcoef[1] = dd self.ws = st.findxcor(self.xarr, self.farr, self.swarr, self.sfarr, self.ws, dcoef=dcoef, ndstep=self.ndstep, best=False, inttype='interp') self.plotArt() self.redraw_canvas() def findxcorfit(self): """Maximize the normalized correlation coefficient using the full wavelength solution. """ self.ws = st.fitxcor( self.xarr, self.farr, self.swarr, self.sfarr, self.ws, interptype='interp') self.plotArt() self.redraw_canvas() def findfit(self): if len(self.xp) < self.ws.order: raise SALTSpecError( "Insufficient sources number of points for fit") return try: self.ws = st.findfit( np.array( self.xp), np.array( self.wp), ws=self.ws, thresh=self.ws.thresh) except SALTSpecError as e: self.log.warning(e) return del_list = [] for i in range(len(self.ws.func.mask)): if self.ws.func.mask[i] == 0: self.deletepoints(self.ws.func.x[i], w=self.ws.func.y[i], save=True) self.rms = self.ws.sigma(self.ws.x_arr, self.ws.w_arr) self.redraw_canvas() def autoidentify(self, rstep=1, istart=None, nrows=1, oneline=True): """Run the autoidentify method for the current line""" # update the line list such that it is only the line list of selected # lines if self.wp: slines = np.array(self.wp) sfluxes = self.farr[self.xp] # sfluxes=np.zeros(len(slines)) # for i in range(len(slines)): # try: # sfluxes[i]=self.sfluxes[self.slines==slines[i]][0] # except: # if sfluxes.mean()==0: # sfluxes[i]=1 # else: # sfluxes[i]=sfluxes.mean() else: slines = self.slines sfluxes = self.sfluxes iws = ai.AutoIdentify(self.xarr, self.specarr, slines, sfluxes, self.ws, farr=self.farr, method=self.method, rstep=rstep, istart=istart, nrows=nrows, res=self.res, dres=self.dres, mdiff=self.mdiff, sigma=self.sigma, smooth=self.smooth, niter=self.niter, dc=self.dc, ndstep=self.ndstep, oneline=oneline, log=self.log, verbose=self.verbose) if oneline: self.ws = iws else: return iws def addpoints(self, x, w): """Add points to the line list """ if isinstance(x, list) and isinstance(w, list): self.xp.extend(x) self.wp.extend(w) else: self.xp.append(x) self.wp.append(w) def deletepoints(self, x, y=None, w=None, save=False): """ Delete points from the line list """ dist = (np.array(self.xp) - x) ** 2 # assumes you are using the error plot if y is not None: w = self.ws.value(np.array(self.xp)) norm = self.xarr.max() / abs(self.wp - w).max() dist += norm * (self.wp - w - y) ** 2 # print y, norm, dist.min() # print y, dist.min() elif w is not None: norm = self.xarr.max() / abs(self.wp - w).max() dist += norm * (self.wp - w)**2 in_minw = dist.argmin() if save: self.dxp.append(self.xp[in_minw]) self.dwp.append(self.wp[in_minw]) self.xp.__delitem__(in_minw) self.wp.__delitem__(in_minw) def undeletepoints(self, x, y=None): """ Delete points from the line list """ if len(self.dxp) < 1: return if len(self.dxp) == 1: self.xp.append(self.dxp[0]) self.wp.append(self.dwp[0]) self.dxp.__delitem__(0) self.dwp.__delitem__(0) return dist = (self.dxp - x) ** 2 if y is not None: w = self.ws.value(np.array(self.dxp)) # dist += (self.dwp-w-y)**2 in_minw = dist.argmin() self.xp.append(self.dxp[in_minw]) self.wp.append(self.dwp[in_minw]) self.dxp.__delitem__(in_minw) self.dwp.__delitem__(in_minw) return def reset(self): self.ws = copy.deepcopy(self.orig_ws) self.redraw_canvas() def redraw_canvas(self, keepzoom=False): if keepzoom: # Store current zoom level xmin, xmax = self.axes.get_xlim() ymin, ymax = self.axes.get_ylim() # Clear plot self.axes.clear() # Draw image self.plotArc() # if necessary, redraw the features if self.isFeature: self.plotFeatures() # if necessary, draw the artificial spectrum if self.isArt: self.plotArt() # Restore zoom level if keepzoom: self.axes.set_xlim((self.xmin, self.xmax)) self.axes.set_ylim((self.ymin, self.ymax)) # Force redraw self.arcfigure.draw() self.err_redraw_canvas() def err_redraw_canvas(self, keepzoom=False): if keepzoom: # Store current zoom level xmin, xmax = self.erraxes.get_xlim() ymin, ymax = self.erraxes.get_ylim() else: self.xmin, self.xmax = self.axes.get_xlim() # Clear plot self.erraxes.clear() # Draw image self.plotErr() # Restore zoom level if keepzoom: self.erraxes.set_xlim((xmin, xmax)) self.erraxes.set_ylim((ymin, ymax)) else: self.erraxes.set_xlim((self.xmin, self.xmax)) self.errfigure.draw() self.emit(QtCore.SIGNAL("fitUpdate()"))
class SpectraViewWidget(QtGui.QWidget): def __init__(self, warr, farr, snarr, name='', y1=1010, y2=1030, hmin=150, wmin=400, smooth=5, parent=None): super(SpectraViewWidget, self).__init__(parent) self.y1=y1 self.y2=y2 self.smooth = smooth self.name=name #set up the arc display self.arcfigure=MplCanvas() # Add central axes instance self.axes = self.arcfigure.figure.add_subplot(111) #set up the variables self.loaddata(warr, farr, snarr, name) #force a re-draw self.redraw_canvas() # Add navigation toolbars for each widget to enable zooming self.toolbar=NavigationToolbar2QTAgg(self.arcfigure,self) #set up the information panel self.infopanel=QtGui.QWidget() #add the name of the file self.NameLabel = QtGui.QLabel("Filename:") self.NameLabel.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Raised ) self.NameValueLabel = QtGui.QLabel(self.name) self.NameValueLabel.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Sunken ) #add extraction window self.y1Label = QtGui.QLabel("y1:") self.y1Label.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Raised ) self.y1ValueLabel = QtGui.QLineEdit(str(self.y1)) self.y2Label = QtGui.QLabel("y2:") self.y2Label.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Raised ) self.y2ValueLabel = QtGui.QLineEdit(str(self.y2)) self.apButton = QtGui.QPushButton('Extract') self.apButton.clicked.connect(self.extractspectra) #add default button self.defaultBox = QtGui.QCheckBox('Use values as default') self.defaultBox.stateChanged.connect(self.updatedefaults) #add smoothing self.smoothLabel = QtGui.QLabel("Smooth") self.smoothLabel.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Raised ) self.smoothValueLabel = QtGui.QLineEdit(str(self.smooth)) self.smoothValueLabel.textChanged.connect(self.updatesmooth) #set up the info panel layout infoLayout=QtGui.QGridLayout(self.infopanel) infoLayout.addWidget(self.NameLabel, 0, 0, 1, 1) infoLayout.addWidget(self.NameValueLabel, 0, 1, 1, 5) infoLayout.addWidget(self.y1Label, 1, 0, 1, 1) infoLayout.addWidget(self.y1ValueLabel, 1, 1, 1, 1) infoLayout.addWidget(self.y2Label, 1, 2, 1, 1) infoLayout.addWidget(self.y2ValueLabel, 1, 3, 1, 1) infoLayout.addWidget(self.apButton, 1, 4, 1, 1) infoLayout.addWidget(self.defaultBox, 2, 0, 1, 2) infoLayout.addWidget(self.smoothLabel, 2, 2, 1, 1) infoLayout.addWidget(self.smoothValueLabel, 2, 3, 1, 1) # Set up the layout mainLayout = QtGui.QVBoxLayout() mainLayout.addWidget(self.arcfigure) mainLayout.addWidget(self.toolbar) mainLayout.addWidget(self.infopanel) self.setLayout(mainLayout) def updatedefaults(self): print self.defaultBox.checkState() return def updatesmooth(self): try: self.smooth = int(self.smoothValueLabel.text()) except ValueError: return print self.smooth self.redraw_canvas() def updatename(self, name): self.name=name self.NameValueLabel.setText(self.name) print self.name def updaterange(self, y1, y2): self.y1=y1 self.y2=y2 self.y1ValueLabel.setText(str(self.y1)) self.y2ValueLabel.setText(str(self.y2)) def extractspectra(self): y1=int(self.y1ValueLabel.text()) y2=int(self.y2ValueLabel.text()) print self.name self.emit(QtCore.SIGNAL("updateextract(int, int)"), y1,y2) def loaddata(self, warr, farr, snarr, name=''): print "Loading data" self.warr=warr self.farr=farr self.snarr=snarr self.name=name return def plotSpectra(self): if self.smooth > 0 and self.farr is not None: farr = np.convolve(self.farr, np.ones(self.smooth), mode='same')/self.smooth else: farr = self.farr self.splot=self.axes.plot(self.warr, farr, linewidth=0.5,linestyle='-', marker='None',color='b') def redraw_canvas(self,keepzoom=False): if keepzoom: # Store current zoom level xmin, xmax = self.axes.get_xlim() ymin, ymax = self.axes.get_ylim() # Clear plot self.axes.clear() # Draw image self.plotSpectra() # Restore zoom level if keepzoom: self.axes.set_xlim((self.xmin,self.xmax)) self.axes.set_ylim((self.ymin,self.ymax)) # Force redraw self.arcfigure.draw()
class FpRingWidget(QtGui.QWidget): def __init__(self, filenumber, flatnumber, parent=None): super(FpRingWidget, self).__init__(parent) self.filenumber = filenumber self.flatnumber = flatnumber #set up the ring plot self.ringplot = MplCanvas() self.axes = self.ringplot.figure.add_subplot(211) self.erraxes = self.ringplot.figure.add_subplot(212) self.ringplot.setMinimumHeight(500) # self.ringplot.setMinimumHeight(500) self.loadfpring() self.plotRing() # self.redraw_canvas() #set up the information panel self.infopanel = QtGui.QWidget() # add a label: self.NameLabel = QtGui.QLabel("File number:") #add the name of the file self.NameValueLabel = QtGui.QLineEdit(str(self.filenumber)) # and a button to process the new ring self.ringButton = QtGui.QPushButton('Load new ring') self.ringButton.clicked.connect(self.redrawRing) # add a label for the flat field: self.flatLabel = QtGui.QLabel("Flat file number:") #add the name of the file self.flatValueLabel = QtGui.QLineEdit(str(self.flatnumber)) #set up info panel layout infoLayout = QtGui.QGridLayout(self.infopanel) infoLayout.addWidget(self.NameLabel, 0, 0, 1, 1) infoLayout.addWidget(self.NameValueLabel, 0, 1, 1, 1) infoLayout.addWidget(self.ringButton, 0, 2, 2, 1) infoLayout.addWidget(self.flatLabel, 0, 3, 1, 1) infoLayout.addWidget(self.flatValueLabel, 0, 4, 1, 1) # fitLayout=QtGui.QGridLayout(self.infopanel) # add a panel to display the fit results self.fitpanel = QtGui.QWidget() self.fitLabel = QtGui.QLabel("Fit Results:") fitXresult = "X:" + str(self.etalon_x) fitYresult = "Y:" + str(self.etalon_y) fitZresult = "Z:" + str(self.etalon_z) fitRresult = "R: %.1f" % float(self.pars['R'][0]) fitAmpresult = "Amplitude: %.1f" % float(self.pars['Amplitude'][0]) fitRmsresult = "RMS: %.1f" % float(self.rms) fitGammaresult = "Gamma: %.1f" % float(self.pars['Gamma'][0]) fitFWHMresult = "FWHM: %.1f" % float(self.pars['FWHM'][0]) #add the text to the fit results panel self.fitX = QtGui.QLabel(fitXresult) self.fitY = QtGui.QLabel(fitYresult) self.fitZ = QtGui.QLabel(fitZresult) self.fitR = QtGui.QLabel(fitRresult) self.fitAmp = QtGui.QLabel(fitAmpresult) self.fitRms = QtGui.QLabel(fitRmsresult) self.fitGamma = QtGui.QLabel(fitGammaresult) self.fitFWHM = QtGui.QLabel(fitFWHMresult) # lay them out nicely... fitLayout = QtGui.QGridLayout(self.fitpanel) fitLayout.addWidget(self.fitLabel, 0, 0, 1, 1) fitLayout.addWidget(self.fitX, 0, 1, 1, 1) fitLayout.addWidget(self.fitY, 0, 2, 1, 1) fitLayout.addWidget(self.fitZ, 0, 3, 1, 1) fitLayout.addWidget(self.fitR, 0, 4, 1, 1) fitLayout.addWidget(self.fitAmp, 0, 5, 1, 2) fitLayout.addWidget(self.fitRms, 0, 7, 1, 1) fitLayout.addWidget(self.fitGamma, 0, 8, 1, 1) fitLayout.addWidget(self.fitFWHM, 0, 9, 1, 1) # Set up the main layout mainLayout = QtGui.QVBoxLayout() mainLayout.addWidget(self.infopanel) mainLayout.addWidget(self.ringplot) mainLayout.addWidget(self.fitpanel) self.setLayout(mainLayout) def loadfpring(self): date = os.getcwd().split('/')[-1] self.getFitsHeader() fits = "mbxpP%s%04d.fits" % (date, self.filenumber) if self.flatnumber != 0: flat = "mbxpP%s%04d.fits" % (date, self.flatnumber) else: flat = "/home/ccd/erc/FP_utils/DefaultNeFlat.fits" ffits = 'f' + fits fpfile = 'p' + ffits maskedfile = 'm' + fpfile if (not os.path.isfile(maskedfile)): saltflat(fits, ffits, '', flat, clobber='yes', verbose='no') saltfpprep(ffits, fpfile, '', clobber='yes', verbose='no') saltfpmask(fpfile, maskedfile, '', axc=798 * 4 / self.xbin, ayc=503 * 4 / self.ybin, arad=450 * 4 / self.xbin, clobber='yes', verbose='no') self.good, self.rsq, self.prof, self.fit, self.pars = fit_rings( maskedfile) self.resid = self.prof - self.fit self.rms = self.resid.std() self.saveFitToFile() return def plotRing(self): #set up the plots.... self.axes.plot(self.rsq, self.prof, label="Profile") self.axes.plot(self.rsq, self.fit, label="Fit") self.axes.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=3, ncol=2, mode="expand", borderaxespad=0.) self.erraxes.plot(self.rsq, self.resid, label="Profile - Fit") self.erraxes.legend(loc=1) self.show() return def redrawRing(self): # read the new filenumber from the input box self.filenumber = int(self.NameValueLabel.text()) # recalculate and re-draw self.loadfpring() self.axes.clear() self.erraxes.clear() self.plotRing() #Force a redraw!!! self.ringplot.draw() def getFitsHeader(self): date = os.getcwd().split('/')[-1] fits = "mbxpP%s%04d.fits" % (date, self.filenumber) hdu = pyfits.open(fits) (data, header) = (hdu[0].data, hdu[0].header) etalon = int(header['ET-STATE'].split()[3]) hetalon_x = "ET%dX" % etalon hetalon_y = "ET%dY" % etalon hetalon_z = "ET%dZ" % etalon self.etalon_x = int(header[hetalon_x]) self.etalon_y = int(header[hetalon_y]) self.etalon_z = int(header[hetalon_z]) self.xbin = int(header['CCDSUM'].split()[0]) self.ybin = int(header['CCDSUM'].split()[1]) print self.xbin, self.ybin return def saveFitToFile(self): pars = self.pars self.getFitsHeader() if os.path.isfile('outparams'): try: outparams = open('outparams', 'a') except IOError, e: print 'Failed to open the ring file' else: