<commit_before>from __future__ import absolute_import, division, print_function

from glue.core import Data
from glue.config import colormaps
from glue.viewers.matplotlib.state import (MatplotlibDataViewerState,
                                           MatplotlibLayerState,
                                           DeferredDrawCallbackProperty)
from glue.core.state_objects import StateAttributeLimitsHelper
from glue.utils import defer_draw

__all__ = ['ImageViewerState', 'ImageLayerState']

# Define shortcut for readability
DDCProperty = DeferredDrawCallbackProperty


class ImageViewerState(MatplotlibDataViewerState):

    x_att = DDCProperty(docstring='The component ID giving the pixel component '
                                  'shown on the x axis')
    y_att = DDCProperty(docstring='The component ID giving the pixel component '
                                  'shown on the y axis')
    x_att_world = DDCProperty(docstring='The component ID giving the world component '
                                        'shown on the x axis')
    y_att_world = DDCProperty(docstring='The component ID giving the world component '
                                        'shown on the y axis')
    aspect = DDCProperty('equal', docstring='Whether to enforce square pixels (``equal``) '
                                            'or fill the axes (``auto``)')
    reference_data = DDCProperty(docstring='The dataset that is used to define the '
                                           'available pixel/world components, and '
                                           'which defines the coordinate frame in '
                                           'which the images are shown')
    slices = DDCProperty(docstring='The current slice along all dimensions')
    color_mode = DDCProperty('Colormaps', docstring='Whether each layer can have '
                                                    'its own colormap (``Colormaps``) or '
                                                    'whether each layer is assigned '
                                                    'a single color (``One color per layer``)')

    def __init__(self, **kwargs):

        super(ImageViewerState, self).__init__(**kwargs)

        self.add_callback('x_att_world', self._update_x_att, priority=500)
        self.add_callback('y_att_world', self._update_y_att, priority=500)

        self.limits_cache = {}

        self.x_att_helper = StateAttributeLimitsHelper(self, attribute='x_att',
                                                       lower='x_min', upper='x_max',
                                                       limits_cache=self.limits_cache)

        self.y_att_helper = StateAttributeLimitsHelper(self, attribute='y_att',
                                                       lower='y_min', upper='y_max',
                                                       limits_cache=self.limits_cache)

        self.add_callback('reference_data', self.set_default_slices)
        self.add_callback('layers', self.set_reference_data)

        self.add_callback('x_att_world', self._on_xatt_world_change, priority=1000)
        self.add_callback('y_att_world', self._on_yatt_world_change, priority=1000)

    def update_priority(self, name):
        if name == 'layers':
            return 3
        elif name == 'reference_data':
            return 2
        elif name.endswith(('_min', '_max')):
            return 0
        else:
            return 1

    @defer_draw
    def _update_x_att(self, *args):
        index = self.reference_data.world_component_ids.index(self.x_att_world)
        self.x_att = self.reference_data.pixel_component_ids[index]

    @defer_draw
    def _update_y_att(self, *args):
        index = self.reference_data.world_component_ids.index(self.y_att_world)
        self.y_att = self.reference_data.pixel_component_ids[index]

    @defer_draw
    def _on_xatt_world_change(self, *args):
        if self.x_att_world == self.y_att_world:
            world_ids = self.reference_data.world_component_ids
            if self.x_att_world == world_ids[-1]:
                self.y_att_world = world_ids[-2]
            else:
                self.y_att_world = world_ids[-1]

    @defer_draw
    def _on_yatt_world_change(self, *args):
        if self.y_att_world == self.x_att_world:
            world_ids = self.reference_data.world_component_ids
            if self.y_att_world == world_ids[-1]:
                self.x_att_world = world_ids[-2]
            else:
                self.x_att_world = world_ids[-1]

    def set_reference_data(self, *args):
        # TODO: make sure this doesn't get called for changes *in* the layers
        # for list callbacks maybe just have an event for length change in list
        if self.reference_data is None:
            for layer in self.layers:
                if isinstance(layer.layer, Data):
                    self.reference_data = layer.layer
                    return
<commit_msg>Avoid ending up in a situation where x_att == y_att, causing issues with the image extraction<commit_after>from __future__ import absolute_import, division, print_function

from glue.core import Data
from glue.config import colormaps
from glue.viewers.matplotlib.state import (MatplotlibDataViewerState,
                                           MatplotlibLayerState,
                                           DeferredDrawCallbackProperty)
