Exemple #1
0
 def _saveImage(self):
     filename = QFileDialog.getSaveFileName(
         self,
         "Save FITS file",
         self._save_dir,
         "FITS files(*.fits *.FITS *fts *FTS)",
         options=QFileDialog.DontUseNativeDialog)
     filename = str(filename[0])
     if not filename:
         return
     busy = BusyIndicator()
     self._imgman.signalShowMessage.emit(
         """Writing FITS image %s""" % filename, 3000)
     QApplication.flush()
     try:
         self.image.save(filename)
     except Exception as exc:
         busy.reset_cursor()
         traceback.print_exc()
         self._imgman.signalShowErrorMessage.emit(
             """Error writing FITS image %s: %s""" %
             (filename, str(sys.exc_info()[1])))
         return None
     self.renderControl().startSavingConfig(filename)
     self.setName(self.image.name)
     self._qa_save.setVisible(False)
     self._wsave.hide()
     busy.reset_cursor()
Exemple #2
0
 def openFile(self, _filename=None, _format=None, _merge=False, _show=True):
     # check that we can close existing model
     if not _merge and not self._canCloseExistingModel():
         return False
     if isinstance(_filename, QStringList):
         _filename = _filename[0]
     _filename = str(_filename)
     # try to determine the file type
     filetype, import_func, export_func, doc = Tigger.Models.Formats.resolveFormat(
         _filename, _format)
     if import_func is None:
         self.signalShowErrorMessage.emit(
             """Error loading model file %s: unknown file format""" %
             _filename)
         return
     # try to load the specified file
     busy = BusyIndicator()
     self.signalShowMessage.emit(
         """Reading %s file %s""" % (filetype, _filename), 3000)
     QApplication.flush()
     try:
         model = import_func(_filename)
         model.setFilename(_filename)
     except:
         busy.reset_cursor()
         self.signalShowErrorMessage.emit(
             """Error loading '%s' file %s: %s""" %
             (filetype, _filename, str(sys.exc_info()[1])))
         return
     else:
         # set the layout
         if _show:
             self.setLayout(self.LayoutImageModel)
         # add to content
         if _merge and self.model:
             self.model.addSources(model.sources)
             self.signalShowMessage.emit(
                 """Merged in %d sources from '%s' file %s""" %
                 (len(model.sources), filetype, _filename), 3000)
             self.model.emitUpdate(SkyModel.SkyModel.UpdateAll)
         else:
             print("""Loaded %d sources from '%s' file %s""" %
                   (len(model.sources), filetype, _filename))
             self.signalShowMessage.emit(
                 """Loaded %d sources from '%s' file %s""" %
                 (len(model.sources), filetype, _filename), 3000)
             self._display_filename = os.path.basename(_filename)
             self.setModel(model)
             self._indicateModelUpdated(updated=False)
             # only set self.filename if an export function is available for this format. Otherwise set it to None, so that trying to save
             # the file results in a save-as operation (so that we don't save to a file in an unsupported format).
             self.filename = _filename if export_func else None
     finally:
         busy.reset_cursor()
