Пример #1
0
 def updateColorMapParameters(self):
     """Call this when the colormap parameters have changed"""
     busy = BusyIndicator()
     self.image.updateCurrentColorMap()
     if self._config:
         self._cmap_list[self._current_cmap_index].saveConfig(self._config)
     busy.reset_cursor()
Пример #2
0
 def _refreshModel(self, what=SkyModel.UpdateAll, origin=None):
     if origin is self or not what & (SkyModel.UpdateSourceList
                                      | SkyModel.UpdateSourceContent):
         return
     # if only selection was changed, take shortcut
     if what & SkyModel.UpdateSelectionOnly:
         dprint(2, "model update -- selection only")
         return self._refreshSelectedItems(origin)
     busy = BusyIndicator()
     # else repopulate widget completely
     dprint(2, "model update -- complete")
     TigGUI.kitties.widgets.ClickableTreeWidget.clear(self)
     dprint(2, "creating model items")
     items = [SkyModelTreeWidgetItem(src) for src in self.model.sources]
     self._itemdict = dict(
         list(zip([src.name for src in self.model.sources], items)))
     dprint(2, "adding to tree widget")
     self.addTopLevelItems(items)
     self.header().updateGeometry()
     # show/hide columns based on tag availability
     self._enableColumn(ColumnIapp, 'Iapp' in self.model.tagnames)
     self._enableColumn(ColumnR, 'r' in self.model.tagnames)
     dprint(2, "re-sorting")
     self.sortItems(('Iapp' in self.model.tagnames and ColumnIapp)
                    or ColumnI, Qt.DescendingOrder)
     busy.reset_cursor()
Пример #3
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()
Пример #4
0
 def selectSources(self, predicate, curry=False):
     """Selects sources according to predicate(src)"""
     busy = BusyIndicator()
     for src in self.model.sources:
         src.selected = predicate(src)
     self.model.emitSelection(origin=self)
     busy.reset_cursor()
Пример #5
0
 def _showMeanStd(self, busy=True):
     if busy:
         busy = BusyIndicator()
     dmin, dmax = self._subset_range
     subset, mask = self.image.optimalRavel(self._subset)
     dprint(5, "computing mean")
     mean = measurements.mean(subset, labels=mask, index=None if mask is None else False)
     dprint(5, "computing std")
     std = measurements.standard_deviation(subset, labels=mask, index=None if mask is None else False)
     dprint(5, "done")
     text = "  ".join([("%s: " + DataValueFormat) % (name, value) for name, value in
                       (("min", dmin), ("max", dmax), ("mean", mean), ("\n std", std))] + ["np: %d" % self._subset.size])
     self._wlab_stats.setText(text)
     self._wmore_stats.hide()
     # update markers
     ypos = 0.3
     self._line_mean.line.setData([mean, mean], [0, 1])
     self._line_mean.marker.setValue(mean, ypos)
     self._line_mean.setText(("\u03BC=" + DataValueFormat) % mean)
     self._line_mean.show()
     self._line_std.line.setData([mean - std, mean + std], [ypos, ypos])
     self._line_std.marker.setValue(mean, ypos)
     self._line_std.setText(("\u03C3=" + DataValueFormat) % std)
     self._line_std.show()
     self._histplot.replot()
     if not isinstance(busy, bool):
         busy.reset_cursor()
