Example #1
0
    def set_colormap(self, cmap):
        """Set colormap to the given colormap name.

        Parameters
        ----------
        cmap : str
            Colormap name. Possible values can be obtained from
            :meth:`colormap_options`.

        Raises
        ------
        ValueError
            Invalid colormap name.

        """
        cm = None
        for member in colormaps.members:
            if member[1].name == cmap:
                cm = member[1]
                break

        if cm is None:
            raise ValueError(
                f"Invalid colormap '{cmap}', must be one of {self.colormap_options}"
            )

        i_top = get_top_layer_index(self)
        self.state.layers[i_top].cmap = cm
Example #2
0
    def cuts(self, val):
        i_top = get_top_layer_index(self)

        if isinstance(val, str):  # autocut
            if val == 'minmax':
                val = 100
            elif val == '99.5%':
                val = 99.5
            elif val == '99%':
                val = 99
            elif val == '95%':
                val = 95
            elif val == '90%':
                val = 90
            else:
                raise ValueError(
                    f"Invalid autocut '{val}', must be one of {self.autocut_options}"
                )
            self.state.layers[i_top].percentile = val
        else:  # (low, high)
            if (not isinstance(val, (list, tuple)) or len(val) != 2
                    or not np.all([isinstance(x, (int, float)) for x in val])):
                raise ValueError(
                    f"Invalid cut levels {val}, must be (low, high)")
            self.state.layers[i_top].v_min = val[0]
            self.state.layers[i_top].v_max = val[1]
Example #3
0
 def on_limits_change(self, *args):
     try:
         i = get_top_layer_index(self)
     except IndexError:
         if self.compass is not None:
             self.compass.clear_compass()
         return
     self.set_compass(self.state.layers[i].layer)
Example #4
0
    def on_mouse_or_key_event(self, data):
        from jdaviz.configs.imviz.helper import get_top_layer_index

        event = data['event']

        # Note that we throttle this to 200ms here as changing the contrast
        # and bias it expensive since it forces the whole image to be redrawn
        if event == 'dragmove':
            if (time.time() - self._time_last) <= 0.2:
                return

            event_x = data['pixel']['x']
            event_y = data['pixel']['y']
            max_x = self.viewer.shape[1]
            max_y = self.viewer.shape[0]

            if ((event_x < 0) or (event_x >= max_x) or
                    (event_y < 0) or (event_y >= max_y)):
                return

            # Normalize w.r.t. viewer display from 0 to 1
            x = event_x / (max_x - 1)
            y = event_y / (max_y - 1)

            # When blinked, first layer might not be top layer
            i_top = get_top_layer_index(self.viewer)
            state = self.viewer.layers[i_top].state

            # bias range 0..1
            # contrast range 0..4
            with delay_callback(state, 'bias', 'contrast'):
                state.bias = x
                state.contrast = y * 4

            self._time_last = time.time()

        elif event == 'dblclick':
            # When blinked, first layer might not be top layer
            i_top = get_top_layer_index(self.viewer)
            state = self.viewer.layers[i_top].state

            # Restore defaults that are applied on load
            with delay_callback(state, 'bias', 'contrast'):
                state.bias = 0.5
                state.contrast = 1
Example #5
0
    def cuts(self):
        """Current image cut levels.

        To set new cut levels, either provide a tuple of ``(low, high)`` values
        or one of the options from `autocut_options`.

        """
        i_top = get_top_layer_index(self)
        return self.state.layers[i_top].v_min, self.state.layers[i_top].v_max
