def __init__(self, parent, modal=True, flags=Qt.WindowFlags()): QDialog.__init__(self, parent, flags) self.setModal(modal) self.setWindowTitle("Add FITS brick") lo = QVBoxLayout(self) lo.setMargin(10) lo.setSpacing(5) # file selector self.wfile = FileSelector(self, label="FITS filename:", dialog_label="FITS file", default_suffix="fits", file_types="FITS files (*.fits *.FITS)", file_mode=QFileDialog.ExistingFile) lo.addWidget(self.wfile) # overwrite or add mode lo1 = QGridLayout() lo.addLayout(lo1) lo1.setContentsMargins(0, 0, 0, 0) lo1.addWidget(QLabel("Padding factor:", self), 0, 0) self.wpad = QLineEdit("2", self) self.wpad.setValidator(QDoubleValidator(self)) lo1.addWidget(self.wpad, 0, 1) lo1.addWidget(QLabel("Assign source name:", self), 1, 0) self.wname = QLineEdit(self) lo1.addWidget(self.wname, 1, 1) # OK/cancel buttons lo.addSpacing(10) lo2 = QHBoxLayout() lo.addLayout(lo2) lo2.setContentsMargins(0, 0, 0, 0) lo2.setMargin(5) self.wokbtn = QPushButton("OK", self) self.wokbtn.setMinimumWidth(128) QObject.connect(self.wokbtn, SIGNAL("clicked()"), self.accept) self.wokbtn.setEnabled(False) cancelbtn = QPushButton("Cancel", self) cancelbtn.setMinimumWidth(128) QObject.connect(cancelbtn, SIGNAL("clicked()"), self.reject) lo2.addWidget(self.wokbtn) lo2.addStretch(1) lo2.addWidget(cancelbtn) self.setMinimumWidth(384) # signals QObject.connect(self.wfile, SIGNAL("filenameSelected"), self._fileSelected) # internal state self.qerrmsg = QErrorMessage(self)
def __init__ (self,parent,modal=True,flags=Qt.WindowFlags()): QDialog.__init__(self,parent,flags); self.setModal(modal); self.setWindowTitle("Export Karma annotations"); lo = QVBoxLayout(self); lo.setMargin(10); lo.setSpacing(5); # file selector self.wfile = FileSelector(self,label="Filename:",dialog_label="Karma annotations filename",default_suffix="ann",file_types="Karma annotations (*.ann)"); lo.addWidget(self.wfile); # selected sources checkbox self.wsel = QCheckBox("selected sources only",self); lo.addWidget(self.wsel); # OK/cancel buttons lo.addSpacing(10); lo2 = QHBoxLayout(); lo.addLayout(lo2); lo2.setContentsMargins(0,0,0,0); lo2.setMargin(5); self.wokbtn = QPushButton("OK",self); self.wokbtn.setMinimumWidth(128); QObject.connect(self.wokbtn,SIGNAL("clicked()"),self.accept); self.wokbtn.setEnabled(False); cancelbtn = QPushButton("Cancel",self); cancelbtn.setMinimumWidth(128); QObject.connect(cancelbtn,SIGNAL("clicked()"),self.reject); lo2.addWidget(self.wokbtn); lo2.addStretch(1); lo2.addWidget(cancelbtn); self.setMinimumWidth(384); # signals QObject.connect(self.wfile,SIGNAL("valid"),self.wokbtn.setEnabled); # internal state self.qerrmsg = QErrorMessage(self); self._model_filename = None;
def __init__(self, parent, modal=True, flags=Qt.WindowFlags()): QDialog.__init__(self, parent, flags) self.setModal(modal) self.setWindowTitle("Export Karma annotations") lo = QVBoxLayout(self) lo.setMargin(10) lo.setSpacing(5) # file selector self.wfile = FileSelector(self, label="Filename:", dialog_label="Karma annotations filename", default_suffix="ann", file_types="Karma annotations (*.ann)") lo.addWidget(self.wfile) # selected sources checkbox self.wsel = QCheckBox("selected sources only", self) lo.addWidget(self.wsel) # OK/cancel buttons lo.addSpacing(10) lo2 = QHBoxLayout() lo.addLayout(lo2) lo2.setContentsMargins(0, 0, 0, 0) lo2.setMargin(5) self.wokbtn = QPushButton("OK", self) self.wokbtn.setMinimumWidth(128) QObject.connect(self.wokbtn, SIGNAL("clicked()"), self.accept) self.wokbtn.setEnabled(False) cancelbtn = QPushButton("Cancel", self) cancelbtn.setMinimumWidth(128) QObject.connect(cancelbtn, SIGNAL("clicked()"), self.reject) lo2.addWidget(self.wokbtn) lo2.addStretch(1) lo2.addWidget(cancelbtn) self.setMinimumWidth(384) # signals QObject.connect(self.wfile, SIGNAL("valid"), self.wokbtn.setEnabled) # internal state self.qerrmsg = QErrorMessage(self) self._model_filename = None
def __init__ (self,parent,modal=True,flags=Qt.WindowFlags()): QDialog.__init__(self,parent,flags); self.setModal(modal); self.setWindowTitle("Add FITS brick"); lo = QVBoxLayout(self); lo.setMargin(10); lo.setSpacing(5); # file selector self.wfile = FileSelector(self,label="FITS filename:",dialog_label="FITS file",default_suffix="fits",file_types="FITS files (*.fits *.FITS)",file_mode=QFileDialog.ExistingFile); lo.addWidget(self.wfile); # overwrite or add mode lo1 = QGridLayout(); lo.addLayout(lo1); lo1.setContentsMargins(0,0,0,0); lo1.addWidget(QLabel("Padding factor:",self),0,0); self.wpad = QLineEdit("2",self); self.wpad.setValidator(QDoubleValidator(self)); lo1.addWidget(self.wpad,0,1); lo1.addWidget(QLabel("Assign source name:",self),1,0); self.wname = QLineEdit(self); lo1.addWidget(self.wname,1,1); # OK/cancel buttons lo.addSpacing(10); lo2 = QHBoxLayout(); lo.addLayout(lo2); lo2.setContentsMargins(0,0,0,0); lo2.setMargin(5); self.wokbtn = QPushButton("OK",self); self.wokbtn.setMinimumWidth(128); QObject.connect(self.wokbtn,SIGNAL("clicked()"),self.accept); self.wokbtn.setEnabled(False); cancelbtn = QPushButton("Cancel",self); cancelbtn.setMinimumWidth(128); QObject.connect(cancelbtn,SIGNAL("clicked()"),self.reject); lo2.addWidget(self.wokbtn); lo2.addStretch(1); lo2.addWidget(cancelbtn); self.setMinimumWidth(384); # signals QObject.connect(self.wfile,SIGNAL("filenameSelected"),self._fileSelected); # internal state self.qerrmsg = QErrorMessage(self);
class AddBrickDialog(QDialog): def __init__(self, parent, modal=True, flags=Qt.WindowFlags()): QDialog.__init__(self, parent, flags) self.setModal(modal) self.setWindowTitle("Add FITS brick") lo = QVBoxLayout(self) lo.setMargin(10) lo.setSpacing(5) # file selector self.wfile = FileSelector(self, label="FITS filename:", dialog_label="FITS file", default_suffix="fits", file_types="FITS files (*.fits *.FITS)", file_mode=QFileDialog.ExistingFile) lo.addWidget(self.wfile) # overwrite or add mode lo1 = QGridLayout() lo.addLayout(lo1) lo1.setContentsMargins(0, 0, 0, 0) lo1.addWidget(QLabel("Padding factor:", self), 0, 0) self.wpad = QLineEdit("2", self) self.wpad.setValidator(QDoubleValidator(self)) lo1.addWidget(self.wpad, 0, 1) lo1.addWidget(QLabel("Assign source name:", self), 1, 0) self.wname = QLineEdit(self) lo1.addWidget(self.wname, 1, 1) # OK/cancel buttons lo.addSpacing(10) lo2 = QHBoxLayout() lo.addLayout(lo2) lo2.setContentsMargins(0, 0, 0, 0) lo2.setMargin(5) self.wokbtn = QPushButton("OK", self) self.wokbtn.setMinimumWidth(128) QObject.connect(self.wokbtn, SIGNAL("clicked()"), self.accept) self.wokbtn.setEnabled(False) cancelbtn = QPushButton("Cancel", self) cancelbtn.setMinimumWidth(128) QObject.connect(cancelbtn, SIGNAL("clicked()"), self.reject) lo2.addWidget(self.wokbtn) lo2.addStretch(1) lo2.addWidget(cancelbtn) self.setMinimumWidth(384) # signals QObject.connect(self.wfile, SIGNAL("filenameSelected"), self._fileSelected) # internal state self.qerrmsg = QErrorMessage(self) def setModel(self, model): self.model = model if model.filename(): self._model_dir = os.path.dirname(os.path.abspath( model.filename())) else: self._model_dir = os.path.abspath('.') self.wfile.setDirectory(self._model_dir) self._fileSelected(self.wfile.filename(), quiet=True) def _fileSelected(self, filename, quiet=False): self.wokbtn.setEnabled(False) if not filename: return None # check that filename matches model if not os.path.samefile(self._model_dir, os.path.dirname(filename)): self.wfile.setFilename('') if not quiet: QMessageBox.warning( self, "Directory mismatch", """<P>The FITS file must reside in the same directory as the current sky model.</P>""") self.wfile.setDirectory(self._model_dir) return None # if filename is not in model already, enable the "add to model" control for src in self.model.sources: if isinstance(getattr(src, 'shape', None), ModelClasses.FITSImage): if os.path.exists(src.shape.filename) and os.path.samefile( src.shape.filename, filename): if not quiet: QMessageBox.warning( self, "Already in model", "This FITS brick is already present in the model.") self.wfile.setFilename('') return None if not str(self.wname.text()): self.wname.setText( os.path.splitext(os.path.basename(str(filename)))[0]) self.wokbtn.setEnabled(True) return filename def accept(self): """Tries to add brick, and closes the dialog if successful.""" filename = self.wfile.filename() # read fits file busy = BusyIndicator() try: input_hdu = pyfits.open(filename)[0] except Exception, err: busy = None QMessageBox.warning( self, "Error reading FITS", "Error reading FITS file %s: %s" % (filename, str(err))) return # check name srcname = str(self.wname.text()) or os.path.splitext( os.path.basename(str(filename)))[0] if srcname in set([src.name for src in self.model.sources]): QMessageBox.warning( self, "Already in model", "<p>The model already contains a source named '%s'. Please select a different name.</p>" % srcname) return # get image parameters hdr = input_hdu.header max_flux = float(input_hdu.data.max()) wcs = WCS(hdr, mode='pyfits') # Get reference pixel coordinates # wcs.getCentreWCSCoords() doesn't work, as that gives us the middle of the image # So scan the header to get the CRPIX values ra0 = dec0 = 1 for iaxis in range(hdr['NAXIS']): axs = str(iaxis + 1) name = hdr.get('CTYPE' + axs, axs).upper() if name.startswith("RA"): ra0 = hdr.get('CRPIX' + axs, 1) - 1 elif name.startswith("DEC"): dec0 = hdr.get('CRPIX' + axs, 1) - 1 # convert pixel to degrees # print ra0,dec0; ra0, dec0 = wcs.pix2wcs(ra0, dec0) ra0 *= DEG dec0 *= DEG # print ModelClasses.Position.ra_hms_static(ra0); # print ModelClasses.Position.dec_sdms_static(dec0); sx, sy = wcs.getHalfSizeDeg() sx *= DEG sy *= DEG nx, ny = input_hdu.data.shape[-1:-3:-1] pos = ModelClasses.Position(ra0, dec0) flux = ModelClasses.Flux(max_flux) shape = ModelClasses.FITSImage(sx, sy, 0, os.path.basename(filename), nx, ny, pad=float(str(self.wpad.text()) or "1")) img_src = SkyModel.Source(srcname, pos, flux, shape=shape) self.model.setSources(self.model.sources + [img_src]) self.model.emitUpdate(SkyModel.SkyModel.UpdateAll, origin=self) busy = None return QDialog.accept(self)
def __init__ (self,parent,modal=True,flags=Qt.WindowFlags()): QDialog.__init__(self,parent,flags); self.setModal(modal); self.setWindowTitle("Restore model into image"); lo = QVBoxLayout(self); lo.setMargin(10); lo.setSpacing(5); # file selector self.wfile_in = FileSelector(self,label="Input FITS file:",dialog_label="Input FITS file",default_suffix="fits",file_types="FITS files (*.fits *.FITS)",file_mode=QFileDialog.ExistingFile); lo.addWidget(self.wfile_in); self.wfile_out = FileSelector(self,label="Output FITS file:",dialog_label="Output FITS file",default_suffix="fits",file_types="FITS files (*.fits *.FITS)",file_mode=QFileDialog.AnyFile); lo.addWidget(self.wfile_out); # beam size lo1 = QHBoxLayout(); lo.addLayout(lo1); lo1.setContentsMargins(0,0,0,0); lo1.addWidget(QLabel("Restoring beam FWHM, major axis:",self)); self.wbmaj = QLineEdit(self); lo1.addWidget(self.wbmaj); lo1.addWidget(QLabel("\" minor axis:",self)); self.wbmin = QLineEdit(self); lo1.addWidget(self.wbmin); lo1.addWidget(QLabel("\" P.A.:",self)); self.wbpa = QLineEdit(self); lo1.addWidget(self.wbpa); lo1.addWidget(QLabel(u"\u00B0",self)); for w in self.wbmaj,self.wbmin,self.wbpa: w.setValidator(QDoubleValidator(self)); lo1 = QHBoxLayout(); lo.addLayout(lo1); lo1.setContentsMargins(0,0,0,0); self.wfile_psf = FileSelector(self,label="Set restoring beam by fitting PSF image:",dialog_label="PSF FITS file",default_suffix="fits",file_types="FITS files (*.fits *.FITS)",file_mode=QFileDialog.ExistingFile); lo1.addSpacing(32); lo1.addWidget(self.wfile_psf); # selection only self.wselonly = QCheckBox("restore selected model sources only",self); lo.addWidget(self.wselonly ); # OK/cancel buttons lo.addSpacing(10); lo2 = QHBoxLayout(); lo.addLayout(lo2); lo2.setContentsMargins(0,0,0,0); lo2.setMargin(5); self.wokbtn = QPushButton("OK",self); self.wokbtn.setMinimumWidth(128); QObject.connect(self.wokbtn,SIGNAL("clicked()"),self.accept); self.wokbtn.setEnabled(False); cancelbtn = QPushButton("Cancel",self); cancelbtn.setMinimumWidth(128); QObject.connect(cancelbtn,SIGNAL("clicked()"),self.reject); lo2.addWidget(self.wokbtn); lo2.addStretch(1); lo2.addWidget(cancelbtn); self.setMinimumWidth(384); # signals QObject.connect(self.wfile_in,SIGNAL("filenameSelected"),self._fileSelected); QObject.connect(self.wfile_in,SIGNAL("filenameSelected"),self._inputFileSelected); QObject.connect(self.wfile_out,SIGNAL("filenameSelected"),self._fileSelected); QObject.connect(self.wfile_psf,SIGNAL("filenameSelected"),self._psfFileSelected); # internal state self.qerrmsg = QErrorMessage(self);
class RestoreImageDialog (QDialog): def __init__ (self,parent,modal=True,flags=Qt.WindowFlags()): QDialog.__init__(self,parent,flags); self.setModal(modal); self.setWindowTitle("Restore model into image"); lo = QVBoxLayout(self); lo.setMargin(10); lo.setSpacing(5); # file selector self.wfile_in = FileSelector(self,label="Input FITS file:",dialog_label="Input FITS file",default_suffix="fits",file_types="FITS files (*.fits *.FITS)",file_mode=QFileDialog.ExistingFile); lo.addWidget(self.wfile_in); self.wfile_out = FileSelector(self,label="Output FITS file:",dialog_label="Output FITS file",default_suffix="fits",file_types="FITS files (*.fits *.FITS)",file_mode=QFileDialog.AnyFile); lo.addWidget(self.wfile_out); # beam size lo1 = QHBoxLayout(); lo.addLayout(lo1); lo1.setContentsMargins(0,0,0,0); lo1.addWidget(QLabel("Restoring beam FWHM, major axis:",self)); self.wbmaj = QLineEdit(self); lo1.addWidget(self.wbmaj); lo1.addWidget(QLabel("\" minor axis:",self)); self.wbmin = QLineEdit(self); lo1.addWidget(self.wbmin); lo1.addWidget(QLabel("\" P.A.:",self)); self.wbpa = QLineEdit(self); lo1.addWidget(self.wbpa); lo1.addWidget(QLabel(u"\u00B0",self)); for w in self.wbmaj,self.wbmin,self.wbpa: w.setValidator(QDoubleValidator(self)); lo1 = QHBoxLayout(); lo.addLayout(lo1); lo1.setContentsMargins(0,0,0,0); self.wfile_psf = FileSelector(self,label="Set restoring beam by fitting PSF image:",dialog_label="PSF FITS file",default_suffix="fits",file_types="FITS files (*.fits *.FITS)",file_mode=QFileDialog.ExistingFile); lo1.addSpacing(32); lo1.addWidget(self.wfile_psf); # selection only self.wselonly = QCheckBox("restore selected model sources only",self); lo.addWidget(self.wselonly ); # OK/cancel buttons lo.addSpacing(10); lo2 = QHBoxLayout(); lo.addLayout(lo2); lo2.setContentsMargins(0,0,0,0); lo2.setMargin(5); self.wokbtn = QPushButton("OK",self); self.wokbtn.setMinimumWidth(128); QObject.connect(self.wokbtn,SIGNAL("clicked()"),self.accept); self.wokbtn.setEnabled(False); cancelbtn = QPushButton("Cancel",self); cancelbtn.setMinimumWidth(128); QObject.connect(cancelbtn,SIGNAL("clicked()"),self.reject); lo2.addWidget(self.wokbtn); lo2.addStretch(1); lo2.addWidget(cancelbtn); self.setMinimumWidth(384); # signals QObject.connect(self.wfile_in,SIGNAL("filenameSelected"),self._fileSelected); QObject.connect(self.wfile_in,SIGNAL("filenameSelected"),self._inputFileSelected); QObject.connect(self.wfile_out,SIGNAL("filenameSelected"),self._fileSelected); QObject.connect(self.wfile_psf,SIGNAL("filenameSelected"),self._psfFileSelected); # internal state self.qerrmsg = QErrorMessage(self); def setModel (self,model): nsel = len([ src for src in model.sources if src.selected ]); self.wselonly.setVisible(nsel>0 and nsel<len(model.sources)); self.model = model; self._fileSelected(None); def _fileSelected (self,filename): self.wokbtn.setEnabled(bool(self.wfile_in.filename() and self.wfile_out.filename())); def _inputFileSelected (self,filename): if filename: try: header = pyfits.open(filename)[0].header; except: self.qerrmsg.showMessage("Error reading FITS file %s: %s"%(filename,str(err))); self.wfile_in.setFilename(""); return; # try to get beam extents gx,gy,grot = [ header.get(x,None) for x in 'BMAJ','BMIN','BPA' ]; if all([x is not None for x in gx,gy,grot]): # if beam size is already set, ask before overwriting print [ str(x.text()) for x in self.wbmaj,self.wbmin,self.wbpa ] if any([ bool(str(x.text())) for x in self.wbmaj,self.wbmin,self.wbpa ]) and \ QMessageBox.question(self,"Set restoring beam","Also reset restoring beam size from this FITS file?", QMessageBox.Yes|QMessageBox.No) != QMessageBox.Yes: return; self.wbmaj.setText("%.2f"%(gx*3600)); self.wbmin.setText("%.2f"%(gy*3600)); self.wbpa.setText("%.2f"%grot);
class RestoreImageDialog (QDialog): def __init__ (self,parent,modal=True,flags=Qt.WindowFlags()): QDialog.__init__(self,parent,flags); self.setModal(modal); self.setWindowTitle("Restore model into image"); lo = QVBoxLayout(self); lo.setMargin(10); lo.setSpacing(5); # file selector self.wfile_in = FileSelector(self,label="Input FITS file:",dialog_label="Input FITS file",default_suffix="fits",file_types="FITS files (*.fits *.FITS)",file_mode=QFileDialog.ExistingFile); lo.addWidget(self.wfile_in); self.wfile_out = FileSelector(self,label="Output FITS file:",dialog_label="Output FITS file",default_suffix="fits",file_types="FITS files (*.fits *.FITS)",file_mode=QFileDialog.AnyFile); lo.addWidget(self.wfile_out); # beam size lo1 = QHBoxLayout(); lo.addLayout(lo1); lo1.setContentsMargins(0,0,0,0); lo1.addWidget(QLabel("Restoring beam FWHM, major axis:",self)); self.wbmaj = QLineEdit(self); lo1.addWidget(self.wbmaj); lo1.addWidget(QLabel("\" minor axis:",self)); self.wbmin = QLineEdit(self); lo1.addWidget(self.wbmin); lo1.addWidget(QLabel("\" P.A.:",self)); self.wbpa = QLineEdit(self); lo1.addWidget(self.wbpa); lo1.addWidget(QLabel(u"\u00B0",self)); for w in self.wbmaj,self.wbmin,self.wbpa: w.setValidator(QDoubleValidator(self)); lo1 = QHBoxLayout(); lo.addLayout(lo1); lo1.setContentsMargins(0,0,0,0); self.wfile_psf = FileSelector(self,label="Set restoring beam by fitting PSF image:",dialog_label="PSF FITS file",default_suffix="fits",file_types="FITS files (*.fits *.FITS)",file_mode=QFileDialog.ExistingFile); lo1.addSpacing(32); lo1.addWidget(self.wfile_psf); # selection only self.wselonly = QCheckBox("restore selected model sources only",self); lo.addWidget(self.wselonly ); # OK/cancel buttons lo.addSpacing(10); lo2 = QHBoxLayout(); lo.addLayout(lo2); lo2.setContentsMargins(0,0,0,0); lo2.setMargin(5); self.wokbtn = QPushButton("OK",self); self.wokbtn.setMinimumWidth(128); QObject.connect(self.wokbtn,SIGNAL("clicked()"),self.accept); self.wokbtn.setEnabled(False); cancelbtn = QPushButton("Cancel",self); cancelbtn.setMinimumWidth(128); QObject.connect(cancelbtn,SIGNAL("clicked()"),self.reject); lo2.addWidget(self.wokbtn); lo2.addStretch(1); lo2.addWidget(cancelbtn); self.setMinimumWidth(384); # signals QObject.connect(self.wfile_in,SIGNAL("filenameSelected"),self._fileSelected); QObject.connect(self.wfile_in,SIGNAL("filenameSelected"),self._inputFileSelected); QObject.connect(self.wfile_out,SIGNAL("filenameSelected"),self._fileSelected); QObject.connect(self.wfile_psf,SIGNAL("filenameSelected"),self._psfFileSelected); # internal state self.qerrmsg = QErrorMessage(self); def setModel (self,model): nsel = len([ src for src in model.sources if src.selected ]); self.wselonly.setVisible(nsel>0 and nsel<len(model.sources)); self.model = model; self._fileSelected(None); def _fileSelected (self,filename): self.wokbtn.setEnabled(bool(self.wfile_in.filename() and self.wfile_out.filename())); def _inputFileSelected (self,filename): if filename: try: header = pyfits.open(filename)[0].header; except: self.qerrmsg.showMessage("Error reading FITS file %s: %s"%(filename,str(err))); self.wfile_in.setFilename(""); return; # try to get beam extents gx,gy,grot = [ header.get(x,None) for x in 'BMAJ','BMIN','BPA' ]; if all([x is not None for x in gx,gy,grot]): # if beam size is already set, ask before overwriting print [ str(x.text()) for x in self.wbmaj,self.wbmin,self.wbpa ]
class ExportKarmaDialog(QDialog): def __init__(self, parent, modal=True, flags=Qt.WindowFlags()): QDialog.__init__(self, parent, flags) self.setModal(modal) self.setWindowTitle("Export Karma annotations") lo = QVBoxLayout(self) lo.setMargin(10) lo.setSpacing(5) # file selector self.wfile = FileSelector(self, label="Filename:", dialog_label="Karma annotations filename", default_suffix="ann", file_types="Karma annotations (*.ann)") lo.addWidget(self.wfile) # selected sources checkbox self.wsel = QCheckBox("selected sources only", self) lo.addWidget(self.wsel) # OK/cancel buttons lo.addSpacing(10) lo2 = QHBoxLayout() lo.addLayout(lo2) lo2.setContentsMargins(0, 0, 0, 0) lo2.setMargin(5) self.wokbtn = QPushButton("OK", self) self.wokbtn.setMinimumWidth(128) QObject.connect(self.wokbtn, SIGNAL("clicked()"), self.accept) self.wokbtn.setEnabled(False) cancelbtn = QPushButton("Cancel", self) cancelbtn.setMinimumWidth(128) QObject.connect(cancelbtn, SIGNAL("clicked()"), self.reject) lo2.addWidget(self.wokbtn) lo2.addStretch(1) lo2.addWidget(cancelbtn) self.setMinimumWidth(384) # signals QObject.connect(self.wfile, SIGNAL("valid"), self.wokbtn.setEnabled) # internal state self.qerrmsg = QErrorMessage(self) self._model_filename = None def setModel(self, model): self.model = model # set the default annotations filename, whenever a new model filename is set filename = self.model.filename() if filename and filename != self._model_filename: self._model_filename = filename self.wfile.setFilename(os.path.splitext(filename)[0] + ".ann") def accept(self): """Tries to export annotations, and closes the dialog if successful.""" try: filename = self.wfile.filename() if os.path.exists(filename) and QMessageBox.question( self, "Exporting Karma annotations", "<P>Overwrite the file %s?</P>" % filename, QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes) != QMessageBox.Yes: return f = file(self.wfile.filename(), "wt") f.write('COORD W\nPA STANDARD\nCOLOR GREEN\nFONT hershey12\n') # source list if self.wsel.isChecked(): sources = [src for src in self.model.sources if src.selected] else: sources = self.model.sources # calculate basis size for crosses (TODO: replace min_size with something more sensible, as this value is in degrees) brightnesses = [ abs(src.brightness()) for src in sources if src.brightness() != 0 ] min_bright = brightnesses and min(brightnesses) min_size = 0.01 # loop over sources busy = BusyIndicator() for src in sources: ra = src.pos.ra / DEG dec = src.pos.dec / DEG # figure out source size if src.brightness() and min_bright: ysize = (math.log10(abs(src.brightness())) - math.log10(min_bright) + 1) * min_size else: ysize = min_size xsize = ysize / (math.cos(src.pos.dec) or 1) # figure out source style style, label = self.model.getSourcePlotStyle(src) if style: f.write('# %s\n' % src.name) # write symbol for source f.write('COLOR %s\n' % style.symbol_color) if style.symbol == "plus": f.write('CROSS %.12f %.12f %f %f\n' % (ra, dec, xsize, ysize)) elif style.symbol == "cross": f.write('CROSS %.12f %.12f %f %f 45\n' % (ra, dec, ysize, ysize)) elif style.symbol == "circle": f.write('CIRCLE %.12f %.12f %f\n' % (ra, dec, ysize)) elif style.symbol == "dot": f.write('DOT %.12f %.12f\n' % (ra, dec)) elif style.symbol == "square": f.write('CBOX %.12f %.12f %f %f\n' % (ra, dec, xsize, ysize)) elif style.symbol == "diamond": f.write('CBOX %.12f %.12f %f %f 45\n' % (ra, dec, xsize, ysize)) # write label if label: f.write('FONT hershey%d\n' % (style.label_size * 2)) f.write('COLOR %s\n' % style.label_color) f.write('TEXT %.12f %.12f %s\n' % (ra, dec, label)) f.close() except IOError, err: busy = None self.qerrmsg.showMessage( "Error writing Karma annotations file %s: %s" % (filename, str(err))) return busy = None self.parent().showMessage( "Wrote Karma annotations for %d sources to file %s" % (len(sources), filename)) return QDialog.accept(self)
class AddBrickDialog (QDialog): def __init__ (self,parent,modal=True,flags=Qt.WindowFlags()): QDialog.__init__(self,parent,flags); self.setModal(modal); self.setWindowTitle("Add FITS brick"); lo = QVBoxLayout(self); lo.setMargin(10); lo.setSpacing(5); # file selector self.wfile = FileSelector(self,label="FITS filename:",dialog_label="FITS file",default_suffix="fits",file_types="FITS files (*.fits *.FITS)",file_mode=QFileDialog.ExistingFile); lo.addWidget(self.wfile); # overwrite or add mode lo1 = QGridLayout(); lo.addLayout(lo1); lo1.setContentsMargins(0,0,0,0); lo1.addWidget(QLabel("Padding factor:",self),0,0); self.wpad = QLineEdit("2",self); self.wpad.setValidator(QDoubleValidator(self)); lo1.addWidget(self.wpad,0,1); lo1.addWidget(QLabel("Assign source name:",self),1,0); self.wname = QLineEdit(self); lo1.addWidget(self.wname,1,1); # OK/cancel buttons lo.addSpacing(10); lo2 = QHBoxLayout(); lo.addLayout(lo2); lo2.setContentsMargins(0,0,0,0); lo2.setMargin(5); self.wokbtn = QPushButton("OK",self); self.wokbtn.setMinimumWidth(128); QObject.connect(self.wokbtn,SIGNAL("clicked()"),self.accept); self.wokbtn.setEnabled(False); cancelbtn = QPushButton("Cancel",self); cancelbtn.setMinimumWidth(128); QObject.connect(cancelbtn,SIGNAL("clicked()"),self.reject); lo2.addWidget(self.wokbtn); lo2.addStretch(1); lo2.addWidget(cancelbtn); self.setMinimumWidth(384); # signals QObject.connect(self.wfile,SIGNAL("filenameSelected"),self._fileSelected); # internal state self.qerrmsg = QErrorMessage(self); def setModel (self,model): self.model = model; if model.filename(): self._model_dir = os.path.dirname(os.path.abspath(model.filename())); else: self._model_dir = os.path.abspath('.'); self.wfile.setDirectory(self._model_dir); self._fileSelected(self.wfile.filename(),quiet=True); def _fileSelected (self,filename,quiet=False): self.wokbtn.setEnabled(False); if not filename: return None; # check that filename matches model if not os.path.samefile(self._model_dir,os.path.dirname(filename)): self.wfile.setFilename(''); if not quiet: QMessageBox.warning(self,"Directory mismatch","""<P>The FITS file must reside in the same directory as the current sky model.</P>"""); self.wfile.setDirectory(self._model_dir); return None; # if filename is not in model already, enable the "add to model" control for src in self.model.sources: if isinstance(getattr(src,'shape',None),ModelClasses.FITSImage): if os.path.exists(src.shape.filename) and os.path.samefile(src.shape.filename,filename): if not quiet: QMessageBox.warning(self,"Already in model","This FITS brick is already present in the model."); self.wfile.setFilename(''); return None; if not str(self.wname.text()): self.wname.setText(os.path.splitext(os.path.basename(str(filename)))[0]); self.wokbtn.setEnabled(True); return filename; def accept (self): """Tries to add brick, and closes the dialog if successful."""; filename = self.wfile.filename(); # read fits file busy = BusyIndicator(); try: input_hdu = pyfits.open(filename)[0]; except Exception,err: busy = None; QMessageBox.warning(self,"Error reading FITS","Error reading FITS file %s: %s"%(filename,str(err))); return; # check name srcname = str(self.wname.text()) or os.path.splitext(os.path.basename(str(filename)))[0]; if srcname in set([src.name for src in self.model.sources]): QMessageBox.warning(self,"Already in model","<p>The model already contains a source named '%s'. Please select a different name.</p>"%srcname); return; # get image parameters hdr = input_hdu.header; max_flux = float(input_hdu.data.max()); wcs = WCS(hdr,mode='pyfits'); # Get reference pixel coordinates # wcs.getCentreWCSCoords() doesn't work, as that gives us the middle of the image # So scan the header to get the CRPIX values ra0 = dec0 = 1; for iaxis in range(hdr['NAXIS']): axs = str(iaxis+1); name = hdr.get('CTYPE'+axs,axs).upper(); if name.startswith("RA"): ra0 = hdr.get('CRPIX'+axs,1)-1; elif name.startswith("DEC"): dec0 = hdr.get('CRPIX'+axs,1)-1; # convert pixel to degrees # print ra0,dec0; ra0,dec0 = wcs.pix2wcs(ra0,dec0); ra0 *= DEG; dec0 *= DEG; # print ModelClasses.Position.ra_hms_static(ra0); # print ModelClasses.Position.dec_sdms_static(dec0); sx,sy = wcs.getHalfSizeDeg(); sx *= DEG; sy *= DEG; nx,ny = input_hdu.data.shape[-1:-3:-1]; pos = ModelClasses.Position(ra0,dec0); flux = ModelClasses.Flux(max_flux); shape = ModelClasses.FITSImage(sx,sy,0,os.path.basename(filename),nx,ny,pad=float(str(self.wpad.text()) or "1")); img_src = SkyModel.Source(srcname,pos,flux,shape=shape); self.model.setSources(self.model.sources + [img_src]); self.model.emitUpdate(SkyModel.SkyModel.UpdateAll,origin=self); busy = None; return QDialog.accept(self);
def __init__ (self,parent,modal=True,flags=Qt.WindowFlags()): QDialog.__init__(self,parent,flags); self.setModal(modal); self.setWindowTitle("Convert sources to FITS brick"); lo = QVBoxLayout(self); lo.setMargin(10); lo.setSpacing(5); # file selector self.wfile = FileSelector(self,label="FITS filename:",dialog_label="Output FITS file",default_suffix="fits", file_types="FITS files (*.fits *.FITS)",file_mode=QFileDialog.ExistingFile); lo.addWidget(self.wfile); # reference frequency lo1 = QHBoxLayout(); lo.addLayout(lo1); lo1.setContentsMargins(0,0,0,0); label = QLabel("Frequency, MHz:",self); lo1.addWidget(label); tip = """<P>If your sky model contains spectral information (such as spectral indices), then a brick may be generated for a specific frequency. If a frequency is not specified here, the reference frequency of the model sources will be assumed.</P>"""; self.wfreq = QLineEdit(self); self.wfreq.setValidator(QDoubleValidator(self)); label.setToolTip(tip); self.wfreq.setToolTip(tip); lo1.addWidget(self.wfreq); # beam gain lo1 = QHBoxLayout(); lo.addLayout(lo1); lo1.setContentsMargins(0,0,0,0); self.wpb_apply = QCheckBox("Apply primary beam expression:",self); self.wpb_apply.setChecked(True); lo1.addWidget(self.wpb_apply); tip = """<P>If this option is specified, a primary power beam gain will be applied to the sources before inserting them into the brick. This can be any valid Python expression making use of the variables 'r' (corresponding to distance from field centre, in radians) and 'fq' (corresponding to frequency.)</P>"""; self.wpb_exp = QLineEdit(self); self.wpb_apply.setToolTip(tip); self.wpb_exp.setToolTip(tip); lo1.addWidget(self.wpb_exp); # overwrite or add mode lo1 = QHBoxLayout(); lo.addLayout(lo1); lo1.setContentsMargins(0,0,0,0); self.woverwrite = QRadioButton("overwrite image",self); self.woverwrite.setChecked(True); lo1.addWidget(self.woverwrite); self.waddinto = QRadioButton("add into image",self); lo1.addWidget(self.waddinto); # add to model self.wadd = QCheckBox("Add resulting brick to sky model as a FITS image component",self); lo.addWidget(self.wadd); lo1 = QHBoxLayout(); lo.addLayout(lo1); lo1.setContentsMargins(0,0,0,0); self.wpad = QLineEdit(self); self.wpad.setValidator(QDoubleValidator(self)); self.wpad.setText("1.1"); lab = QLabel("...with padding factor:",self); lab.setToolTip("""<P>The padding factor determines the amount of null padding inserted around the image during the prediction stage. Padding alleviates the effects of tapering and detapering in the uv-brick, which can show up towards the edges of the image. For a factor of N, the image will be padded out to N times its original size. This increases memory use, so if you have no flux at the edges of the image anyway, then a pad factor of 1 is perfectly fine.</P>"""); self.wpad.setToolTip(lab.toolTip()); QObject.connect(self.wadd,SIGNAL("toggled(bool)"),self.wpad.setEnabled); QObject.connect(self.wadd,SIGNAL("toggled(bool)"),lab.setEnabled); self.wpad.setEnabled(False); lab.setEnabled(False); lo1.addStretch(1); lo1.addWidget(lab,0); lo1.addWidget(self.wpad,1); self.wdel = QCheckBox("Remove from the sky model sources that go into the brick",self); lo.addWidget(self.wdel); # OK/cancel buttons lo.addSpacing(10); lo2 = QHBoxLayout(); lo.addLayout(lo2); lo2.setContentsMargins(0,0,0,0); lo2.setMargin(5); self.wokbtn = QPushButton("OK",self); self.wokbtn.setMinimumWidth(128); QObject.connect(self.wokbtn,SIGNAL("clicked()"),self.accept); self.wokbtn.setEnabled(False); cancelbtn = QPushButton("Cancel",self); cancelbtn.setMinimumWidth(128); QObject.connect(cancelbtn,SIGNAL("clicked()"),self.reject); lo2.addWidget(self.wokbtn); lo2.addStretch(1); lo2.addWidget(cancelbtn); self.setMinimumWidth(384); # signals QObject.connect(self.wfile,SIGNAL("filenameSelected"),self._fileSelected); # internal state self.qerrmsg = QErrorMessage(self);
class MakeBrickDialog (QDialog): def __init__ (self,parent,modal=True,flags=Qt.WindowFlags()): QDialog.__init__(self,parent,flags); self.setModal(modal); self.setWindowTitle("Convert sources to FITS brick"); lo = QVBoxLayout(self); lo.setMargin(10); lo.setSpacing(5); # file selector self.wfile = FileSelector(self,label="FITS filename:",dialog_label="Output FITS file",default_suffix="fits", file_types="FITS files (*.fits *.FITS)",file_mode=QFileDialog.ExistingFile); lo.addWidget(self.wfile); # reference frequency lo1 = QHBoxLayout(); lo.addLayout(lo1); lo1.setContentsMargins(0,0,0,0); label = QLabel("Frequency, MHz:",self); lo1.addWidget(label); tip = """<P>If your sky model contains spectral information (such as spectral indices), then a brick may be generated for a specific frequency. If a frequency is not specified here, the reference frequency of the model sources will be assumed.</P>"""; self.wfreq = QLineEdit(self); self.wfreq.setValidator(QDoubleValidator(self)); label.setToolTip(tip); self.wfreq.setToolTip(tip); lo1.addWidget(self.wfreq); # beam gain lo1 = QHBoxLayout(); lo.addLayout(lo1); lo1.setContentsMargins(0,0,0,0); self.wpb_apply = QCheckBox("Apply primary beam expression:",self); self.wpb_apply.setChecked(True); lo1.addWidget(self.wpb_apply); tip = """<P>If this option is specified, a primary power beam gain will be applied to the sources before inserting them into the brick. This can be any valid Python expression making use of the variables 'r' (corresponding to distance from field centre, in radians) and 'fq' (corresponding to frequency.)</P>"""; self.wpb_exp = QLineEdit(self); self.wpb_apply.setToolTip(tip); self.wpb_exp.setToolTip(tip); lo1.addWidget(self.wpb_exp); # overwrite or add mode lo1 = QHBoxLayout(); lo.addLayout(lo1); lo1.setContentsMargins(0,0,0,0); self.woverwrite = QRadioButton("overwrite image",self); self.woverwrite.setChecked(True); lo1.addWidget(self.woverwrite); self.waddinto = QRadioButton("add into image",self); lo1.addWidget(self.waddinto); # add to model self.wadd = QCheckBox("Add resulting brick to sky model as a FITS image component",self); lo.addWidget(self.wadd); lo1 = QHBoxLayout(); lo.addLayout(lo1); lo1.setContentsMargins(0,0,0,0); self.wpad = QLineEdit(self); self.wpad.setValidator(QDoubleValidator(self)); self.wpad.setText("1.1"); lab = QLabel("...with padding factor:",self); lab.setToolTip("""<P>The padding factor determines the amount of null padding inserted around the image during the prediction stage. Padding alleviates the effects of tapering and detapering in the uv-brick, which can show up towards the edges of the image. For a factor of N, the image will be padded out to N times its original size. This increases memory use, so if you have no flux at the edges of the image anyway, then a pad factor of 1 is perfectly fine.</P>"""); self.wpad.setToolTip(lab.toolTip()); QObject.connect(self.wadd,SIGNAL("toggled(bool)"),self.wpad.setEnabled); QObject.connect(self.wadd,SIGNAL("toggled(bool)"),lab.setEnabled); self.wpad.setEnabled(False); lab.setEnabled(False); lo1.addStretch(1); lo1.addWidget(lab,0); lo1.addWidget(self.wpad,1); self.wdel = QCheckBox("Remove from the sky model sources that go into the brick",self); lo.addWidget(self.wdel); # OK/cancel buttons lo.addSpacing(10); lo2 = QHBoxLayout(); lo.addLayout(lo2); lo2.setContentsMargins(0,0,0,0); lo2.setMargin(5); self.wokbtn = QPushButton("OK",self); self.wokbtn.setMinimumWidth(128); QObject.connect(self.wokbtn,SIGNAL("clicked()"),self.accept); self.wokbtn.setEnabled(False); cancelbtn = QPushButton("Cancel",self); cancelbtn.setMinimumWidth(128); QObject.connect(cancelbtn,SIGNAL("clicked()"),self.reject); lo2.addWidget(self.wokbtn); lo2.addStretch(1); lo2.addWidget(cancelbtn); self.setMinimumWidth(384); # signals QObject.connect(self.wfile,SIGNAL("filenameSelected"),self._fileSelected); # internal state self.qerrmsg = QErrorMessage(self); def setModel (self,model): self.model = model; pb = self.model.primaryBeam(); if pb: self.wpb_exp.setText(pb); else: self.wpb_apply.setChecked(False); self.wpb_exp.setText(""); if model.filename(): self._model_dir = os.path.dirname(os.path.abspath(model.filename())); else: self._model_dir = os.path.abspath('.'); self.wfile.setDirectory(self._model_dir); self._fileSelected(self.wfile.filename(),quiet=True); def _fileSelected (self,filename,quiet=False): self.wokbtn.setEnabled(False); if not filename: return None; # check that filename matches model if not os.path.samefile(self._model_dir,os.path.dirname(filename)): self.wfile.setFilename(''); if not quiet: QMessageBox.warning(self,"Directory mismatch","""<P>The FITS file must reside in the same directory as the current sky model.</P>"""); self.wfile.setDirectory(self._model_dir); return None; # read fits file busy = BusyIndicator(); try: input_hdu = pyfits.open(filename)[0]; hdr = input_hdu.header; # get frequency, if specified for axis in range(1,hdr['NAXIS']+1): if hdr['CTYPE%d'%axis].upper() == 'FREQ': self.wfreq.setText(str(hdr['CRVAL%d'%axis]/1e+6)); break; except Exception,err: busy = None; self.wfile.setFilename(''); if not quiet: QMessageBox.warning(self,"Error reading FITS","Error reading FITS file %s: %s"%(filename,str(err))); return None; self.wokbtn.setEnabled(True); # if filename is not in model already, enable the "add to model" control for src in self.model.sources: if isinstance(getattr(src,'shape',None),ModelClasses.FITSImage) \ and os.path.exists(src.shape.filename) and os.path.exists(filename) \ and os.path.samefile(src.shape.filename,filename): self.wadd.setChecked(True); self.wadd.setEnabled(False); self.wadd.setText("image already in sky model"); break; else: self.wadd.setText("add image to sky model"); return filename;
class ExportKarmaDialog (QDialog): def __init__ (self,parent,modal=True,flags=Qt.WindowFlags()): QDialog.__init__(self,parent,flags); self.setModal(modal); self.setWindowTitle("Export Karma annotations"); lo = QVBoxLayout(self); lo.setMargin(10); lo.setSpacing(5); # file selector self.wfile = FileSelector(self,label="Filename:",dialog_label="Karma annotations filename",default_suffix="ann",file_types="Karma annotations (*.ann)"); lo.addWidget(self.wfile); # selected sources checkbox self.wsel = QCheckBox("selected sources only",self); lo.addWidget(self.wsel); # OK/cancel buttons lo.addSpacing(10); lo2 = QHBoxLayout(); lo.addLayout(lo2); lo2.setContentsMargins(0,0,0,0); lo2.setMargin(5); self.wokbtn = QPushButton("OK",self); self.wokbtn.setMinimumWidth(128); QObject.connect(self.wokbtn,SIGNAL("clicked()"),self.accept); self.wokbtn.setEnabled(False); cancelbtn = QPushButton("Cancel",self); cancelbtn.setMinimumWidth(128); QObject.connect(cancelbtn,SIGNAL("clicked()"),self.reject); lo2.addWidget(self.wokbtn); lo2.addStretch(1); lo2.addWidget(cancelbtn); self.setMinimumWidth(384); # signals QObject.connect(self.wfile,SIGNAL("valid"),self.wokbtn.setEnabled); # internal state self.qerrmsg = QErrorMessage(self); self._model_filename = None; def setModel (self,model): self.model = model; # set the default annotations filename, whenever a new model filename is set filename = self.model.filename(); if filename and filename != self._model_filename: self._model_filename = filename; self.wfile.setFilename(os.path.splitext(filename)[0] + ".ann"); def accept (self): """Tries to export annotations, and closes the dialog if successful."""; try: filename = self.wfile.filename(); if os.path.exists(filename) and QMessageBox.question(self,"Exporting Karma annotations","<P>Overwrite the file %s?</P>"%filename, QMessageBox.Yes|QMessageBox.No,QMessageBox.Yes) != QMessageBox.Yes: return; f = file(self.wfile.filename(),"wt"); f.write('COORD W\nPA STANDARD\nCOLOR GREEN\nFONT hershey12\n'); # source list if self.wsel.isChecked(): sources = [ src for src in self.model.sources if src.selected ]; else: sources = self.model.sources; # calculate basis size for crosses (TODO: replace min_size with something more sensible, as this value is in degrees) brightnesses = [ abs(src.brightness()) for src in sources if src.brightness() != 0 ]; min_bright = brightnesses and min(brightnesses) ; min_size = 0.01; # loop over sources busy = BusyIndicator(); for src in sources: ra = src.pos.ra/DEG; dec = src.pos.dec/DEG; # figure out source size if src.brightness() and min_bright: ysize = (math.log10(abs(src.brightness())) - math.log10(min_bright) + 1)*min_size; else: ysize = min_size; xsize = ysize/(math.cos(src.pos.dec) or 1); # figure out source style style,label = self.model.getSourcePlotStyle(src); if style: f.write('# %s\n'%src.name); # write symbol for source f.write('COLOR %s\n'%style.symbol_color); if style.symbol == "plus": f.write('CROSS %.12f %.12f %f %f\n'%(ra,dec,xsize,ysize)); elif style.symbol == "cross": f.write('CROSS %.12f %.12f %f %f 45\n'%(ra,dec,ysize,ysize)); elif style.symbol == "circle": f.write('CIRCLE %.12f %.12f %f\n'%(ra,dec,ysize)); elif style.symbol == "dot": f.write('DOT %.12f %.12f\n'%(ra,dec)); elif style.symbol == "square": f.write('CBOX %.12f %.12f %f %f\n'%(ra,dec,xsize,ysize)); elif style.symbol == "diamond": f.write('CBOX %.12f %.12f %f %f 45\n'%(ra,dec,xsize,ysize)); # write label if label: f.write('FONT hershey%d\n'%(style.label_size*2)); f.write('COLOR %s\n'%style.label_color); f.write('TEXT %.12f %.12f %s\n'%(ra,dec,label)); f.close(); except IOError,err: busy = None; self.qerrmsg.showMessage("Error writing Karma annotations file %s: %s"%(filename,str(err))); return; busy = None; self.parent().showMessage("Wrote Karma annotations for %d sources to file %s"%(len(sources),filename)); return QDialog.accept(self);