Пример #6
0
 def saveFile(self,
              filename=None,
              confirm=False,
              overwrite=True,
              non_native=False):
     """Saves file using the specified 'filename'. If filename is None, uses current filename, if
     that is not set, goes to saveFileAs() to open dialog and get a filename.
     If overwrite=False, will ask for confirmation before overwriting an existing file.
     If non_native=False, will ask for confirmation before exporting in non-native format.
     If confirm=True, will ask for confirmation regardless.
     Returns True if saving succeeded, False on error (or if cancelled by user).
     """
     if isinstance(filename, QStringList):
         filename = filename[0]
     filename = (filename and str(filename)) or self.filename
     if filename is None:
         return self.saveFileAs()
     else:
         warning = ''
         # try to determine the file type
         filetype, import_func, export_func, doc = Tigger.Models.Formats.resolveFormat(
             filename, None)
         if export_func is None:
             self.signalShowErrorMessage.emit(
                 """Error saving model file %s: unsupported output format"""
                 % filename)
             return
         if os.path.exists(filename) and not overwrite:
             warning += "<P>The file already exists and will be overwritten.</P>"
         if filetype != 'Tigger' and not non_native:
             warning += """<P>Please note that you are exporting the model using the external format '%s'.
           Source types, tags and other model features not supported by this
           format will be omitted during the export.</P>""" % filetype
         # get confirmation
         if confirm or warning:
             dialog = QMessageBox.warning if warning else QMessageBox.question
             if dialog(self, "Saving sky model",
                       "<P>Save model to %s?</P>%s" % (filename, warning),
                       QMessageBox.Save | QMessageBox.Cancel,
                       QMessageBox.Save) != QMessageBox.Save:
                 return False
         busy = BusyIndicator()
         try:
             export_func(self.model, filename)
             self.model.setFilename(filename)
         except:
             busy.reset_cursor()
             self.signalShowErrorMessage.emit(
                 """Error saving model file %s: %s""" %
                 (filename, str(sys.exc_info()[1])))
             return False
         else:
             self.signalShowMessage.emit(
                 """Saved model to file %s""" % filename, 3000)
             self._display_filename = os.path.basename(filename)
             self._indicateModelUpdated(updated=False)
             self.filename = filename
             return True
         finally:
             busy.reset_cursor()
Пример #7
0
 def _select_percentile_threshold(self, percent, do_select=False):
     # ignore if no sort index set up, or if _select_threshold() is being called
     if self._sort_index is None or self._in_select_threshold:
         return
     dprint(1, "select_precentile_threshold", percent)
     busy = BusyIndicator()
     # number of objects to select
     nsrc = len(self._sort_index)
     nsel = int(math.ceil(nsrc * float(percent) / 100))
     # get comparison operator
     opstr = str(self.wgele.currentText())
     op, select = self.Operators[opstr]
     # select head or tail of list, depending on direction of operator
     if select:
         thr = self._sort_index[min(nsel, nsrc - 1)]
         slc1 = slice(0, nsel)
         slc2 = slice(nsel, None)
     else:
         thr = self._sort_index[-min(nsel + 1, nsrc)]
         slc1 = slice(nsrc - nsel, None)
         slc2 = slice(0, nsrc - nsel)
     if do_select:
         for val, src, cumsum in self._sort_index[slc1]:
             src.selected = True
         for val, src, cumsum in self._sort_index[slc2]:
             src.selected = False
         self.model.emitSelection(self)
     self.wpercent_lbl.setText("%3d%%" % percent)
     self.wthreshold.setText(
         "%g" % (thr[2] if opstr.startswith("sum") else thr[0]))
     busy.reset_cursor()
     return nsel
Пример #8
0
 def _unselectAll(self):
     if not self.model:
         return
     busy = BusyIndicator()
     for src in self.model.sources:
         src.selected = False
     self.model.emitSelection(self)
     busy.reset_cursor()
Пример #9
0
 def _selectInvert(self):
     if not self.model:
         return
     busy = BusyIndicator()
     for src in self.model.sources:
         src.selected = not src.selected
     self.model.emitSelection(self)
     busy.reset_cursor()
Пример #10
0
 def accept(self):
     """Tries to restore the image, and closes the dialog if successful."""
     # get list of sources to restore
     sources = self.model.sources
     sel_sources = [src for src in sources if src.selected]
     if len(sel_sources) > 0 and len(sel_sources) < len(
             sources) and self.wselonly.isChecked():
         sources = sel_sources
     if not sources:
         self.qerrmsg.showMessage("No sources to restore.")
         return
     busy = BusyIndicator()
     # get filenames
     infile = self.wfile_in.filename()
     outfile = self.wfile_out.filename()
     self.parent().showMessage(
         "Restoring %d model sources to image %s, writing to %s" %
         (len(sources), infile, outfile))
     # read fits file
     try:
         input_hdu = pyfits.open(infile)[0]
     except Exception as err:
         busy.reset_cursor()
         self.qerrmsg.showMessage("Error reading FITS file %s: %s" %
                                  (infile, str(err)))
         return
     # get beam sizes
     try:
         bmaj = float(str(self.wbmaj.text()))
         bmin = float(str(self.wbmin.text()))
         pa = float(str(self.wbpa.text()) or "0")
     except Exception as err:
         busy.reset_cursor()
         self.qerrmsg.showMessage("Invalid beam size specified")
         return
     bmaj = bmaj / (Imaging.FWHM * 3600) * DEG
     bmin = bmin / (Imaging.FWHM * 3600) * DEG
     pa = pa * DEG
     # restore
     try:
         Imaging.restoreSources(input_hdu, sources, bmaj, bmin, pa)
     except Exception as err:
         busy.reset_cursor()
         self.qerrmsg.showMessage("Error restoring model into image: %s" %
                                  str(err))
         return
     # save fits file
     try:
         input_hdu.writeto(outfile, overwrite=True)
     except Exception as err:
         busy.reset_cursor()
         self.qerrmsg.showMessage("Error writing FITS file %s: %s" %
                                  (outfile, str(err)))
         return
     self.parent().loadImage(outfile)
     busy.reset_cursor()
     return QDialog.accept(self)
