class BqplotEllipseMode(BqplotCircleMode): icon = os.path.join(ICONS_DIR, 'glue_ellipse.svg') tool_id = 'bqplot:ellipse' action_text = 'Elliptical ROI' tool_tip = 'Define an elliptical region of interest' def __init__(self, viewer, roi=None, finalize_callback=None, **kwargs): super().__init__(viewer, **kwargs) self.interact = BrushEllipseSelector(x_scale=self.viewer.scale_x, y_scale=self.viewer.scale_y) # Workaround for bug that causes the `color` trait to not be recognized style = self.interact.style.copy() style['fill'] = INTERACT_COLOR border_style = self.interact.border_style.copy() border_style['fill'] = INTERACT_COLOR border_style['stroke'] = INTERACT_COLOR self.interact.style = style self.interact.border_style = border_style if roi is not None: self.update_from_roi(roi) self.interact.observe(self.update_selection, "brushing") self.interact.observe(self.on_selection_change, "selected_x") self.interact.observe(self.on_selection_change, "selected_y") self.finalize_callback = finalize_callback
def __init__(self, viewer, roi=None, finalize_callback=None, **kwargs): super().__init__(viewer, **kwargs) self.interact = BrushEllipseSelector(x_scale=self.viewer.scale_x, y_scale=self.viewer.scale_y) # Workaround for bug that causes the `color` trait to not be recognized style = self.interact.style.copy() style['fill'] = INTERACT_COLOR border_style = self.interact.border_style.copy() border_style['fill'] = INTERACT_COLOR border_style['stroke'] = INTERACT_COLOR self.interact.style = style self.interact.border_style = border_style if roi is not None: self.update_from_roi(roi) self.interact.observe(self.update_selection, "brushing") self.interact.observe(self.on_selection_change, "selected_x") self.interact.observe(self.on_selection_change, "selected_y") self.finalize_callback = finalize_callback
class BqplotCircleMode(InteractCheckableTool): icon = 'glue_circle' tool_id = 'bqplot:circle' action_text = 'Circular ROI' tool_tip = 'Define a circular region of interest' def __init__(self, viewer, roi=None, finalize_callback=None, **kwargs): super().__init__(viewer, **kwargs) self.interact = BrushEllipseSelector(x_scale=self.viewer.scale_x, y_scale=self.viewer.scale_y, pixel_aspect=1) # Workaround for bug that causes the `color` trait to not be recognized style = self.interact.style.copy() style['fill'] = INTERACT_COLOR border_style = self.interact.border_style.copy() border_style['fill'] = INTERACT_COLOR border_style['stroke'] = INTERACT_COLOR self.interact.style = style self.interact.border_style = border_style if roi is not None: self.update_from_roi(roi) self.interact.observe(self.update_selection, "brushing") self.interact.observe(self.on_selection_change, "selected_x") self.interact.observe(self.on_selection_change, "selected_y") self.finalize_callback = finalize_callback def update_selection(self, *args): if self.interact.brushing: return with self.viewer._output_widget: if self.interact.selected_x is not None and self.interact.selected_y is not None: x = self.interact.selected_x y = self.interact.selected_y # similar to https://github.com/glue-viz/glue/blob/b14ccffac6a5 # 271c2869ead9a562a2e66232e397/glue/core/roi.py#L1275-L1297 # We should now check if the radius in data coordinates is the same # along x and y, as if so then we can return a circle, otherwise we # should return an ellipse. xc = x.mean() yc = y.mean() rx = abs(x[1] - x[0])/2 ry = abs(y[1] - y[0])/2 if np.allclose(rx, ry): roi = CircularROI(xc=xc, yc=yc, radius=rx) else: roi = EllipticalROI(xc=xc, yc=yc, radius_x=rx, radius_y=ry) self.viewer.apply_roi(roi) if self.finalize_callback is not None: self.finalize_callback() def update_from_roi(self, roi): if isinstance(roi, CircularROI): rx = ry = roi.radius elif isinstance(roi, EllipticalROI): rx, ry = roi.radius_x, roi.radius_y else: raise TypeError(f'Cannot initialize a BqplotCircleMode from a {type(roi)}') self.interact.selected_x = [roi.xc - rx, roi.xc + rx] self.interact.selected_y = [roi.yc - ry, roi.yc + ry] def on_selection_change(self, *args): if self.interact.selected_x is None or self.interact.selected_y is None: if self.finalize_callback is not None: self.finalize_callback() def activate(self): with self.viewer._output_widget: self.interact.selected_x = None self.interact.selected_y = None super().activate()