Exemple #3
0
    def computeImage(self, expression=None):
        """Computes image from expression (if expression is None, pops up dialog)"""
        if expression is None:
            (expression, ok) = QInputDialog.getText(
                self, "Compute image", """Enter an image expression to compute.
                                              Any valid numpy expression is supported, and
                                              all functions from the numpy module are available (including sub-modules such as fft).
                                              Use 'a', 'b', 'c' to refer to images.
                                              Examples:  "(a+b)/2", "cos(a)+sin(b)", "a-a.mean()", "fft.fft2(a)", etc."""
            )
            #      (expression,ok) = QInputDialog.getText(self,"Compute image","""<P>Enter an expression to compute.
            #        Use 'a', 'b', etc. to refer to loaded images. Any valid numpy expression is supported, and all the
            #       functions from the numpy module are available. Examples of valid expressions include "(a+b)/2",
            #       "cos(a)+sin(b)", "a-a.mean()", etc.
            #        </P>
            #      """)
            expression = str(expression)
            if not ok or not expression:
                return
        # try to parse expression
        arglist = [(chr(ord('a') + ic.getNumber()), ic.image)
                   for ic in self._imagecons]
        try:
            exprfunc = eval(
                "lambda " + (",".join([x[0]
                                       for x in arglist])) + ":" + expression,
                numpy.__dict__, {})
        except Exception as exc:
            self.signalShowErrorMessage.emit(
                """Error parsing expression "%s": %s.""" %
                (expression, str(exc)))
            return None
        # try to evaluate expression
        self.signalShowMessage.emit("Computing expression \"%s\"" % expression,
                                    10000)
        busy = BusyIndicator()
        QApplication.flush()

        # trim trivial trailing dimensions. This avoids the problem of when an NxMx1 and an NxMx1x1 arrays are added,
        # the result is promoted to NxMxMx1 following the numpy rules.
        def trimshape(shape):
            out = shape
            while out and out[-1] == 1:
                out = out[:-1]
            return out

        def trimarray(array):
            return array.reshape(trimshape(array.shape))

        try:
            result = exprfunc(*[trimarray(x[1].data()) for x in arglist])
        except Exception as exc:
            busy.reset_cursor()
            traceback.print_exc()
            self.signalShowErrorMessage.emit("""Error evaluating "%s": %s.""" %
                                             (expression, str(exc)))
            return None
        busy.reset_cursor()
        if type(result) != numpy.ma.masked_array and type(
                result) != numpy.ndarray:
            self.signalShowErrorMessage.emit(
                """Result of "%s" is of invalid type "%s" (array expected)."""
                % (expression, type(result).__name__))
            return None
        # convert coomplex results to real
        if numpy.iscomplexobj(result):
            self.signalShowErrorMessage.emit(
                """Result of "%s" is complex. Complex images are currently
      not fully supported, so we'll implicitly use the absolute value instead."""
                % (expression))
            expression = "abs(%s)" % expression
            result = abs(result)
        # determine which image this expression can be associated with
        res_shape = trimshape(result.shape)
        arglist = [
            x for x in arglist if hasattr(x[1], 'fits_header')
            and trimshape(x[1].data().shape) == res_shape
        ]
        if not arglist:
            self.signalShowErrorMessage.emit(
                """Result of "%s" has shape %s, which does not match any loaded FITS image."""
                % (expression, "x".join(map(str, result.shape))))
            return None
        # look for an image in the arglist with the same projection, and with a valid dirname
        # (for the where-to-save hint)
        template = arglist[0][1]
        # if all images in arglist have the same projection, then it doesn't matter what we use
        # else ask
        if len(
            [x for x in arglist[1:] if x[1].projection == template.projection
             ]) != len(arglist) - 1:
            options = [x[0] for x in arglist]
            (which, ok) = QInputDialog.getItem(
                self, "Compute image",
                "Coordinate system to use for the result of \"%s\":" %
                expression, options, 0, False)
            if not ok:
                return None
            try:
                template = arglist[options.index(which)][1]
            except:
                pass
        # create a FITS image
        busy = BusyIndicator()
        dprint(2, "creating FITS image", expression)
        self.signalShowMessage.emit("""Creating image for %s""" % expression,
                                    3000)
        QApplication.flush()
        try:
            hdu = pyfits.PrimaryHDU(result.transpose(), template.fits_header)
            skyimage = SkyImage.FITSImagePlotItem(name=expression,
                                                  filename=None,
                                                  hdu=hdu)
        except:
            busy.reset_cursor()
            traceback.print_exc()
            self.signalShowErrorMessage.emit(
                """Error creating FITS image %s: %s""" %
                (expression, str(sys.exc_info()[1])))
            return None
        # get directory name for save-to hint
        dirname = getattr(template, 'filename', None)
        if not dirname:
            dirnames = [
                getattr(img, 'filename') for x, img in arglist
                if hasattr(img, 'filename')
            ]
            dirname = dirnames[0] if dirnames else None
        # create control bar, add to widget stack
        self._createImageController(
            skyimage,
            expression,
            expression,
            save=((dirname and os.path.dirname(dirname)) or "."))
        self.signalShowMessage.emit("Created new image for %s" % expression,
                                    3000)
        dprint(2, "image created")
        busy.reset_cursor()
Exemple #4
0
 def loadImage(self,
               filename=None,
               duplicate=True,
               to_top=True,
               model=None):
     """Loads image. Returns ImageControlBar object.
     If image is already loaded: returns old ICB if duplicate=False (raises to top if to_top=True),
     or else makes a new control bar.
     If model is set to a source name, marks the image as associated with a model source. These can be unloaded en masse by calling
     unloadModelImages().
     """
     if filename is None:
         if not self._load_image_dialog:
             dialog = self._load_image_dialog = QFileDialog(
                 self, "Load FITS image", ".",
                 "FITS images (%s);;All files (*)" %
                 (" ".join(["*" + ext for ext in FITS_ExtensionList])))
             dialog.setFileMode(QFileDialog.ExistingFile)
             dialog.setModal(True)
             dialog.filesSelected['QStringList'].connect(self.loadImage)
         self._load_image_dialog.exec_()
         return None
     if isinstance(filename, QStringList):
         filename = filename[0]
     filename = str(filename)
     # report error if image does not exist
     if not os.path.exists(filename):
         self.signalShowErrorMessage.emit(
             """FITS image %s does not exist.""" % filename)
         return None
     # see if image is already loaded
     if not duplicate:
         for ic in self._imagecons:
             if ic.getFilename() and os.path.samefile(
                     filename, ic.getFilename()):
                 if to_top:
                     self.raiseImage(ic)
                 if model:
                     self._model_imagecons.add(id(ic))
                 return ic
     # load the FITS image
     busy = BusyIndicator()
     dprint(2, "reading FITS image", filename)
     self.signalShowMessage.emit("""Reading FITS image %s""" % filename,
                                 3000)
     QApplication.flush()
     try:
         image = SkyImage.FITSImagePlotItem(str(filename))
     except KeyboardInterrupt:
         raise
     except:
         busy.reset_cursor()
         traceback.print_exc()
         print(
             """Error loading FITS image %s: %s. This may be due to a bug in Tigger; if the FITS file loads fine in another viewer,
       please send the FITS file, along with a copy of any error messages from the text console, to [email protected]."""
             % (filename, str(sys.exc_info()[1])))
         self.signalShowErrorMessage.emit(
             """<P>Error loading FITS image %s: %s. This may be due to a bug in Tigger; if the FITS file loads fine in another viewer,
       please send the FITS file, along with a copy of any error messages from the text console, to [email protected].</P>"""
             % (filename, str(sys.exc_info()[1])))
         return None
     # create control bar, add to widget stack
     ic = self._createImageController(image,
                                      "model source '%s'" %
                                      model if model else filename,
                                      model or image.name,
                                      model=model)
     print("""Loaded FITS image %s""" % filename)
     self.signalShowMessage.emit("""Loaded FITS image %s""" % filename,
                                 3000)
     busy.reset_cursor()
     return ic