Пример #11
0
 def setColorMapNumber(self, index, write_config=True):
     busy = BusyIndicator()
     self._current_cmap_index = index
     cmap = self._cmap_list[index]
     self.image.setColorMap(cmap)
     self.colorMapChanged.emit(cmap)
     if self._config and write_config:
         self._config.set("colour-map-number", index)
     busy.reset_cursor()
Пример #12
0
 def _refreshSelectedItems(self, origin=None):
     busy = BusyIndicator()
     dprint(3, "refreshing selected items")
     for item in self.iterator():
         if item.isSelected():
             dprint(4, "resetting item", item._src.name)
             item.setSource(item._src)
     dprint(3, "refreshing selected items done")
     busy.reset_cursor()
Пример #13
0
 def saveSelectionAs(self, filename=None, force=False):
     if not self.model:
         return
     if filename is None:
         if not self._save_sel_as_dialog:
             filters = ";;".join([
                 "%s (%s)" % (name, " ".join(patterns))
                 for name, patterns, func in self._save_file_types
             ])
             dialog = self._save_sel_as_dialog = QFileDialog(
                 self, "Save sky model", ".", filters)
             dialog.setDefaultSuffix(ModelHTML.DefaultExtension)
             dialog.setFileMode(QFileDialog.AnyFile)
             dialog.setAcceptMode(QFileDialog.AcceptSave)
             dialog.setOption(QFileDialog.DontConfirmOverwrite, False)
             dialog.setModal(True)
             dialog.filesSelected['QStringList'].connect(
                 self.saveSelectionAs)
         return self._save_sel_as_dialog.exec_() == QDialog.Accepted
     # save selection
     if isinstance(filename, QStringList):
         filename = filename[0]
     filename = str(filename)
     selmodel = self.model.copy()
     sources = [src for src in self.model.sources if src.selected]
     if not sources:
         self.signalShowErrorMessage.emit(
             """You have not selected any sources to save.""")
         return
     # try to determine the file type
     filetype, import_func, export_func, doc = Tigger.Models.Formats.resolveFormat(
         filename, None)
     if export_func is None:
         self.signalShowErrorMessage.emit(
             """Error saving model file %s: unsupported output format""" %
             filename)
         return
     busy = BusyIndicator()
     try:
         export_func(self.model, filename, sources=sources)
     except:
         busy.reset_cursor()
         self.signalShowErrorMessage.emit(
             """Error saving selection to model file %s: %s""" %
             (filename, str(sys.exc_info()[1])))
         return False
     else:
         self.signalShowMessage.emit(
             """Wrote %d selected source%s to file %s""" %
             (len(selmodel.sources),
              "" if len(selmodel.sources) == 1 else "s", filename), 3000)
     finally:
         busy.reset_cursor()
     pass
Пример #14
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()
Пример #15
0
 def setIntensityMapNumber(self, index, write_config=True):
     busy = BusyIndicator()
     self._current_imap_index = index
     imap = self._imap_list[index][1]
     imap.setDataSubset(self._displaydata, self._displaydata_minmax)
     imap.setDataRange(*self._displayrange)
     self.image.setIntensityMap(imap)
     self.intensityMapChanged.emit(imap, index)
     if self._config and write_config:
         self._config.set("intensity-map-number", index)
     busy.reset_cursor()
