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()
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()
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()
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()
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()
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()
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
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()
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()
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)
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()
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()
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
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()
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()
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()
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()
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()
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)
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()
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
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()
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()
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)
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()
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()
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)
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)
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()
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()