def update_selection(selection, viewer): """Called after an ImageJ selection keypress. Assumes first dataset contains the 'x' and 'y' components. Builds a Glue SubsetState and applies it using Glue's current settings. Selection consists of (xmin, xmax, ymin, ymax) """ xmin, xmax, ymin, ymax = selection roi = RectangularROI(xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax) xatt = lasagna.config.app.data_collection[0].data.find_component_id('x') yatt = lasagna.config.app.data_collection[0].data.find_component_id('y') xy_state = RoiSubsetState(xatt=xatt, yatt=yatt, roi=roi) file_state = CategorySubsetState(viewer.source_id, viewer.source_val) # selection only applies to data in displayed file subset_state = AndState(xy_state, file_state) data_collection = lasagna.config.app.data_collection # if no subset groups selected, make a new one layers = (lasagna.config.app._layer_widget.selected_layers()) subset_groups = [s for s in layers if isinstance(s, SubsetGroup)] if len(subset_groups) == 0: global fiji_label new_label = 'Fiji %d' % fiji_label fiji_label += 1 data_collection.new_subset_group(label=new_label, subset_state=subset_state) else: edit_mode = EditSubsetMode() edit_mode.update(data_collection, subset_state)
def apply_roi(self, roi): # every editable subset is updated # using specified ROI if isinstance(roi, RangeROI): lo, hi = roi.range() att = self.xatt if roi.ori == 'x' else self.yatt if self._check_categorical(att): comp = list(self._get_data_components(roi.ori)) if comp: subset_state = CategoricalRoiSubsetState.from_range(comp[0], att, lo, hi) else: subset_state = None else: subset_state = RangeSubsetState(lo, hi, att) else: if self._check_categorical(self.xatt) or self._check_categorical(self.yatt): subset_state = self._process_categorical_roi(roi) else: subset_state = RoiSubsetState() subset_state.xatt = self.xatt subset_state.yatt = self.yatt x, y = roi.to_polygon() subset_state.roi = PolygonalROI(x, y) mode = EditSubsetMode() visible = [d for d in self._data if self.is_visible(d)] focus = visible[0] if len(visible) > 0 else None mode.update(self._data, subset_state, focus_data=focus)
def mark_selected_dict(self, indices_dict): subset_state = MultiElementSubsetState(indices_dict=indices_dict) mode = EditSubsetMode() if len(indices_dict) > 0: mode.update(self.viewer._data, subset_state, focus_data=list(indices_dict)[0])
def _update_editable_subset(self): """Update edit subsets to match current selection""" mode = EditSubsetMode() mode.edit_subset = [ s for s in self.selected_layers() if isinstance(s, core.SubsetGroup) ]
def apply_roi(self, roi): x, _ = roi.to_polygon() lo = min(x) hi = max(x) # expand roi to match bin edges bins = self.bins if lo >= bins.min(): lo = bins[bins <= lo].max() if hi <= bins.max(): hi = bins[bins >= hi].min() if self.xlog: lo = 10 ** lo hi = 10 ** hi comp = list(self._get_data_components('x')) if comp: comp = comp[0] if comp.categorical: state = CategoricalRoiSubsetState.from_range(comp, self.component, lo, hi) else: state = RangeSubsetState(lo, hi) state.att = self.component mode = EditSubsetMode() visible = [d for d in self.data if self.is_layer_visible(d)] focus = visible[0] if len(visible) > 0 else None mode.update(self.data, state, focus_data=focus)
def apply_roi(self, roi): # TODO: move this to state class? # TODO: add back command stack here so as to be able to undo? # cmd = command.ApplyROI(client=self.client, roi=roi) # self._session.command_stack.do(cmd) # TODO Does subset get applied to all data or just visible data? bins = self.state.bins x = roi.to_polygon()[0] lo, hi = min(x), max(x) if lo >= bins.min(): lo = bins[bins <= lo].max() if hi <= bins.max(): hi = bins[bins >= hi].min() roi_new = RangeROI(min=lo, max=hi, orientation='x') for layer_artist in self._layer_artist_container: if not isinstance(layer_artist.layer, Data): continue x_comp = layer_artist.layer.get_component(self.state.x_att) subset_state = x_comp.subset_from_roi(self.state.x_att, roi_new, coord='x') mode = EditSubsetMode() mode.update(self._data, subset_state, focus_data=layer_artist.layer)
def do(self, session): self.old_states = {} for data in self.data_collection: for subset in data.subsets: self.old_states[subset] = subset.subset_state mode = EditSubsetMode() mode.update(self.data_collection, self.subset_state)
def mark_selected(self, mask, data): # We now make a subset state. For scatter plots we'll want to use an # ElementSubsetState, while for cubes, we'll need to change to a # MaskSubsetState. subset_state = ElementSubsetState(indices=np.where(mask)[0], data=data) # We now check what the selection mode is, and update the selection as # needed (this is delegated to the correct subset mode). mode = EditSubsetMode() mode.update(self.viewer._data, subset_state, focus_data=data)
def apply_roi(self, roi): subset_state = RoiSubsetState() xroi, yroi = roi.to_polygon() x, y = self._get_plot_attributes() subset_state.xatt = x subset_state.yatt = y subset_state.roi = PolygonalROI(xroi, yroi) mode = EditSubsetMode() mode.update(self.data, subset_state, focus_data=self.display_data)
def _broadcast_selection(self): if self.data is not None: model = self.ui.table.selectionModel() self.selected_rows = [self.model.order[x.row()] for x in model.selectedRows()] subset_state = ElementSubsetState(self.selected_rows) mode = EditSubsetMode() mode.update(self.data, subset_state, focus_data=self.data)
def mark_selected(self, mask, visible_data): # We now make a subset state. For scatter plots we'll want to use an # ElementSubsetState, while for cubes, we'll need to change to a # MaskSubsetState. subset_state = ElementSubsetState(np.where(mask)[0]) # We now check what the selection mode is, and update the selection as # needed (this is delegated to the correct subset mode). mode = EditSubsetMode() focus = visible_data[0] if len(visible_data) > 0 else None mode.update(self._data_collection, subset_state, focus_data=focus)
def finalize_selection(self, clear=True): model = self.ui.table.selectionModel() selected_rows = [self.model.order[x.row()] for x in model.selectedRows()] subset_state = ElementSubsetState(indices=selected_rows, data=self.data) mode = EditSubsetMode() mode.update(self._data, subset_state, focus_data=self.data) if clear: # We block the signals here to make sure that we don't update # the subset again once the selection is cleared. self.ui.table.blockSignals(True) self.ui.table.clearSelection() self.ui.table.blockSignals(False)
def _apply_roi(self, roi): x_comp = self.state.x_att.parent.get_component(self.state.x_att) y_comp = self.state.y_att.parent.get_component(self.state.y_att) subset_state = x_comp.subset_from_roi(self.state.x_att, roi, other_comp=y_comp, other_att=self.state.y_att, coord='x') mode = EditSubsetMode() mode.update(self._data, subset_state)
def _broadcast_selection(self): if self.data is not None: model = self.ui.table.selectionModel() self.selected_rows = [ self.model.order[x.row()] for x in model.selectedRows() ] subset_state = ElementSubsetState(self.selected_rows) mode = EditSubsetMode() mode.update(self.data, subset_state, focus_data=self.data)
def _apply_roi(self, roi): # TODO Does subset get applied to all data or just visible data? x_comp = self.state.x_att.parent.get_component(self.state.x_att) y_comp = self.state.y_att.parent.get_component(self.state.y_att) subset_state = x_comp.subset_from_roi(self.state.x_att, roi, other_comp=y_comp, other_att=self.state.y_att, coord='x') mode = EditSubsetMode() mode.update(self._data, subset_state)
def apply_roi(self, roi): # every editable subset is updated # using specified ROI for x_comp, y_comp in zip(self._get_data_components('x'), self._get_data_components('y')): subset_state = x_comp.subset_from_roi(self.xatt, roi, other_comp=y_comp, other_att=self.yatt, coord='x') mode = EditSubsetMode() visible = [d for d in self._data if self.is_visible(d)] focus = visible[0] if len(visible) > 0 else None mode.update(self._data, subset_state, focus_data=focus)
def _floodfill_roi(self, mode): """ Callback for FloodfillMode. """ if mode._start_event is None or mode._end_event is None: return data = self.widget.client.display_data att = self.widget.client.display_attribute if data is None or att is None: return if data.size > WARN_THRESH and not self.widget._confirm_large_image( data): return # Determine length of dragging action in units relative to the figure width, height = mode._start_event.canvas.get_width_height() dx = (mode._end_event.x - mode._start_event.x) / width dy = (mode._end_event.y - mode._start_event.y) / height length = np.hypot(dx, dy) # Make sure the coordinates are converted to the nearest integer x = int(round(mode._start_event.xdata)) y = int(round(mode._start_event.ydata)) if data.ndim == 2: start_coord = (y, x) else: z = int(round(self.widget.client.slice[self.profile_axis])) start_coord = (z, y, x) # We convert the length in relative figure units to a threshold - we make # it so that moving by 0.1 produces a threshold of 1.1, 0.2 -> 2, 0.3 -> 11 # etc threshold = 1 + 10**(length / 0.1 - 1) # coordinate should be integers as index for array values = np.asarray(data[att], dtype=float) mask = floodfill_scipy(values, start_coord, threshold) if mask is not None: cids = data.pixel_component_ids subset_state = MaskSubsetState(mask, cids) mode = EditSubsetMode() mode.update(data, subset_state, focus_data=data)
def __init__(self, title="Subset Update Mode", parent=None): super(EditSubsetModeToolBar, self).__init__(title, parent) self._group = QtWidgets.QActionGroup(self) self._modes = {} self._add_actions() self._modes[EditSubsetMode().mode].trigger() self._backup_mode = None
def apply_roi(self, roi): if not isinstance(roi, PointROI): raise NotImplementedError("Only PointROI supported") if self._layout is None or self.display_data is None: return x, y = roi.x, roi.y if not roi.defined(): return xs, ys = self._layout[:, ::3] parent_ys = self._layout[1, 1::3] delt = np.abs(x - xs) delt[y > ys] = np.nan delt[y < parent_ys] = np.nan if np.isfinite(delt).any(): select = np.nanargmin(delt) if self.select_substruct: select = self._substructures(select) select = np.asarray(select, dtype=np.int) else: select = np.array([], dtype=np.int) state = CategorySubsetState(self.display_data.pixel_component_ids[0], select) EditSubsetMode().update(self.collect, state, focus_data=self.display_data)
def _floodfill_roi(self, mode): """ Callback for FloodfillMode. """ if mode._start_event is None or mode._end_event is None: return data = self.widget.client.display_data att = self.widget.client.display_attribute if data is None or att is None: return if data.size > WARN_THRESH and not self.widget._confirm_large_image(data): return # Determine length of dragging action in units relative to the figure width, height = mode._start_event.canvas.get_width_height() dx = (mode._end_event.x - mode._start_event.x) / width dy = (mode._end_event.y - mode._start_event.y) / height length = np.hypot(dx, dy) # Make sure the coordinates are converted to the nearest integer x = int(round(mode._start_event.xdata)) y = int(round(mode._start_event.ydata)) if data.ndim == 2: start_coord = (y, x) else: z = int(round(self.widget.client.slice[self.profile_axis])) start_coord = (z, y, x) # We convert the length in relative figure units to a threshold - we make # it so that moving by 0.1 produces a threshold of 1.1, 0.2 -> 2, 0.3 -> 11 # etc threshold = 1 + 10 ** (length / 0.1 - 1) # coordinate should be integers as index for array values = np.asarray(data[att], dtype=float) mask = floodfill_scipy(values, start_coord, threshold) if mask is not None: cids = data.pixel_component_ids subset_state = MaskSubsetState(mask, cids) mode = EditSubsetMode() mode.update(data, subset_state, focus_data=data)
def setup_method(self, method): self.data = Data(parent=[4, 4, 5, 5, 5, -1], height=[5, 4, 3, 2, 1, 0], label='dendro') self.dc = DataCollection([self.data]) self.hub = self.dc.hub self.client = DendroClient(self.dc, figure=FIGURE) EditSubsetMode().data_collection = self.dc
def test_single_selection_updates_editable(self): mode = EditSubsetMode() self.widget.bind_selection_to_edit_subset() self.add_layer() grp1 = self.collect.new_subset_group() grp2 = self.collect.new_subset_group() assert mode.edit_subset[0] is not grp1 self.select_layers(grp1) assert mode.edit_subset[0] is grp1
def apply_roi(self, roi): if len(self.artists) > 0: focus = self.artists[0].layer.data elif len(self.collect) > 0: focus = self.collect[0] else: return s = self._coordinator._build_subset_state(roi=roi) if s: EditSubsetMode().update(self.collect, s, focus_data=focus)
def test_multi_selection_updates_editable(self): """Selection disables edit_subset for all other data""" mode = EditSubsetMode() self.widget.bind_selection_to_edit_subset() self.add_layer() self.add_layer() grps = [self.collect.new_subset_group() for _ in range(3)] self.select_layers(*grps[:2]) assert grps[0] in mode.edit_subset assert grps[1] in mode.edit_subset assert grps[2] not in mode.edit_subset
def __init__(self, application=None, data_collection=None, command_stack=None, hub=None): self.application = application self.data_collection = data_collection or DataCollection() self.hub = self.data_collection.hub self.command_stack = command_stack or CommandStack() self.command_stack.session = self self.edit_subset_mode = EditSubsetMode() self.edit_subset_mode.data_collection = self.data_collection
def set_mode(self, mode): """Temporarily set the edit mode to mode :param mode: Name of the mode (Or, Not, And, Xor, Replace) :type mode: str """ try: mode = self._modes[mode] # label to mode class except KeyError: raise KeyError("Unrecognized mode: %s" % mode) self._backup_mode = self._backup_mode or EditSubsetMode().mode self._modes[mode].trigger() # mode class to action
def _apply_roi(self, roi): # TODO Does subset get applied to all data or just visible data? bins = self.state.bins x = roi.to_polygon()[0] lo, hi = min(x), max(x) if lo >= bins.min(): lo = bins[bins <= lo].max() if hi <= bins.max(): hi = bins[bins >= hi].min() roi_new = RangeROI(min=lo, max=hi, orientation='x') x_comp = self.state.x_att.parent.get_component(self.state.x_att) subset_state = x_comp.subset_from_roi(self.state.x_att, roi_new, coord='x') mode = EditSubsetMode() mode.update(self._data, subset_state)
def __init__(self, application=None, data_collection=None, command_stack=None, hub=None): # applications can be added after instantiation self.application = application self.data_collection = data_collection or DataCollection() self.hub = self.data_collection.hub self.command_stack = command_stack or CommandStack() self.command_stack.session = self # set the global data_collection for subset updates from glue.core.edit_subset_mode import EditSubsetMode EditSubsetMode().data_collection = self.data_collection
def apply_roi(self, roi): x, _ = roi.to_polygon() lo = min(x) hi = max(x) # expand roi to match bin edges bins = self.bins if lo >= bins.min(): lo = bins[bins <= lo].max() if hi <= bins.max(): hi = bins[bins >= hi].min() if self.xlog: lo = 10 ** lo hi = 10 ** hi nroi = RangeROI(min=lo, max=hi, orientation='x') for comp in self._get_data_components('x'): state = comp.subset_from_roi(self.component, nroi, coord='x') mode = EditSubsetMode() visible = [d for d in self.data if self.is_layer_visible(d)] focus = visible[0] if len(visible) > 0 else None mode.update(self.data, state, focus_data=focus)
def apply_roi(self, roi): x, _ = roi.to_polygon() lo = min(x) hi = max(x) # expand roi to match bin edges bins = self.bins if lo >= bins.min(): lo = bins[bins <= lo].max() if hi <= bins.max(): hi = bins[bins >= hi].min() if self.xlog: lo = 10**lo hi = 10**hi nroi = RangeROI(min=lo, max=hi, orientation='x') for comp in self._get_data_components('x'): state = comp.subset_from_roi(self.component, nroi, coord='x') mode = EditSubsetMode() visible = [d for d in self.data if self.is_layer_visible(d)] focus = visible[0] if len(visible) > 0 else None mode.update(self.data, state, focus_data=focus)
def __init__(self, data_collection=None, session=None): if session is not None: self._session = session session.application = self self._data = session.data_collection else: self._data = data_collection or DataCollection() self._session = Session(data_collection=self._data, application=self) EditSubsetMode().data_collection = self._data self._hub = self._session.hub self._cmds = self._session.command_stack self._cmds.add_callback(lambda x: self._update_undo_redo_enabled()) self._settings = {} for key, value, validator in settings: self._settings[key] = [value, validator]
def setup_method(self, method): self.data = example_data.test_data() self.ids = [ self.data[0].find_component_id('a'), self.data[0].find_component_id('b'), self.data[1].find_component_id('c'), self.data[1].find_component_id('d') ] self.roi_limits = (0.5, 0.5, 1.5, 1.5) self.roi_points = (np.array([1]), np.array([1])) self.collect = DataCollection() EditSubsetMode().data_collection = self.collect self.hub = self.collect.hub FIGURE.clf() axes = FIGURE.add_subplot(111) self.client = ScatterClient(self.collect, axes=axes) self.connect()
def __init__(self, title="Subset Update Mode", parent=None): super(EditSubsetModeToolBar, self).__init__(title, parent) spacer = QtWidgets.QWidget() spacer.setMinimumSize(20, 10) spacer.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred) self.addWidget(spacer) self.addWidget(QtWidgets.QLabel("Selection Mode:")) self.setIconSize(QtCore.QSize(20, 20)) self._group = QtWidgets.QActionGroup(self) self._modes = {} self._add_actions() self._modes[EditSubsetMode().mode].trigger() self._backup_mode = None spacer = QtWidgets.QWidget() spacer.setMinimumSize(20, 10) spacer.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred) self.addWidget(spacer)
def mark_selected_dict(self, mask_dict): subset_state = MultiMaskSubsetState(mask_dict=mask_dict) mode = EditSubsetMode() if len(mask_dict) > 0: mode.update(self.viewer._data, subset_state, focus_data=list(mask_dict)[0])
def set_mode(mode): edit_mode = EditSubsetMode() edit_mode.mode = mode
def _update_editable_subset(self): """Update edit subsets to match current selection""" mode = EditSubsetMode() mode.edit_subset = [s for s in self.selected_layers() if isinstance(s, core.SubsetGroup)]
def test_table_widget(tmpdir): # Start off by creating a glue application instance with a table viewer and # some data pre-loaded. app = get_qapp() d = Data(a=[1, 2, 3, 4, 5], b=[3.2, 1.2, 4.5, 3.3, 2.2], c=['e', 'b', 'c', 'a', 'f']) dc = DataCollection([d]) gapp = GlueApplication(dc) widget = gapp.new_data_viewer(TableWidget) widget.add_data(d) subset_mode = EditSubsetMode() # Create two subsets sg1 = dc.new_subset_group('D <= 3', d.id['a'] <= 3) sg1.style.color = '#aa0000' sg2 = dc.new_subset_group('1 < D < 4', (d.id['a'] > 1) & (d.id['a'] < 4)) sg2.style.color = '#0000cc' model = widget.ui.table.model() # We now check what the data and colors of the table are, and try various # sorting methods to make sure that things are still correct. data = { 'a': [1, 2, 3, 4, 5], 'b': [3.2, 1.2, 4.5, 3.3, 2.2], 'c': ['e', 'b', 'c', 'a', 'f'] } colors = ['#aa0000', '#380088', '#380088', None, None] check_values_and_color(model, data, colors) model.sort(1, Qt.AscendingOrder) data = { 'a': [2, 5, 1, 4, 3], 'b': [1.2, 2.2, 3.2, 3.3, 4.5], 'c': ['b', 'f', 'e', 'a', 'c'] } colors = ['#380088', None, '#aa0000', None, '#380088'] check_values_and_color(model, data, colors) model.sort(2, Qt.AscendingOrder) data = { 'a': [4, 2, 3, 1, 5], 'b': [3.3, 1.2, 4.5, 3.2, 2.2], 'c': ['a', 'b', 'c', 'e', 'f'] } colors = [None, '#380088', '#380088', '#aa0000', None] check_values_and_color(model, data, colors) model.sort(0, Qt.DescendingOrder) data = { 'a': [5, 4, 3, 2, 1], 'b': [2.2, 3.3, 4.5, 1.2, 3.2], 'c': ['f', 'a', 'c', 'b', 'e'] } colors = [None, None, '#380088', '#380088', '#aa0000'] check_values_and_color(model, data, colors) model.sort(0, Qt.AscendingOrder) # We now modify the subsets using the table. selection = widget.ui.table.selectionModel() widget.toolbar.actions['table:rowselect'].toggle() def press_key(key): event = QtGui.QKeyEvent(QtCore.QEvent.KeyPress, key, Qt.NoModifier) app.postEvent(widget.ui.table, event) app.processEvents() app.processEvents() # We now use key presses to navigate down to the third row press_key(Qt.Key_Tab) press_key(Qt.Key_Down) press_key(Qt.Key_Down) indices = selection.selectedRows() # We make sure that the third row is selected assert len(indices) == 1 assert indices[0].row() == 2 # At this point, the subsets haven't changed yet np.testing.assert_equal(d.subsets[0].to_mask(), [1, 1, 1, 0, 0]) np.testing.assert_equal(d.subsets[1].to_mask(), [0, 1, 1, 0, 0]) # We specify that we are editing the second subset, and use a 'not' logical # operation to remove the currently selected line from the second subset. d.edit_subset = [d.subsets[1]] subset_mode.mode = AndNotMode press_key(Qt.Key_Enter) np.testing.assert_equal(d.subsets[0].to_mask(), [1, 1, 1, 0, 0]) np.testing.assert_equal(d.subsets[1].to_mask(), [0, 1, 0, 0, 0]) # At this point, the selection should be cleared indices = selection.selectedRows() assert len(indices) == 0 # We move to the fourth row and now do an 'or' selection with the first # subset. press_key(Qt.Key_Down) subset_mode.mode = OrMode d.edit_subset = [d.subsets[0]] press_key(Qt.Key_Enter) np.testing.assert_equal(d.subsets[0].to_mask(), [1, 1, 1, 1, 0]) np.testing.assert_equal(d.subsets[1].to_mask(), [0, 1, 0, 0, 0]) # Finally we move to the fifth row and deselect all subsets so that # pressing enter now creates a new subset. press_key(Qt.Key_Down) subset_mode.mode = ReplaceMode d.edit_subset = None press_key(Qt.Key_Enter) np.testing.assert_equal(d.subsets[0].to_mask(), [1, 1, 1, 1, 0]) np.testing.assert_equal(d.subsets[1].to_mask(), [0, 1, 0, 0, 0]) np.testing.assert_equal(d.subsets[2].to_mask(), [0, 0, 0, 0, 1]) # Make the color for the new subset deterministic dc.subset_groups[2].style.color = '#bababa' # Now finally check saving and restoring session session_file = tmpdir.join('table.glu').strpath gapp.save_session(session_file) gapp2 = GlueApplication.restore_session(session_file) gapp2.show() d = gapp2.data_collection[0] widget2 = gapp2.viewers[0][0] model2 = widget2.ui.table.model() data = { 'a': [1, 2, 3, 4, 5], 'b': [3.2, 1.2, 4.5, 3.3, 2.2], 'c': ['e', 'b', 'c', 'a', 'f'] } # Need to take into account new selections above colors = ['#aa0000', '#380088', '#aa0000', "#aa0000", "#bababa"] check_values_and_color(model2, data, colors)
def pytest_runtest_setup(item): mode = EditSubsetMode() mode.mode = ReplaceMode mode.edit_subset = []