Пример #16
0
 def dropEvent(self, event):
     busy = None
     filenames = self._getFilenamesFromDropEvent(event)
     dprint(1, "dropping", filenames)
     if filenames:
         event.acceptProposedAction()
         busy = BusyIndicator()
         for name in filenames:
             self.imgman.loadImage(name)
     if busy is not None:
         busy.reset_cursor()
Пример #17
0
 def _displayAllImages(self, enabled):
     busy = BusyIndicator()
     if enabled:
         for ic in self._imagecons:
             ic.setImageVisible(True)
     else:
         self._imagecons[0].setImageVisible(True)
         for ic in self._imagecons[1:]:
             ic.setImageVisible(False)
     self.replot()
     busy.reset_cursor()
Пример #18
0
 def raiseImage(self, imagecon, foo=None):
     busy = None
     # reshuffle image stack, if more than one image image
     if len(self._imagecons) > 1:
         busy = BusyIndicator()
         # reshuffle image stack
         self._imagecons.remove(imagecon)
         self._imagecons.insert(0, imagecon)
         # notify imagecons
         for i, ic in enumerate(self._imagecons):
             label = "%d" % (i + 1) if i else "<B>1</B>"
             ic.setZ(self._z0 - i * 10,
                     top=not i,
                     depthlabel=label,
                     can_raise=True)
         # adjust visibility
         for j, ic in enumerate(self._imagecons):
             ic.setImageVisible(not j
                                or bool(self._qa_plot_all.isChecked()))
         # issue replot signal fixed with assumption that this signal is now correct according to the old version
         # self.imageRaised.emit(self._imagecons[0])  # This was the old signal
         self.imagePlotRaised.emit()
         self.fastReplot()
     # else simply update labels
     else:
         self._imagecons[0].setZ(self._z0,
                                 top=True,
                                 depthlabel=None,
                                 can_raise=False)
         self._imagecons[0].setImageVisible(True)
     # update slice menus
     img = imagecon.image
     axes = imagecon.renderControl().slicedAxes()
     for i, (_next, _prev) in enumerate(self._qa_slices):
         _next.setVisible(False)
         _prev.setVisible(False)
         if i < len(axes):
             iaxis, name, labels = axes[i]
             _next.setVisible(True)
             _prev.setVisible(True)
             _next.setText("Show next slice along %s axis" % name)
             _prev.setText("Show previous slice along %s axis" % name)
     # emit signals
     self.imageRaised.emit(img)
     # if dockable control dialog is docked and tabbed then raise to front
     if imagecon._dockable_colour_ctrl is not None:
         if imagecon._dockable_colour_ctrl.isVisible():
             if not imagecon._dockable_colour_ctrl.isFloating():
                 list_of_tabbed_widgets = self.mainwin.tabifiedDockWidgets(
                     imagecon._dockable_colour_ctrl)
                 if list_of_tabbed_widgets:
                     imagecon._dockable_colour_ctrl.raise_()
     if busy is not None:
         busy.reset_cursor()
Пример #19
0
 def show(self):
     dprint(4, "show entrypoint")
     if self._geometry:
         dprint(4, "setting geometry")
         self.setGeometry(self._geometry)
     if self._hist is None:
         busy = BusyIndicator()
         dprint(4, "updating histogram")
         self._updateHistogram()
         dprint(4, "updating stats")
         self._updateStats(self._subset, self._subset_range)
         busy.reset_cursor()
     dprint(4, "calling QDialog.show")
     QDialog.show(self)
Пример #20
0
 def setIntensityMapLogCycles(self,
                              cycles,
                              notify_image=True,
                              write_config=True):
     busy = BusyIndicator()
     imap = self.currentIntensityMap()
     if isinstance(imap, Colormaps.LogIntensityMap):
         imap.log_cycles = cycles
         if notify_image:
             self.image.setIntensityMap()
         self.intensityMapChanged.emit(imap, self._current_imap_index)
     if self._config and write_config:
         self._config.set("intensity-log-cycles", cycles)
     busy.reset_cursor()
Пример #21
0
 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 as err:
         busy.reset_cursor()
         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")
     busy.reset_cursor()
     return filename
