def __init__(self, session, parent=None): self.logger = log.get_logger( name='ginga', level=20, null=True, # uncomment for debugging # log_stderr=True ) self.viewer = ImageViewCanvas(self.logger, render='widget') self.canvas = self.viewer # prevent widget from grabbing focus try: self.canvas.set_enter_focus(False) except AttributeError: self.canvas.set_follow_focus(False) # enable interactive features bindings = self.canvas.get_bindings() bindings.enable_all(True) self.canvas.add_callback('none-move', self.motion_readout) self.canvas.add_callback('draw-event', self._apply_roi_cb) self.canvas.add_callback('draw-down', self._clear_roi_cb) self.canvas.enable_draw(False) self.canvas.enable_autozoom('off') self.canvas.set_zoom_algorithm('rate') self.canvas.set_zoomrate(1.4) bm = self.canvas.get_bindmap() bm.add_callback('mode-set', self.mode_set_cb) self.mode_w = None self.mode_actns = {} # Create settings and set defaults settings = self.canvas.get_settings() self.settings = settings settings.getSetting('cuts').add_callback('set', self.cut_levels_cb) settings.set(autozoom='off', autocuts='override', autocenter='override') # make color bar, with color maps shared from ginga canvas rgbmap = self.viewer.get_rgbmap() self.colorbar = ColorBar.ColorBar(self.logger) rgbmap.add_callback('changed', self.rgbmap_cb, self.viewer) self.colorbar.set_rgbmap(rgbmap) # make coordinates/value readout self.readout = Readout.Readout(-1, 20) self.roi_tag = None super(GingaWidget, self).__init__(session, parent)
def new_client(self, dc=None, canvas=None): from glue.utils.qt import get_qapp get_qapp() dc = dc or self.collect l = log.get_logger(name='ginga', log_stderr=True) canvas = ImageViewCanvas(l, render='widget') return GingaClient(dc, canvas)
def __init__(self): """Default constructor.""" #logger = log.get_logger(log_stderr=True, level=20) logger = log.get_logger(null=True) # Initialize base class GingaCanvas.__init__(self, logger=logger) # Keep track of all patches self.patches = {} #self.zorder=10 self.get_bindings().enable_all(True) self.enable_draw(True) self.enable_edit(True) self.set_drawtype('line', color='green', cap='ball', linewidth=2) #self.add_callback('draw-event', self.draw_cb) #self.add_callback('edit-event', self.edit_cb) self.add_callback('drag-drop', self.drop_file)
def __init__(self): """Default constructor.""" #logger = log.get_logger(log_stderr=True, level=20) logger = log.get_logger(null=True) # Initialize base class GingaCanvas.__init__(self, logger=logger) # Keep track of all patches self.patches={} #self.zorder=10 self.get_bindings().enable_all(True) self.enable_draw(True) self.enable_edit(True) self.set_drawtype('line', color='green', cap='ball', linewidth=2) #self.add_callback('draw-event', self.draw_cb) #self.add_callback('edit-event', self.edit_cb) self.add_callback('drag-drop', self.drop_file)
def __init__(self, session, parent=None): self.logger = log.get_logger( name="ginga", level=20, null=True, # uncomment for debugging # log_stderr=True ) self.canvas = ImageViewCanvas(self.logger, render="widget") # prevent widget from grabbing focus try: self.canvas.set_enter_focus(False) except AttributeError: self.canvas.set_follow_focus(False) # enable interactive features bindings = self.canvas.get_bindings() bindings.enable_all(True) self.canvas.add_callback("none-move", self.motion_readout) self.canvas.add_callback("draw-event", self._apply_roi_cb) self.canvas.add_callback("draw-down", self._clear_roi_cb) self.canvas.enable_draw(False) self.canvas.enable_autozoom("off") self.canvas.set_zoom_algorithm("rate") self.canvas.set_zoomrate(1.4) bm = self.canvas.get_bindmap() bm.add_callback("mode-set", self.mode_set_cb) self.mode_w = None self.mode_actns = {} # Create settings and set defaults settings = self.canvas.get_settings() self.settings = settings settings.getSetting("cuts").add_callback("set", self.cut_levels_cb) settings.set(autozoom="off", autocuts="override", autocenter="override") # make color bar, with color maps shared from ginga canvas self.colorbar = ColorBar.ColorBar(self.logger) rgbmap = self.canvas.get_rgbmap() rgbmap.add_callback("changed", self.rgbmap_cb, self.canvas) self.colorbar.set_rgbmap(rgbmap) # make coordinates/value readout self.readout = Readout.Readout(-1, -1) self.roi_tag = None super(GingaWidget, self).__init__(session, parent)
def __init__(self, session, parent=None): self.logger = log.get_logger(name='ginga', level=20, null=True, # uncomment for debugging #log_stderr=True ) self.canvas = ImageViewCanvas(self.logger, render='widget') # prevent widget from grabbing focus self.canvas.set_follow_focus(False) # enable interactive features bindings = self.canvas.get_bindings() bindings.enable_all(True) self.canvas.add_callback('none-move', self.motion_readout) self.canvas.add_callback('draw-event', self._apply_roi_cb) self.canvas.add_callback('draw-down', self._clear_roi_cb) self.canvas.enable_draw(False) self.canvas.enable_autozoom('off') self.canvas.set_zoom_algorithm('rate') self.canvas.set_zoomrate(1.4) bm = self.canvas.get_bindmap() bm.add_callback('mode-set', self.mode_set_cb) self.mode_w = None self.mode_actns = {} # Create settings and set defaults settings = self.canvas.get_settings() self.settings = settings settings.getSetting('cuts').add_callback('set', self.cut_levels_cb) settings.set(autozoom='off', autocuts='override', autocenter='override') # make color bar, with color maps shared from ginga canvas self.colorbar = ColorBar.ColorBar(self.logger) rgbmap = self.canvas.get_rgbmap() rgbmap.add_callback('changed', self.rgbmap_cb, self.canvas) self.colorbar.set_rgbmap(rgbmap) # make coordinates/value readout self.readout = Readout.Readout(-1, -1) self.roi_tag = None super(GingaWidget, self).__init__(session, parent)
def __init__(self, qtmain, logger, ev_quit, options): super(GingaVision, self).__init__() self.qtmain = qtmain self.logger = logger self.ev_quit = ev_quit self.card = 'default' # playback rate; changed when we know the actual rate self.fps = 30 self.playback_rate = 1.0 / self.fps # Use an AstroImage, not RGBImage for now because we get a # different default (faster) scaling algorithm self.pimage = AstroImage.AstroImage() self.pdata = None fi = ImageViewCanvas(self.logger, render='widget') fi.enable_autocuts('off') fi.set_autocut_params('histogram') fi.enable_autozoom('off') fi.cut_levels(0, 255) fi.defer_redraw = False fi.set_bg(0.2, 0.2, 0.2) # flip y fi.transform(False, False, False) fi.ui_setActive(True) self.fitsimage = fi # Some optomizations to smooth playback at decent FPS fi.set_redraw_lag(self.playback_rate) #fi.set_redraw_lag(0.0) fi._invertY = False # PassThruRGBMapper doesn't color map data--data is already colored rgbmap = RGBMap.PassThruRGBMapper(self.logger) fi.set_rgbmap(rgbmap) # Clip cuts assumes data does not need to be scaled in cut levels-- # only clipped fi.set_autocuts(AutoCuts.Clip(logger=self.logger)) bd = fi.get_bindings() bd.enable_pan(True) bd.enable_zoom(True) bd.enable_cuts(True) bd.enable_flip(True) bd.enable_cmap(True) w = fi.get_widget() w.resize(512, 512) vbox = QtGui.QVBoxLayout() vbox.setContentsMargins(QtCore.QMargins(2, 2, 2, 2)) vbox.setSpacing(1) vbox.addWidget(w, stretch=1) hbox = QtGui.QHBoxLayout() hbox.setContentsMargins(QtCore.QMargins(4, 2, 4, 2)) wopen = QtGui.QPushButton("Open File") #wopen.clicked.connect(self.open_file) wquit = QtGui.QPushButton("Quit") wquit.clicked.connect(self.quit) hbox.addStretch(1) for w in (wopen, wquit): hbox.addWidget(w, stretch=0) hw = QtGui.QWidget() hw.setLayout(hbox) vbox.addWidget(hw, stretch=0) vw = QtGui.QWidget() self.setCentralWidget(vw) vw.setLayout(vbox) self.setWindowTitle("Video Example Viewer")
def __init__(self, logger): super(FitsViewer, self).__init__() self.logger = logger self.drawcolors = colors.get_colors() fi = ImageViewCanvas(logger, render='widget') fi.enable_autocuts('on') fi.set_autocut_params('zscale') fi.enable_autozoom('on') fi.enable_draw(True) fi.set_drawtype('ruler') fi.set_drawcolor('blue') fi.set_callback('drag-drop', self.drop_file) fi.set_callback('none-move', self.motion) fi.set_bg(0.2, 0.2, 0.2) fi.ui_setActive(True) self.fitsimage = fi bd = fi.get_bindings() bd.enable_all(True) w = fi.get_widget() w.resize(512, 512) vbox = QtGui.QVBoxLayout() vbox.setContentsMargins(QtCore.QMargins(2, 2, 2, 2)) vbox.setSpacing(1) vbox.addWidget(w, stretch=1) self.readout = QtGui.QLabel("") vbox.addWidget(self.readout, stretch=0, alignment=QtCore.Qt.AlignCenter) hbox = QtGui.QHBoxLayout() hbox.setContentsMargins(QtCore.QMargins(4, 2, 4, 2)) wdrawtype = QtGui.QComboBox() self.drawtypes = fi.get_drawtypes() for name in self.drawtypes: wdrawtype.addItem(name) index = self.drawtypes.index('ruler') wdrawtype.setCurrentIndex(index) wdrawtype.activated.connect(self.set_drawparams) self.wdrawtype = wdrawtype wdrawcolor = QtGui.QComboBox() for name in self.drawcolors: wdrawcolor.addItem(name) index = self.drawcolors.index('blue') wdrawcolor.setCurrentIndex(index) wdrawcolor.activated.connect(self.set_drawparams) self.wdrawcolor = wdrawcolor wclear = QtGui.QPushButton("Clear Canvas") wclear.clicked.connect(self.clear_canvas) wopen = QtGui.QPushButton("Open File") wopen.clicked.connect(self.open_file) wquit = QtGui.QPushButton("Quit") wquit.clicked.connect(self.quit) hbox.addStretch(1) for w in (wopen, wdrawtype, wdrawcolor, wclear, wquit): hbox.addWidget(w, stretch=0) hw = QtGui.QWidget() hw.setLayout(hbox) vbox.addWidget(hw, stretch=0) vw = QtGui.QWidget() self.setCentralWidget(vw) vw.setLayout(vbox)
def __init__(self, logger): super(FitsViewer, self).__init__() self.logger = logger self.drawcolors = colors.get_colors() fi = ImageViewCanvas(logger, render="widget") fi.enable_autocuts("on") fi.set_autocut_params("zscale") fi.enable_autozoom("on") fi.enable_draw(True) fi.set_drawtype("ruler") fi.set_drawcolor("blue") fi.set_callback("drag-drop", self.drop_file) fi.set_callback("none-move", self.motion) fi.set_bg(0.2, 0.2, 0.2) fi.ui_setActive(True) self.fitsimage = fi bd = fi.get_bindings() bd.enable_pan(True) bd.enable_zoom(True) bd.enable_cuts(True) bd.enable_flip(True) bd.enable_rotate(True) bd.enable_cmap(True) w = fi.get_widget() w.resize(512, 512) vbox = QtGui.QVBoxLayout() vbox.setContentsMargins(QtCore.QMargins(2, 2, 2, 2)) vbox.setSpacing(1) vbox.addWidget(w, stretch=1) self.readout = QtGui.QLabel("") vbox.addWidget(self.readout, stretch=0, alignment=QtCore.Qt.AlignCenter) hbox = QtGui.QHBoxLayout() hbox.setContentsMargins(QtCore.QMargins(4, 2, 4, 2)) wdrawtype = QtGui.QComboBox() self.drawtypes = fi.get_drawtypes() for name in self.drawtypes: wdrawtype.addItem(name) index = self.drawtypes.index("ruler") wdrawtype.setCurrentIndex(index) self.connect(wdrawtype, QtCore.SIGNAL("activated(QString)"), self.set_drawparams) self.wdrawtype = wdrawtype wdrawcolor = QtGui.QComboBox() for name in self.drawcolors: wdrawcolor.addItem(name) index = self.drawcolors.index("blue") wdrawcolor.setCurrentIndex(index) self.connect(wdrawcolor, QtCore.SIGNAL("activated(QString)"), self.set_drawparams) self.wdrawcolor = wdrawcolor wclear = QtGui.QPushButton("Clear Canvas") self.connect(wclear, QtCore.SIGNAL("clicked()"), self.clear_canvas) wopen = QtGui.QPushButton("Open File") self.connect(wopen, QtCore.SIGNAL("clicked()"), self.open_file) wquit = QtGui.QPushButton("Quit") self.connect(wquit, QtCore.SIGNAL("clicked()"), self, QtCore.SLOT("close()")) hbox.addStretch(1) for w in (wopen, wdrawtype, wdrawcolor, wclear, wquit): hbox.addWidget(w, stretch=0) hw = QtGui.QWidget() hw.setLayout(hbox) vbox.addWidget(hw, stretch=0) vw = QtGui.QWidget() self.setCentralWidget(vw) vw.setLayout(vbox)
def __init__(self, logger): super(FitsViewer, self).__init__() self.logger = logger # create the ginga viewer and configure it fi = ImageViewCanvas(self.logger, render='widget') fi.enable_autocuts('on') fi.set_autocut_params('zscale') fi.enable_autozoom('on') fi.set_callback('drag-drop', self.drop_file) fi.set_bg(0.2, 0.2, 0.2) fi.ui_setActive(True) fi.enable_draw(False) self.fitsimage = fi # enable some user interaction bd = fi.get_bindings() bd.enable_all(True) w = fi.get_widget() w.resize(512, 512) # add scrollbar interface around this viewer si = ScrolledView(fi) vbox = QtGui.QVBoxLayout() vbox.setContentsMargins(QtCore.QMargins(2, 2, 2, 2)) vbox.setSpacing(1) vbox.addWidget(si, stretch=1) hbox = QtGui.QHBoxLayout() hbox.setContentsMargins(QtCore.QMargins(4, 2, 4, 2)) wopen = QtGui.QPushButton("Open File") wopen.clicked.connect(self.open_file) wquit = QtGui.QPushButton("Quit") wquit.clicked.connect(self.quit) hbox.addStretch(1) for w in (wopen, wquit): hbox.addWidget(w, stretch=0) hw = QtGui.QWidget() hw.setLayout(hbox) vbox.addWidget(hw, stretch=0) vw = QtGui.QWidget() self.setCentralWidget(vw) vw.setLayout(vbox)
def __init__(self, logger): super(FitsViewer, self).__init__() self.logger = logger fi = ImageViewCanvas(self.logger, render='widget') fi.enable_autocuts('on') fi.set_autocut_params('zscale') fi.enable_autozoom('on') fi.set_callback('drag-drop', self.drop_file) fi.set_bg(0.2, 0.2, 0.2) fi.ui_setActive(True) fi.enable_draw(False) self.fitsimage = fi bd = fi.get_bindings() bd.enable_pan(True) bd.enable_zoom(True) bd.enable_cuts(True) bd.enable_flip(True) w = fi.get_widget() w.resize(512, 512) vbox = QtGui.QVBoxLayout() vbox.setContentsMargins(QtCore.QMargins(2, 2, 2, 2)) vbox.setSpacing(1) vbox.addWidget(w, stretch=1) hbox = QtGui.QHBoxLayout() hbox.setContentsMargins(QtCore.QMargins(4, 2, 4, 2)) wopen = QtGui.QPushButton("Open File") wopen.clicked.connect(self.open_file) wquit = QtGui.QPushButton("Quit") wquit.clicked.connect(self.quit) hbox.addStretch(1) for w in (wopen, wquit): hbox.addWidget(w, stretch=0) hw = QtGui.QWidget() hw.setLayout(hbox) vbox.addWidget(hw, stretch=0) vw = QtGui.QWidget() self.setCentralWidget(vw) vw.setLayout(vbox)
class GingaWidget(ImageWidgetBase): LABEL = "Ginga Viewer" _toolbar_cls = BasicToolbar tools = ['ginga:rectangle', 'ginga:circle', 'ginga:polygon', 'ginga:lasso', 'ginga:xrange', 'ginga:yrange', 'ginga:pan', 'ginga:freepan', 'ginga:rotate', 'ginga:contrast', 'ginga:cuts', 'ginga:dist', 'ginga:colormap', 'ginga:spectrum', 'ginga:slicer'] def __init__(self, session, parent=None): self.logger = log.get_logger(name='ginga', level=20, # switch commenting for debugging null=True, log_stderr=False, #null=False, log_stderr=True ) # load binding preferences if available cfgfile = os.path.join(ginga_home, "bindings.cfg") bindprefs = SettingGroup(name='bindings', logger=self.logger, preffile=cfgfile) bindprefs.load(onError='silent') bd = ImageViewBindings(self.logger, settings=bindprefs) # make Ginga viewer self.viewer = ImageViewCanvas(self.logger, render='widget', bindings=bd) self.canvas = self.viewer # prevent widget from grabbing focus self.viewer.set_enter_focus(False) self.viewer.set_desired_size(300, 300) # enable interactive features bindings = self.viewer.get_bindings() bindings.enable_all(True) self.canvas.add_callback('none-move', self.motion_readout) self.canvas.register_for_cursor_drawing(self.viewer) self.canvas.add_callback('draw-event', self._apply_roi_cb) self.canvas.add_callback('edit-event', self._update_roi_cb) self.canvas.add_callback('draw-down', self._clear_roi_cb) self.canvas.enable_draw(False) self.canvas.enable_edit(False) self.viewer.enable_autozoom('off') self.viewer.set_zoom_algorithm('rate') self.viewer.set_zoomrate(1.4) self.viewer.set_fg(*colors.lookup_color("#D0F0E0")) bm = self.viewer.get_bindmap() bm.add_callback('mode-set', self.mode_set_cb) self.mode_w = None self.mode_actns = {} # Create settings and set defaults settings = self.viewer.get_settings() self.settings = settings settings.getSetting('cuts').add_callback('set', self.cut_levels_cb) settings.set(autozoom='off', autocuts='override', autocenter='override') # make color bar, with color maps shared from ginga canvas rgbmap = self.viewer.get_rgbmap() self.colorbar = ColorBar.ColorBar(self.logger) rgbmap.add_callback('changed', self.rgbmap_cb, self.viewer) self.colorbar.set_rgbmap(rgbmap) # make coordinates/value readout self.readout = Readout.Readout(-1, 20) self.roi_tag = None self.opn_obj = None super(GingaWidget, self).__init__(session, parent) def make_client(self): return GingaClient(self._data, self.viewer, self._layer_artist_container) def make_central_widget(self): topw = QtWidgets.QWidget() layout = QtWidgets.QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) layout.addWidget(self.viewer.get_widget(), stretch=1) cbar_w = self.colorbar.get_widget() if not isinstance(cbar_w, QtWidgets.QWidget): # ginga wrapped widget cbar_w = cbar_w.get_widget() layout.addWidget(cbar_w, stretch=0) readout_w = self.readout.get_widget() if not isinstance(readout_w, QtWidgets.QWidget): # ginga wrapped widget readout_w = readout_w.get_widget() layout.addWidget(readout_w, stretch=0) topw.setLayout(layout) return topw def match_colorbar(self, canvas, colorbar): rgbmap = self.viewer.get_rgbmap() loval, hival = self.viewer.get_cut_levels() colorbar.set_range(loval, hival) colorbar.set_rgbmap(rgbmap) def rgbmap_cb(self, rgbmap, canvas): self.match_colorbar(canvas, self.colorbar) def cut_levels_cb(self, setting, tup): (loval, hival) = tup self.colorbar.set_range(loval, hival) def _set_roi_mode(self, opn_obj, name, mode, **kwargs): self.opn_obj = opn_obj en_draw = (mode == 'draw') self.canvas.enable_draw(en_draw) self.canvas.set_draw_mode(mode) # XXX need better way of setting draw contexts self.canvas.draw_context = self self.canvas.set_drawtype(name, **kwargs) ## bm = self.viewer.get_bindmap() ## bm.set_mode('draw', mode_type='locked') def _clear_roi_cb(self, canvas, *args): if self.opn_obj is not None: self.opn_obj.opn_init(self, self.roi_tag) else: try: self.canvas.delete_object_by_tag(self.roi_tag) except: pass def _apply_roi_cb(self, canvas, tag): if self.canvas.draw_context is not self: return self.roi_tag = tag obj = self.canvas.get_object_by_tag(tag) if self.opn_obj is None: # delete outline self.canvas.delete_object(obj) self.roi_tag = None return self.opn_obj.opn_exec(self, tag, obj) def _update_roi_cb(self, canvas, obj): if self.canvas.draw_context is not self: return if self.opn_obj is None: return self.opn_obj.opn_update(self, obj) def _tweak_geometry(self): super(GingaWidget, self)._tweak_geometry() # rgb mode not supported yet, so hide option self.ui.monochrome.hide() self.ui.rgb.hide() def motion_readout(self, canvas, button, data_x, data_y): """This method is called when the user moves the mouse around the Ginga canvas. """ d = self.client.point_details(data_x, data_y) # Get the value under the data coordinates try: # value = fitsimage.get_data(data_x, data_y) # We report the value across the pixel, even though the coords # change halfway across the pixel value = self.viewer.get_data(int(data_x + 0.5), int(data_y + 0.5)) except Exception: value = None x_lbl, y_lbl = d['labels'][0], d['labels'][1] # x_txt, y_txt = d['world'][0], d['world'][1] text = "%s %s X=%.2f Y=%.2f Value=%s" % ( x_lbl, y_lbl, data_x, data_y, value) self.readout.set_text(text) def mode_cb(self, modname, tf): """This method is called when a toggle button in the toolbar is pressed selecting one of the modes. """ bm = self.viewer.get_bindmap() if not tf: bm.reset_mode(self.viewer) return bm.set_mode(modname, mode_type='locked') return True def mode_set_cb(self, bm, modname, mtype): """This method is called when a mode is selected in the viewer widget. NOTE: it may be called when mode_cb() is not called (for example, when a keypress initiates a mode); however, the converse is not true: calling mode_cb() will always result in this method also being called as a result. This logic is to insure that the toggle buttons are left in a sane state that reflects the current mode, however it was initiated. """ if modname in self.mode_actns: if self.mode_w and (self.mode_w != self.mode_actns[modname]): self.mode_w.setChecked(False) self.mode_w = self.mode_actns[modname] self.mode_w.setChecked(True) elif self.mode_w: # keystroke turned on a mode for which we have no GUI button # and a GUI button is selected--unselect it self.mode_w.setChecked(False) self.mode_w = None return True
def __init__(self, logger): super(FitsViewer, self).__init__() self.logger = logger self.drawcolors = colors.get_colors() fi = ImageViewCanvas(logger, render='widget') fi.enable_autocuts('on') fi.set_autocut_params('zscale') fi.enable_autozoom('on') fi.set_zoom_algorithm('rate') fi.set_zoomrate(1.4) fi.show_pan_mark(True) fi.enable_draw(False) fi.set_callback('drag-drop', self.drop_file) fi.set_callback('none-move', self.motion) fi.set_bg(0.2, 0.2, 0.2) fi.ui_setActive(True) self.fitsimage = fi bd = fi.get_bindings() bd.enable_all(True) # canvas that we will draw on canvas = DrawingCanvas() canvas.enable_draw(True) canvas.set_drawtype('rectangle', color='lightblue') canvas.setSurface(fi) self.canvas = canvas # add canvas to view fi.add(canvas) canvas.ui_setActive(True) canvas.set_callback('cursor-down', self.clicked) w = fi.get_widget() w.resize(512, 512) vbox = QtGui.QVBoxLayout() vbox.setContentsMargins(QtCore.QMargins(2, 2, 2, 2)) vbox.setSpacing(1) vbox.addWidget(w, stretch=1) self.readout = QtGui.QLabel("") vbox.addWidget(self.readout, stretch=0, alignment=QtCore.Qt.AlignCenter) hbox = QtGui.QHBoxLayout() hbox.setContentsMargins(QtCore.QMargins(4, 2, 4, 2)) wdrawtype = QtGui.QComboBox() self.drawtypes = fi.get_drawtypes() for name in self.drawtypes: wdrawtype.addItem(name) index = self.drawtypes.index('rectangle') wdrawtype.setCurrentIndex(index) wdrawtype.activated.connect(self.set_drawparams) self.wdrawtype = wdrawtype wdrawcolor = QtGui.QComboBox() for name in self.drawcolors: wdrawcolor.addItem(name) index = self.drawcolors.index('lightblue') wdrawcolor.setCurrentIndex(index) wdrawcolor.activated.connect(self.set_drawparams) self.wdrawcolor = wdrawcolor wfill = QtGui.QCheckBox("Fill") wfill.stateChanged.connect(self.set_drawparams) self.wfill = wfill walpha = QtGui.QDoubleSpinBox() walpha.setRange(0.0, 1.0) walpha.setSingleStep(0.1) walpha.setValue(1.0) walpha.valueChanged.connect(self.set_drawparams) self.walpha = walpha wclear = QtGui.QPushButton("Clear Canvas") wclear.clicked.connect(self.clear_canvas) wopen = QtGui.QPushButton("Open File") wopen.clicked.connect(self.open_file) wquit = QtGui.QPushButton("Quit") wquit.clicked.connect(self.quit) hbox.addStretch(1) for w in (wopen, wdrawtype, wdrawcolor, wfill, QtGui.QLabel('Alpha:'), walpha, wclear, wquit): hbox.addWidget(w, stretch=0) hw = QtGui.QWidget() hw.setLayout(hbox) vbox.addWidget(hw, stretch=0) vw = QtGui.QWidget() self.setCentralWidget(vw) vw.setLayout(vbox)
def __init__(self, session, parent=None): self.logger = log.get_logger(name='ginga', level=20, # switch commenting for debugging null=True, log_stderr=False, #null=False, log_stderr=True ) # load binding preferences if available cfgfile = os.path.join(ginga_home, "bindings.cfg") bindprefs = SettingGroup(name='bindings', logger=self.logger, preffile=cfgfile) bindprefs.load(onError='silent') bd = ImageViewBindings(self.logger, settings=bindprefs) # make Ginga viewer self.viewer = ImageViewCanvas(self.logger, render='widget', bindings=bd) self.canvas = self.viewer # prevent widget from grabbing focus self.viewer.set_enter_focus(False) self.viewer.set_desired_size(300, 300) # enable interactive features bindings = self.viewer.get_bindings() bindings.enable_all(True) self.canvas.add_callback('none-move', self.motion_readout) self.canvas.register_for_cursor_drawing(self.viewer) self.canvas.add_callback('draw-event', self._apply_roi_cb) self.canvas.add_callback('edit-event', self._update_roi_cb) self.canvas.add_callback('draw-down', self._clear_roi_cb) self.canvas.enable_draw(False) self.canvas.enable_edit(False) self.viewer.enable_autozoom('off') self.viewer.set_zoom_algorithm('rate') self.viewer.set_zoomrate(1.4) self.viewer.set_fg(*colors.lookup_color("#D0F0E0")) bm = self.viewer.get_bindmap() bm.add_callback('mode-set', self.mode_set_cb) self.mode_w = None self.mode_actns = {} # Create settings and set defaults settings = self.viewer.get_settings() self.settings = settings settings.getSetting('cuts').add_callback('set', self.cut_levels_cb) settings.set(autozoom='off', autocuts='override', autocenter='override') # make color bar, with color maps shared from ginga canvas rgbmap = self.viewer.get_rgbmap() self.colorbar = ColorBar.ColorBar(self.logger) rgbmap.add_callback('changed', self.rgbmap_cb, self.viewer) self.colorbar.set_rgbmap(rgbmap) # make coordinates/value readout self.readout = Readout.Readout(-1, 20) self.roi_tag = None self.opn_obj = None super(GingaWidget, self).__init__(session, parent)
class GingaWidget(ImageWidgetBase): LABEL = "Ginga Viewer" def __init__(self, session, parent=None): self.logger = log.get_logger(name='ginga', log_stderr=True) self.canvas = ImageViewCanvas(self.logger, render='widget') # prevent widget from grabbing focus self.canvas.set_follow_focus(False) self.canvas.enable_overlays(True) # enable interactive features bindings = self.canvas.get_bindings() bindings.enable_all(True) self.canvas.set_callback('none-move', self.motion_readout) self.canvas.set_callback('draw-event', self._apply_roi_cb) self.canvas.set_callback('draw-down', self._clear_roi_cb) self.canvas.enable_draw(False) self.canvas.enable_autozoom('off') self.canvas.set_zoom_algorithm('rate') self.canvas.set_zoomrate(1.4) bm = self.canvas.get_bindmap() bm.add_callback('mode-set', self.mode_set_cb) self.mode_w = None self.mode_actns = {} # Create settings and set defaults settings = self.canvas.get_settings() self.settings = settings settings.getSetting('cuts').add_callback('set', self.cut_levels_cb) settings.set(autozoom='off', autocuts='override', autocenter='override') # make color bar, with color maps shared from ginga canvas self.colorbar = ColorBar.ColorBar(self.logger) rgbmap = self.canvas.get_rgbmap() rgbmap.add_callback('changed', self.rgbmap_cb, self.canvas) self.colorbar.set_rgbmap(rgbmap) # make coordinates/value readout self.readout = Readout.Readout(-1, -1) self.roi_tag = None super(GingaWidget, self).__init__(session, parent) @staticmethod def _get_default_tools(): return [] def make_client(self): return GingaClient(self._data, self.canvas, self._container) def make_central_widget(self): topw = QWidget() layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) layout.addWidget(self.canvas.get_widget(), stretch=1) layout.addWidget(self.colorbar, stretch=0) layout.addWidget(self.readout.get_widget(), stretch=0) topw.setLayout(layout) return topw def match_colorbar(self, canvas, colorbar): rgbmap = canvas.get_rgbmap() loval, hival = canvas.get_cut_levels() colorbar.set_range(loval, hival, redraw=False) colorbar.set_rgbmap(rgbmap) def rgbmap_cb(self, rgbmap, canvas): self.match_colorbar(canvas, self.colorbar) def cut_levels_cb(self, setting, tup): (loval, hival) = tup self.colorbar.set_range(loval, hival) def make_toolbar(self): tb = QToolBar(parent=self) tb.setIconSize(QSize(25, 25)) tb.layout().setSpacing(1) tb.setFocusPolicy(Qt.StrongFocus) agroup = QActionGroup(tb) agroup.setExclusive(True) for (mode_text, mode_icon, mode_cb) in self._mouse_modes(): # TODO: add icons similar to the Matplotlib toolbar action = tb.addAction(mode_icon, mode_text) action.setCheckable(True) action.toggled.connect(mode_cb) agroup.addAction(action) action = tb.addAction(get_icon('glue_move'), "Pan") self.mode_actns['pan'] = action action.setCheckable(True) action.toggled.connect(lambda tf: self.mode_cb('pan', tf)) agroup.addAction(action) icon = QIcon(os.path.join(ginga_icon_dir, 'hand_48.png')) action = tb.addAction(icon, "Free Pan") self.mode_actns['freepan'] = action action.setCheckable(True) action.toggled.connect(lambda tf: self.mode_cb('freepan', tf)) agroup.addAction(action) icon = QIcon(os.path.join(ginga_icon_dir, 'rotate_48.png')) action = tb.addAction(icon, "Rotate") self.mode_actns['rotate'] = action action.setCheckable(True) action.toggled.connect(lambda tf: self.mode_cb('rotate', tf)) agroup.addAction(action) action = tb.addAction(get_icon('glue_contrast'), "Contrast") self.mode_actns['contrast'] = action action.setCheckable(True) action.toggled.connect(lambda tf: self.mode_cb('contrast', tf)) agroup.addAction(action) icon = QIcon(os.path.join(ginga_icon_dir, 'cuts_48.png')) action = tb.addAction(icon, "Cuts") self.mode_actns['cuts'] = action action.setCheckable(True) action.toggled.connect(lambda tf: self.mode_cb('cuts', tf)) agroup.addAction(action) cmap_w = _colormap_mode(self, self.client.set_cmap) tb.addWidget(cmap_w) return tb def _mouse_modes(self): modes = [] modes.append(("Rectangle", get_icon('glue_square'), lambda tf: self._set_roi_mode('rectangle', tf))) modes.append(("Circle", get_icon('glue_circle'), lambda tf: self._set_roi_mode('circle', tf))) modes.append(("Polygon", get_icon('glue_lasso'), lambda tf: self._set_roi_mode('polygon', tf))) for tool in self._tools: modes += tool._get_modes(self.canvas) add_callback(self.client, 'display_data', tool._display_data_hook) return modes def _set_roi_mode(self, name, tf): self.canvas.enable_draw(True) # XXX need better way of setting draw contexts self.canvas.draw_context = self self.canvas.set_drawtype(name, color='cyan', linestyle='dash') bm = self.canvas.get_bindmap() bm.set_modifier('draw', modtype='locked') def _clear_roi_cb(self, canvas, *args): try: self.canvas.deleteObjectByTag(self.roi_tag) except: pass def _apply_roi_cb(self, canvas, tag): if self.canvas.draw_context is not self: return self.roi_tag = tag obj = self.canvas.getObjectByTag(self.roi_tag) roi = ginga_graphic_to_roi(obj) # delete outline self.canvas.deleteObject(obj, redraw=False) self.apply_roi(roi) def _tweak_geometry(self): super(GingaWidget, self)._tweak_geometry() # rgb mode not supported yet, so hide option self.ui.monochrome.hide() self.ui.rgb.hide() def motion_readout(self, canvas, button, data_x, data_y): """This method is called when the user moves the mouse around the Ginga canvas. """ d = self.client.point_details(data_x, data_y) # Get the value under the data coordinates try: # value = fitsimage.get_data(data_x, data_y) # We report the value across the pixel, even though the coords # change halfway across the pixel value = canvas.get_data(int(data_x + 0.5), int(data_y + 0.5)) except Exception: value = None x_lbl, y_lbl = d['labels'][0], d['labels'][1] # x_txt, y_txt = d['world'][0], d['world'][1] text = "%s %s X=%.2f Y=%.2f Value=%s" % ( x_lbl, y_lbl, data_x, data_y, value) self.readout.set_text(text) def mode_cb(self, modname, tf): """This method is called when a toggle button in the toolbar is pressed selecting one of the modes. """ bm = self.canvas.get_bindmap() if not tf: bm.reset_modifier(self.canvas) return bm.set_modifier(modname, modtype='locked') return True def mode_set_cb(self, bm, modname, mtype): """This method is called when a mode is selected in the viewer widget. NOTE: it may be called when mode_cb() is not called (for example, when a keypress initiates a mode); however, the converse is not true: calling mode_cb() will always result in this method also being called as a result. This logic is to insure that the toggle buttons are left in a sane state that reflects the current mode, however it was initiated. """ if modname in self.mode_actns: if self.mode_w and (self.mode_w != self.mode_actns[modname]): self.mode_w.setChecked(False) self.mode_w = self.mode_actns[modname] self.mode_w.setChecked(True) elif self.mode_w: # keystroke turned on a mode for which we have no GUI button # and a GUI button is selected--unselect it self.mode_w.setChecked(False) self.mode_w = None return True
def __init__(self, logger): super(PDS4ImageViewer, self).__init__() self.logger = logger pi = ImageViewCanvas(self.logger, render='widget') pi.enable_autocuts('on') pi.set_autocut_params('zscale') pi.enable_autozoom('on') pi.set_callback('drag-drop', self.drop_file) pi.set_bg(0.2, 0.2, 0.2) pi.ui_setActive(True) pi.enable_draw(False) self.pds4image = pi bd = pi.get_bindings() bd.enable_all(True) w = pi.get_widget() w.resize(512, 512) vbox = QtGui.QVBoxLayout() vbox.setContentsMargins(QtCore.QMargins(2, 2, 2, 2)) vbox.setSpacing(1) vbox.addWidget(w, stretch=1) hbox = QtGui.QHBoxLayout() hbox.setContentsMargins(QtCore.QMargins(4, 2, 4, 2)) wopen = QtGui.QPushButton("Open File") wopen.clicked.connect(self.open_file) wquit = QtGui.QPushButton("Quit") wquit.clicked.connect(self.quit) hbox.addStretch(1) for w in (wopen, wquit): hbox.addWidget(w, stretch=0) hw = QtGui.QWidget() hw.setLayout(hbox) vbox.addWidget(hw, stretch=0) vw = QtGui.QWidget() self.setCentralWidget(vw) vw.setLayout(vbox)
class GingaWidget(ImageWidgetBase): LABEL = "Ginga Viewer" _toolbar_cls = BasicToolbar tools = ['ginga:rectangle', 'ginga:circle', 'ginga:polygon', 'ginga:pan', 'ginga:freepan', 'ginga:rotate', 'ginga:contrast', 'ginga:cuts', 'ginga:colormap', 'ginga:slicer', 'ginga:spectrum'] def __init__(self, session, parent=None): self.logger = log.get_logger(name='ginga', level=20, null=True, # uncomment for debugging # log_stderr=True ) self.viewer = ImageViewCanvas(self.logger, render='widget') self.canvas = self.viewer # prevent widget from grabbing focus try: self.canvas.set_enter_focus(False) except AttributeError: self.canvas.set_follow_focus(False) # enable interactive features bindings = self.canvas.get_bindings() bindings.enable_all(True) self.canvas.add_callback('none-move', self.motion_readout) self.canvas.add_callback('draw-event', self._apply_roi_cb) self.canvas.add_callback('draw-down', self._clear_roi_cb) self.canvas.enable_draw(False) self.canvas.enable_autozoom('off') self.canvas.set_zoom_algorithm('rate') self.canvas.set_zoomrate(1.4) bm = self.canvas.get_bindmap() bm.add_callback('mode-set', self.mode_set_cb) self.mode_w = None self.mode_actns = {} # Create settings and set defaults settings = self.canvas.get_settings() self.settings = settings settings.getSetting('cuts').add_callback('set', self.cut_levels_cb) settings.set(autozoom='off', autocuts='override', autocenter='override') # make color bar, with color maps shared from ginga canvas rgbmap = self.viewer.get_rgbmap() self.colorbar = ColorBar.ColorBar(self.logger) rgbmap.add_callback('changed', self.rgbmap_cb, self.viewer) self.colorbar.set_rgbmap(rgbmap) # make coordinates/value readout self.readout = Readout.Readout(-1, 20) self.roi_tag = None super(GingaWidget, self).__init__(session, parent) def make_client(self): return GingaClient(self._data, self.viewer, self._layer_artist_container) def make_central_widget(self): topw = QtWidgets.QWidget() layout = QtWidgets.QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) layout.addWidget(self.viewer.get_widget(), stretch=1) cbar_w = self.colorbar.get_widget() if not isinstance(cbar_w, QtWidgets.QWidget): # ginga wrapped widget cbar_w = cbar_w.get_widget() layout.addWidget(cbar_w, stretch=0) readout_w = self.readout.get_widget() if not isinstance(readout_w, QtWidgets.QWidget): # ginga wrapped widget readout_w = readout_w.get_widget() layout.addWidget(readout_w, stretch=0) topw.setLayout(layout) return topw def match_colorbar(self, canvas, colorbar): rgbmap = self.viewer.get_rgbmap() loval, hival = self.viewer.get_cut_levels() colorbar.set_range(loval, hival) colorbar.set_rgbmap(rgbmap) def rgbmap_cb(self, rgbmap, canvas): self.match_colorbar(canvas, self.colorbar) def cut_levels_cb(self, setting, tup): (loval, hival) = tup self.colorbar.set_range(loval, hival) def _set_roi_mode(self, name, tf): self.canvas.enable_draw(True) # XXX need better way of setting draw contexts self.canvas.draw_context = self self.canvas.set_drawtype(name, color='cyan', linestyle='dash') bm = self.viewer.get_bindmap() bm.set_mode('draw', mode_type='locked') def _clear_roi_cb(self, canvas, *args): try: self.canvas.deleteObjectByTag(self.roi_tag) except: pass def _apply_roi_cb(self, canvas, tag): if self.canvas.draw_context is not self: return self.roi_tag = tag obj = self.canvas.getObjectByTag(self.roi_tag) roi = ginga_graphic_to_roi(obj) # delete outline self.canvas.deleteObject(obj, redraw=False) self.apply_roi(roi) def _tweak_geometry(self): super(GingaWidget, self)._tweak_geometry() # rgb mode not supported yet, so hide option self.ui.monochrome.hide() self.ui.rgb.hide() def motion_readout(self, canvas, button, data_x, data_y): """This method is called when the user moves the mouse around the Ginga canvas. """ d = self.client.point_details(data_x, data_y) # Get the value under the data coordinates try: # value = fitsimage.get_data(data_x, data_y) # We report the value across the pixel, even though the coords # change halfway across the pixel value = self.viewer.get_data(int(data_x + 0.5), int(data_y + 0.5)) except Exception: value = None x_lbl, y_lbl = d['labels'][0], d['labels'][1] # x_txt, y_txt = d['world'][0], d['world'][1] text = "%s %s X=%.2f Y=%.2f Value=%s" % ( x_lbl, y_lbl, data_x, data_y, value) self.readout.set_text(text) def mode_cb(self, modname, tf): """This method is called when a toggle button in the toolbar is pressed selecting one of the modes. """ bm = self.viewer.get_bindmap() if not tf: bm.reset_mode(self.viewer) return bm.set_mode(modname, mode_type='locked') return True def mode_set_cb(self, bm, modname, mtype): """This method is called when a mode is selected in the viewer widget. NOTE: it may be called when mode_cb() is not called (for example, when a keypress initiates a mode); however, the converse is not true: calling mode_cb() will always result in this method also being called as a result. This logic is to insure that the toggle buttons are left in a sane state that reflects the current mode, however it was initiated. """ if modname in self.mode_actns: if self.mode_w and (self.mode_w != self.mode_actns[modname]): self.mode_w.setChecked(False) self.mode_w = self.mode_actns[modname] self.mode_w.setChecked(True) elif self.mode_w: # keystroke turned on a mode for which we have no GUI button # and a GUI button is selected--unselect it self.mode_w.setChecked(False) self.mode_w = None return True
def __init__(self, image_set): super(PDSViewer, self).__init__() self.image_set = image_set self.image_set.register(self) self.controller = PDSController(self.image_set, self) # Set the sub window names here. This implementation will help prevent # the main window from spawning duplicate children. Even if the # duplication prevention is not set up for a window, this will be a # handy reference list of windows(or dialogs in most cases) that can # be spawned out of this window. self._label_window = None self._label_window_pos = None self.channels_window = None self.channels_window_is_open = False self.channels_window_pos = None self.view_canvas = ImageViewCanvas(render='widget') self.view_canvas.set_autocut_params('zscale') self.view_canvas.enable_autozoom('override') self.view_canvas.enable_autocuts('override') self.view_canvas.set_callback('drag-drop', self.drop_file) self.view_canvas.set_bg(0.5, 0.5, 0.5) self.view_canvas.ui_setActive(True) self.view_canvas.get_bindings().enable_all(True) # Activate left mouse click to display values self.view_canvas.set_callback('cursor-down', self.display_values) # Activate click and drag to update values self.view_canvas.set_callback('cursor-move', self.display_values) self.view_canvas.set_callback('draw-down', self.start_ROI) self.view_canvas.set_callback('draw-up', self.stop_ROI) self.view_canvas.enable_draw(True) self.view_canvas.set_drawtype('rectangle') main_layout = QtWidgets.QGridLayout() # self.open_label is need as an attribute to determine whether the user # should be able to open the label window. The other side of this # toggle is found in load_file(). open_file = QtWidgets.QPushButton("Open File") open_file.clicked.connect(self.open_file) self.next_image_btn = QtWidgets.QPushButton("Next") self.next_image_btn.clicked.connect(self.next_image) self.next_image_btn.setEnabled(image_set.next_prev_enabled) self.previous_image_btn = QtWidgets.QPushButton("Previous") self.previous_image_btn.clicked.connect(self.previous_image) self.previous_image_btn.setEnabled(image_set.next_prev_enabled) self.open_label = QtWidgets.QPushButton("Label") self.open_label.clicked.connect(self.display_label) quit_button = QtWidgets.QPushButton("Quit") quit_button.clicked.connect(self.quit) self.rgb_check_box = QtWidgets.QCheckBox("RGB") self.rgb_check_box.stateChanged.connect(self.switch_rgb) self.next_channel_btn = QtWidgets.QPushButton('CH +') self.next_channel_btn.clicked.connect(self.next_channel) self.previous_channel_btn = QtWidgets.QPushButton('CH -') self.previous_channel_btn.clicked.connect(self.previous_channel) self.restore_defaults = QtWidgets.QPushButton("Restore Defaults") self.restore_defaults.clicked.connect(self.restore) self.channels_button = QtWidgets.QPushButton("Channels") self.channels_button.clicked.connect(self.channels_dialog) # Set Text so the size of the boxes are at an appropriate size self.x_value_lbl = QtWidgets.QLabel('X: #####') self.y_value_lbl = QtWidgets.QLabel('Y: #####') self.pixel_value_lbl = QtWidgets.QLabel( 'R: ######, G: ###### B: ######') self.pixels = QtWidgets.QLabel('#Pixels: #######') self.std_dev = QtWidgets.QLabel( 'Std Dev: R: ######### G: ######### B: #########') self.mean = QtWidgets.QLabel( 'Mean: R: ######## G: ######## B: ########') self.median = QtWidgets.QLabel( 'Median: R: ######## G: ######## B: ########') self.min = QtWidgets.QLabel('Min: R: ### G: ### B: ###') self.max = QtWidgets.QLabel('Max: R: ### G: ### B: ###') main_layout.setHorizontalSpacing(10) # Set format for each information box to be the same for info_box in (self.x_value_lbl, self.y_value_lbl, self.pixel_value_lbl, self.pixels, self.std_dev, self.mean, self.median, self.min, self.max): info_box.setFrameShape(QtWidgets.QFrame.Panel) info_box.setFrameShadow(QtWidgets.QFrame.Sunken) info_box.setLineWidth(3) info_box.setMidLineWidth(1) info_box.setAlignment(QtCore.Qt.AlignBottom | QtCore.Qt.AlignLeft) for main_box, second_box in ((self.std_dev, self.pixels), (self.mean, self.median), (self.min, self.max)): main_box.setMinimumSize(main_box.sizeHint()) main_box.setMaximumSize(main_box.sizeHint()) second_box.setMinimumSize(main_box.sizeHint()) second_box.setMaximumSize(main_box.sizeHint()) self.histogram = HistogramModel(self.view_canvas, bins=100) self.histogram_widget = HistogramWidget(self.histogram) min_width = self.histogram_widget.histogram.width() for widget in (open_file, self.next_image_btn, self.previous_image_btn, self.channels_button, self.open_label, self.restore_defaults, self.rgb_check_box, self.x_value_lbl, self.y_value_lbl, quit_button, self.next_channel_btn, self.previous_channel_btn, self.pixel_value_lbl): widget.setMinimumWidth(min_width) widget.setMaximumWidth(min_width) fixed_size = self.pixel_value_lbl.sizeHint().width() self.x_value_lbl.setMinimumWidth(fixed_size / 2) self.x_value_lbl.setMaximumWidth(fixed_size / 2) self.y_value_lbl.setMinimumWidth(fixed_size / 2) self.y_value_lbl.setMaximumWidth(fixed_size / 2) column_spacing_x_y = 5 self.pixel_value_lbl.setMinimumWidth(fixed_size + column_spacing_x_y) self.pixel_value_lbl.setMaximumWidth(fixed_size + column_spacing_x_y) main_layout.addWidget(open_file, 0, 0) main_layout.addWidget(quit_button, 0, 1) main_layout.addWidget(self.pixels, 0, 2) main_layout.addWidget(self.mean, 0, 3) main_layout.addWidget(self.min, 0, 4) main_layout.addWidget(self.previous_image_btn, 1, 0) main_layout.addWidget(self.next_image_btn, 1, 1) main_layout.addWidget(self.std_dev, 1, 2) main_layout.addWidget(self.median, 1, 3) main_layout.addWidget(self.max, 1, 4) main_layout.addWidget(self.previous_channel_btn, 2, 0) main_layout.addWidget(self.next_channel_btn, 2, 1) main_layout.addWidget(self.channels_button, 3, 0) main_layout.addWidget(self.open_label, 3, 1) main_layout.addWidget(self.restore_defaults, 4, 0) main_layout.addWidget(self.rgb_check_box, 4, 1) main_layout.addWidget(self.histogram_widget, 5, 0, 2, 2) x_y_layout = QtWidgets.QGridLayout() x_y_layout.setHorizontalSpacing(column_spacing_x_y) x_y_layout.addWidget(self.x_value_lbl, 0, 0) x_y_layout.addWidget(self.y_value_lbl, 0, 1) main_layout.addLayout(x_y_layout, 7, 0) main_layout.addWidget(self.pixel_value_lbl, 8, 0, 1, 2) main_layout.addWidget(self.view_canvas.get_widget(), 2, 2, 9, 4) main_layout.setRowStretch(9, 1) main_layout.setColumnStretch(5, 1) vw = QtWidgets.QWidget() self.setCentralWidget(vw) vw.setLayout(main_layout) self.view_canvas.set_desired_size(100, 100) if self.image_set.current_image: self.display_image() self._reset_display_values()
class PDSViewer(QtWidgets.QMainWindow): """A display of a single image with the option to view other images Parameters ---------- image_set: list A list of ginga objects with attributes set in ImageStamp""" def __init__(self, image_set): super(PDSViewer, self).__init__() self.image_set = image_set self.image_set.register(self) self.controller = PDSController(self.image_set, self) # Set the sub window names here. This implementation will help prevent # the main window from spawning duplicate children. Even if the # duplication prevention is not set up for a window, this will be a # handy reference list of windows(or dialogs in most cases) that can # be spawned out of this window. self._label_window = None self._label_window_pos = None self.channels_window = None self.channels_window_is_open = False self.channels_window_pos = None self.view_canvas = ImageViewCanvas(render='widget') self.view_canvas.set_autocut_params('zscale') self.view_canvas.enable_autozoom('override') self.view_canvas.enable_autocuts('override') self.view_canvas.set_callback('drag-drop', self.drop_file) self.view_canvas.set_bg(0.5, 0.5, 0.5) self.view_canvas.ui_setActive(True) self.view_canvas.get_bindings().enable_all(True) # Activate left mouse click to display values self.view_canvas.set_callback('cursor-down', self.display_values) # Activate click and drag to update values self.view_canvas.set_callback('cursor-move', self.display_values) self.view_canvas.set_callback('draw-down', self.start_ROI) self.view_canvas.set_callback('draw-up', self.stop_ROI) self.view_canvas.enable_draw(True) self.view_canvas.set_drawtype('rectangle') main_layout = QtWidgets.QGridLayout() # self.open_label is need as an attribute to determine whether the user # should be able to open the label window. The other side of this # toggle is found in load_file(). open_file = QtWidgets.QPushButton("Open File") open_file.clicked.connect(self.open_file) self.next_image_btn = QtWidgets.QPushButton("Next") self.next_image_btn.clicked.connect(self.next_image) self.next_image_btn.setEnabled(image_set.next_prev_enabled) self.previous_image_btn = QtWidgets.QPushButton("Previous") self.previous_image_btn.clicked.connect(self.previous_image) self.previous_image_btn.setEnabled(image_set.next_prev_enabled) self.open_label = QtWidgets.QPushButton("Label") self.open_label.clicked.connect(self.display_label) quit_button = QtWidgets.QPushButton("Quit") quit_button.clicked.connect(self.quit) self.rgb_check_box = QtWidgets.QCheckBox("RGB") self.rgb_check_box.stateChanged.connect(self.switch_rgb) self.next_channel_btn = QtWidgets.QPushButton('CH +') self.next_channel_btn.clicked.connect(self.next_channel) self.previous_channel_btn = QtWidgets.QPushButton('CH -') self.previous_channel_btn.clicked.connect(self.previous_channel) self.restore_defaults = QtWidgets.QPushButton("Restore Defaults") self.restore_defaults.clicked.connect(self.restore) self.channels_button = QtWidgets.QPushButton("Channels") self.channels_button.clicked.connect(self.channels_dialog) # Set Text so the size of the boxes are at an appropriate size self.x_value_lbl = QtWidgets.QLabel('X: #####') self.y_value_lbl = QtWidgets.QLabel('Y: #####') self.pixel_value_lbl = QtWidgets.QLabel( 'R: ######, G: ###### B: ######') self.pixels = QtWidgets.QLabel('#Pixels: #######') self.std_dev = QtWidgets.QLabel( 'Std Dev: R: ######### G: ######### B: #########') self.mean = QtWidgets.QLabel( 'Mean: R: ######## G: ######## B: ########') self.median = QtWidgets.QLabel( 'Median: R: ######## G: ######## B: ########') self.min = QtWidgets.QLabel('Min: R: ### G: ### B: ###') self.max = QtWidgets.QLabel('Max: R: ### G: ### B: ###') main_layout.setHorizontalSpacing(10) # Set format for each information box to be the same for info_box in (self.x_value_lbl, self.y_value_lbl, self.pixel_value_lbl, self.pixels, self.std_dev, self.mean, self.median, self.min, self.max): info_box.setFrameShape(QtWidgets.QFrame.Panel) info_box.setFrameShadow(QtWidgets.QFrame.Sunken) info_box.setLineWidth(3) info_box.setMidLineWidth(1) info_box.setAlignment(QtCore.Qt.AlignBottom | QtCore.Qt.AlignLeft) for main_box, second_box in ((self.std_dev, self.pixels), (self.mean, self.median), (self.min, self.max)): main_box.setMinimumSize(main_box.sizeHint()) main_box.setMaximumSize(main_box.sizeHint()) second_box.setMinimumSize(main_box.sizeHint()) second_box.setMaximumSize(main_box.sizeHint()) self.histogram = HistogramModel(self.view_canvas, bins=100) self.histogram_widget = HistogramWidget(self.histogram) min_width = self.histogram_widget.histogram.width() for widget in (open_file, self.next_image_btn, self.previous_image_btn, self.channels_button, self.open_label, self.restore_defaults, self.rgb_check_box, self.x_value_lbl, self.y_value_lbl, quit_button, self.next_channel_btn, self.previous_channel_btn, self.pixel_value_lbl): widget.setMinimumWidth(min_width) widget.setMaximumWidth(min_width) fixed_size = self.pixel_value_lbl.sizeHint().width() self.x_value_lbl.setMinimumWidth(fixed_size / 2) self.x_value_lbl.setMaximumWidth(fixed_size / 2) self.y_value_lbl.setMinimumWidth(fixed_size / 2) self.y_value_lbl.setMaximumWidth(fixed_size / 2) column_spacing_x_y = 5 self.pixel_value_lbl.setMinimumWidth(fixed_size + column_spacing_x_y) self.pixel_value_lbl.setMaximumWidth(fixed_size + column_spacing_x_y) main_layout.addWidget(open_file, 0, 0) main_layout.addWidget(quit_button, 0, 1) main_layout.addWidget(self.pixels, 0, 2) main_layout.addWidget(self.mean, 0, 3) main_layout.addWidget(self.min, 0, 4) main_layout.addWidget(self.previous_image_btn, 1, 0) main_layout.addWidget(self.next_image_btn, 1, 1) main_layout.addWidget(self.std_dev, 1, 2) main_layout.addWidget(self.median, 1, 3) main_layout.addWidget(self.max, 1, 4) main_layout.addWidget(self.previous_channel_btn, 2, 0) main_layout.addWidget(self.next_channel_btn, 2, 1) main_layout.addWidget(self.channels_button, 3, 0) main_layout.addWidget(self.open_label, 3, 1) main_layout.addWidget(self.restore_defaults, 4, 0) main_layout.addWidget(self.rgb_check_box, 4, 1) main_layout.addWidget(self.histogram_widget, 5, 0, 2, 2) x_y_layout = QtWidgets.QGridLayout() x_y_layout.setHorizontalSpacing(column_spacing_x_y) x_y_layout.addWidget(self.x_value_lbl, 0, 0) x_y_layout.addWidget(self.y_value_lbl, 0, 1) main_layout.addLayout(x_y_layout, 7, 0) main_layout.addWidget(self.pixel_value_lbl, 8, 0, 1, 2) main_layout.addWidget(self.view_canvas.get_widget(), 2, 2, 9, 4) main_layout.setRowStretch(9, 1) main_layout.setColumnStretch(5, 1) vw = QtWidgets.QWidget() self.setCentralWidget(vw) vw.setLayout(main_layout) self.view_canvas.set_desired_size(100, 100) if self.image_set.current_image: self.display_image() self._reset_display_values() @property def current_image(self): return self.image_set.current_image[self.image_set.channel] def display_image(self): self.controller.update_rgb() self._set_rgb_state() self._update_channels_image() self.view_canvas.set_image(self.current_image) if self.current_image.not_been_displayed: self.restore() else: self.apply_parameters(self.current_image, self.view_canvas) self.view_canvas.delayed_redraw() self.current_image.not_been_displayed = False self.histogram.set_data() self._disable_next_previous() self._reset_ROI() self._update_label() self.setWindowTitle(self.current_image.image_name) def _refresh_ROI_text(self): self.stop_ROI(self.view_canvas, None, None, None) def _reset_ROI(self): if len(self.view_canvas.objects) > 1: self._refresh_ROI_text() self.view_canvas.update_canvas() else: self.set_ROI_text( 0, 0, self.current_image.width, self.current_image.height) def _update_channels_image(self): if self.channels_window: self.channels_window.change_image() def _set_rgb_state(self): state = self.rgb_check_box.checkState() self.switch_rgb(state) def _disable_next_previous(self): if len(self.image_set.current_image) < 3: self.next_channel_btn.setEnabled(False) self.previous_channel_btn.setEnabled(False) def _renew_display_values(self): try: data_x = self.image_set.x_value data_y = self.image_set.y_value self.display_values(self.view_canvas, None, data_x, data_y) except ValueError: pass def _reset_display_values(self): self.x_value_lbl.setText('X: ????') self.y_value_lbl.setText('Y: ????') if self.current_image.ndim == 3: self.pixel_value_lbl.setText('R: ???? G: ???? B: ????') elif self.current_image.ndim == 2: self.pixel_value_lbl.setText('Value: ????') def _change_wrapper(image_was_changed): # To be more explicit later channel_was_changed = not image_was_changed def decorator(func): @wraps(func) def wrapper(self): self.save_parameters() result = func(self) if image_was_changed: self._reset_display_values() elif channel_was_changed: self._renew_display_values() return result return wrapper return decorator @_change_wrapper(True) def next_image(self): self.controller.next_image() @_change_wrapper(True) def previous_image(self): self.controller.previous_image() @_change_wrapper(False) def next_channel(self): self.controller.next_channel() @_change_wrapper(False) def previous_channel(self): self.controller.previous_channel() def display_rgb_image(self): rgb_image = self.image_set.create_rgb_image() self.current_image.set_data(rgb_image) self.next_channel_btn.setEnabled(False) self.previous_channel_btn.setEnabled(False) def _undo_display_rgb_image(self): self.current_image.set_data(self.current_image.data) if len(self.image_set.current_image) == 3: self.next_channel_btn.setEnabled(True) self.previous_channel_btn.setEnabled(True) if self.channels_window: self.channels_window.rgb_check_box.setCheckState( QtCore.Qt.Unchecked) def switch_rgb(self, state): """Display rgb image when rgb box is checked, single band otherwise""" if state == QtCore.Qt.Checked: if self.channels_window: self.channels_window.rgb_check_box.setCheckState( QtCore.Qt.Checked) else: if self.image_set.bands_are_composite: self.display_rgb_image() else: print("Images must be the same size") print("Use the channels button to select the bands") self.rgb_check_box.setCheckState(QtCore.Qt.Unchecked) elif state == QtCore.Qt.Unchecked: self._undo_display_rgb_image() if len(self.view_canvas.objects) >= 1: self._refresh_ROI_text() if self.view_canvas.get_image() is not None: self.histogram.set_data() def _point_is_in_image(self, point): data_x, data_y = point height, width = self.current_image.shape[:2] in_width = data_x >= -0.5 and data_x <= (width + 0.5) in_height = data_y >= -0.5 and data_y <= (height + 0.5) return in_width and in_height def _set_point_in_image(self, point): data_x, data_y = point image = self.view_canvas.get_image() self.controller.new_x_value(data_x) self.controller.new_y_value(data_y) x, y = self.image_set.x_value, self.image_set.y_value self.controller.new_pixel_value(image.get_data_xy(x, y)) def _set_point_out_of_image(self): x, y = self.view_canvas.get_last_data_xy() self.controller.new_x_value(x) self.controller.new_y_value(y) if self.current_image.ndim == 3: self.controller.new_pixel_value((0, 0, 0)) elif self.current_image.ndim == 2: self.controller.new_pixel_value(0) def set_x_value_text(self): self.x_value_lbl.setText(self.image_set.x_value_text) def set_y_value_text(self): self.y_value_lbl.setText(self.image_set.y_value_text) def set_pixel_value_text(self): self.pixel_value_lbl.setText(self.image_set.pixel_value_text) def display_values(self, view_canvas, button, data_x, data_y): "Display the x, y, and pixel value when the mouse is pressed and moved" point = (data_x, data_y) if self._point_is_in_image(point): self._set_point_in_image(point) else: self._set_point_out_of_image() def display_label(self): """Display the label over the image""" # Utilizing the sub window variables to check if the label window has # been opened before. If not, the window is initialized. if self._label_window is None: self._label_window = label.LabelView(self) self._label_window.is_open = True self._label_window.show() self._label_window.activateWindow() def _update_label(self): # Update label self.image_label = self.current_image.label # This checks to see if the label window exists and is open. If so, # this resets the label field so that the label being displayed is the # label for the current product. The label does not reset its position. if self._label_window is not None: pos = self._label_window.pos() label_text = '\n'.join(self.image_label) self._label_window.label_contents.setText(label_text) if self._label_window.is_open: self._label_window.cancel() self._label_window.move(pos) self._label_window.show() self._label_window.is_open = True self._label_window.activateWindow() def open_file(self): """Open a new image file from a file explorer""" file_name = QtWidgets.QFileDialog() file_name.setFileMode(QtWidgets.QFileDialog.ExistingFiles) new_files = file_name.getOpenFileNames(self)[0] if new_files: if self.image_set.current_image: self.save_parameters() first_new_image = len(self.image_set.images) self.image_set.append(new_files, first_new_image) # If there are no new images, don't continue if first_new_image == len(self.image_set.images): warnings.warn("The image(s) chosen are not PDS compatible") return self.next_image_btn.setEnabled( self.image_set.next_prev_enabled) self.previous_image_btn.setEnabled( self.image_set.next_prev_enabled) self._display_image() else: # integrate with logger print("No file selected!") return def channels_dialog(self): """Display the channels dialog box""" if not self.channels_window: self.channels_window = ChannelsDialog(ChannelsDialogModel(self)) self.channels_window_is_open = True if self.channels_window_pos: self.channels_window.move(self.channels_window_pos) self.channels_window.show() def save_parameters(self): """Save the view parameters on the image""" last_image = self.image_set.current_image[self.image_set.channel] last_image.sarr = self.view_canvas.get_rgbmap().get_sarr() last_image.zoom = self.view_canvas.get_zoom() last_image.rotation = self.view_canvas.get_rotation() last_image.transforms = self.view_canvas.get_transforms() last_image.cuts = self.view_canvas.get_cut_levels() def apply_parameters(self, image, view): """Display image with the images parameters""" if image.sarr is None: pass else: view.get_rgbmap().set_sarr(image.sarr) if image.zoom is None: pass else: view.zoom_to(image.zoom) if image.rotation is None: pass else: view.rotate(image.rotation) if image.transforms is None: pass else: flip_x = image.transforms[0] flip_y = image.transforms[1] switch_xy = image.transforms[2] view.transform(flip_x, flip_y, switch_xy) if image.cuts is None: pass else: loval, hival = image.cuts view.cut_levels(loval, hival, True) def restore(self): """Restore image to the default settings""" self.view_canvas.get_rgbmap().reset_sarr() self.view_canvas.enable_autocuts('on') self.view_canvas.auto_levels() self.view_canvas.enable_autocuts('override') self.view_canvas.rotate(0.0) # The default transform/rotation of the image will be image specific so # transform bools will change in the future self.view_canvas.transform(False, False, False) self.view_canvas.zoom_fit() self.histogram.restore() def start_ROI(self, view_canvas, button, data_x, data_y): """Ensure only one Region of Interest (ROI) exists at a time Note ---- This method is called when the right mouse button is pressed. Even though the arguments are not used, they are necessary to catch the right mouse button press event. Parameters ---------- view_canvas : ImageViewCanvas object The view that displays the image button : Qt.RightButton The right mouse button data_x : float The x-value of the location of the right button data_y : float The y-value of the location of the right button """ if len(view_canvas.objects) > 1: self.delete_ROI() def stop_ROI(self, view_canvas, button, data_x, data_y): """Create a Region of Interest (ROI) When drawing stops (release of the right mouse button), the ROI border snaps to inclusive pixel (see top_right_pixel_snap and bottom_left_pixel_snap). The ROI's information is set as an attributes of the current image (see calculate_ROI_info). Note ---- This method is called when the right mouse button is released. Even though only the view_canvas argument is used, they are all necessary to catch the right mouse button release event. Parameters ---------- See start_ROI parameters """ # If there are no draw objects, stop current_image = self.image_set.current_image[self.image_set.channel] if len(view_canvas.objects) == 1: self.set_ROI_text(0, 0, current_image.width, current_image.height) return draw_obj = view_canvas.objects[1] # Retrieve the left, right, top, & bottom x and y values roi = self.left_right_bottom_top( draw_obj.x1, draw_obj.x2, draw_obj.y1, draw_obj.y2) left_x, right_x, bot_y, top_y, x2_is_right, y2_is_top = roi # Single right click deletes any ROI & sets the whole image as the ROI if left_x == right_x and bot_y == top_y: self.set_ROI_text(0, 0, current_image.width, current_image.height) self.delete_ROI() return # Determine if the ROI is outside the image. max_height = current_image.height max_width = current_image.width top_y, top_in_image = self.top_right_pixel_snap(top_y, max_height) bot_y, bot_in_image = self.bottom_left_pixel_snap(bot_y, max_height) right_x, right_in_image = self.top_right_pixel_snap(right_x, max_width) left_x, left_in_image = self.bottom_left_pixel_snap(left_x, max_width) # If the entire ROI is outside the ROI, delete the ROI and set the ROI # to the whole image in_image = any( (left_in_image, right_in_image, top_in_image, bot_in_image) ) if not in_image: self.set_ROI_text(0, 0, current_image.width, current_image.height) self.delete_ROI() return # Snap the ROI to the edge of the image if it is outside the image if y2_is_top: draw_obj.y2 = top_y draw_obj.y1 = bot_y else: draw_obj.y1 = top_y draw_obj.y2 = bot_y if x2_is_right: draw_obj.x2 = right_x draw_obj.x1 = left_x else: draw_obj.x1 = right_x draw_obj.x2 = left_x # Calculate the ROI information self.set_ROI_text(left_x, bot_y, right_x, top_y) def top_right_pixel_snap(self, ROI_side, image_edge): """Snaps the top or right side of the ROI to the inclusive pixel Parameters ---------- ROI_side : float Either the ROI's top-y or right-x value image_edge : float The top or right edge of the image Returns ------- ROI_side : float The x or y value of the right or top ROI side respectively side_in_image : bool True if the side is in the image, False otherwise """ # If the top/right ROI edge is outside the image, reset the top/right # ROI side value to the edge if ROI_side > image_edge: ROI_side = image_edge + .5 side_in_image = True # If the right side is to the left of the image or the top side is # below the image, then the entire ROI is outside the image elif ROI_side < 0.0: side_in_image = False # If the top/right ROI values is inside the image, snap it the edge # of the inclusive pixel. If the value is already on the edge, pass else: if ROI_side - int(ROI_side) == .5: pass else: ROI_side = round(ROI_side) + .5 side_in_image = True return (ROI_side, side_in_image) def bottom_left_pixel_snap(self, ROI_side, image_edge): """Snaps the bottom or left side of the ROI to the inclusive pixel Parameters ---------- ROI_side : float Either the ROI's bottom-y or left-x value image_edge : float The top or right edge of the image Returns ------- ROI_side : float The x or y value of the left or bottom ROI side respectively side_in_image : bool True if the side is in the image, False otherwise """ # If the bottom/left ROI edge is outside the image, reset the # bottom/left ROI side value to the bottom/left edge (-0.5) if ROI_side < 0.0: ROI_side = -0.5 side_in_image = True # If the left side is to the right of the image or the bottom side is # above the image, then the entire ROI is outside the image elif ROI_side > image_edge: side_in_image = False # If the bottom/left ROI values is inside the image, snap it the edge # of the inclusive pixel. If the value is already on the edge, pass else: if ROI_side - int(ROI_side) == .5: pass else: ROI_side = round(ROI_side) - 0.5 side_in_image = True return (ROI_side, side_in_image) def left_right_bottom_top(self, x1, x2, y1, y2): """Determines the values for the left, right, bottom, and top vertices Parameters ---------- x1 : float The x-value of where the right cursor was clicked x2 : float The x-value of where the right cursor was released y1 : float The y-value of where the right cursor was clicked y2 : float The y-value of where the right cursor was released Returns ------- left_x : float The x-value of the left side of the ROI right_x : float The x-value of the right side of the ROI bot_y : float The y-value of the bottom side of the ROI top_y : float The y-value of the top side of the ROI x2_is_right : bool True if the x2 input is the right side of the ROI, False otherwise y2_is_top : bool True if the y2 input is the top side of the ROI, False otherwise """ if x2 > x1: right_x = x2 left_x = x1 x2_is_right = True else: right_x = x1 left_x = x2 x2_is_right = False if y2 > y1: top_y = y2 bot_y = y1 y2_is_top = True else: top_y = y1 bot_y = y2 y2_is_top = False return (left_x, right_x, bot_y, top_y, x2_is_right, y2_is_top) def delete_ROI(self): """Deletes the Region of Interest""" try: self.view_canvas.deleteObject(self.view_canvas.objects[1]) except: return def set_ROI_text(self, left, bottom, right, top): """Set the text of the ROI information boxes When the image has three bands (colored), the ROI value boxes will display the values for each band. Parameters ---------- left : float The x coordinate value of the left side of the ROI bottom : float The y coordinate value of the bottom side of the ROI right : float The x coordinate value of the right side of the ROI bottom : float The y coordinate value of the top side of the ROI """ data = self.image_set.ROI_data( left, bottom, right, top) # Calculate the number of pixels in the ROI ROI_pixels = self.image_set.ROI_pixels(left, bottom, right, top) self.pixels.setText('#Pixels: %d' % (ROI_pixels)) if data.ndim == 2: # 2 band image is a gray scale image self.set_ROI_gray_text(data) elif data.ndim == 3: # Three band image is a RGB colored image try: self.set_ROI_RGB_text(data) except: # If the ROI does not contain values for each band, treat the # ROI like a gray scale image self.set_ROI_gray_text(data) def set_ROI_gray_text(self, data): """Set the values for the ROI in the text boxes for a gray image Parameters ---------- data : array The data from the Region of Interest """ ROI_std_dev = self.image_set.ROI_std_dev(data=data) ROI_mean = self.image_set.ROI_mean(data=data) ROI_median = self.image_set.ROI_median(data=data) ROI_min = self.image_set.ROI_min(data=data) ROI_max = self.image_set.ROI_max(data=data) self.std_dev.setText('Std Dev: %.6f' % (ROI_std_dev)) self.mean.setText('Mean: %.4f' % (ROI_mean)) self.median.setText('Median: %.1f' % (ROI_median)) self.min.setText('Min: %d' % (ROI_min)) self.max.setText('Max: %d' % (ROI_max)) def set_ROI_RGB_text(self, data): """Set the values for the ROI in the text boxes for a RGB image Parameters ---------- data : array The data from the Region of Interest """ calc = self.image_set ROI_stdev = [calc.ROI_std_dev(data=data[:, :, n]) for n in range(3)] ROI_mean = [calc.ROI_mean(data=data[:, :, n]) for n in range(3)] ROI_median = [calc.ROI_median(data=data[:, :, n]) for n in range(3)] ROI_max = [int(calc.ROI_max(data=data[:, :, n])) for n in range(3)] ROI_min = [int(calc.ROI_min(data=data[:, :, n])) for n in range(3)] self.std_dev.setText( 'Std Dev: R: %.6f G: %.6f B: %.6f' % (tuple(ROI_stdev))) self.mean.setText( 'Mean: R: %s G: %s B: %s' % (tuple(ROI_mean))) self.median.setText( 'Median: R: %s G: %s B: %s' % (tuple(ROI_median))) self.max.setText( 'Max: R: %s G: %s B: %s' % (tuple(ROI_max))) self.min.setText( 'Min: R: %s G: %s B: %s' % (tuple(ROI_min))) def drop_file(self, pdsimage, paths): """This function is not yet supported""" # file_name = paths[0] # self.load_file(file_name) pass def quit(self, *args): """Close pdsview""" if self._label_window is not None: self._label_window.cancel() if self.channels_window: self.channels_window.hide() self.close()
class GingaWidget(ImageWidgetBase): LABEL = "Ginga Viewer" def __init__(self, session, parent=None): self.logger = log.get_logger( name='ginga', level=20, null=True, # uncomment for debugging # log_stderr=True ) self.viewer = ImageViewCanvas(self.logger, render='widget') self.canvas = self.viewer # prevent widget from grabbing focus try: self.canvas.set_enter_focus(False) except AttributeError: self.canvas.set_follow_focus(False) # enable interactive features bindings = self.canvas.get_bindings() bindings.enable_all(True) self.canvas.add_callback('none-move', self.motion_readout) self.canvas.add_callback('draw-event', self._apply_roi_cb) self.canvas.add_callback('draw-down', self._clear_roi_cb) self.canvas.enable_draw(False) self.canvas.enable_autozoom('off') self.canvas.set_zoom_algorithm('rate') self.canvas.set_zoomrate(1.4) bm = self.canvas.get_bindmap() bm.add_callback('mode-set', self.mode_set_cb) self.mode_w = None self.mode_actns = {} # Create settings and set defaults settings = self.canvas.get_settings() self.settings = settings settings.getSetting('cuts').add_callback('set', self.cut_levels_cb) settings.set(autozoom='off', autocuts='override', autocenter='override') # make color bar, with color maps shared from ginga canvas rgbmap = self.viewer.get_rgbmap() self.colorbar = ColorBar.ColorBar(self.logger) rgbmap.add_callback('changed', self.rgbmap_cb, self.viewer) self.colorbar.set_rgbmap(rgbmap) # make coordinates/value readout self.readout = Readout.Readout(-1, 20) self.roi_tag = None super(GingaWidget, self).__init__(session, parent) @staticmethod def _get_default_tools(): return [] def make_client(self): return GingaClient(self._data, self.viewer, self._layer_artist_container) def make_central_widget(self): topw = QtWidgets.QWidget() layout = QtWidgets.QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) layout.addWidget(self.viewer.get_widget(), stretch=1) cbar_w = self.colorbar.get_widget() if not isinstance(cbar_w, QtWidgets.QWidget): # ginga wrapped widget cbar_w = cbar_w.get_widget() layout.addWidget(cbar_w, stretch=0) readout_w = self.readout.get_widget() if not isinstance(readout_w, QtWidgets.QWidget): # ginga wrapped widget readout_w = readout_w.get_widget() layout.addWidget(readout_w, stretch=0) topw.setLayout(layout) return topw def match_colorbar(self, canvas, colorbar): rgbmap = self.viewer.get_rgbmap() loval, hival = self.viewer.get_cut_levels() colorbar.set_range(loval, hival) colorbar.set_rgbmap(rgbmap) def rgbmap_cb(self, rgbmap, canvas): self.match_colorbar(canvas, self.colorbar) def cut_levels_cb(self, setting, tup): (loval, hival) = tup self.colorbar.set_range(loval, hival) def make_toolbar(self): tb = QtWidgets.QToolBar(parent=self) tb.setIconSize(QtCore.QSize(25, 25)) tb.layout().setSpacing(1) tb.setFocusPolicy(Qt.StrongFocus) agroup = QtWidgets.QActionGroup(tb) agroup.setExclusive(True) for (mode_text, mode_icon, mode_cb) in self._mouse_modes(): # TODO: add icons similar to the Matplotlib toolbar action = tb.addAction(mode_icon, mode_text) action.setCheckable(True) action.toggled.connect(mode_cb) agroup.addAction(action) action = tb.addAction(get_icon('glue_move'), "Pan") self.mode_actns['pan'] = action action.setCheckable(True) action.toggled.connect(lambda tf: self.mode_cb('pan', tf)) agroup.addAction(action) icon = QtGui.QIcon(os.path.join(ginga_icon_dir, 'hand_48.png')) action = tb.addAction(icon, "Free Pan") self.mode_actns['freepan'] = action action.setCheckable(True) action.toggled.connect(lambda tf: self.mode_cb('freepan', tf)) agroup.addAction(action) icon = QtGui.QIcon(os.path.join(ginga_icon_dir, 'rotate_48.png')) action = tb.addAction(icon, "Rotate") self.mode_actns['rotate'] = action action.setCheckable(True) action.toggled.connect(lambda tf: self.mode_cb('rotate', tf)) agroup.addAction(action) action = tb.addAction(get_icon('glue_contrast'), "Contrast") self.mode_actns['contrast'] = action action.setCheckable(True) action.toggled.connect(lambda tf: self.mode_cb('contrast', tf)) agroup.addAction(action) icon = QtGui.QIcon(os.path.join(ginga_icon_dir, 'cuts_48.png')) action = tb.addAction(icon, "Cuts") self.mode_actns['cuts'] = action action.setCheckable(True) action.toggled.connect(lambda tf: self.mode_cb('cuts', tf)) agroup.addAction(action) cmap_w = _colormap_mode(self, self.client.set_cmap) tb.addWidget(cmap_w) return tb def _mouse_modes(self): modes = [] modes.append(("Rectangle", get_icon('glue_square'), lambda tf: self._set_roi_mode('rectangle', tf))) modes.append(("Circle", get_icon('glue_circle'), lambda tf: self._set_roi_mode('circle', tf))) modes.append(("Polygon", get_icon('glue_lasso'), lambda tf: self._set_roi_mode('polygon', tf))) for tool in self._tools: modes += tool._get_modes(self.viewer) add_callback(self.client, 'display_data', tool._display_data_hook) return modes def _set_roi_mode(self, name, tf): self.canvas.enable_draw(True) # XXX need better way of setting draw contexts self.canvas.draw_context = self self.canvas.set_drawtype(name, color='cyan', linestyle='dash') bm = self.viewer.get_bindmap() bm.set_mode('draw', mode_type='locked') def _clear_roi_cb(self, canvas, *args): try: self.canvas.deleteObjectByTag(self.roi_tag) except: pass def _apply_roi_cb(self, canvas, tag): if self.canvas.draw_context is not self: return self.roi_tag = tag obj = self.canvas.getObjectByTag(self.roi_tag) roi = ginga_graphic_to_roi(obj) # delete outline self.canvas.deleteObject(obj, redraw=False) self.apply_roi(roi) def _tweak_geometry(self): super(GingaWidget, self)._tweak_geometry() # rgb mode not supported yet, so hide option self.ui.monochrome.hide() self.ui.rgb.hide() def motion_readout(self, canvas, button, data_x, data_y): """This method is called when the user moves the mouse around the Ginga canvas. """ d = self.client.point_details(data_x, data_y) # Get the value under the data coordinates try: # value = fitsimage.get_data(data_x, data_y) # We report the value across the pixel, even though the coords # change halfway across the pixel value = self.viewer.get_data(int(data_x + 0.5), int(data_y + 0.5)) except Exception: value = None x_lbl, y_lbl = d['labels'][0], d['labels'][1] # x_txt, y_txt = d['world'][0], d['world'][1] text = "%s %s X=%.2f Y=%.2f Value=%s" % (x_lbl, y_lbl, data_x, data_y, value) self.readout.set_text(text) def mode_cb(self, modname, tf): """This method is called when a toggle button in the toolbar is pressed selecting one of the modes. """ bm = self.viewer.get_bindmap() if not tf: bm.reset_mode(self.viewer) return bm.set_mode(modname, mode_type='locked') return True def mode_set_cb(self, bm, modname, mtype): """This method is called when a mode is selected in the viewer widget. NOTE: it may be called when mode_cb() is not called (for example, when a keypress initiates a mode); however, the converse is not true: calling mode_cb() will always result in this method also being called as a result. This logic is to insure that the toggle buttons are left in a sane state that reflects the current mode, however it was initiated. """ if modname in self.mode_actns: if self.mode_w and (self.mode_w != self.mode_actns[modname]): self.mode_w.setChecked(False) self.mode_w = self.mode_actns[modname] self.mode_w.setChecked(True) elif self.mode_w: # keystroke turned on a mode for which we have no GUI button # and a GUI button is selected--unselect it self.mode_w.setChecked(False) self.mode_w = None return True
def __init__(self): Viewer.__init__(self) from ginga.qtw.ImageViewCanvasQt import ImageViewCanvas fi = ImageViewCanvas(render='widget') fi.enable_autocuts('on') fi.set_autocut_params('zscale') fi.enable_autozoom('on') fi.set_bg(0.2, 0.2, 0.2) fi.ui_setActive(True) fi.enable_draw(False) self.fitsimage = fi bd = fi.get_bindings() bd.enable_all(True) w = fi.get_widget() w.resize(512, 512) vbox = QtWidgets.QVBoxLayout() vbox.setContentsMargins(QtCore.QMargins(2, 2, 2, 2)) vbox.setSpacing(1) vbox.addWidget(w, stretch=1) self.setLayout(vbox)
def __init__(self, logger): super(FitsViewer, self).__init__() self.logger = logger menubar = self.menuBar() # create a File pulldown menu, and add it to the menu bar filemenu = menubar.addMenu("File") item = QtGui.QAction("Open File", menubar) item.triggered.connect(self.open_file) filemenu.addAction(item) sep = QtGui.QAction(menubar) sep.setSeparator(True) filemenu.addAction(sep) item = QtGui.QAction("Quit", menubar) item.triggered.connect(self.close) filemenu.addAction(item) # Add matplotlib color maps to our built in ones cmap.add_matplotlib_cmaps() self.cmaps = cmap.get_names() self.imaps = imap.get_names() wd, ht = 500, 500 # Create a Ginga widget fi = ImageViewCanvas(logger, render='widget') fi.enable_autocuts('on') fi.set_autocut_params('zscale') fi.enable_autozoom('on') fi.enable_draw(False) fi.set_callback('drag-drop', self.drop_file_cb) fi.set_callback('cursor-changed', self.cursor_cb) fi.set_bg(0.2, 0.2, 0.2) fi.ui_set_active(True) self.fitsimage = fi fi.show_color_bar(True) # enable various key and mouse controlled actions bd = fi.get_bindings() bd.enable_all(True) self.cp_tag = 'compass' # pack widget into layout gingaw = fi.get_widget() gingaw.resize(wd, ht) vbox1 = QtGui.QWidget() layout = QtGui.QVBoxLayout() layout.addWidget(gingaw, stretch=1) self.cm = cmap.get_cmap('gray') self.im = imap.get_imap('ramp') # color map selection widget wcmap = QtGui.QComboBox() for name in self.cmaps: wcmap.addItem(name) index = self.cmaps.index('gray') wcmap.setCurrentIndex(index) wcmap.activated.connect(self.set_cmap_cb) self.wcmap = wcmap # intensity map selection widget wimap = QtGui.QComboBox() for name in self.imaps: wimap.addItem(name) index = self.imaps.index('ramp') wimap.setCurrentIndex(index) wimap.activated.connect(self.set_cmap_cb) self.wimap = wimap #wopen = QtGui.QPushButton("Open File") #wopen.clicked.connect(self.open_file) # add buttons to layout hbox = QtGui.QHBoxLayout() hbox.setContentsMargins(QtCore.QMargins(4, 2, 4, 2)) hbox.addStretch(1) for w in (wcmap, wimap): hbox.addWidget(w, stretch=0) hw = QtGui.QWidget() hw.setLayout(hbox) layout.addWidget(hw, stretch=0) vbox1.setLayout(layout) # Create a matplotlib Figure #self.fig = matplotlib.figure.Figure(figsize=(wd, ht)) self.fig = matplotlib.figure.Figure() self.canvas = FigureCanvas(self.fig) vbox2 = QtGui.QWidget() layout = QtGui.QVBoxLayout() layout.addWidget(self.canvas, stretch=1) # Add matplotlib buttons hbox = QtGui.QHBoxLayout() hbox.setContentsMargins(QtCore.QMargins(4, 2, 4, 2)) wgetimg = QtGui.QPushButton("Get Data") wgetimg.clicked.connect(self.get_image) wgetrgb = QtGui.QPushButton("Get RGB") wgetrgb.clicked.connect(self.get_rgb_image) #wquit = QtGui.QPushButton("Quit") #wquit.clicked.connect(self.close) hbox.addStretch(1) for w in (wgetimg, wgetrgb): hbox.addWidget(w, stretch=0) hw = QtGui.QWidget() hw.setLayout(hbox) layout.addWidget(hw, stretch=0) vbox2.setLayout(layout) vbox = QtGui.QVBoxLayout() vbox.setContentsMargins(QtCore.QMargins(2, 2, 2, 2)) vbox.setSpacing(1) w = QtGui.QWidget() layout = QtGui.QHBoxLayout() layout.addWidget(vbox1, stretch=1.0) layout.addWidget(vbox2, stretch=1.0) w.setLayout(layout) vbox.addWidget(w, stretch=1) self.readout = QtGui.QLabel("") vbox.addWidget(self.readout, stretch=0, alignment=QtCore.Qt.AlignCenter) vw = QtGui.QWidget() vw.setLayout(vbox) self.setCentralWidget(vw)
def __init__(self, logger): super(FitsViewer, self).__init__() self.logger = logger self.drawcolors = colors.get_colors() fi = ImageViewCanvas(logger, render='widget') fi.enable_autocuts('on') fi.set_autocut_params('zscale') fi.enable_autozoom('on') fi.set_zoom_algorithm('rate') fi.set_zoomrate(1.4) fi.show_pan_mark(True) fi.enable_draw(False) fi.set_callback('drag-drop', self.drop_file) fi.set_callback('none-move', self.motion) fi.set_bg(0.2, 0.2, 0.2) fi.ui_setActive(True) self.fitsimage = fi bd = fi.get_bindings() bd.enable_all(True) # canvas that we will draw on canvas = DrawingCanvas() canvas.enable_draw(True) canvas.set_drawtype('rectangle', color='lightblue') canvas.setSurface(fi) self.canvas = canvas # add canvas to view fi.add(canvas) canvas.ui_setActive(True) w = fi.get_widget() w.resize(512, 512) vbox = QtGui.QVBoxLayout() vbox.setContentsMargins(QtCore.QMargins(2, 2, 2, 2)) vbox.setSpacing(1) vbox.addWidget(w, stretch=1) self.readout = QtGui.QLabel("") vbox.addWidget(self.readout, stretch=0, alignment=QtCore.Qt.AlignCenter) hbox = QtGui.QHBoxLayout() hbox.setContentsMargins(QtCore.QMargins(4, 2, 4, 2)) wdrawtype = QtGui.QComboBox() self.drawtypes = fi.get_drawtypes() for name in self.drawtypes: wdrawtype.addItem(name) index = self.drawtypes.index('rectangle') wdrawtype.setCurrentIndex(index) wdrawtype.activated.connect(self.set_drawparams) self.wdrawtype = wdrawtype wdrawcolor = QtGui.QComboBox() for name in self.drawcolors: wdrawcolor.addItem(name) index = self.drawcolors.index('lightblue') wdrawcolor.setCurrentIndex(index) wdrawcolor.activated.connect(self.set_drawparams) self.wdrawcolor = wdrawcolor wfill = QtGui.QCheckBox("Fill") wfill.stateChanged.connect(self.set_drawparams) self.wfill = wfill walpha = QtGui.QDoubleSpinBox() walpha.setRange(0.0, 1.0) walpha.setSingleStep(0.1) walpha.setValue(1.0) walpha.valueChanged.connect(self.set_drawparams) self.walpha = walpha wclear = QtGui.QPushButton("Clear Canvas") wclear.clicked.connect(self.clear_canvas) wopen = QtGui.QPushButton("Open File") wopen.clicked.connect(self.open_file) wquit = QtGui.QPushButton("Quit") wquit.clicked.connect(self.quit) hbox.addStretch(1) for w in (wopen, wdrawtype, wdrawcolor, wfill, QtGui.QLabel('Alpha:'), walpha, wclear, wquit): hbox.addWidget(w, stretch=0) hw = QtGui.QWidget() hw.setLayout(hbox) vbox.addWidget(hw, stretch=0) vw = QtGui.QWidget() self.setCentralWidget(vw) vw.setLayout(vbox)
def __init__(self, logger): super(FitsViewer, self).__init__() self.logger = logger menubar = self.menuBar() # create a File pulldown menu, and add it to the menu bar filemenu = menubar.addMenu("File") item = QtGui.QAction("Open File", menubar) item.triggered.connect(self.open_file) filemenu.addAction(item) sep = QtGui.QAction(menubar) sep.setSeparator(True) filemenu.addAction(sep) item = QtGui.QAction("Quit", menubar) item.triggered.connect(self.close) filemenu.addAction(item) # Add matplotlib color maps to our built in ones cmap.add_matplotlib_cmaps() self.cmaps = cmap.get_names() self.imaps = imap.get_names() wd, ht = 500, 500 # Create a Ginga widget fi = ImageViewCanvas(logger, render='widget') fi.enable_autocuts('on') fi.set_autocut_params('zscale') fi.enable_autozoom('on') fi.enable_draw(False) fi.set_callback('drag-drop', self.drop_file) fi.set_callback('none-move', self.motion) fi.set_bg(0.2, 0.2, 0.2) fi.ui_setActive(True) self.fitsimage = fi # enable various key and mouse controlled actions bd = fi.get_bindings() bd.enable_all(True) self.cp_tag = 'compass' # pack widget into layout gingaw = fi.get_widget() gingaw.resize(wd, ht) vbox1 = QtGui.QWidget() layout = QtGui.QVBoxLayout() layout.addWidget(gingaw, stretch=1) self.cm = cmap.get_cmap('gray') self.im = imap.get_imap('ramp') # add color bar rgbmap = fi.get_rgbmap() rgbmap.set_hash_size(256) cbar = ColorBar.ColorBar(self.logger, rgbmap=rgbmap, link=True) cbar.resize(-1, 15) #cbar.show() self.colorbar = cbar layout.addWidget(cbar, stretch=0) settings = fi.get_settings() settings.getSetting('cuts').add_callback('set', self.change_range_cb, fi, self.colorbar) # color map selection widget wcmap = QtGui.QComboBox() for name in self.cmaps: wcmap.addItem(name) index = self.cmaps.index('gray') wcmap.setCurrentIndex(index) wcmap.activated.connect(self.set_cmap_cb) self.wcmap = wcmap # intensity map selection widget wimap = QtGui.QComboBox() for name in self.imaps: wimap.addItem(name) index = self.imaps.index('ramp') wimap.setCurrentIndex(index) wimap.activated.connect(self.set_cmap_cb) self.wimap = wimap #wopen = QtGui.QPushButton("Open File") #wopen.clicked.connect(self.open_file) # add buttons to layout hbox = QtGui.QHBoxLayout() hbox.setContentsMargins(QtCore.QMargins(4, 2, 4, 2)) hbox.addStretch(1) for w in (wcmap, wimap): hbox.addWidget(w, stretch=0) hw = QtGui.QWidget() hw.setLayout(hbox) layout.addWidget(hw, stretch=0) vbox1.setLayout(layout) # Create a matplotlib Figure #self.fig = matplotlib.figure.Figure(figsize=(wd, ht)) self.fig = matplotlib.figure.Figure() self.canvas = FigureCanvas(self.fig) vbox2 = QtGui.QWidget() layout = QtGui.QVBoxLayout() # scrw = QtGui.QScrollArea() # scrw.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded) # scrw.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded) # scrw.setWidgetResizable(True) # layout.addWidget(scrw, stretch=1) # scrw.setWidget(self.canvas) layout.addWidget(self.canvas, stretch=1) # Add matplotlib buttons hbox = QtGui.QHBoxLayout() hbox.setContentsMargins(QtCore.QMargins(4, 2, 4, 2)) wgetimg = QtGui.QPushButton("Get Data") wgetimg.clicked.connect(self.get_image) wgetrgb = QtGui.QPushButton("Get RGB") wgetrgb.clicked.connect(self.get_rgb_image) #wquit = QtGui.QPushButton("Quit") #wquit.clicked.connect(self.close) hbox.addStretch(1) for w in (wgetimg, wgetrgb): hbox.addWidget(w, stretch=0) hw = QtGui.QWidget() hw.setLayout(hbox) layout.addWidget(hw, stretch=0) vbox2.setLayout(layout) vbox = QtGui.QVBoxLayout() vbox.setContentsMargins(QtCore.QMargins(2, 2, 2, 2)) vbox.setSpacing(1) w = QtGui.QWidget() layout = QtGui.QHBoxLayout() layout.addWidget(vbox1, stretch=1.0) layout.addWidget(vbox2, stretch=1.0) w.setLayout(layout) vbox.addWidget(w, stretch=1) self.readout = QtGui.QLabel("") vbox.addWidget(self.readout, stretch=0, alignment=QtCore.Qt.AlignCenter) vw = QtGui.QWidget() vw.setLayout(vbox) self.setCentralWidget(vw)