def resume(self): # turn off any mode user may be in self.modes_off() self.canvas.ui_setActive(True) self.fv.showStatus("Draw a rectangle with the right mouse button") # Setup the region if self.region is None: self.region = Region() self.region.coord = 'wcs' self.region.image = self.fitsimage.get_image() # See if multiimage is active chname = self.fv.get_channelName(self.fitsimage) chinfo = self.fv.get_channelInfo(chname) opmon = chinfo.opmon multiimage = None if opmon.is_active('MultiImage'): try: multiimage = opmon.getPlugin('MultiImage') multiimage.region = self.region except: multiimage = None self.multiimage = multiimage
def resume(self): super(MIPick, self).resume() # Setup the region if self.region is None: self.region = Region() self.region.coord = 'wcs' self.region.image = self.fitsimage.get_image() # See if multiimage is active opmon = self.chinfo.opmon multiimage = None if opmon.is_active(self.multiimage_name): try: multiimage = opmon.getPlugin(self.multiimage_name) except: multiimage = None else: multiimage.region = self.region self.multiimage = multiimage
class MIPick(Pick): """This is like ``Pick`` plugin but modified to work with ``MultiImage`` plugin.""" def __init__(self, fv, fitsimage): # superclass defines some variables for us, like logger super(MIPick, self).__init__(fv, fitsimage) # Override parent attributes self.layertag = 'mipick-canvas' self._textlabel = 'MIPick' # Additional attributes self.multiimage_name = 'MultiImage' self.region = None def resume(self): super(MIPick, self).resume() # Setup the region if self.region is None: self.region = Region() self.region.coord = 'wcs' self.region.image = self.fitsimage.get_image() # See if multiimage is active opmon = self.chinfo.opmon multiimage = None if opmon.is_active(self.multiimage_name): try: multiimage = opmon.getPlugin(self.multiimage_name) except: multiimage = None else: multiimage.region = self.region self.multiimage = multiimage def redo(self): if self.picktag is None: return serialnum = self.bump_serial() self.ev_intr.set() fig = self.canvas.get_object_by_tag(self.picktag) if fig.kind != 'compound': return True bbox = fig.objects[0] self.region.image = self.fitsimage.get_image() self.draw_compound(bbox, self.canvas, *self.region.bbox(coord='data')) fig = self.canvas.getObjectByTag(self.picktag) bbox = fig.objects[0] # set the pick image to have the same cut levels and transforms self.fitsimage.copy_attributes(self.pickimage, ['transforms', 'cutlevels', 'rgbmap']) try: # Get other parts of the indicator point = fig.objects[1] text = fig.objects[2] # sanity check on region width = bbox.x2 - bbox.x1 height = bbox.y2 - bbox.y1 if (width > self.max_side) or (height > self.max_side): errmsg = "Image area (%dx%d) too large!" % (width, height) self.fv.show_error(errmsg) raise Exception(errmsg) # Cut and show pick image in pick window self.logger.debug("bbox %f,%f %f,%f" % (bbox.x1, bbox.y1, bbox.x2, bbox.y2)) x1, y1, x2, y2, data = self.cutdetail(self.fitsimage, self.pickimage, int(bbox.x1), int(bbox.y1), int(bbox.x2), int(bbox.y2)) self.logger.debug("cut box %f,%f %f,%f" % (x1, y1, x2, y2)) # calculate center of pick image wd, ht = self.pickimage.get_data_size() xc = wd // 2 yc = ht // 2 if self.pickcenter is None: p_canvas = self.pickimage.get_canvas() tag = p_canvas.add(self.dc.Point(xc, yc, 5, linewidth=1, color='red')) self.pickcenter = p_canvas.get_object_by_tag(tag) self.pick_x1, self.pick_y1 = x1, y1 self.pick_data = data self.wdetail.sample_area.set_text('%dx%d' % (x2 - x1, y2 - y1)) point.color = 'red' text.text = '{0}: calc'.format(self._textlabel) self.pickcenter.x = xc self.pickcenter.y = yc self.pickcenter.color = 'red' # clear contour and fwhm plots if self.have_mpl: self.clear_contours() self.clear_fwhm() self.clear_radial() # If multiimage, redo there also. try: self.multiimage.redo() except: """Doesn't matter""" pass # Delete previous peak marks objs = self.canvas.getObjectsByTagpfx('peak') self.canvas.delete_objects(objs) # Offload this task to another thread so that GUI remains # responsive self.fv.nongui_do(self.search, serialnum, data, x1, y1, wd, ht, fig) except Exception as e: self.logger.error("Error calculating quality metrics: %s" % ( str(e))) return True def draw_cb(self, canvas, tag): obj = canvas.getObjectByTag(tag) self.draw_compound(obj, canvas) return self.redo() def edit_cb(self, canvas, obj): if obj.kind != 'rectangle': return True # Get the compound object that sits on the canvas. # Make sure edited rectangle was our pick rectangle. c_obj = self.canvas.get_object_by_tag(self.picktag) if ((c_obj.kind != 'compound') or (len(c_obj.objects) < 3) or (c_obj.objects[0] != obj)): return False # determine center of rectangle x1, y1, x2, y2 = obj.get_llur() x = x1 + (x2 - x1) // 2 y = y1 + (y2 - y1) // 2 # reposition other elements to match point = c_obj.objects[1] point.x, point.y = x, y text = c_obj.objects[2] text.x, text.y = x1, y2 + 4 self.regions.set_bbox(x1, y1, x2, y2, coord='data') return self.redo() def reset_region(self): self.dx = region_default_width self.dy = region_default_height obj = self.canvas.get_object_by_tag(self.picktag) if obj.kind != 'compound': return True bbox = obj.objects[0] # calculate center of bbox wd = bbox.x2 - bbox.x1 dw = wd // 2 ht = bbox.y2 - bbox.y1 dh = ht // 2 x, y = bbox.x1 + dw, bbox.y1 + dh # calculate new coords bbox.x1, bbox.y1, bbox.x2, bbox.y2 = (x - self.dx, y - self.dy, x + self.dx, y + self.dy) self.regions.set_bbox(bbox.x1, bbox.y1, bbox.x2, bbox.y2, coord='data') self.redo() def draw_compound(self, obj, canvas, *args): """Draw the pick info box.""" if obj.kind != 'rectangle': return True canvas.deleteObject(obj) if self.picktag: try: canvas.deleteObjectByTag(self.picktag) except: pass # Get rectangle: if len(args) == 4: x1, y1, x2, y2 = args else: x1, y1, x2, y2 = obj.get_llur() # determine center of rectangle x = x1 + (x2 - x1) // 2 y = y1 + (y2 - y1) // 2 tag = canvas.add(self.dc.CompoundObject( self.dc.Rectangle(x1, y1, x2, y2, color=self.pickcolor), self.dc.Point(x, y, 10, color='red'), self.dc.Text(x1, y2 + 4, '{0}: calc'.format(self._textlabel), color=self.pickcolor))) self.picktag = tag self.region.set_bbox(x1, y1, x2, y2, coord='data') def __str__(self): return 'mipick'
class MIPick(Pick): """This is like ``Pick`` plugin but modified to work with ``MultiImage`` plugin.""" def __init__(self, fv, fitsimage): # superclass defines some variables for us, like logger super(MIPick, self).__init__(fv, fitsimage) # Override parent attributes self.layertag = 'mipick-canvas' self._textlabel = 'MIPick' # Additional attributes self.multiimage_name = 'MultiImage' self.region = None def resume(self): super(MIPick, self).resume() # Setup the region if self.region is None: self.region = Region() self.region.coord = 'wcs' self.region.image = self.fitsimage.get_image() # See if multiimage is active opmon = self.chinfo.opmon multiimage = None if opmon.is_active(self.multiimage_name): try: multiimage = opmon.getPlugin(self.multiimage_name) except Exception: multiimage = None else: multiimage.region = self.region self.multiimage = multiimage def redo(self): if self.picktag is None: return serialnum = self.bump_serial() self.ev_intr.set() fig = self.canvas.get_object_by_tag(self.picktag) if fig.kind != 'compound': return True bbox = fig.objects[0] self.region.image = self.fitsimage.get_image() self.draw_compound(bbox, self.canvas, *self.region.bbox(coord='data')) fig = self.canvas.getObjectByTag(self.picktag) bbox = fig.objects[0] # set the pick image to have the same cut levels and transforms self.fitsimage.copy_attributes(self.pickimage, ['transforms', 'cutlevels', 'rgbmap']) try: # Get other parts of the indicator point = fig.objects[1] text = fig.objects[2] # sanity check on region width = bbox.x2 - bbox.x1 height = bbox.y2 - bbox.y1 if (width > self.max_side) or (height > self.max_side): errmsg = "Image area (%dx%d) too large!" % (width, height) self.fv.show_error(errmsg) raise Exception(errmsg) # Cut and show pick image in pick window self.logger.debug("bbox %f,%f %f,%f" % (bbox.x1, bbox.y1, bbox.x2, bbox.y2)) x1, y1, x2, y2, data = self.cutdetail(self.fitsimage, self.pickimage, int(bbox.x1), int(bbox.y1), int(bbox.x2), int(bbox.y2)) self.logger.debug("cut box %f,%f %f,%f" % (x1, y1, x2, y2)) # calculate center of pick image wd, ht = self.pickimage.get_data_size() xc = wd // 2 yc = ht // 2 if self.pickcenter is None: p_canvas = self.pickimage.get_canvas() tag = p_canvas.add( self.dc.Point(xc, yc, 5, linewidth=1, color='red')) self.pickcenter = p_canvas.get_object_by_tag(tag) self.pick_x1, self.pick_y1 = x1, y1 self.pick_data = data self.wdetail.sample_area.set_text('%dx%d' % (x2 - x1, y2 - y1)) point.color = 'red' text.text = '{0}: calc'.format(self._textlabel) self.pickcenter.x = xc self.pickcenter.y = yc self.pickcenter.color = 'red' # clear contour and fwhm plots if self.have_mpl: self.clear_contours() self.clear_fwhm() self.clear_radial() # If multiimage, redo there also. try: self.multiimage.redo() except Exception: """Doesn't matter""" pass # Delete previous peak marks objs = self.canvas.getObjectsByTagpfx('peak') self.canvas.delete_objects(objs) # Offload this task to another thread so that GUI remains # responsive self.fv.nongui_do(self.search, serialnum, data, x1, y1, wd, ht, fig) except Exception as e: self.logger.error("Error calculating quality metrics: %s" % (str(e))) return True def draw_cb(self, canvas, tag): obj = canvas.getObjectByTag(tag) self.draw_compound(obj, canvas) return self.redo() def edit_cb(self, canvas, obj): if obj.kind != 'rectangle': return True # Get the compound object that sits on the canvas. # Make sure edited rectangle was our pick rectangle. c_obj = self.canvas.get_object_by_tag(self.picktag) if ((c_obj.kind != 'compound') or (len(c_obj.objects) < 3) or (c_obj.objects[0] != obj)): return False # determine center of rectangle x1, y1, x2, y2 = obj.get_llur() x = x1 + (x2 - x1) // 2 y = y1 + (y2 - y1) // 2 # reposition other elements to match point = c_obj.objects[1] point.x, point.y = x, y text = c_obj.objects[2] text.x, text.y = x1, y2 + 4 self.regions.set_bbox(x1, y1, x2, y2, coord='data') return self.redo() def reset_region(self): self.dx = region_default_width self.dy = region_default_height obj = self.canvas.get_object_by_tag(self.picktag) if obj.kind != 'compound': return True bbox = obj.objects[0] # calculate center of bbox wd = bbox.x2 - bbox.x1 dw = wd // 2 ht = bbox.y2 - bbox.y1 dh = ht // 2 x, y = bbox.x1 + dw, bbox.y1 + dh # calculate new coords bbox.x1, bbox.y1, bbox.x2, bbox.y2 = (x - self.dx, y - self.dy, x + self.dx, y + self.dy) self.regions.set_bbox(bbox.x1, bbox.y1, bbox.x2, bbox.y2, coord='data') self.redo() def draw_compound(self, obj, canvas, *args): """Draw the pick info box.""" if obj.kind != 'rectangle': return True canvas.deleteObject(obj) if self.picktag: try: canvas.deleteObjectByTag(self.picktag) except Exception: pass # Get rectangle: if len(args) == 4: x1, y1, x2, y2 = args else: x1, y1, x2, y2 = obj.get_llur() # determine center of rectangle x = x1 + (x2 - x1) // 2 y = y1 + (y2 - y1) // 2 tag = canvas.add( self.dc.CompoundObject( self.dc.Rectangle(x1, y1, x2, y2, color=self.pickcolor), self.dc.Point(x, y, 10, color='red'), self.dc.Text(x1, y2 + 4, '{0}: calc'.format(self._textlabel), color=self.pickcolor))) self.picktag = tag self.region.set_bbox(x1, y1, x2, y2, coord='data') def __str__(self): return 'mipick'
class MIPick(GingaPlugin.LocalPlugin): def __init__(self, fv, fitsimage): # superclass defines some variables for us, like logger super(MIPick, self).__init__(fv, fitsimage) self.layertag = 'pick-canvas' self.pickimage = None self.pickcenter = None self.pick_qs = None self.picktag = None self.region = None # get Pick preferences prefs = self.fv.get_preferences() self.settings = prefs.createCategory('plugin_Pick') self.settings.load(onError='silent') self.sync_preferences() self.pick_x1 = 0 self.pick_y1 = 0 self.pick_data = None self.pick_log = None self.dx = region_default_width self.dy = region_default_height # For offloading intensive calculation from graphics thread self.serialnum = 0 self.lock = threading.RLock() self.lock2 = threading.RLock() self.ev_intr = threading.Event() self.last_rpt = {} self.iqcalc = iqcalc.IQCalc(self.logger) self.dc = self.fv.getDrawClasses() canvas = self.dc.DrawingCanvas() canvas.enable_draw(True) canvas.enable_edit(True) canvas.set_drawtype('rectangle', color='cyan', linestyle='dash', drawdims=True) canvas.set_callback('draw-event', self.draw_cb) canvas.set_callback('edit-event', self.edit_cb) canvas.add_draw_mode('move', down=self.btndown, move=self.drag, up=self.update) canvas.register_for_cursor_drawing(self.fitsimage) canvas.setSurface(self.fitsimage) canvas.set_draw_mode('move') self.canvas = canvas self.have_mpl = have_mpl def sync_preferences(self): # Load various preferences self.pickcolor = self.settings.get('color_pick', 'green') self.candidate_color = self.settings.get('color_candidate', 'purple') # Peak finding parameters and selection criteria self.max_side = self.settings.get('max_side', 1024) self.radius = self.settings.get('radius', 10) self.threshold = self.settings.get('threshold', None) self.min_fwhm = self.settings.get('min_fwhm', 2.0) self.max_fwhm = self.settings.get('max_fwhm', 50.0) self.min_ellipse = self.settings.get('min_ellipse', 0.5) self.edgew = self.settings.get('edge_width', 0.01) self.show_candidates = self.settings.get('show_candidates', False) # Report in 0- or 1-based coordinates coord_offset = self.fv.settings.get('pixel_coords_offset', 0.0) self.pixel_coords_offset = self.settings.get('pixel_coords_offset', coord_offset) # For controls self.delta_sky = self.settings.get('delta_sky', 0.0) self.delta_bright = self.settings.get('delta_bright', 0.0) # Formatting for reports self.do_record = self.settings.get('record_picks', False) self.rpt_header = self.settings.get('report_header', "# ra, dec, eq, x, y, fwhm, fwhm_x, fwhm_y, starsize, ellip, bg, sky, bright, time_local, time_ut") self.rpt_format = self.settings.get('report_format', "%(ra_deg)f, %(dec_deg)f, %(equinox)6.1f, %(x)f, %(y)f, %(fwhm)f, %(fwhm_x)f, %(fwhm_y)f, %(starsize)f, %(ellipse)f, %(background)f, %(skylevel)f, %(brightness)f, %(time_local)s, %(time_ut)s") self.do_report_log = self.settings.get('report_to_log', False) report_log = self.settings.get('report_log_path', None) if report_log is None: report_log = "pick_log.txt" self.report_log = report_log # For contour plot self.num_contours = self.settings.get('num_contours', 8) self.contour_size_limit = self.settings.get('contour_size_limit', 70) def build_gui(self, container): assert iqcalc.have_scipy == True, \ Exception("Please install python-scipy to use this plugin") self.pickcenter = None vtop = Widgets.VBox() vtop.set_border_width(4) vbox, sw, orientation = Widgets.get_oriented_box(container) vbox.set_border_width(4) vbox.set_spacing(2) self.msgFont = self.fv.getFont("sansFont", 12) tw = Widgets.TextArea(wrap=True, editable=False) tw.set_font(self.msgFont) self.tw = tw fr = Widgets.Expander("Instructions") fr.set_widget(tw) vbox.add_widget(fr, stretch=0) vpaned = Widgets.Splitter(orientation=orientation) nb = Widgets.TabWidget(tabpos='bottom') self.w.nb1 = nb vpaned.add_widget(nb) cm, im = self.fv.cm, self.fv.im di = Viewers.ImageViewCanvas(logger=self.logger) width, height = 200, 200 #di.set_desired_size(width, height) di.configure_window(width, height) di.enable_autozoom('off') di.enable_autocuts('off') di.zoom_to(3) settings = di.get_settings() settings.getSetting('zoomlevel').add_callback('set', self.zoomset, di) di.set_cmap(cm) di.set_imap(im) di.set_callback('none-move', self.detailxy) di.set_bg(0.4, 0.4, 0.4) # for debugging di.set_name('pickimage') self.pickimage = di bd = di.get_bindings() bd.enable_pan(True) bd.enable_zoom(True) bd.enable_cuts(True) iw = Viewers.GingaViewerWidget(viewer=di) nb.add_widget(iw, title="Image") di.configure(width, height) if have_mpl: # Contour plot self.contour_plot = plots.ContourPlot(logger=self.logger) self.contour_plot.add_axis(axisbg='black') pw = Plot.PlotWidget(self.contour_plot) pw.resize(400, 300) nb.add_widget(pw, title="Contour") # FWHM gaussians plot self.fwhm_plot = plots.FWHMPlot(logger=self.logger) self.fwhm_plot.add_axis(axisbg='white') pw = Plot.PlotWidget(self.fwhm_plot) pw.resize(400, 300) nb.add_widget(pw, title="FWHM") # Radial profile plot self.radial_plot = plots.RadialPlot(logger=self.logger) self.radial_plot.add_axis(axisbg='white') pw = Plot.PlotWidget(self.radial_plot) pw.resize(400, 300) nb.add_widget(pw, title="Radial") vpaned.add_widget(Widgets.Label('')) vbox.add_widget(vpaned, stretch=1) #vbox.add_widget(nb, stretch=1) fr = Widgets.Frame("Pick") nb = Widgets.TabWidget(tabpos='bottom') self.w.nb2 = nb # Build report panel captions = (('Zoom:', 'label', 'Zoom', 'llabel', 'Contour Zoom:', 'label', 'Contour Zoom', 'llabel'), ('Object_X', 'label', 'Object_X', 'llabel', 'Object_Y', 'label', 'Object_Y', 'llabel'), ('RA:', 'label', 'RA', 'llabel', 'DEC:', 'label', 'DEC', 'llabel'), ('Equinox:', 'label', 'Equinox', 'llabel', 'Background:', 'label', 'Background', 'llabel'), ('Sky Level:', 'label', 'Sky Level', 'llabel', 'Brightness:', 'label', 'Brightness', 'llabel'), ('FWHM X:', 'label', 'FWHM X', 'llabel', 'FWHM Y:', 'label', 'FWHM Y', 'llabel'), ('FWHM:', 'label', 'FWHM', 'llabel', 'Star Size:', 'label', 'Star Size', 'llabel'), ('Sample Area:', 'label', 'Sample Area', 'llabel', 'Default Region', 'button'), ('Pan to pick', 'button'), ) w, b = Widgets.build_info(captions, orientation=orientation) self.w.update(b) b.zoom.set_text(self.fv.scale2text(di.get_scale())) self.wdetail = b b.default_region.add_callback('activated', lambda w: self.reset_region()) b.default_region.set_tooltip("Reset region size to default") b.pan_to_pick.add_callback('activated', lambda w: self.pan_to_pick_cb()) b.pan_to_pick.set_tooltip("Pan image to pick center") vbox1 = Widgets.VBox() vbox1.add_widget(w, stretch=0) # spacer vbox1.add_widget(Widgets.Label(''), stretch=0) # Pick field evaluation status hbox = Widgets.HBox() hbox.set_spacing(4) hbox.set_border_width(4) label = Widgets.Label() #label.set_alignment(0.05, 0.5) self.w.eval_status = label hbox.add_widget(self.w.eval_status, stretch=0) hbox.add_widget(Widgets.Label(''), stretch=1) vbox1.add_widget(hbox, stretch=0) # Pick field evaluation progress bar and stop button hbox = Widgets.HBox() hbox.set_spacing(4) hbox.set_border_width(4) btn = Widgets.Button("Stop") btn.add_callback('activated', lambda w: self.eval_intr()) btn.set_enabled(False) self.w.btn_intr_eval = btn hbox.add_widget(btn, stretch=0) self.w.eval_pgs = Widgets.ProgressBar() hbox.add_widget(self.w.eval_pgs, stretch=1) vbox1.add_widget(hbox, stretch=0) nb.add_widget(vbox1, title="Readout") # Build settings panel captions = (('Show Candidates', 'checkbutton'), ('Radius:', 'label', 'xlbl_radius', 'label', 'Radius', 'spinbutton'), ('Threshold:', 'label', 'xlbl_threshold', 'label', 'Threshold', 'entry'), ('Min FWHM:', 'label', 'xlbl_min_fwhm', 'label', 'Min FWHM', 'spinbutton'), ('Max FWHM:', 'label', 'xlbl_max_fwhm', 'label', 'Max FWHM', 'spinbutton'), ('Ellipticity:', 'label', 'xlbl_ellipticity', 'label', 'Ellipticity', 'entry'), ('Edge:', 'label', 'xlbl_edge', 'label', 'Edge', 'entry'), ('Max side:', 'label', 'xlbl_max_side', 'label', 'Max side', 'spinbutton'), ('Coordinate Base:', 'label', 'xlbl_coordinate_base', 'label', 'Coordinate Base', 'entry'), ('Redo Pick', 'button'), ) w, b = Widgets.build_info(captions, orientation=orientation) self.w.update(b) b.radius.set_tooltip("Radius for peak detection") b.threshold.set_tooltip("Threshold for peak detection (blank=default)") b.min_fwhm.set_tooltip("Minimum FWHM for selection") b.max_fwhm.set_tooltip("Maximum FWHM for selection") b.ellipticity.set_tooltip("Minimum ellipticity for selection") b.edge.set_tooltip("Minimum edge distance for selection") b.show_candidates.set_tooltip("Show all peak candidates") b.coordinate_base.set_tooltip("Base of pixel coordinate system") # radius control #b.radius.set_digits(2) #b.radius.set_numeric(True) b.radius.set_limits(5.0, 200.0, incr_value=1.0) def chg_radius(w, val): self.radius = float(val) self.w.xlbl_radius.set_text(str(self.radius)) return True b.xlbl_radius.set_text(str(self.radius)) b.radius.add_callback('value-changed', chg_radius) # threshold control def chg_threshold(w): threshold = None ths = w.get_text().strip() if len(ths) > 0: threshold = float(ths) self.threshold = threshold self.w.xlbl_threshold.set_text(str(self.threshold)) return True b.xlbl_threshold.set_text(str(self.threshold)) b.threshold.add_callback('activated', chg_threshold) # min fwhm #b.min_fwhm.set_digits(2) #b.min_fwhm.set_numeric(True) b.min_fwhm.set_limits(0.1, 200.0, incr_value=0.1) b.min_fwhm.set_value(self.min_fwhm) def chg_min(w, val): self.min_fwhm = float(val) self.w.xlbl_min_fwhm.set_text(str(self.min_fwhm)) return True b.xlbl_min_fwhm.set_text(str(self.min_fwhm)) b.min_fwhm.add_callback('value-changed', chg_min) # max fwhm #b.max_fwhm.set_digits(2) #b.max_fwhm.set_numeric(True) b.max_fwhm.set_limits(0.1, 200.0, incr_value=0.1) b.max_fwhm.set_value(self.max_fwhm) def chg_max(w, val): self.max_fwhm = float(val) self.w.xlbl_max_fwhm.set_text(str(self.max_fwhm)) return True b.xlbl_max_fwhm.set_text(str(self.max_fwhm)) b.max_fwhm.add_callback('value-changed', chg_max) # Ellipticity control def chg_ellipticity(w): minellipse = None val = w.get_text().strip() if len(val) > 0: minellipse = float(val) self.min_ellipse = minellipse self.w.xlbl_ellipticity.set_text(str(self.min_ellipse)) return True b.xlbl_ellipticity.set_text(str(self.min_ellipse)) b.ellipticity.add_callback('activated', chg_ellipticity) # Edge control def chg_edgew(w): edgew = None val = w.get_text().strip() if len(val) > 0: edgew = float(val) self.edgew = edgew self.w.xlbl_edge.set_text(str(self.edgew)) return True b.xlbl_edge.set_text(str(self.edgew)) b.edge.add_callback('activated', chg_edgew) #b.max_side.set_digits(0) #b.max_side.set_numeric(True) b.max_side.set_limits(5, 10000, incr_value=10) b.max_side.set_value(self.max_side) def chg_max_side(w, val): self.max_side = int(val) self.w.xlbl_max_side.set_text(str(self.max_side)) return True b.xlbl_max_side.set_text(str(self.max_side)) b.max_side.add_callback('value-changed', chg_max_side) b.redo_pick.add_callback('activated', lambda w: self.redo()) b.show_candidates.set_state(self.show_candidates) b.show_candidates.add_callback('activated', self.show_candidates_cb) self.w.xlbl_coordinate_base.set_text(str(self.pixel_coords_offset)) b.coordinate_base.set_text(str(self.pixel_coords_offset)) b.coordinate_base.add_callback('activated', self.coordinate_base_cb) nb.add_widget(w, title="Settings") # Build controls panel vbox3 = Widgets.VBox() captions = ( ('Sky cut', 'button', 'Delta sky:', 'label', 'xlbl_delta_sky', 'label', 'Delta sky', 'entry'), ('Bright cut', 'button', 'Delta bright:', 'label', 'xlbl_delta_bright', 'label', 'Delta bright', 'entry'), ) w, b = Widgets.build_info(captions, orientation=orientation) self.w.update(b) b.sky_cut.set_tooltip("Set image low cut to Sky Level") b.delta_sky.set_tooltip("Delta to apply to low cut") b.bright_cut.set_tooltip("Set image high cut to Sky Level+Brightness") b.delta_bright.set_tooltip("Delta to apply to high cut") b.sky_cut.set_enabled(False) self.w.btn_sky_cut = b.sky_cut self.w.btn_sky_cut.add_callback('activated', lambda w: self.sky_cut()) self.w.sky_cut_delta = b.delta_sky b.xlbl_delta_sky.set_text(str(self.delta_sky)) b.delta_sky.set_text(str(self.delta_sky)) def chg_delta_sky(w): delta_sky = 0.0 val = w.get_text().strip() if len(val) > 0: delta_sky = float(val) self.delta_sky = delta_sky self.w.xlbl_delta_sky.set_text(str(self.delta_sky)) return True b.delta_sky.add_callback('activated', chg_delta_sky) b.bright_cut.set_enabled(False) self.w.btn_bright_cut = b.bright_cut self.w.btn_bright_cut.add_callback('activated', lambda w: self.bright_cut()) self.w.bright_cut_delta = b.delta_bright b.xlbl_delta_bright.set_text(str(self.delta_bright)) b.delta_bright.set_text(str(self.delta_bright)) def chg_delta_bright(w): delta_bright = 0.0 val = w.get_text().strip() if len(val) > 0: delta_bright = float(val) self.delta_bright = delta_bright self.w.xlbl_delta_bright.set_text(str(self.delta_bright)) return True b.delta_bright.add_callback('activated', chg_delta_bright) vbox3.add_widget(w, stretch=0) vbox3.add_widget(Widgets.Label(''), stretch=1) nb.add_widget(vbox3, title="Controls") vbox3 = Widgets.VBox() msgFont = self.fv.getFont("fixedFont", 10) tw = Widgets.TextArea(wrap=False, editable=True) tw.set_font(msgFont) self.w.report = tw sw1 = Widgets.ScrollArea() sw1.set_widget(tw) vbox3.add_widget(sw1, stretch=1) tw.append_text(self._make_report_header()) btns = Widgets.HBox() btns.set_spacing(4) btn = Widgets.Button("Add Pick") btn.add_callback('activated', lambda w: self.add_pick_cb()) btns.add_widget(btn) btn = Widgets.CheckBox("Record Picks automatically") btn.set_state(self.do_record) btn.add_callback('activated', self.record_cb) btns.add_widget(btn) btns.add_widget(Widgets.Label(''), stretch=1) vbox3.add_widget(btns, stretch=0) btns = Widgets.HBox() btns.set_spacing(4) btn = Widgets.CheckBox("Log Records") btn.set_state(self.do_report_log) btn.add_callback('activated', self.do_report_log_cb) btns.add_widget(btn) btns.add_widget(Widgets.Label("File:")) ent = Widgets.TextEntry() ent.set_text(self.report_log) ent.add_callback('activated', self.set_report_log_cb) btns.add_widget(ent, stretch=1) vbox3.add_widget(btns, stretch=0) nb.add_widget(vbox3, title="Report") fr.set_widget(nb) vbox.add_widget(fr, stretch=0) mode = self.canvas.get_draw_mode() hbox = Widgets.HBox() btn1 = Widgets.RadioButton("Move") btn1.set_state(mode == 'move') btn1.add_callback('activated', lambda w, val: self.set_mode_cb('move', val)) btn1.set_tooltip("Choose this to position pick") self.w.btn_move = btn1 hbox.add_widget(btn1) btn2 = Widgets.RadioButton("Draw", group=btn1) btn2.set_state(mode == 'draw') btn2.add_callback('activated', lambda w, val: self.set_mode_cb('draw', val)) btn2.set_tooltip("Choose this to draw a replacement pick") self.w.btn_draw = btn2 hbox.add_widget(btn2) btn3 = Widgets.RadioButton("Edit", group=btn1) btn3.set_state(mode == 'edit') btn3.add_callback('activated', lambda w, val: self.set_mode_cb('edit', val)) btn3.set_tooltip("Choose this to edit a pick") self.w.btn_edit = btn3 hbox.add_widget(btn3) hbox.add_widget(Widgets.Label(''), stretch=1) vbox.add_widget(hbox, stretch=0) vtop.add_widget(sw, stretch=1) ## spacer = Widgets.Label('') ## vtop.add_widget(spacer, stretch=0) btns = Widgets.HBox() btns.set_spacing(4) btn = Widgets.Button("Close") btn.add_callback('activated', lambda w: self.close()) btns.add_widget(btn) btns.add_widget(Widgets.Label(''), stretch=1) vtop.add_widget(btns, stretch=0) container.add_widget(vtop, stretch=1) def copyText(self, w): text = w.get_text() # TODO: put it in the clipboard def record_cb(self, w, tf): self.do_record = tf return True def do_report_log_cb(self, w, tf): self.do_report_log = tf if tf and (self.pick_log is None): self.open_report_log() return True def set_report_log_cb(self, w): self.close_report_log() report_log = w.get_text().strip() if len(report_log) == 0: report_log = "pick_log.txt" w.set_text(report_log) self.report_log = report_log self.open_report_log() return True def instructions(self): self.tw.set_text("""Left-click to place region. Left-drag to position region. Redraw region with the right mouse button.""") self.tw.set_font(self.msgFont) def update_status(self, text): self.fv.gui_do(self.w.eval_status.set_text, text) def init_progress(self): self.w.btn_intr_eval.set_enabled(True) self.w.eval_pgs.set_value(0.0) def update_progress(self, pct): self.w.eval_pgs.set_value(pct) def show_candidates_cb(self, w, state): self.show_candidates = state if not self.show_candidates: # Delete previous peak marks objs = self.canvas.getObjectsByTagpfx('peak') self.canvas.delete_objects(objs) def coordinate_base_cb(self, w): self.pixel_coords_offset = float(w.get_text()) self.w.xlbl_coordinate_base.set_text(str(self.pixel_coords_offset)) def bump_serial(self): with self.lock: self.serialnum += 1 return self.serialnum def get_serial(self): with self.lock: return self.serialnum def plot_contours(self, image): # Make a contour plot ht, wd = self.pick_data.shape # If size of pick region is too large, carve out a subset around # the picked object coordinates for plotting contours maxsize = max(ht, wd) if maxsize > self.contour_size_limit: radius = int(self.contour_size_limit // 2) x, y = self.pick_qs.x, self.pick_qs.y data, x1, y1, x2, y2 = image.cutout_radius(x, y, radius) x, y = x - x1, y - y1 ht, wd = data.shape else: data = self.pick_data x, y = self.pickcenter.x, self.pickcenter.y try: # TODO: fix self.contour_plot.num_contours = self.num_contours self.contour_plot.plot_contours(x, y, data) except Exception as e: self.logger.error("Error making contour plot: %s" % ( str(e))) def clear_contours(self): self.contour_plot.clear() def plot_fwhm(self, qs, image): # Make a FWHM plot x, y, radius = qs.x, qs.y, qs.fwhm_radius try: self.fwhm_plot.plot_fwhm(x, y, radius, self.pick_data, image, iqcalc=self.iqcalc) except Exception as e: self.logger.error("Error making fwhm plot: %s" % ( str(e))) def clear_fwhm(self): self.fwhm_plot.clear() def plot_radial(self, qs, image): # Make a radial plot x, y, radius = qs.x, qs.y, qs.fwhm_radius try: self.radial_plot.plot_radial(x, y, radius, image) except Exception as e: self.logger.error("Error making radial plot: %s" % ( str(e))) def clear_radial(self): self.radial_plot.clear() def open_report_log(self): # Open report log if user specified one if self.do_report_log and (self.report_log is not None) and \ (self.pick_log is None): try: file_exists = os.path.exists(self.report_log) self.pick_log = open(self.report_log, 'a') if not file_exists: self.pick_log.write(self.rpt_header + '\n') self.logger.info("Opened Pick log '%s'" % (self.report_log)) except IOError as e: self.logger.error("Error opening Pick log (%s): %s" % ( self.report_log, str(e))) def close_report_log(self): if self.pick_log is not None: try: self.pick_log.close() self.logger.info("Closed Pick log '%s'" % (self.report_log)) except IOError as e: self.logger.error("Error closing Pick log (%s): %s" % ( self.report_log, str(e))) finally: self.pick_log = None def close(self): chname = self.fv.get_channelName(self.fitsimage) self.fv.stop_local_plugin(chname, str(self)) return True def start(self): self.instructions() self.open_report_log() # insert layer if it is not already p_canvas = self.fitsimage.get_canvas() try: obj = p_canvas.get_object_by_tag(self.layertag) except KeyError: # Add canvas layer p_canvas.add(self.canvas, tag=self.layertag) self.resume() def pause(self): self.canvas.ui_setActive(False) def resume(self): # turn off any mode user may be in self.modes_off() self.canvas.ui_setActive(True) self.fv.showStatus("Draw a rectangle with the right mouse button") # Setup the region if self.region is None: self.region = Region() self.region.coord = 'wcs' self.region.image = self.fitsimage.get_image() # See if multiimage is active chname = self.fv.get_channelName(self.fitsimage) chinfo = self.fv.get_channelInfo(chname) opmon = chinfo.opmon multiimage = None if opmon.is_active('MultiImage'): try: multiimage = opmon.getPlugin('MultiImage') multiimage.region = self.region except: multiimage = None self.multiimage = multiimage def stop(self): # Delete previous peak marks objs = self.canvas.getObjectsByTagpfx('peak') self.canvas.delete_objects(objs) # close pick log, if any self.close_report_log() # deactivate the canvas self.canvas.ui_setActive(False) p_canvas = self.fitsimage.get_canvas() try: p_canvas.delete_object_by_tag(self.layertag) except: pass self.fv.showStatus("") def redo(self): if self.picktag is None: return serialnum = self.bump_serial() self.ev_intr.set() fig = self.canvas.get_object_by_tag(self.picktag) if fig.kind != 'compound': return True bbox = fig.objects[0] self.region.image = self.fitsimage.get_image() self.draw_compound(bbox, self.canvas, *self.region.bbox(coord='data')) fig = self.canvas.getObjectByTag(self.picktag) bbox = fig.objects[0] # set the pick image to have the same cut levels and transforms self.fitsimage.copy_attributes(self.pickimage, ['transforms', 'cutlevels', 'rgbmap']) try: # Get other parts of the indicator point = fig.objects[1] text = fig.objects[2] # sanity check on region width = bbox.x2 - bbox.x1 height = bbox.y2 - bbox.y1 if (width > self.max_side) or (height > self.max_side): errmsg = "Image area (%dx%d) too large!" % ( width, height) self.fv.show_error(errmsg) raise Exception(errmsg) # Cut and show pick image in pick window self.logger.debug("bbox %f,%f %f,%f" % (bbox.x1, bbox.y1, bbox.x2, bbox.y2)) x1, y1, x2, y2, data = self.cutdetail(self.fitsimage, self.pickimage, int(bbox.x1), int(bbox.y1), int(bbox.x2), int(bbox.y2)) self.logger.debug("cut box %f,%f %f,%f" % (x1, y1, x2, y2)) # calculate center of pick image wd, ht = self.pickimage.get_data_size() xc = wd // 2 yc = ht // 2 if self.pickcenter is None: p_canvas = self.pickimage.get_canvas() tag = p_canvas.add(self.dc.Point(xc, yc, 5, linewidth=1, color='red')) self.pickcenter = p_canvas.get_object_by_tag(tag) self.pick_x1, self.pick_y1 = x1, y1 self.pick_data = data self.wdetail.sample_area.set_text('%dx%d' % (x2-x1, y2-y1)) point.color = 'red' text.text = 'Pick: calc' self.pickcenter.x = xc self.pickcenter.y = yc self.pickcenter.color = 'red' # clear contour and fwhm plots if self.have_mpl: self.clear_contours() self.clear_fwhm() self.clear_radial() # If multiimage, redo there also. try: self.multiimage.redo() except: """Doesn't matter""" pass # Delete previous peak marks objs = self.canvas.getObjectsByTagpfx('peak') self.canvas.delete_objects(objs) # Offload this task to another thread so that GUI remains # responsive self.fv.nongui_do(self.search, serialnum, data, x1, y1, wd, ht, fig) except Exception as e: self.logger.error("Error calculating quality metrics: %s" % ( str(e))) return True def search(self, serialnum, data, x1, y1, wd, ht, fig): if serialnum != self.get_serial(): return with self.lock2: self.pgs_cnt = 0 self.ev_intr.clear() self.fv.gui_call(self.init_progress) msg, results, qs = None, None, None try: self.update_status("Finding bright peaks...") # Find bright peaks in the cutout peaks = self.iqcalc.find_bright_peaks(data, threshold=self.threshold, radius=self.radius) num_peaks = len(peaks) if num_peaks == 0: raise Exception("Cannot find bright peaks") def cb_fn(obj): self.pgs_cnt += 1 pct = float(self.pgs_cnt) / num_peaks self.fv.gui_do(self.update_progress, pct) # Evaluate those peaks self.update_status("Evaluating %d bright peaks..." % ( num_peaks)) objlist = self.iqcalc.evaluate_peaks(peaks, data, fwhm_radius=self.radius, cb_fn=cb_fn, ev_intr=self.ev_intr) num_candidates = len(objlist) if num_candidates == 0: raise Exception("Error evaluating bright peaks: no candidates found") self.update_status("Selecting from %d candidates..." % ( num_candidates)) height, width = data.shape results = self.iqcalc.objlist_select(objlist, width, height, minfwhm=self.min_fwhm, maxfwhm=self.max_fwhm, minelipse=self.min_ellipse, edgew=self.edgew) if len(results) == 0: raise Exception("No object matches selection criteria") qs = results[0] except Exception as e: msg = str(e) self.update_status(msg) if serialnum == self.get_serial(): self.fv.gui_do(self.update_pick, serialnum, results, qs, x1, y1, wd, ht, fig, msg) def _make_report_header(self): return self.rpt_header + '\n' def _make_report(self, image, qs): d = Bunch.Bunch() try: x, y = qs.objx, qs.objy equinox = float(image.get_keyword('EQUINOX', 2000.0)) try: ra_deg, dec_deg = image.pixtoradec(x, y, coords='data') ra_txt, dec_txt = wcs.deg2fmt(ra_deg, dec_deg, 'str') except Exception as e: self.logger.warn("Couldn't calculate sky coordinates: %s" % (str(e))) ra_deg, dec_deg = 0.0, 0.0 ra_txt = dec_txt = 'BAD WCS' # Calculate star size from pixel pitch try: header = image.get_header() ((xrot, yrot), (cdelt1, cdelt2)) = wcs.get_xy_rotation_and_scale(header) starsize = self.iqcalc.starsize(qs.fwhm_x, cdelt1, qs.fwhm_y, cdelt2) except Exception as e: self.logger.warn("Couldn't calculate star size: %s" % (str(e))) starsize = 0.0 rpt_x = x + self.pixel_coords_offset rpt_y = y + self.pixel_coords_offset # make a report in the form of a dictionary d.setvals(x = rpt_x, y = rpt_y, ra_deg = ra_deg, dec_deg = dec_deg, ra_txt = ra_txt, dec_txt = dec_txt, equinox = equinox, fwhm = qs.fwhm, fwhm_x = qs.fwhm_x, fwhm_y = qs.fwhm_y, ellipse = qs.elipse, background = qs.background, skylevel = qs.skylevel, brightness = qs.brightness, starsize = starsize, time_local = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), time_ut = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime()), ) except Exception as e: self.logger.error("Error making report: %s" % (str(e))) return d def update_pick(self, serialnum, objlist, qs, x1, y1, wd, ht, fig, msg): if serialnum != self.get_serial(): return try: image = self.fitsimage.get_image() point = fig.objects[1] text = fig.objects[2] text.text = "Pick" if msg is not None: raise Exception(msg) # Mark new peaks, if desired if self.show_candidates: for obj in objlist: tag = self.canvas.add(self.dc.Point(x1+obj.objx, y1+obj.objy, 5, linewidth=1, color=self.candidate_color), tagpfx='peak') # Add back in offsets into image to get correct values with respect # to the entire image qs.x += x1 qs.y += y1 qs.objx += x1 qs.objy += y1 # Calculate X/Y of center of star obj_x = qs.objx obj_y = qs.objy fwhm = qs.fwhm fwhm_x, fwhm_y = qs.fwhm_x, qs.fwhm_y point.x, point.y = obj_x, obj_y text.color = 'cyan' # Make report self.last_rpt = self._make_report(image, qs) d = self.last_rpt if self.do_record: self.add_pick_cb() self.wdetail.fwhm_x.set_text('%.3f' % fwhm_x) self.wdetail.fwhm_y.set_text('%.3f' % fwhm_y) self.wdetail.fwhm.set_text('%.3f' % fwhm) self.wdetail.object_x.set_text('%.3f' % (d.x)) self.wdetail.object_y.set_text('%.3f' % (d.y)) self.wdetail.sky_level.set_text('%.3f' % qs.skylevel) self.wdetail.background.set_text('%.3f' % qs.background) self.wdetail.brightness.set_text('%.3f' % qs.brightness) self.wdetail.ra.set_text(d.ra_txt) self.wdetail.dec.set_text(d.dec_txt) self.wdetail.equinox.set_text(str(d.equinox)) self.wdetail.star_size.set_text('%.3f' % d.starsize) self.w.btn_sky_cut.set_enabled(True) self.w.btn_bright_cut.set_enabled(True) # Mark center of object on pick image i1 = point.x - x1 j1 = point.y - y1 self.pickcenter.x = i1 self.pickcenter.y = j1 self.pickcenter.color = 'cyan' self.pick_qs = qs self.pickimage.panset_xy(i1, j1) # Mark object center on image point.color = 'cyan' #self.fitsimage.panset_xy(obj_x, obj_y) self.update_status("Done") self.plot_panx = float(i1) / wd self.plot_pany = float(j1) / ht if self.have_mpl: self.plot_contours(image) self.plot_fwhm(qs, image) self.plot_radial(qs, image) except Exception as e: errmsg = "Error calculating quality metrics: %s" % ( str(e)) self.logger.error(errmsg) self.fv.show_error(errmsg, raisetab=False) #self.update_status("Error") for key in ('sky_level', 'background', 'brightness', 'star_size', 'fwhm_x', 'fwhm_y'): self.wdetail[key].set_text('') self.wdetail.fwhm.set_text('Failed') self.w.btn_sky_cut.set_enabled(False) self.w.btn_bright_cut.set_enabled(False) self.pick_qs = None text.color = 'red' self.plot_panx = self.plot_pany = 0.5 #self.plot_contours(image) # TODO: could calc background based on numpy calc self.w.btn_intr_eval.set_enabled(False) self.pickimage.redraw(whence=3) self.canvas.redraw(whence=3) self.fv.showStatus("Click left mouse button to reposition pick") return True def eval_intr(self): self.ev_intr.set() def btndown(self, canvas, event, data_x, data_y, viewer): try: obj = self.canvas.get_object_by_tag(self.picktag) if obj.kind == 'rectangle': bbox = obj else: bbox = obj.objects[0] point = obj.objects[1] self.dx = (bbox.x2 - bbox.x1) // 2 self.dy = (bbox.y2 - bbox.y1) // 2 except Exception as e: pass dx = self.dx dy = self.dy # Mark center of object and region on main image try: self.canvas.delete_object_by_tag(self.picktag) except: pass x1, y1 = data_x - dx, data_y - dy x2, y2 = data_x + dx, data_y + dy tag = self.canvas.add(self.dc.Rectangle(x1, y1, x2, y2, color='cyan', linestyle='dash')) self.picktag = tag #self.draw_cb(self.canvas, tag) return True def update(self, canvas, event, data_x, data_y, viewer): try: obj = self.canvas.get_object_by_tag(self.picktag) if obj.kind == 'rectangle': bbox = obj else: bbox = obj.objects[0] point = obj.objects[1] self.dx = (bbox.x2 - bbox.x1) // 2 self.dy = (bbox.y2 - bbox.y1) // 2 except Exception as e: obj = None pass dx = self.dx dy = self.dy x1, y1 = data_x - dx, data_y - dy x2, y2 = data_x + dx, data_y + dy if (not obj) or (obj.kind == 'compound'): # Replace compound image with rectangle try: self.canvas.delete_object_by_tag(self.picktag) except: pass tag = self.canvas.add(self.dc.Rectangle(x1, y1, x2, y2, color='cyan', linestyle='dash')) else: # Update current rectangle with new coords bbox.x1, bbox.y1, bbox.x2, bbox.y2 = x1, y1, x2, y2 tag = self.picktag self.draw_cb(self.canvas, tag) return True def drag(self, canvas, event, data_x, data_y, viewer): obj = self.canvas.get_object_by_tag(self.picktag) if obj.kind == 'compound': bbox = obj.objects[0] elif obj.kind == 'rectangle': bbox = obj else: return True # calculate center of bbox wd = bbox.x2 - bbox.x1 dw = wd // 2 ht = bbox.y2 - bbox.y1 dh = ht // 2 x, y = bbox.x1 + dw, bbox.y1 + dh # calculate offsets of move dx = (data_x - x) dy = (data_y - y) # calculate new coords x1, y1, x2, y2 = bbox.x1+dx, bbox.y1+dy, bbox.x2+dx, bbox.y2+dy if (not obj) or (obj.kind == 'compound'): # Replace compound image with rectangle try: self.canvas.delete_object_by_tag(self.picktag) except: pass self.picktag = self.canvas.add(self.dc.Rectangle(x1, y1, x2, y2, color='cyan', linestyle='dash')) else: # Update current rectangle with new coords and redraw bbox.x1, bbox.y1, bbox.x2, bbox.y2 = x1, y1, x2, y2 self.canvas.redraw(whence=3) return True def draw_cb(self, canvas, tag): obj = canvas.getObjectByTag(tag) self.draw_compound(obj, canvas) return self.redo() def edit_cb(self, canvas, obj): if obj.kind != 'rectangle': return True # Get the compound object that sits on the canvas. # Make sure edited rectangle was our pick rectangle. c_obj = self.canvas.get_object_by_tag(self.picktag) if (c_obj.kind != 'compound') or (len(c_obj.objects) < 3) or \ (c_obj.objects[0] != obj): return False # determine center of rectangle x1, y1, x2, y2 = obj.get_llur() x = x1 + (x2 - x1) // 2 y = y1 + (y2 - y1) // 2 # reposition other elements to match point = c_obj.objects[1] point.x, point.y = x, y text = c_obj.objects[2] text.x, text.y = x1, y2 + 4 self.regions.set_bbox(x1, y1, x2, y2, coord='data') return self.redo() def reset_region(self): self.dx = region_default_width self.dy = region_default_height obj = self.canvas.get_object_by_tag(self.picktag) if obj.kind != 'compound': return True bbox = obj.objects[0] # calculate center of bbox wd = bbox.x2 - bbox.x1 dw = wd // 2 ht = bbox.y2 - bbox.y1 dh = ht // 2 x, y = bbox.x1 + dw, bbox.y1 + dh # calculate new coords bbox.x1, bbox.y1, bbox.x2, bbox.y2 = (x-self.dx, y-self.dy, x+self.dx, y+self.dy) self.regions.set_bbox(bbox.x1, bbox.y1, bbox.x2, bbox.y2, coord='data') self.redo() def pan_to_pick_cb(self): if not self.pick_qs: self.fv.showStatus("Please pick an object to set the sky level!") return pan_x, pan_y = self.pick_qs.objx, self.pick_qs.objy # TODO: convert to WCS coords based on user preference self.fitsimage.set_pan(pan_x, pan_y, coord='data') return True def sky_cut(self): if not self.pick_qs: self.fv.showStatus("Please pick an object to set the sky level!") return loval = self.pick_qs.skylevel oldlo, hival = self.fitsimage.get_cut_levels() try: loval += self.delta_sky self.fitsimage.cut_levels(loval, hival) except Exception as e: self.fv.showStatus("No valid sky level: '%s'" % (loval)) def bright_cut(self): if not self.pick_qs: self.fv.showStatus("Please pick an object to set the brightness!") return skyval = self.pick_qs.skylevel hival = self.pick_qs.brightness loval, oldhi = self.fitsimage.get_cut_levels() try: # brightness is measured ABOVE sky level hival = skyval + hival + self.delta_bright self.fitsimage.cut_levels(loval, hival) except Exception as e: self.fv.showStatus("No valid brightness level: '%s'" % (hival)) def zoomset(self, setting, zoomlevel, fitsimage): scalefactor = fitsimage.get_scale() self.logger.debug("scalefactor = %.2f" % (scalefactor)) text = self.fv.scale2text(scalefactor) self.wdetail.zoom.set_text(text) def detailxy(self, canvas, button, data_x, data_y): """Motion event in the pick fits window. Show the pointing information under the cursor. """ if button == 0: # TODO: we could track the focus changes to make this check # more efficient fitsimage = self.fv.getfocus_fitsimage() # Don't update global information if our fitsimage isn't focused if fitsimage != self.fitsimage: return True # Add offsets from cutout data_x = data_x + self.pick_x1 data_y = data_y + self.pick_y1 return self.fv.showxy(self.fitsimage, data_x, data_y) def cutdetail(self, srcimage, dstimage, x1, y1, x2, y2): image = srcimage.get_image() data, x1, y1, x2, y2 = image.cutout_adjust(x1, y1, x2, y2) dstimage.set_data(data) return (x1, y1, x2, y2, data) def pan_plot(self, xdelta, ydelta): x1, x2 = self.w.ax.get_xlim() y1, y2 = self.w.ax.get_ylim() self.w.ax.set_xlim(x1+xdelta, x2+xdelta) self.w.ax.set_ylim(y1+ydelta, y2+ydelta) self.w.canvas.draw() def write_pick_log(self, rpt): if self.pick_log is not None: self.pick_log.write(rpt) self.pick_log.flush() def add_pick_cb(self): if self.last_rpt is not None: rpt = (self.rpt_format % self.last_rpt) + '\n' self.w.report.append_text(rpt) ## if self.pick_log: ## self.fv.nongui_do(self.write_pick_log, rpt) self.write_pick_log(rpt) def edit_select_pick(self): if self.picktag is not None: obj = self.canvas.get_object_by_tag(self.picktag) if obj.kind != 'compound': return True # drill down to reference shape bbox = obj.objects[0] self.canvas.edit_select(bbox) else: self.canvas.clear_selected() self.canvas.update_canvas() def set_mode_cb(self, mode, tf): if tf: self.canvas.set_draw_mode(mode) if mode == 'edit': self.edit_select_pick() return True def __str__(self): return 'mipick' def draw_compound(self, obj, canvas, *args): """Draw the pick info box""" if obj.kind != 'rectangle': return True canvas.deleteObject(obj) if self.picktag: try: canvas.deleteObjectByTag(self.picktag) except: pass # Get rectangle: if len(args) == 4: x1, y1, x2, y2 = args else: x1, y1, x2, y2 = obj.get_llur() # determine center of rectangle x = x1 + (x2 - x1) // 2 y = y1 + (y2 - y1) // 2 tag = canvas.add(self.dc.CompoundObject( self.dc.Rectangle(x1, y1, x2, y2, color=self.pickcolor), self.dc.Point(x, y, 10, color='red'), self.dc.Text(x1, y2+4, "Pick: calc", color=self.pickcolor))) self.picktag = tag self.region.set_bbox(x1, y1, x2, y2, coord='data')