Пример #22
0
 def _updateSlice(self, write_config=True):
     """Common internal method called to finalize changes to _current_slice"""
     busy = BusyIndicator()
     dprint(2, "_updateSlice", self._current_slice, time.time() % 60)
     indices = tuple(self._current_slice)
     self.image.selectSlice(*indices)
     dprint(2, "image slice selected", time.time() % 60)
     img = self.image.image()
     self._slicerange = self._sliceranges.get(indices)
     if self._slicerange is None:
         self._slicerange = self._sliceranges[
             indices] = self.image.imageMinMax()[:2]
     dprint(2, "min/max updated", time.time() % 60)
     self.setSliceSubset(set_display_range=False)
     if write_config and self._config:
         self._config.set("slice", " ".join(map(str, indices)))
     busy.reset_cursor()
Пример #23
0
 def _psfFileSelected(self, filename):
     busy = BusyIndicator()
     filename = str(filename)
     self.parent().showMessage("Fitting gaussian to PSF file %s" % filename)
     try:
         bmaj, bmin, pa = [x / DEG for x in Imaging.fitPsf(filename)]
     except Exception as err:
         busy.reset_cursor()
         self.qerrmsg.showMessage("Error fitting PSF file %s: %s" %
                                  (filename, str(err)))
         return
     bmaj *= 3600 * Imaging.FWHM
     bmin *= 3600 * Imaging.FWHM
     self.wbmaj.setText(str(bmaj))
     self.wbmin.setText(str(bmin))
     self.wbpa.setText(str(pa))
     busy.reset_cursor()
Пример #24
0
 def setDisplayRange(self,
                     dmin,
                     dmax,
                     notify_image=True,
                     write_config=True):
     if dmax < dmin:
         dmin, dmax = dmax, dmin
     if (dmin, dmax) != self._displayrange:
         self._displayrange = dmin, dmax
         self.image.intensityMap().setDataRange(dmin, dmax)
         if notify_image:
             busy = BusyIndicator()
             self.image.setIntensityMap(emit=True)
             busy.reset_cursor()
         self.displayRangeChanged.emit(dmin, dmax)
         if self._config and write_config:
             self._config.set("range-min", dmin, save=False)
             self._config.set("range-max", dmax)
Пример #25
0
 def _changeDisplayRangeToPercent(self, percent):
     busy = BusyIndicator()
     if self._hist is None:
         self._updateHistogram()
         self._updateStats(self._subset, self._subset_range)
     # delta: we need the [delta,100-delta] interval of the total distribution
     delta = self._subset.size * ((100. - percent) / 200.)
     # get F(x): cumulative sum
     cumsum = numpy.zeros(len(self._hist_hires) + 1, dtype=int)
     cumsum[1:] = numpy.cumsum(self._hist_hires)
     bins = numpy.zeros(len(self._hist_hires) + 1, dtype=float)
     bins[0] = self._subset_range[0]
     bins[1:] = self._hist_bins_hires + self._hist_binsize_hires / 2
     # use interpolation to find value interval corresponding to [delta,100-delta] of the distribution
     dprint(2, self._subset.size, delta, self._subset.size - delta)
     dprint(2, cumsum, self._hist_bins_hires)
     # if first bin is already > delta, then set colour range to first bin
     x0, x1 = numpy.interp([delta, self._subset.size - delta], cumsum, bins)
     # and change the display range (this will also cause a histplot.replot() via _updateDisplayRange above)
     self._rc.setDisplayRange(x0, x1)
     busy.reset_cursor()
Пример #26
0
 def _select_threshold(self, *dum):
     dprint(1, "select_threshold", dum)
     self._in_select_threshold = True
     busy = BusyIndicator()
     try:
         # get threshold, ignore if not set
         threshold = str(self.wthreshold.text())
         if not threshold:
             self._reset_percentile()
             return
         # try to parse threshold, ignore if invalid
         try:
             threshold = float(threshold)
         except:
             self._reset_percentile()
             return
         # get comparison operator
         op, select = self.Operators[str(self.wgele.currentText())]
         # apply to initial segment (that matches operator)
         for num, entry in enumerate(self._sort_index):
             if not op(entry, threshold):
                 break
             entry[1].selected = select
         else:
             num = len(self._sort_index)
         # apply to remaining segment
         for val, src, cumsum in self._sort_index[num:]:
             src.selected = not select
         # set percentile
         percent = round(float(num * 100) / len(self._sort_index))
         if not select:
             percent = 100 - percent
         self.wpercent.setValue(percent)
         self.wpercent_lbl.setText("%3d%%" % percent)
         # emit signal
         self.model.emitSelection(self)
     finally:
         self._in_select_threshold = False
         busy.reset_cursor()