from glue.core.state_objects import StateAttributeLimitsHelper
from glue.utils import defer_draw
from glue.external.echo import delay_callback

__all__ = ['ImageViewerState', 'ImageLayerState']

# Define shortcut for readability
DDCProperty = DeferredDrawCallbackProperty


class ImageViewerState(MatplotlibDataViewerState):

    x_att = DDCProperty(docstring='The component ID giving the pixel component '
                                  'shown on the x axis')
    y_att = DDCProperty(docstring='The component ID giving the pixel component '
                                  'shown on the y axis')
    x_att_world = DDCProperty(docstring='The component ID giving the world component '
                                        'shown on the x axis')
    y_att_world = DDCProperty(docstring='The component ID giving the world component '
                                        'shown on the y axis')
    aspect = DDCProperty('equal', docstring='Whether to enforce square pixels (``equal``) '
                                            'or fill the axes (``auto``)')
    reference_data = DDCProperty(docstring='The dataset that is used to define the '
                                           'available pixel/world components, and '
                                           'which defines the coordinate frame in '
                                           'which the images are shown')
    slices = DDCProperty(docstring='The current slice along all dimensions')
    color_mode = DDCProperty('Colormaps', docstring='Whether each layer can have '
                                                    'its own colormap (``Colormaps``) or '
                                                    'whether each layer is assigned '
                                                    'a single color (``One color per layer``)')

    def __init__(self, **kwargs):

        super(ImageViewerState, self).__init__(**kwargs)

        self.limits_cache = {}

        self.x_att_helper = StateAttributeLimitsHelper(self, attribute='x_att',
                                                       lower='x_min', upper='x_max',
                                                       limits_cache=self.limits_cache)

        self.y_att_helper = StateAttributeLimitsHelper(self, attribute='y_att',
                                                       lower='y_min', upper='y_max',
                                                       limits_cache=self.limits_cache)

        self.add_callback('reference_data', self.set_default_slices)
        self.add_callback('layers', self.set_reference_data)

        self.add_callback('x_att_world', self._update_att, priority=500)
        self.add_callback('y_att_world', self._update_att, priority=500)

        self.add_callback('x_att_world', self._on_xatt_world_change, priority=1000)
        self.add_callback('y_att_world', self._on_yatt_world_change, priority=1000)

    def update_priority(self, name):
        if name == 'layers':
            return 3
        elif name == 'reference_data':
            return 2
        elif name.endswith(('_min', '_max')):
            return 0
        else:
            return 1

    @defer_draw
    def _update_att(self, *args):
        # Need to delay the callbacks here to make sure that we get a chance to
        # update both x_att and y_att otherwise could end up triggering image
        # slicing with two pixel components that are the same.
        with delay_callback(self, 'x_att', 'y_att'):
            index = self.reference_data.world_component_ids.index(self.x_att_world)
            self.x_att = self.reference_data.pixel_component_ids[index]
            index = self.reference_data.world_component_ids.index(self.y_att_world)
            self.y_att = self.reference_data.pixel_component_ids[index]

    @defer_draw
    def _on_xatt_world_change(self, *args):
        if self.x_att_world == self.y_att_world:
            world_ids = self.reference_data.world_component_ids
            if self.x_att_world == world_ids[-1]:
                self.y_att_world = world_ids[-2]
            else:
                self.y_att_world = world_ids[-1]

    @defer_draw
    def _on_yatt_world_change(self, *args):
        if self.y_att_world == self.x_att_world:
            world_ids = self.reference_data.world_component_ids
            if self.y_att_world == world_ids[-1]:
                self.x_att_world = world_ids[-2]
            else:
                self.x_att_world = world_ids[-1]

    def set_reference_data(self, *args):
        # TODO: make sure this doesn't get called for changes *in* the layers
        # for list callbacks maybe just have an event for length change in list
        if self.reference_data is None:
            for layer in self.layers:
                if isinstance(layer.layer, Data):
                    self.reference_data = layer.layer
                    return

{'fraction_non_alphanumeric': 0.0767661063064814, 'fraction_numerical': 0.004664269750267224, 'mean_word_length': 1.886146943353898, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 60, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '786255', 'n_tokens_mistral': 2684, 'n_tokens_neox': 2573, 'n_words': 665}