Example #6
0
    def center_on(self, point):
        """Centers the view on a particular point.

        Parameters
        ----------
        point : tuple or `~astropy.coordinates.SkyCoord`
            If tuple of ``(X, Y)`` is given, it is assumed
            to be in data coordinates and 0-indexed.

        Raises
        ------
        AttributeError
            Sky coordinates are given but image does not have a valid WCS.

        """
        i_top = get_top_layer_index(self)
        image = self.layers[i_top].layer

        if isinstance(point, SkyCoord):
            if data_has_valid_wcs(image):
                try:
                    pix = image.coords.world_to_pixel(point)  # 0-indexed X, Y
                except NoConvergence as e:  # pragma: no cover
                    self.session.hub.broadcast(
                        SnackbarMessage(
                            f'{point} is likely out of bounds: {repr(e)}',
                            color="warning",
                            sender=self))
                    return
            else:
                raise AttributeError(
                    f'{getattr(image, "label", None)} does not have a valid WCS'
                )
        else:
            pix = point

        # Disallow centering outside of display; image.shape is (Y, X)
        eps = sys.float_info.epsilon
        if (not np.all(np.isfinite(pix)) or pix[0] < -eps or pix[0] >=
            (image.shape[1] + eps) or pix[1] < -eps or pix[1] >=
            (image.shape[0] + eps)):
            self.session.hub.broadcast(
                SnackbarMessage(f'{pix} is out of bounds',
                                color="warning",
                                sender=self))
            return

        width = self.state.x_max - self.state.x_min
        height = self.state.y_max - self.state.y_min

        with delay_callback(self.state, 'x_min', 'x_max', 'y_min', 'y_max'):
            self.state.x_min = pix[0] - (width * 0.5)
            self.state.y_min = pix[1] - (height * 0.5)
            self.state.x_max = self.state.x_min + width
            self.state.y_max = self.state.y_min + height
Example #7
0
    def stretch(self, val):
        valid_vals = self.stretch_options

        if isinstance(val, type):  # is a class
            # Translate astropy.visualization
            from astropy.visualization import AsinhStretch, LinearStretch, LogStretch, SqrtStretch
            if issubclass(val, AsinhStretch):
                val = 'arcsinh'
            elif issubclass(val, LinearStretch):
                val = 'linear'
            elif issubclass(val, LogStretch):
                val = 'log'
            elif issubclass(val, SqrtStretch):
                val = 'sqrt'
            else:
                raise ValueError(
                    f"Invalid stretch {val}, must be one of {valid_vals}")
        elif val not in valid_vals:
            raise ValueError(
                f"Invalid stretch '{val}', must be one of {valid_vals}")

        i_top = get_top_layer_index(self)
        self.state.layers[i_top].stretch = val
Example #8
0
 def stretch(self):
     """The image stretching algorithm in use."""
     i_top = get_top_layer_index(self)
     return self.state.layers[i_top].stretch
Example #9
0
    def offset_by(self, dx, dy):
        """Move the center to a point that is given offset
        away from the current center.

        Parameters
        ----------
        dx, dy : float or `~astropy.units.Quantity`
            Offset value. Without a unit, assumed to be pixel offsets.
            If a unit is attached, offset by pixel or sky is assumed from
            the unit.

        Raises
        ------
        AttributeError
            Sky offset is given but image does not have a valid WCS.

        ValueError
            Offsets are of different types.

        astropy.units.core.UnitTypeError
            Sky offset has invalid unit.

        """
        width = self.state.x_max - self.state.x_min
        height = self.state.y_max - self.state.y_min

        dx, dx_coord = _offset_is_pixel_or_sky(dx)
        dy, dy_coord = _offset_is_pixel_or_sky(dy)

        if dx_coord != dy_coord:
            raise ValueError(
                f'dx is of type {dx_coord} but dy is of type {dy_coord}')

        if dx_coord == 'wcs':
            i_top = get_top_layer_index(self)
            image = self.layers[i_top].layer
            if data_has_valid_wcs(image):
                # To avoid distortion headache, assume offset is relative to
                # displayed center.
                x_cen = self.state.x_min + (width * 0.5)
                y_cen = self.state.y_min + (height * 0.5)
                sky_cen = image.coords.pixel_to_world(x_cen, y_cen)
                if ASTROPY_LT_4_3:
                    from astropy.coordinates import SkyOffsetFrame
                    new_sky_cen = sky_cen.__class__(
                        SkyOffsetFrame(
                            dx, dy,
                            origin=sky_cen.frame).transform_to(sky_cen))
                else:
                    new_sky_cen = sky_cen.spherical_offsets_by(dx, dy)
                self.center_on(new_sky_cen)
            else:
                raise AttributeError(
                    f'{getattr(image, "label", None)} does not have a valid WCS'
                )
        else:
            with delay_callback(self.state, 'x_min', 'x_max', 'y_min',
                                'y_max'):
                self.state.x_min += dx
                self.state.y_min += dy
                self.state.x_max = self.state.x_min + width
                self.state.y_max = self.state.y_min + height