Пример #27
0
    def _exportImageToPNG(self, filename=None):
        if not filename:
            if not self._export_png_dialog:
                dialog = self._export_png_dialog = QFileDialog(
                    self, "Export image to PNG", ".", "*.png")
                dialog.setDefaultSuffix("png")
                dialog.setFileMode(QFileDialog.AnyFile)
                dialog.setAcceptMode(QFileDialog.AcceptSave)
                dialog.setModal(True)
                dialog.filesSelected['QStringList'].connect(
                    self._exportImageToPNG)
                # attempt to add limit 4K option - not available on Ubuntu Unity
                layout = dialog.layout()
                if layout is not None:
                    checkbox = QCheckBox("Limit to 4K image")
                    checkbox.setChecked(False)
                    checkbox.setToolTip("Limits the image output to 4K")
                    checkbox.toggled.connect(self._exportImageResolution)
                    layout.addWidget(checkbox)
                    dialog.setLayout(layout)
            return self._export_png_dialog.exec_() == QDialog.Accepted
        busy = BusyIndicator()
        if isinstance(filename, QStringList):
            filename = filename[0]
        filename = str(filename)
        # get image dimensions
        nx, ny = self.image.imageDims()
        # export either max resolution possible or default to 4K. If image is small then no scaling occurs.
        if not self._exportMaxRes:
            # get free memory. Note: Linux only!
            import os
            total_memory, used_memory, free_memory = map(
                int,
                os.popen('free -t -m').readlines()[-1].split()[1:])
            # use 90% of free memory available
            free_memory = free_memory * 0.9
            # use an approximation to find the max image size that can be generated
            if nx >= ny and nx > free_memory:
                scale_factor = round(free_memory / nx, 1)
            elif ny > nx and ny > free_memory:
                scale_factor = round(free_memory / ny, 1)
            else:
                scale_factor = 1
        else:
            # default to 4K
            if nx > 4000:
                scale_factor = 4000 / nx
            elif ny > nx and ny > 4000:
                scale_factor = 4000 / ny
            else:
                scale_factor = 1

        # make QPixmap
        nx = nx * scale_factor
        ny = ny * scale_factor
        (l0, l1), (m0, m1) = self.image.getExtents()
        pixmap = QPixmap(nx, ny)
        painter = QPainter(pixmap)
        # use QwtPlot implementation of draw canvas, since we want to avoid caching
        xmap = QwtScaleMap()
        xmap.setPaintInterval(0, nx)
        xmap.setScaleInterval(l1, l0)
        ymap = QwtScaleMap()
        ymap.setPaintInterval(ny, 0)
        ymap.setScaleInterval(m0, m1)
        # call painter with clear cache option for consistent file size output.
        self.image.draw(painter, xmap, ymap, pixmap.rect(), use_cache=False)
        painter.end()
        # save to file
        try:
            pixmap.save(filename, "PNG")
            # clean up export items
            pixmap.detach()
            del xmap
            del ymap
            del pixmap
            del painter
        except Exception as exc:
            self._imgman.signalShowErrorMessage[str, int].emit(
                "Error writing %s: %s" % (filename, str(exc)), 3000)
            busy.reset_cursor()
        else:
            busy.reset_cursor()
            self._imgman.signalShowMessage[str, int].emit(
                "Exported image to file %s" % filename, 3000)
Пример #28
0
 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 = open(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 as err:
         busy.reset_cursor()
         self.qerrmsg.showMessage(
             "Error writing Karma annotations file %s: %s" %
             (filename, str(err)))
         return
     busy.reset_cursor()
     self.parent().showMessage(
         "Wrote Karma annotations for %d sources to file %s" %
         (len(sources), filename))
     return QDialog.accept(self)
Пример #29
0
 def _enableColumn(self, column, enable=True):
     busy = BusyIndicator()
     self._column_enabled[column] = enable
     self._showColumn(column, enable and self._column_shown[column])
     busy.reset_cursor()
Пример #30
0
 def _showColumnCategory(self, columns, show):
     busy = BusyIndicator()
     for col in columns:
         self._column_shown[col] = show
         self._showColumn(col, self._column_enabled[col] and show)
     busy.reset_cursor()