예제 #1
0
    def test_range_rois_preserved(self):
        data = self.add_data_and_attributes()
        assert self.client.xatt is not self.client.yatt

        roi = XRangeROI()
        roi.set_range(1, 2)
        self.client.apply_roi(roi)
        assert isinstance(data.edit_subset.subset_state,
                          RangeSubsetState)
        assert data.edit_subset.subset_state.att == self.client.xatt

        roi = RectangularROI()
        roi = YRangeROI()
        roi.set_range(1, 2)
        self.client.apply_roi(roi)
        assert data.edit_subset.subset_state.att == self.client.yatt
예제 #2
0
 def test_apply_roi_empty(self):
     # Make sure that doing an ROI selection on an empty viewer doesn't
     # produce error messsages
     roi = XRangeROI(-0.2, 0.1)
     self.viewer.apply_roi(roi)
예제 #3
0
def roi_to_subset_state(roi, x_att=None, y_att=None, x_comp=None, y_comp=None):
    """
    Given a 2D ROI and attributes on the x and y axis, determine the
    corresponding subset state.
    """

    if isinstance(roi, RangeROI):

        if roi.ori == 'x':
            att = x_att
            comp = x_comp
        else:
            att = y_att
            comp = y_comp

        if comp.categorical:
            return CategoricalROISubsetState.from_range(comp, att, roi.min, roi.max)
        else:
            return RangeSubsetState(roi.min, roi.max, att)

    elif x_comp.categorical or y_comp.categorical:

        if isinstance(roi, RectangularROI):

            # In this specific case, we can decompose the rectangular ROI into
            # two RangeROIs that are combined with an 'and' logical operation.

            range1 = XRangeROI(roi.xmin, roi.xmax)
            range2 = YRangeROI(roi.ymin, roi.ymax)

            subset1 = roi_to_subset_state(range1, x_att=x_att, x_comp=x_comp)
            subset2 = roi_to_subset_state(range2, y_att=y_att, y_comp=y_comp)

            return AndState(subset1, subset2)

        elif isinstance(roi, CategoricalROI):

            # The selection is categorical itself. We assume this is along the x axis

            return CategoricalROISubsetState(roi=roi, att=x_att)

        else:

            # The selection is polygon-like, which requires special care.

            if x_comp.categorical and y_comp.categorical:

                # For each category, we check which categories along the other
                # axis fall inside the polygon:

                selection = {}

                for code, label in enumerate(x_comp.categories):

                    # Determine the coordinates of the points to check
                    n_other = len(y_comp.categories)
                    y = np.arange(n_other)
                    x = np.repeat(code, n_other)

                    # Determine which points are in the polygon, and which
                    # categories these correspond to
                    in_poly = roi.contains(x, y)
                    categories = y_comp.categories[in_poly]

                    if len(categories) > 0:
                        selection[label] = set(categories)

                return CategoricalROISubsetState2D(selection, x_att, y_att)

            else:

                # If one of the components is not categorical, we treat this as
                # if each categorical component was mapped to a numerical value,
                # and at each value, we keep track of the polygon intersection
                # with the component. This will result in zero, one, or multiple
                # separate numerical ranges for each categorical value.

                # TODO: if we ever allow the category order to be changed, we
                # need to figure out how to update this!

                # We loop over each category and for each one we find the
                # numerical ranges

                selection = {}

                if x_comp.categorical:
                    cat_comp = x_comp
                    cat_att = x_att
                    num_att = y_att
                    x, y = roi.to_polygon()
                else:
                    cat_comp = y_comp
                    cat_att = y_att
                    num_att = x_att
                    y, x = roi.to_polygon()

                for code, label in enumerate(cat_comp.categories):

                    # We determine all the numerical segments that represent the
                    # ensemble of points in y that fall in the polygon
                    # TODO: profile the following function
                    segments = polygon_line_intersections(x, y, xval=code)

                    if len(segments) > 0:
                        selection[label] = segments

                return CategoricalMultiRangeSubsetState(selection, cat_att=cat_att, num_att=num_att)

    else:

        # The selection is polygon-like and components are numerical

        subset_state = RoiSubsetState()
        subset_state.xatt = x_att
        subset_state.yatt = y_att
        subset_state.roi = PolygonalROI(*roi.to_polygon())

        return subset_state