From f654cad1dc146979eb7cf5f1eb2199488241490b Mon Sep 17 00:00:00 2001 From: Brianna Major Date: Wed, 21 Jun 2023 15:16:37 -0400 Subject: [PATCH 01/25] Generalize InteractiveTemplate class Decouples the InteractiveTemplate class from the LLNL import tool so that it can be used more broadly across the application. The class can now accept a list of vertices in raw coordinates and create a polygon, rectangle, or ellipse. If the static_mode attribute is set to False the user can translate or rotate the shape. Signed-off-by: Brianna Major --- hexrd/ui/interactive_template.py | 100 +++++++++++++++++++--------- hexrd/ui/llnl_import_tool_dialog.py | 33 ++++++--- 2 files changed, 90 insertions(+), 43 deletions(-) diff --git a/hexrd/ui/interactive_template.py b/hexrd/ui/interactive_template.py index cbe8bbdd6..6e909876d 100644 --- a/hexrd/ui/interactive_template.py +++ b/hexrd/ui/interactive_template.py @@ -8,17 +8,13 @@ from skimage.draw import polygon -from hexrd.ui.create_hedm_instrument import create_hedm_instrument -from hexrd.ui import resource_loader from hexrd.ui.hexrd_config import HexrdConfig from hexrd.ui.utils import has_nan class InteractiveTemplate: - def __init__(self, parent=None): - self.parent = parent.image_tab_widget.image_canvases[0] - self.ax = self.parent.axes_images[0] - self.panels = create_hedm_instrument().detectors + def __init__(self, parent, detector, instrument=None): + self.image_tab_widget = parent.image_tab_widget self.img = None self.shape = None self.press = None @@ -27,11 +23,48 @@ def __init__(self, parent=None): self.translation = [0, 0] self.complete = False self.event_key = None - self.parent.setFocusPolicy(Qt.ClickFocus) + self.detector = detector + self.instrument = instrument + self._static = True + + for canvas in self.image_tab_widget.active_canvases: + canvas.setFocusPolicy(Qt.ClickFocus) + + @property + def current_canvas(self): + idx = self.image_tab_widget.current_index + return self.image_tab_widget.active_canvases[idx] + + @property + def ax(self): + idx = HexrdConfig().current_imageseries_idx + return self.current_canvas.axes_images[idx] @property def raw_axes(self): - return list(self.parent.raw_axes.values())[0] + if not self.current_canvas.raw_axes: + return self.current_canvas.axis + + for axes in self.current_canvas.raw_axes.values(): + if axes.get_title() == self.detector: + return axes + + return list(self.current_canvas.raw_axes.values())[0] + + @property + def static_mode(self): + return self._static + + @static_mode.setter + def static_mode(self, mode): + if mode == self._static: + return + + if mode: + self.disconnect() + else: + self.connect_translate_rotate() + self._static = mode def update_image(self, img): self.img = img @@ -41,20 +74,17 @@ def rotate_shape(self, angle): self.rotate_template(self.shape.xy, angle) self.redraw() - def create_shape(self, module, file_name, det, instr): + def create_polygon(self, verts, **kwargs): self.complete = False - with resource_loader.resource_path(module, file_name) as f: - data = np.loadtxt(f) - verts = self.panels['default'].cartToPixel(data) - verts[:, [0, 1]] = verts[:, [1, 0]] - self.shape = patches.Polygon(verts, fill=False, lw=1, color='cyan') + self.shape = patches.Polygon(verts, **kwargs) if has_nan(verts): # This template contains more than one polygon and the last point # should not be connected to the first. See Tardis IP for example. self.shape.set_closed(False) - self.shape_styles.append({'line': '-', 'width': 1, 'color': 'cyan'}) - self.update_position(instr, det) - self.connect_translate_rotate() + self.shape_styles.append(kwargs) + self.update_position() + if not self.static_mode: + self.connect_translate_rotate() self.raw_axes.add_patch(self.shape) self.redraw() @@ -63,10 +93,13 @@ def update_style(self, style, width, color): self.shape.set_linestyle(style) self.shape.set_linewidth(width) self.shape.set_edgecolor(color) + self.shape.set_fill(False) self.redraw() - def update_position(self, instr, det): - pos = HexrdConfig().boundary_position(instr, det) + def update_position(self): + pos = None + if self.instrument is not None: + pos = HexrdConfig().boundary_position(self.instrument, self.detector) if pos is None: self.center = self.get_midpoint() else: @@ -75,7 +108,7 @@ def update_position(self, instr, det): self.translate_template(dx, dy) self.total_rotation = pos['angle'] self.rotate_template(self.shape.xy, pos['angle']) - if instr == 'PXRDIP': + if self.instrument == 'PXRDIP': self.rotate_shape(angle=90) @property @@ -140,7 +173,8 @@ def toggle_boundaries(self, show): self.shape.remove() self.shape.set_linestyle(self.shape_styles[-1]['line']) self.raw_axes.add_patch(self.shape) - self.connect_translate_rotate() + if not self.static_mode: + self.connect_translate_rotate() self.redraw() else: if self.shape: @@ -149,11 +183,11 @@ def toggle_boundaries(self, show): self.redraw() def disconnect(self): - self.parent.mpl_disconnect(self.button_press_cid) - self.parent.mpl_disconnect(self.button_release_cid) - self.parent.mpl_disconnect(self.motion_cid) - self.parent.mpl_disconnect(self.key_press_cid) - self.parent.mpl_disconnect(self.button_drag_cid) + self.current_canvas.mpl_disconnect(self.button_press_cid) + self.current_canvas.mpl_disconnect(self.button_release_cid) + self.current_canvas.mpl_disconnect(self.motion_cid) + self.current_canvas.mpl_disconnect(self.key_press_cid) + self.current_canvas.mpl_disconnect(self.button_drag_cid) def completed(self): self.disconnect() @@ -199,7 +233,7 @@ def get_paths(self): return all_paths def redraw(self): - self.parent.draw_idle() + self.current_canvas.draw_idle() def scale_template(self, sx=1, sy=1): xy = self.shape.xy @@ -233,17 +267,17 @@ def on_key(self, event): self.on_key_translate(event) def connect_translate_rotate(self): - self.button_press_cid = self.parent.mpl_connect( + self.button_press_cid = self.current_canvas.mpl_connect( 'button_press_event', self.on_press) - self.button_release_cid = self.parent.mpl_connect( + self.button_release_cid = self.current_canvas.mpl_connect( 'button_release_event', self.on_release) - self.motion_cid = self.parent.mpl_connect( + self.motion_cid = self.current_canvas.mpl_connect( 'motion_notify_event', self.on_translate) - self.key_press_cid = self.parent.mpl_connect( + self.key_press_cid = self.current_canvas.mpl_connect( 'key_press_event', self.on_key) - self.button_drag_cid = self.parent.mpl_connect( + self.button_drag_cid = self.current_canvas.mpl_connect( 'motion_notify_event', self.on_rotate) - self.parent.setFocus() + self.current_canvas.setFocus() def translate_template(self, dx, dy): self.shape.set_xy(self.shape.xy + np.array([dx, dy])) diff --git a/hexrd/ui/llnl_import_tool_dialog.py b/hexrd/ui/llnl_import_tool_dialog.py index 3787dfe51..e1b7bd7b1 100644 --- a/hexrd/ui/llnl_import_tool_dialog.py +++ b/hexrd/ui/llnl_import_tool_dialog.py @@ -1,4 +1,5 @@ import os +import numpy as np import yaml import tempfile import h5py @@ -18,6 +19,7 @@ from hexrd.ui.image_load_manager import ImageLoadManager from hexrd.ui.interactive_template import InteractiveTemplate from hexrd.ui import resource_loader +from hexrd.ui.create_hedm_instrument import create_hedm_instrument from hexrd.ui.ui_loader import UiLoader from hexrd.ui.constants import ( UI_TRANS_INDEX_ROTATE_90, YAML_EXTS, LLNLTransform, ViewType) @@ -273,7 +275,9 @@ def load_images(self): # the QProgressDialog. ImageLoadManager().read_data(files, ui_parent=self.ui.parent()) self.cmap.block_updates(False) - self.it = InteractiveTemplate(self.parent()) + self.it = InteractiveTemplate(self.parent(), self.detector, self.instrument) + # We should be able to immediately interact with the template + self.it.static_mode = False file_names = [os.path.split(f[0])[1] for f in files] self.ui.files_label.setText(', '.join(file_names)) @@ -319,6 +323,14 @@ def display_bounds(self): self.ui.bb_height.blockSignals(False) self.ui.bb_width.blockSignals(False) + def read_in_template_bounds(self, module, file_name): + with resource_loader.resource_path(module, file_name) as f: + data = np.loadtxt(f) + panels = create_hedm_instrument().detectors + verts = panels['default'].cartToPixel(data) + verts[:, [0, 1]] = verts[:, [1, 0]] + return verts + def add_template(self): if self.it is None or self.instrument is None or not self.detector: return @@ -330,11 +342,12 @@ def add_template(self): return self.it.clear() - self.it.create_shape( + verts = self.read_in_template_bounds( module=hexrd_resources, - file_name=f'{self.instrument}_{self.detector}_bnd.txt', - det=self.detector, - instr=self.instrument) + file_name=f'{self.instrument}_{self.detector}_bnd.txt' + ) + kwargs = {'fill': False, 'lw': 1, 'linestyle': '-'} + self.it.create_polygon(verts, **kwargs) self.it.update_image(HexrdConfig().image('default', 0)) self.update_template_style() @@ -380,14 +393,14 @@ def save_boundary_position(self): def swap_bounds_for_cropped(self): self.it.clear() line, width, color = self.it.shape_styles[-1].values() - self.it.create_shape( + verts = self.read_in_template_bounds( module=hexrd_resources, - file_name=f'TARDIS_IMAGE-PLATE-3_bnd_cropped.txt', - det=self.detector, - instr=self.instrument) + file_name=f'TARDIS_IMAGE-PLATE-3_bnd_cropped.txt' + ) + kwargs = {'fill': False, 'lw': width, 'color': color, 'linestyle': '--'} + self.it.create_polygon(verts, **kwargs) self.update_bbox_width(1330) self.update_bbox_height(238) - self.it.update_style('--', width, color) def crop_and_mask(self): self.save_boundary_position() From 1295ef9aa20d613f2f440ba776bffb2e503985b6 Mon Sep 17 00:00:00 2001 From: Brianna Major Date: Tue, 8 Aug 2023 17:39:07 -0400 Subject: [PATCH 02/25] Support translation/rotation of drawn patch Once a user draws the bounding rectangle or ellipse for the region they'd like to mask they are able to translate and rotate the shape just like they can in the LLNL import tool. Right-click will complete the current patch and allow starting a new one. Signed-off-by: Brianna Major --- hexrd/ui/mask_regions_dialog.py | 85 ++++++++++++++++++++------------- 1 file changed, 51 insertions(+), 34 deletions(-) diff --git a/hexrd/ui/mask_regions_dialog.py b/hexrd/ui/mask_regions_dialog.py index f0e8880b6..3bd5160b2 100644 --- a/hexrd/ui/mask_regions_dialog.py +++ b/hexrd/ui/mask_regions_dialog.py @@ -2,6 +2,7 @@ from hexrd.ui.create_raw_mask import convert_polar_to_raw, create_raw_mask from hexrd.ui.create_polar_mask import create_polar_mask_from_raw +from hexrd.ui.interactive_template import InteractiveTemplate from hexrd.ui.utils import unique_name from hexrd.ui.hexrd_config import HexrdConfig from hexrd.ui.constants import ViewType @@ -31,6 +32,7 @@ def __init__(self, parent=None): self.image_mode = None self.raw_mask_coords = [] self.drawing_axes = None + self.templates = {} loader = UiLoader() self.ui = loader.load_file('mask_regions_dialog.ui', parent) @@ -86,11 +88,8 @@ def create_patch(self): 'fill': False, 'animated': True, } - if self.selection == 'Rectangle': - self.patch = patches.Rectangle((0, 0), 0, 0, **kwargs) - elif self.selection == 'Ellipse': - self.patch = patches.Ellipse((0, 0), 0, 0, **kwargs) - self.axes.add_patch(self.patch) + self.patch = InteractiveTemplate(self.parent, self.det) + self.patch.create_polygon([[0,0]], **kwargs) self.patches.setdefault(self.det, []).append(self.patch) self.added_patches.append(self.det) @@ -99,14 +98,15 @@ def update_patch(self, event): height = event.ydata - y0 width = event.xdata - x0 if self.selection == 'Rectangle': - self.patch.set_xy(self.press) - self.patch.set_height(height) - self.patch.set_width(width) + shape = patches.Rectangle(self.press, width, height) if self.selection == 'Ellipse': center = [(width / 2 + x0), (height / 2 + y0)] - self.patch.set_center(center) - self.patch.height = height - self.patch.width = width + shape = patches.Ellipse(center, width, height) + verts = shape.get_patch_transform().transform( + shape.get_path().vertices[:-1]) + verts = add_sample_points(verts, 300) + self.patch.template.set_xy(verts) + self.patch.center = self.patch.get_midpoint() def tabbed_view_changed(self): self.disconnect() @@ -133,8 +133,10 @@ def tabbed_view_changed(self): def discard_patch(self): det = self.added_patches.pop() - self.raw_mask_coords.pop() - self.patches[det].pop().remove() + # If not static mode then the raw coords haven't been saved yet + if self.patch.static_mode: + self.raw_mask_coords.pop() + self.patches[det].pop().template.remove() def undo_selection(self): if not self.added_patches: @@ -143,6 +145,7 @@ def undo_selection(self): self.discard_patch() self.canvas.draw_idle() self.update_undo_enable_state() + self.patch.static_mode = True def axes_entered(self, event): self.canvas = event.canvas @@ -207,19 +210,26 @@ def button_pressed(self, event): print('Masking must be done in raw or polar view') return + if event.button == 3 and self.patch: + self.patch.static_mode = True + if not self.axes: return - self.press = [event.xdata, event.ydata] - self.det = self.axes.get_title() - if not self.det: - self.det = self.image_mode - self.create_patch() + if event.button == 1: + if self.patch and not self.patch.static_mode: + return - # For animating the patch - self.bg_cache = self.canvas.copy_from_bbox(self.axes.bbox) + self.press = [event.xdata, event.ydata] + self.det = self.axes.get_title() + if not self.det: + self.det = self.image_mode + self.create_patch() - self.drawing_axes = self.axes + # For animating the patch + self.bg_cache = self.canvas.copy_from_bbox(self.axes.bbox) + + self.drawing_axes = self.axes def drag_motion(self, event): if ( @@ -229,25 +239,30 @@ def drag_motion(self, event): ): return + if not self.patch.static_mode: + return + self.update_patch(event) # Update animation of patch self.canvas.restore_region(self.bg_cache) - self.axes.draw_artist(self.patch) + self.axes.draw_artist(self.patch.template) self.canvas.blit(self.axes.bbox) def save_line_data(self): - data_coords = self.patch.get_patch_transform().transform( - self.patch.get_path().vertices[:-1]) + for det, templates in self.templates.items(): + for template in templates: + data_coords = template.get_patch_transform().transform( + template.get_path().vertices[:-1]) - # So that this gets converted between raw and polar correctly, - # make sure there are at least 300 points. - data_coords = add_sample_points(data_coords, 300) + # So that this gets converted between raw and polar correctly, + # make sure there are at least 300 points. + data_coords = add_sample_points(data_coords, 300) - if self.image_mode == ViewType.raw: - self.raw_mask_coords.append((self.det, data_coords)) - elif self.image_mode == ViewType.polar: - self.raw_mask_coords.append([data_coords]) + if self.image_mode == ViewType.raw: + self.raw_mask_coords.append((det, data_coords)) + elif self.image_mode == ViewType.polar: + self.raw_mask_coords.append([data_coords]) def create_masks(self): for data in self.raw_mask_coords: @@ -269,14 +284,15 @@ def create_masks(self): masks_changed_signal[self.image_mode].emit() def button_released(self, event): - if not self.press: + if not self.press or not self.patch.static_mode: return # Save it - self.save_line_data() + self.templates.setdefault(self.det, []).append(self.patch.template) + self.patch.static_mode = False # Turn off animation so the patch will stay - self.patch.set_animated(False) + self.patch.template.set_animated(False) self.press.clear() self.det = None @@ -286,6 +302,7 @@ def button_released(self, event): self.update_undo_enable_state() def apply_masks(self): + self.save_line_data() self.disconnect() self.create_masks() while self.added_patches: From 5033ae97b22c4a185fa4c1a4c4b804099b8b9002 Mon Sep 17 00:00:00 2001 From: Brianna Major Date: Tue, 8 Aug 2023 17:41:04 -0400 Subject: [PATCH 03/25] Match the behavior of the hand drawn mask dialog If the canvas is changed (by tab, tab mode or image mode) complete the current masks. Signed-off-by: Brianna Major --- hexrd/ui/mask_regions_dialog.py | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/hexrd/ui/mask_regions_dialog.py b/hexrd/ui/mask_regions_dialog.py index 3bd5160b2..6b040e1e1 100644 --- a/hexrd/ui/mask_regions_dialog.py +++ b/hexrd/ui/mask_regions_dialog.py @@ -109,27 +109,9 @@ def update_patch(self, event): self.patch.center = self.patch.get_midpoint() def tabbed_view_changed(self): - self.disconnect() + self.apply_masks() if self.ui.isVisible(): self.setup_canvas_connections() - for canvas in self.parent.image_tab_widget.active_canvases: - for axes in canvas.raw_axes.values(): - for p in self.patches.get(axes.get_title(), []): - # Artists cannot be reused or simply copied, instead - # a new artist must be created - obj, *attrs = p.__str__().split('(') - patch = getattr(patches, obj)((0, 0), 0, 0, fill=False) - for attr in ['xy', 'center', 'width', 'height']: - try: - getattr(patch, 'set_' + attr)( - getattr(p, 'get_' + attr)()) - except Exception: - try: - setattr(patch, attr, getattr(p, attr)) - except Exception: - continue - axes.add_patch(patch) - self.patches[axes.get_title()] = axes.patches def discard_patch(self): det = self.added_patches.pop() From 6db5ecd45d227642df72036f9e40af2f0189c414 Mon Sep 17 00:00:00 2001 From: Brianna Major Date: Tue, 5 Sep 2023 16:14:56 -0400 Subject: [PATCH 04/25] Add updated instructions to masking dialog Signed-off-by: Brianna Major --- hexrd/ui/resources/ui/mask_regions_dialog.ui | 95 ++++++++++++++------ 1 file changed, 68 insertions(+), 27 deletions(-) diff --git a/hexrd/ui/resources/ui/mask_regions_dialog.ui b/hexrd/ui/resources/ui/mask_regions_dialog.ui index 1d54a624e..82dfb1c5f 100644 --- a/hexrd/ui/resources/ui/mask_regions_dialog.ui +++ b/hexrd/ui/resources/ui/mask_regions_dialog.ui @@ -6,40 +6,36 @@ 0 0 - 198 - 125 + 404 + 143 Mask Region - - - - - - - Shape: - - + + + + + Shape: + + + + + + + + Rectangle + - - - - - Rectangle - - - - - Ellipse - - - + + + Ellipse + - + - + false @@ -49,13 +45,58 @@ - + + + + Translate: + + + + + + + left-click and drag or arrow keys + + + + + + + Rotate: + + + + + + + shift + left-click and drag or shift + arrow keys + + + false + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + Complete: + + + + + + + right-click anywhere + + + From 289c602bdaa26ab3c93ff7541c8d35b79fb4e5bf Mon Sep 17 00:00:00 2001 From: Brianna Major Date: Tue, 5 Sep 2023 16:32:35 -0400 Subject: [PATCH 05/25] Check for threshold mask by name before applying Signed-off-by: Brianna Major --- hexrd/ui/hexrd_config.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hexrd/ui/hexrd_config.py b/hexrd/ui/hexrd_config.py index aaae1ba00..2aecca9c8 100644 --- a/hexrd/ui/hexrd_config.py +++ b/hexrd/ui/hexrd_config.py @@ -874,7 +874,8 @@ def raw_masks_dict(self): for det, mask in data: if det == name: final_mask = np.logical_and(final_mask, mask) - if self.threshold_mask_status: + if (self.threshold_mask_status and + self.threshold_masks.get(name, None) is not None): idx = self.current_imageseries_idx thresh_mask = self.threshold_masks[name][idx] final_mask = np.logical_and(final_mask, thresh_mask) From 028f03808a3f03cf61776da1e2666e22eb8a845a Mon Sep 17 00:00:00 2001 From: Brianna Major Date: Wed, 6 Sep 2023 11:37:38 -0400 Subject: [PATCH 06/25] Do not expect main window as parent Instead, update the current canvas on image mode or tab mode change with signals. This behavior now matches the HandDrawnMaskDialog. Signed-off-by: Brianna Major --- hexrd/ui/interactive_template.py | 17 ++++----- hexrd/ui/llnl_import_tool_dialog.py | 3 +- hexrd/ui/main_window.py | 19 ++++++++-- hexrd/ui/mask_regions_dialog.py | 59 +++++++++++++++++------------ 4 files changed, 60 insertions(+), 38 deletions(-) diff --git a/hexrd/ui/interactive_template.py b/hexrd/ui/interactive_template.py index 6e909876d..76e1f97e3 100644 --- a/hexrd/ui/interactive_template.py +++ b/hexrd/ui/interactive_template.py @@ -13,8 +13,8 @@ class InteractiveTemplate: - def __init__(self, parent, detector, instrument=None): - self.image_tab_widget = parent.image_tab_widget + def __init__(self, canvas, detector, instrument=None): + self.current_canvas = canvas self.img = None self.shape = None self.press = None @@ -27,13 +27,7 @@ def __init__(self, parent, detector, instrument=None): self.instrument = instrument self._static = True - for canvas in self.image_tab_widget.active_canvases: - canvas.setFocusPolicy(Qt.ClickFocus) - - @property - def current_canvas(self): - idx = self.image_tab_widget.current_index - return self.image_tab_widget.active_canvases[idx] + self.current_canvas.setFocusPolicy(Qt.ClickFocus) @property def ax(self): @@ -422,3 +416,8 @@ def on_rotate_release(self, event): self.press = None self.rotate_template(xy, angle) self.redraw() + + def canvas_changed(self, canvas): + self.static_mode = True + self.current_canvas = canvas + self.connect_translate_rotate() diff --git a/hexrd/ui/llnl_import_tool_dialog.py b/hexrd/ui/llnl_import_tool_dialog.py index e1b7bd7b1..fcf457371 100644 --- a/hexrd/ui/llnl_import_tool_dialog.py +++ b/hexrd/ui/llnl_import_tool_dialog.py @@ -58,6 +58,7 @@ def __init__(self, cmap=None, parent=None): self.defaults = {} self.import_in_progress = False self.loaded_images = [] + self.canvas = parent.image_tab_widget.active_canvas self.set_default_color() self.setup_connections() @@ -275,7 +276,7 @@ def load_images(self): # the QProgressDialog. ImageLoadManager().read_data(files, ui_parent=self.ui.parent()) self.cmap.block_updates(False) - self.it = InteractiveTemplate(self.parent(), self.detector, self.instrument) + self.it = InteractiveTemplate(self.canvas, self.detector, self.instrument) # We should be able to immediately interact with the template self.it.static_mode = False diff --git a/hexrd/ui/main_window.py b/hexrd/ui/main_window.py index 5ae64979b..9ef69c1d9 100644 --- a/hexrd/ui/main_window.py +++ b/hexrd/ui/main_window.py @@ -303,6 +303,8 @@ def setup_connections(self): self.on_enable_canvas_toolbar) HexrdConfig().tab_images_changed.connect( self.update_drawn_mask_line_picker_canvas) + HexrdConfig().tab_images_changed.connect( + self.update_mask_region_canvas) ImageLoadManager().update_needed.connect(self.update_all) ImageLoadManager().new_images_loaded.connect(self.new_images_loaded) @@ -726,6 +728,7 @@ def on_action_edit_euler_angle_convention(self): def active_canvas_changed(self): self.update_drawn_mask_line_picker_canvas() + self.update_mask_region_canvas() def update_drawn_mask_line_picker_canvas(self): if hasattr(self, '_apply_drawn_mask_line_picker'): @@ -830,10 +833,17 @@ def action_edit_apply_powder_mask_to_polar(self): self.new_mask_added.emit(self.image_mode) HexrdConfig().polar_masks_changed.emit() + def update_mask_region_canvas(self): + if hasattr(self, '_masks_regions_dialog'): + self._masks_regions_dialog.canvas_changed( + self.ui.image_tab_widget.active_canvas + ) + def on_action_edit_apply_region_mask_triggered(self): - mrd = MaskRegionsDialog(self.ui) - mrd.new_mask_added.connect(self.new_mask_added.emit) - mrd.show() + self._masks_regions_dialog = MaskRegionsDialog(self.ui) + self._masks_regions_dialog.new_mask_added.connect( + self.new_mask_added.emit) + self._masks_regions_dialog.show() self.ui.image_tab_widget.toggle_off_toolbar() @@ -921,10 +931,11 @@ def on_show_raw_zoom_dialog(self): dialog.zoom_height = int(img.shape[0] / 5) def change_image_mode(self, mode): - # The line picker canvas change needs to be triggered *before* the image + # The masking canvas change needs to be triggered *before* the image # mode is changed. This makes sure that in-progress masks are completed # and associated with the correct image mode. self.update_drawn_mask_line_picker_canvas() + self.update_mask_region_canvas() self.image_mode = mode self.update_image_mode_enable_states() diff --git a/hexrd/ui/mask_regions_dialog.py b/hexrd/ui/mask_regions_dialog.py index 6b040e1e1..edba2f48a 100644 --- a/hexrd/ui/mask_regions_dialog.py +++ b/hexrd/ui/mask_regions_dialog.py @@ -28,7 +28,7 @@ def __init__(self, parent=None): self.press = [] self.added_patches = [] self.patches = {} - self.canvas = None + self.canvas = parent.image_tab_widget.active_canvas self.image_mode = None self.raw_mask_coords = [] self.drawing_axes = None @@ -47,25 +47,23 @@ def show(self): self.ui.show() def disconnect(self): - for ids, img in zip(self.canvas_ids, self.images): - [img.mpl_disconnect(id) for id in ids] + for id in self.canvas_ids: + self.canvas.mpl_disconnect(id) self.canvas_ids.clear() self.images.clear() def setup_canvas_connections(self): - for canvas in self.parent.image_tab_widget.active_canvases: - press = canvas.mpl_connect( - 'button_press_event', self.button_pressed) - drag = canvas.mpl_connect( - 'motion_notify_event', self.drag_motion) - release = canvas.mpl_connect( - 'button_release_event', self.button_released) - enter = canvas.mpl_connect( - 'axes_enter_event', self.axes_entered) - exit = canvas.mpl_connect( - 'axes_leave_event', self.axes_exited) - self.canvas_ids.append([press, drag, release, enter, exit]) - self.images.append(canvas) + self.canvas_ids.append(self.canvas.mpl_connect( + 'button_press_event', self.button_pressed)) + self.canvas_ids.append(self.canvas.mpl_connect( + 'motion_notify_event', self.drag_motion)) + self.canvas_ids.append(self.canvas.mpl_connect( + 'button_release_event', self.button_released)) + self.canvas_ids.append(self.canvas.mpl_connect( + 'axes_enter_event', self.axes_entered)) + self.canvas_ids.append(self.canvas.mpl_connect( + 'axes_leave_event', self.axes_exited)) + self.images.append(self.canvas) # TODO: Is self.images needed? def setup_ui_connections(self): self.ui.button_box.accepted.connect(self.apply_masks) @@ -73,7 +71,6 @@ def setup_ui_connections(self): self.ui.rejected.connect(self.cancel) self.ui.shape.currentIndexChanged.connect(self.select_shape) self.ui.undo.clicked.connect(self.undo_selection) - HexrdConfig().tab_images_changed.connect(self.tabbed_view_changed) def update_undo_enable_state(self): enabled = bool(self.added_patches) @@ -88,7 +85,7 @@ def create_patch(self): 'fill': False, 'animated': True, } - self.patch = InteractiveTemplate(self.parent, self.det) + self.patch = InteractiveTemplate(self.canvas, self.det) self.patch.create_polygon([[0,0]], **kwargs) self.patches.setdefault(self.det, []).append(self.patch) self.added_patches.append(self.det) @@ -108,11 +105,6 @@ def update_patch(self, event): self.patch.template.set_xy(verts) self.patch.center = self.patch.get_midpoint() - def tabbed_view_changed(self): - self.apply_masks() - if self.ui.isVisible(): - self.setup_canvas_connections() - def discard_patch(self): det = self.added_patches.pop() # If not static mode then the raw coords haven't been saved yet @@ -130,7 +122,6 @@ def undo_selection(self): self.patch.static_mode = True def axes_entered(self, event): - self.canvas = event.canvas self.image_mode = self.canvas.mode if event.inaxes is self.canvas.azimuthal_integral_axis: @@ -245,6 +236,7 @@ def save_line_data(self): self.raw_mask_coords.append((det, data_coords)) elif self.image_mode == ViewType.polar: self.raw_mask_coords.append([data_coords]) + self.templates.clear() def create_masks(self): for data in self.raw_mask_coords: @@ -284,6 +276,9 @@ def button_released(self, event): self.update_undo_enable_state() def apply_masks(self): + if not self.templates: + return + self.save_line_data() self.disconnect() self.create_masks() @@ -298,3 +293,19 @@ def cancel(self): self.disconnect() if self.canvas is not None: self.canvas.draw_idle() + + def canvas_changed(self, canvas): + self.apply_masks() + self.canvas = canvas + if self.patch: + self.patch.canvas_changed(canvas) + if self.ui.isVisible(): + self.setup_canvas_connections() + self.reset_all() + + def reset_all(self): + self.press.clear() + self.added_templates.clear() + self.interactive_templates.clear() + self.raw_mask_coords.clear() + self.templates.clear() From 29f0a01132f614b359d7e23cb30f96ca94bc234d Mon Sep 17 00:00:00 2001 From: Brianna Major Date: Wed, 6 Sep 2023 11:40:22 -0400 Subject: [PATCH 07/25] Remove unused attribute Signed-off-by: Brianna Major --- hexrd/ui/mask_regions_dialog.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/hexrd/ui/mask_regions_dialog.py b/hexrd/ui/mask_regions_dialog.py index edba2f48a..a97a88a87 100644 --- a/hexrd/ui/mask_regions_dialog.py +++ b/hexrd/ui/mask_regions_dialog.py @@ -21,7 +21,6 @@ def __init__(self, parent=None): super().__init__(parent) self.parent = parent - self.images = [] self.canvas_ids = [] self.axes = None self.bg_cache = None @@ -50,7 +49,6 @@ def disconnect(self): for id in self.canvas_ids: self.canvas.mpl_disconnect(id) self.canvas_ids.clear() - self.images.clear() def setup_canvas_connections(self): self.canvas_ids.append(self.canvas.mpl_connect( @@ -63,7 +61,6 @@ def setup_canvas_connections(self): 'axes_enter_event', self.axes_entered)) self.canvas_ids.append(self.canvas.mpl_connect( 'axes_leave_event', self.axes_exited)) - self.images.append(self.canvas) # TODO: Is self.images needed? def setup_ui_connections(self): self.ui.button_box.accepted.connect(self.apply_masks) From 6d0e662ac10ed65267788ef1e4b4112a35b36b3b Mon Sep 17 00:00:00 2001 From: Brianna Major Date: Wed, 6 Sep 2023 12:11:32 -0400 Subject: [PATCH 08/25] Simplify check for threshold mask by name Signed-off-by: Brianna Major --- hexrd/ui/hexrd_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hexrd/ui/hexrd_config.py b/hexrd/ui/hexrd_config.py index 2aecca9c8..40e50fe3b 100644 --- a/hexrd/ui/hexrd_config.py +++ b/hexrd/ui/hexrd_config.py @@ -875,7 +875,7 @@ def raw_masks_dict(self): if det == name: final_mask = np.logical_and(final_mask, mask) if (self.threshold_mask_status and - self.threshold_masks.get(name, None) is not None): + self.threshold_masks.get(name) is not None): idx = self.current_imageseries_idx thresh_mask = self.threshold_masks[name][idx] final_mask = np.logical_and(final_mask, thresh_mask) From d3d7299ffc3ba22d2bf43928dcdd34e2c1634a86 Mon Sep 17 00:00:00 2001 From: Brianna Major Date: Wed, 6 Sep 2023 13:00:15 -0400 Subject: [PATCH 09/25] Rename for consistency Renamed: patch(es) -> interactive_template(s), raw_axes -> axis, kwargs -> polygon_kwargs Signed-off-by: Brianna Major --- hexrd/ui/interactive_template.py | 22 ++++----- hexrd/ui/mask_regions_dialog.py | 76 +++++++++++++++++--------------- 2 files changed, 51 insertions(+), 47 deletions(-) diff --git a/hexrd/ui/interactive_template.py b/hexrd/ui/interactive_template.py index 76e1f97e3..66fe6101e 100644 --- a/hexrd/ui/interactive_template.py +++ b/hexrd/ui/interactive_template.py @@ -35,7 +35,7 @@ def ax(self): return self.current_canvas.axes_images[idx] @property - def raw_axes(self): + def axis(self): if not self.current_canvas.raw_axes: return self.current_canvas.axis @@ -68,18 +68,18 @@ def rotate_shape(self, angle): self.rotate_template(self.shape.xy, angle) self.redraw() - def create_polygon(self, verts, **kwargs): + def create_polygon(self, verts, **polygon_kwargs): self.complete = False - self.shape = patches.Polygon(verts, **kwargs) + self.shape = patches.Polygon(verts, **polygon_kwargs) if has_nan(verts): # This template contains more than one polygon and the last point # should not be connected to the first. See Tardis IP for example. self.shape.set_closed(False) - self.shape_styles.append(kwargs) + self.shape_styles.append(polygon_kwargs) self.update_position() if not self.static_mode: self.connect_translate_rotate() - self.raw_axes.add_patch(self.shape) + self.axis.add_patch(self.shape) self.redraw() def update_style(self, style, width, color): @@ -137,13 +137,13 @@ def rotation(self): return self.total_rotation def clear(self): - if self.shape in self.raw_axes.patches: + if self.shape in self.axis.patches: self.shape.remove() self.redraw() self.total_rotation = 0. def save_boundary(self, color): - if self.shape in self.raw_axes.patches: + if self.shape in self.axis.patches: self.shape.set_linestyle('--') self.redraw() @@ -161,19 +161,19 @@ def toggle_boundaries(self, show): # This template contains more than one polygon and the last point # should not be connected to the first. See Tardis IP for example. shape.set_closed(False) - self.raw_axes.add_patch(shape) + self.axis.add_patch(shape) if self.shape: - self.shape = self.raw_axes.patches[-1] + self.shape = self.axis.patches[-1] self.shape.remove() self.shape.set_linestyle(self.shape_styles[-1]['line']) - self.raw_axes.add_patch(self.shape) + self.axis.add_patch(self.shape) if not self.static_mode: self.connect_translate_rotate() self.redraw() else: if self.shape: self.disconnect() - self.patches = [p for p in self.raw_axes.patches] + self.patches = [p for p in self.axis.patches] self.redraw() def disconnect(self): diff --git a/hexrd/ui/mask_regions_dialog.py b/hexrd/ui/mask_regions_dialog.py index a97a88a87..5c88ca5ec 100644 --- a/hexrd/ui/mask_regions_dialog.py +++ b/hexrd/ui/mask_regions_dialog.py @@ -25,8 +25,8 @@ def __init__(self, parent=None): self.axes = None self.bg_cache = None self.press = [] - self.added_patches = [] - self.patches = {} + self.added_templates = [] + self.interactive_templates = {} self.canvas = parent.image_tab_widget.active_canvas self.image_mode = None self.raw_mask_coords = [] @@ -70,24 +70,25 @@ def setup_ui_connections(self): self.ui.undo.clicked.connect(self.undo_selection) def update_undo_enable_state(self): - enabled = bool(self.added_patches) + enabled = bool(self.added_templates) self.ui.undo.setEnabled(enabled) def select_shape(self): self.selection = self.ui.shape.currentText() - self.patch = None + self.interactive_template = None - def create_patch(self): + def create_interactive_template(self): kwargs = { 'fill': False, 'animated': True, } - self.patch = InteractiveTemplate(self.canvas, self.det) - self.patch.create_polygon([[0,0]], **kwargs) - self.patches.setdefault(self.det, []).append(self.patch) - self.added_patches.append(self.det) + self.interactive_template = InteractiveTemplate(self.canvas, self.det) + self.interactive_template.create_polygon([[0,0]], **kwargs) + self.interactive_templates.setdefault(self.det, []).append( + self.interactive_template) + self.added_templates.append(self.det) - def update_patch(self, event): + def update_interactive_template(self, event): x0, y0 = self.press height = event.ydata - y0 width = event.xdata - x0 @@ -99,24 +100,25 @@ def update_patch(self, event): verts = shape.get_patch_transform().transform( shape.get_path().vertices[:-1]) verts = add_sample_points(verts, 300) - self.patch.template.set_xy(verts) - self.patch.center = self.patch.get_midpoint() + self.interactive_template.template.set_xy(verts) + self.interactive_template.center = ( + self.interactive_template.get_midpoint()) - def discard_patch(self): - det = self.added_patches.pop() + def discard_interactive_template(self): + det = self.added_templates.pop() # If not static mode then the raw coords haven't been saved yet - if self.patch.static_mode: + if self.interactive_template.static_mode: self.raw_mask_coords.pop() - self.patches[det].pop().template.remove() + self.interactive_templates[det].pop().template.remove() def undo_selection(self): - if not self.added_patches: + if not self.added_templates: return - self.discard_patch() + self.discard_interactive_template() self.canvas.draw_idle() self.update_undo_enable_state() - self.patch.static_mode = True + self.interactive_template.static_mode = True def axes_entered(self, event): self.image_mode = self.canvas.mode @@ -180,21 +182,22 @@ def button_pressed(self, event): print('Masking must be done in raw or polar view') return - if event.button == 3 and self.patch: - self.patch.static_mode = True + if event.button == 3 and self.interactive_template: + self.interactive_template.static_mode = True if not self.axes: return if event.button == 1: - if self.patch and not self.patch.static_mode: + if (self.interactive_template and + not self.interactive_template.static_mode): return self.press = [event.xdata, event.ydata] self.det = self.axes.get_title() if not self.det: self.det = self.image_mode - self.create_patch() + self.create_interactive_template() # For animating the patch self.bg_cache = self.canvas.copy_from_bbox(self.axes.bbox) @@ -209,14 +212,14 @@ def drag_motion(self, event): ): return - if not self.patch.static_mode: + if not self.interactive_template.static_mode: return - self.update_patch(event) + self.update_interactive_template(event) # Update animation of patch self.canvas.restore_region(self.bg_cache) - self.axes.draw_artist(self.patch.template) + self.axes.draw_artist(self.interactive_template.template) self.canvas.blit(self.axes.bbox) def save_line_data(self): @@ -255,15 +258,16 @@ def create_masks(self): masks_changed_signal[self.image_mode].emit() def button_released(self, event): - if not self.press or not self.patch.static_mode: + if not self.press or not self.interactive_template.static_mode: return # Save it - self.templates.setdefault(self.det, []).append(self.patch.template) - self.patch.static_mode = False + self.templates.setdefault(self.det, []).append( + self.interactive_template.template) + self.interactive_template.static_mode = False # Turn off animation so the patch will stay - self.patch.template.set_animated(False) + self.interactive_template.template.set_animated(False) self.press.clear() self.det = None @@ -279,13 +283,13 @@ def apply_masks(self): self.save_line_data() self.disconnect() self.create_masks() - while self.added_patches: - self.discard_patch() + while self.added_templates: + self.discard_interactive_template() self.new_mask_added.emit(self.image_mode) def cancel(self): - while self.added_patches: - self.discard_patch() + while self.added_templates: + self.discard_interactive_template() self.disconnect() if self.canvas is not None: @@ -294,8 +298,8 @@ def cancel(self): def canvas_changed(self, canvas): self.apply_masks() self.canvas = canvas - if self.patch: - self.patch.canvas_changed(canvas) + if self.interactive_template: + self.interactive_template.canvas_changed(canvas) if self.ui.isVisible(): self.setup_canvas_connections() self.reset_all() From 5fa0a376516b0b04447eae150018b0230686c02e Mon Sep 17 00:00:00 2001 From: Brianna Major Date: Wed, 6 Sep 2023 13:04:17 -0400 Subject: [PATCH 10/25] Set focus policy on canvas initialization Signed-off-by: Brianna Major --- hexrd/ui/image_canvas.py | 4 +++- hexrd/ui/interactive_template.py | 4 ---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/hexrd/ui/image_canvas.py b/hexrd/ui/image_canvas.py index ec7f62dc6..406921107 100644 --- a/hexrd/ui/image_canvas.py +++ b/hexrd/ui/image_canvas.py @@ -1,7 +1,7 @@ import copy import math -from PySide2.QtCore import QThreadPool, QTimer, Signal +from PySide2.QtCore import QThreadPool, QTimer, Signal, Qt from PySide2.QtWidgets import QFileDialog, QMessageBox from matplotlib.backends.backend_qt5agg import FigureCanvas @@ -71,6 +71,8 @@ def __init__(self, parent=None, image_names=None): if image_names is not None: self.load_images(image_names) + self.setFocusPolicy(Qt.ClickFocus) + self.setup_connections() def setup_connections(self): diff --git a/hexrd/ui/interactive_template.py b/hexrd/ui/interactive_template.py index 66fe6101e..ddffe4728 100644 --- a/hexrd/ui/interactive_template.py +++ b/hexrd/ui/interactive_template.py @@ -1,7 +1,5 @@ import numpy as np -from PySide2.QtCore import Qt - from matplotlib import patches from matplotlib.path import Path from matplotlib.transforms import Affine2D @@ -27,8 +25,6 @@ def __init__(self, canvas, detector, instrument=None): self.instrument = instrument self._static = True - self.current_canvas.setFocusPolicy(Qt.ClickFocus) - @property def ax(self): idx = HexrdConfig().current_imageseries_idx From 5ad2f1fa0e5351f89108c794404227787ae4da2a Mon Sep 17 00:00:00 2001 From: Brianna Major Date: Wed, 6 Sep 2023 13:46:27 -0400 Subject: [PATCH 11/25] Fix incorrect computation of current axes image Signed-off-by: Brianna Major --- hexrd/ui/interactive_template.py | 14 +++++--------- hexrd/ui/llnl_import_tool_dialog.py | 3 ++- hexrd/ui/mask_regions_dialog.py | 3 ++- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/hexrd/ui/interactive_template.py b/hexrd/ui/interactive_template.py index ddffe4728..e55eb92c5 100644 --- a/hexrd/ui/interactive_template.py +++ b/hexrd/ui/interactive_template.py @@ -11,7 +11,7 @@ class InteractiveTemplate: - def __init__(self, canvas, detector, instrument=None): + def __init__(self, canvas, detector, axes=None, instrument=None): self.current_canvas = canvas self.img = None self.shape = None @@ -24,11 +24,7 @@ def __init__(self, canvas, detector, instrument=None): self.detector = detector self.instrument = instrument self._static = True - - @property - def ax(self): - idx = HexrdConfig().current_imageseries_idx - return self.current_canvas.axes_images[idx] + self.axis_image = axes.get_images()[0] if axes else canvas.axes_images[0] @property def axis(self): @@ -112,7 +108,7 @@ def masked_image(self): @property def bounds(self): - l, r, b, t = self.ax.get_extent() + l, r, b, t = self.axis_image.get_extent() x0, y0 = np.nanmin(self.shape.xy, axis=0) x1, y1 = np.nanmax(self.shape.xy, axis=0) return np.array([max(np.floor(y0), t), @@ -339,7 +335,7 @@ def on_press_rotate(self, event): # need to set the press value twice self.press = self.shape.xy, event.xdata, event.ydata self.center = self.get_midpoint() - self.shape.set_transform(self.ax.axes.transData) + self.shape.set_transform(self.axis_image.axes.transData) self.press = self.shape.xy, event.xdata, event.ydata def rotate_template(self, points, angle): @@ -377,7 +373,7 @@ def get_midpoint(self): return [(x1 + x0)/2, (y1 + y0)/2] def mouse_position(self, e): - xmin, xmax, ymin, ymax = self.ax.get_extent() + xmin, xmax, ymin, ymax = self.axis_image.get_extent() x, y = self.get_midpoint() xdata = e.xdata ydata = e.ydata diff --git a/hexrd/ui/llnl_import_tool_dialog.py b/hexrd/ui/llnl_import_tool_dialog.py index fcf457371..a6bb5ac97 100644 --- a/hexrd/ui/llnl_import_tool_dialog.py +++ b/hexrd/ui/llnl_import_tool_dialog.py @@ -276,7 +276,8 @@ def load_images(self): # the QProgressDialog. ImageLoadManager().read_data(files, ui_parent=self.ui.parent()) self.cmap.block_updates(False) - self.it = InteractiveTemplate(self.canvas, self.detector, self.instrument) + self.it = InteractiveTemplate( + self.canvas, self.detector, instrument=self.instrument) # We should be able to immediately interact with the template self.it.static_mode = False diff --git a/hexrd/ui/mask_regions_dialog.py b/hexrd/ui/mask_regions_dialog.py index 5c88ca5ec..e0a8f6534 100644 --- a/hexrd/ui/mask_regions_dialog.py +++ b/hexrd/ui/mask_regions_dialog.py @@ -82,7 +82,8 @@ def create_interactive_template(self): 'fill': False, 'animated': True, } - self.interactive_template = InteractiveTemplate(self.canvas, self.det) + self.interactive_template = InteractiveTemplate( + self.canvas, self.det, axes=self.axes) self.interactive_template.create_polygon([[0,0]], **kwargs) self.interactive_templates.setdefault(self.det, []).append( self.interactive_template) From 4ab41e0989d8cb900259def952de8566becd8718 Mon Sep 17 00:00:00 2001 From: Brianna Major Date: Wed, 6 Sep 2023 14:12:27 -0400 Subject: [PATCH 12/25] Always disconnect before setting up new canvas connections Signed-off-by: Brianna Major --- hexrd/ui/interactive_template.py | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/hexrd/ui/interactive_template.py b/hexrd/ui/interactive_template.py index e55eb92c5..cb251c7a2 100644 --- a/hexrd/ui/interactive_template.py +++ b/hexrd/ui/interactive_template.py @@ -26,6 +26,12 @@ def __init__(self, canvas, detector, axes=None, instrument=None): self._static = True self.axis_image = axes.get_images()[0] if axes else canvas.axes_images[0] + self.button_press_cid = None + self.button_release_cid = None + self.motion_cid = None + self.key_press_cid = None + self.button_drag_cid = None + @property def axis(self): if not self.current_canvas.raw_axes: @@ -46,11 +52,9 @@ def static_mode(self, mode): if mode == self._static: return - if mode: - self.disconnect() - else: - self.connect_translate_rotate() self._static = mode + if not mode: + self.connect_translate_rotate() def update_image(self, img): self.img = img @@ -69,8 +73,7 @@ def create_polygon(self, verts, **polygon_kwargs): self.shape.set_closed(False) self.shape_styles.append(polygon_kwargs) self.update_position() - if not self.static_mode: - self.connect_translate_rotate() + self.connect_translate_rotate() self.axis.add_patch(self.shape) self.redraw() @@ -159,8 +162,7 @@ def toggle_boundaries(self, show): self.shape.remove() self.shape.set_linestyle(self.shape_styles[-1]['line']) self.axis.add_patch(self.shape) - if not self.static_mode: - self.connect_translate_rotate() + self.connect_translate_rotate() self.redraw() else: if self.shape: @@ -253,6 +255,11 @@ def on_key(self, event): self.on_key_translate(event) def connect_translate_rotate(self): + if self.static_mode: + return + + self.disconnect() + self.button_press_cid = self.current_canvas.mpl_connect( 'button_press_event', self.on_press) self.button_release_cid = self.current_canvas.mpl_connect( From 026bc03f50d2f83d304ab1a6c3a82b05f517e346 Mon Sep 17 00:00:00 2001 From: Brianna Major Date: Thu, 7 Sep 2023 14:17:35 -0400 Subject: [PATCH 13/25] Make sure all signals are disconnected Signed-off-by: Brianna Major --- hexrd/ui/interactive_template.py | 5 ----- hexrd/ui/mask_regions_dialog.py | 17 ++++++++++------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/hexrd/ui/interactive_template.py b/hexrd/ui/interactive_template.py index cb251c7a2..c353a763a 100644 --- a/hexrd/ui/interactive_template.py +++ b/hexrd/ui/interactive_template.py @@ -415,8 +415,3 @@ def on_rotate_release(self, event): self.press = None self.rotate_template(xy, angle) self.redraw() - - def canvas_changed(self, canvas): - self.static_mode = True - self.current_canvas = canvas - self.connect_translate_rotate() diff --git a/hexrd/ui/mask_regions_dialog.py b/hexrd/ui/mask_regions_dialog.py index e0a8f6534..18495c05c 100644 --- a/hexrd/ui/mask_regions_dialog.py +++ b/hexrd/ui/mask_regions_dialog.py @@ -51,6 +51,8 @@ def disconnect(self): self.canvas_ids.clear() def setup_canvas_connections(self): + self.disconnect() + self.canvas_ids.append(self.canvas.mpl_connect( 'button_press_event', self.button_pressed)) self.canvas_ids.append(self.canvas.mpl_connect( @@ -107,10 +109,9 @@ def update_interactive_template(self, event): def discard_interactive_template(self): det = self.added_templates.pop() - # If not static mode then the raw coords haven't been saved yet - if self.interactive_template.static_mode: - self.raw_mask_coords.pop() - self.interactive_templates[det].pop().template.remove() + it = self.interactive_templates[det].pop() + it.disconnect() + it.template.remove() def undo_selection(self): if not self.added_templates: @@ -287,6 +288,8 @@ def apply_masks(self): while self.added_templates: self.discard_interactive_template() self.new_mask_added.emit(self.image_mode) + self.disconnect() + self.reset_all() def cancel(self): while self.added_templates: @@ -299,15 +302,15 @@ def cancel(self): def canvas_changed(self, canvas): self.apply_masks() self.canvas = canvas - if self.interactive_template: - self.interactive_template.canvas_changed(canvas) if self.ui.isVisible(): self.setup_canvas_connections() - self.reset_all() def reset_all(self): self.press.clear() self.added_templates.clear() + for key in self.interactive_templates.keys(): + interactive_templates = self.interactive_templates[key] + [it.disconnect() for it in interactive_templates] self.interactive_templates.clear() self.raw_mask_coords.clear() self.templates.clear() From 0a493e0c5c38c8ca4b0d22fcbb11db09e4aa303b Mon Sep 17 00:00:00 2001 From: Brianna Major Date: Fri, 8 Sep 2023 08:40:29 -0400 Subject: [PATCH 14/25] Allow users to manipulate all existing templates Signed-off-by: Brianna Major --- hexrd/ui/mask_regions_dialog.py | 22 +++++-- hexrd/ui/resources/ui/mask_regions_dialog.ui | 68 +++++++++----------- 2 files changed, 45 insertions(+), 45 deletions(-) diff --git a/hexrd/ui/mask_regions_dialog.py b/hexrd/ui/mask_regions_dialog.py index 18495c05c..d19db429e 100644 --- a/hexrd/ui/mask_regions_dialog.py +++ b/hexrd/ui/mask_regions_dialog.py @@ -72,7 +72,7 @@ def setup_ui_connections(self): self.ui.undo.clicked.connect(self.undo_selection) def update_undo_enable_state(self): - enabled = bool(self.added_templates) + enabled = bool(len(self.added_templates)) self.ui.undo.setEnabled(enabled) def select_shape(self): @@ -120,7 +120,6 @@ def undo_selection(self): self.discard_interactive_template() self.canvas.draw_idle() self.update_undo_enable_state() - self.interactive_template.static_mode = True def axes_entered(self, event): self.image_mode = self.canvas.mode @@ -179,18 +178,30 @@ def snap_rectangle_to_edges(self, event): # Trigger another drag motion event where we move the borders self.drag_motion(event) + def check_pick(self, event): + for templates in self.interactive_templates.values(): + for it in templates: + it.static_mode = True + transformed_click = it.template.get_transform().transform( + (event.xdata, event.ydata)) + if it.template.contains_point(transformed_click): + if self.interactive_template: + self.interactive_template.disconnect() + self.interactive_template = it + self.interactive_template.static_mode = False + def button_pressed(self, event): if self.image_mode not in (ViewType.raw, ViewType.polar): print('Masking must be done in raw or polar view') return - if event.button == 3 and self.interactive_template: - self.interactive_template.static_mode = True - if not self.axes: return if event.button == 1: + # Determine if selecting an existing template or drawing a new one + self.check_pick(event) + if (self.interactive_template and not self.interactive_template.static_mode): return @@ -266,7 +277,6 @@ def button_released(self, event): # Save it self.templates.setdefault(self.det, []).append( self.interactive_template.template) - self.interactive_template.static_mode = False # Turn off animation so the patch will stay self.interactive_template.template.set_animated(False) diff --git a/hexrd/ui/resources/ui/mask_regions_dialog.ui b/hexrd/ui/resources/ui/mask_regions_dialog.ui index 82dfb1c5f..5b5683726 100644 --- a/hexrd/ui/resources/ui/mask_regions_dialog.ui +++ b/hexrd/ui/resources/ui/mask_regions_dialog.ui @@ -6,18 +6,18 @@ 0 0 - 404 - 143 + 400 + 120 Mask Region - - - - Shape: + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok @@ -35,27 +35,27 @@ - - - - false - + + - Undo Last Selection + left-click and drag or arrow keys - - + + - Translate: + Shape: - - + + + + false + - left-click and drag or arrow keys + Undo Last Selection @@ -66,6 +66,13 @@ + + + + Translate: + + + @@ -76,29 +83,12 @@ - - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - Complete: - - - - - - - right-click anywhere - - - + + shape + undo + From dc76257a71c9bfa4bc1fcea147a59dcbf340ee8a Mon Sep 17 00:00:00 2001 From: Brianna Major Date: Fri, 8 Sep 2023 09:01:20 -0400 Subject: [PATCH 15/25] Simplify redundant list of templates Signed-off-by: Brianna Major --- hexrd/ui/mask_regions_dialog.py | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/hexrd/ui/mask_regions_dialog.py b/hexrd/ui/mask_regions_dialog.py index d19db429e..54516cb7e 100644 --- a/hexrd/ui/mask_regions_dialog.py +++ b/hexrd/ui/mask_regions_dialog.py @@ -31,7 +31,6 @@ def __init__(self, parent=None): self.image_mode = None self.raw_mask_coords = [] self.drawing_axes = None - self.templates = {} loader = UiLoader() self.ui = loader.load_file('mask_regions_dialog.ui', parent) @@ -87,8 +86,6 @@ def create_interactive_template(self): self.interactive_template = InteractiveTemplate( self.canvas, self.det, axes=self.axes) self.interactive_template.create_polygon([[0,0]], **kwargs) - self.interactive_templates.setdefault(self.det, []).append( - self.interactive_template) self.added_templates.append(self.det) def update_interactive_template(self, event): @@ -236,10 +233,10 @@ def drag_motion(self, event): self.canvas.blit(self.axes.bbox) def save_line_data(self): - for det, templates in self.templates.items(): - for template in templates: - data_coords = template.get_patch_transform().transform( - template.get_path().vertices[:-1]) + for det, its in self.interactive_templates.items(): + for it in its: + data_coords = it.template.get_patch_transform().transform( + it.template.get_path().vertices[:-1]) # So that this gets converted between raw and polar correctly, # make sure there are at least 300 points. @@ -249,7 +246,6 @@ def save_line_data(self): self.raw_mask_coords.append((det, data_coords)) elif self.image_mode == ViewType.polar: self.raw_mask_coords.append([data_coords]) - self.templates.clear() def create_masks(self): for data in self.raw_mask_coords: @@ -275,8 +271,8 @@ def button_released(self, event): return # Save it - self.templates.setdefault(self.det, []).append( - self.interactive_template.template) + self.interactive_templates.setdefault(self.det, []).append( + self.interactive_template) # Turn off animation so the patch will stay self.interactive_template.template.set_animated(False) @@ -289,7 +285,7 @@ def button_released(self, event): self.update_undo_enable_state() def apply_masks(self): - if not self.templates: + if not self.interactive_templates: return self.save_line_data() @@ -323,4 +319,3 @@ def reset_all(self): [it.disconnect() for it in interactive_templates] self.interactive_templates.clear() self.raw_mask_coords.clear() - self.templates.clear() From 1cb06c2e49163b60f58b63eaf408fcb81dd7f5b9 Mon Sep 17 00:00:00 2001 From: Brianna Major Date: Fri, 8 Sep 2023 09:30:40 -0400 Subject: [PATCH 16/25] Color active bounds Signed-off-by: Brianna Major --- hexrd/ui/interactive_template.py | 22 +++++++++++++++++----- hexrd/ui/mask_regions_dialog.py | 3 +++ 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/hexrd/ui/interactive_template.py b/hexrd/ui/interactive_template.py index c353a763a..abb85063e 100644 --- a/hexrd/ui/interactive_template.py +++ b/hexrd/ui/interactive_template.py @@ -53,8 +53,10 @@ def static_mode(self, mode): return self._static = mode + self.update_style(color='black') if not mode: self.connect_translate_rotate() + self.update_style(color='red') def update_image(self, img): self.img = img @@ -77,11 +79,21 @@ def create_polygon(self, verts, **polygon_kwargs): self.axis.add_patch(self.shape) self.redraw() - def update_style(self, style, width, color): - self.shape_styles[-1] = {'line': style, 'width': width, 'color': color} - self.shape.set_linestyle(style) - self.shape.set_linewidth(width) - self.shape.set_edgecolor(color) + def update_style(self, style=None, width=None, color=None): + if not self.shape: + return + + if style: + self.shape.set_linestyle(style) + if width: + self.shape.set_linewidth(width) + if color: + self.shape.set_edgecolor(color) + self.shape_styles[-1] = { + 'line': self.shape.get_linestyle(), + 'width': self.shape.get_linewidth(), + 'color': self.shape.get_edgecolor() + } self.shape.set_fill(False) self.redraw() diff --git a/hexrd/ui/mask_regions_dialog.py b/hexrd/ui/mask_regions_dialog.py index 54516cb7e..41f4fff31 100644 --- a/hexrd/ui/mask_regions_dialog.py +++ b/hexrd/ui/mask_regions_dialog.py @@ -86,6 +86,7 @@ def create_interactive_template(self): self.interactive_template = InteractiveTemplate( self.canvas, self.det, axes=self.axes) self.interactive_template.create_polygon([[0,0]], **kwargs) + self.interactive_template.update_style(color='red') self.added_templates.append(self.det) def update_interactive_template(self, event): @@ -210,6 +211,7 @@ def button_pressed(self, event): self.create_interactive_template() # For animating the patch + self.canvas.draw() # Force canvas re-draw before caching self.bg_cache = self.canvas.copy_from_bbox(self.axes.bbox) self.drawing_axes = self.axes @@ -271,6 +273,7 @@ def button_released(self, event): return # Save it + self.interactive_template.update_style(color='black') self.interactive_templates.setdefault(self.det, []).append( self.interactive_template) From ec58684f89b849d4d504850c8189dc2670366e68 Mon Sep 17 00:00:00 2001 From: Brianna Major Date: Fri, 8 Sep 2023 10:07:40 -0400 Subject: [PATCH 17/25] Reset current template on undo Signed-off-by: Brianna Major --- hexrd/ui/mask_regions_dialog.py | 1 + 1 file changed, 1 insertion(+) diff --git a/hexrd/ui/mask_regions_dialog.py b/hexrd/ui/mask_regions_dialog.py index 41f4fff31..110250c1d 100644 --- a/hexrd/ui/mask_regions_dialog.py +++ b/hexrd/ui/mask_regions_dialog.py @@ -118,6 +118,7 @@ def undo_selection(self): self.discard_interactive_template() self.canvas.draw_idle() self.update_undo_enable_state() + self.interactive_template = None def axes_entered(self, event): self.image_mode = self.canvas.mode From af3796ae5f17e17c596ffe50bd05fc9eca07a065 Mon Sep 17 00:00:00 2001 From: Brianna Major Date: Wed, 20 Sep 2023 11:47:45 -0400 Subject: [PATCH 18/25] Prevent drawing when interacting Signed-off-by: Brianna Major --- hexrd/ui/mask_regions_dialog.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/hexrd/ui/mask_regions_dialog.py b/hexrd/ui/mask_regions_dialog.py index 110250c1d..bb9da8852 100644 --- a/hexrd/ui/mask_regions_dialog.py +++ b/hexrd/ui/mask_regions_dialog.py @@ -178,16 +178,22 @@ def snap_rectangle_to_edges(self, event): self.drag_motion(event) def check_pick(self, event): + pick_found = False for templates in self.interactive_templates.values(): for it in templates: it.static_mode = True transformed_click = it.template.get_transform().transform( (event.xdata, event.ydata)) - if it.template.contains_point(transformed_click): + if (not pick_found and + it.template.contains_point(transformed_click) and + event.inaxes.get_title() == it.detector): if self.interactive_template: self.interactive_template.disconnect() self.interactive_template = it self.interactive_template.static_mode = False + self.interactive_template.on_press(event) + pick_found = True + return pick_found def button_pressed(self, event): if self.image_mode not in (ViewType.raw, ViewType.polar): @@ -199,9 +205,10 @@ def button_pressed(self, event): if event.button == 1: # Determine if selecting an existing template or drawing a new one - self.check_pick(event) + pick_found = self.check_pick(event) - if (self.interactive_template and + if (pick_found or + self.interactive_template and not self.interactive_template.static_mode): return From c8cd7966d6e9270ff0713ae5b0999eb221241207 Mon Sep 17 00:00:00 2001 From: Patrick Avery Date: Wed, 20 Sep 2023 12:13:11 -0500 Subject: [PATCH 19/25] Use `shape.get_verts()` to get vertices This makes the ellipses in the polar view appear much smoother. Signed-off-by: Patrick Avery --- hexrd/ui/mask_regions_dialog.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hexrd/ui/mask_regions_dialog.py b/hexrd/ui/mask_regions_dialog.py index bb9da8852..897195776 100644 --- a/hexrd/ui/mask_regions_dialog.py +++ b/hexrd/ui/mask_regions_dialog.py @@ -98,8 +98,7 @@ def update_interactive_template(self, event): if self.selection == 'Ellipse': center = [(width / 2 + x0), (height / 2 + y0)] shape = patches.Ellipse(center, width, height) - verts = shape.get_patch_transform().transform( - shape.get_path().vertices[:-1]) + verts = shape.get_verts() verts = add_sample_points(verts, 300) self.interactive_template.template.set_xy(verts) self.interactive_template.center = ( From 9cc66f63bb723967c23aa83f6b26e3c0d846d65f Mon Sep 17 00:00:00 2001 From: Patrick Avery Date: Wed, 20 Sep 2023 12:30:06 -0500 Subject: [PATCH 20/25] Correct polar view rotation by aspect ratio This aspect ratio takes into account both the extent and the canvas aspect ratio. Signed-off-by: Patrick Avery --- hexrd/ui/interactive_template.py | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/hexrd/ui/interactive_template.py b/hexrd/ui/interactive_template.py index abb85063e..a65f88c43 100644 --- a/hexrd/ui/interactive_template.py +++ b/hexrd/ui/interactive_template.py @@ -6,6 +6,7 @@ from skimage.draw import polygon +from hexrd.ui.constants import ViewType from hexrd.ui.hexrd_config import HexrdConfig from hexrd.ui.utils import has_nan @@ -358,9 +359,29 @@ def on_press_rotate(self, event): self.press = self.shape.xy, event.xdata, event.ydata def rotate_template(self, points, angle): + center = self.center + canvas = self.current_canvas + if canvas.mode == ViewType.polar: + # We need to correct for the extent ratio and the aspect ratio + # Make a copy to modify (we should *not* modify the original) + points = np.array(points) + extent = canvas.iviewer.pv.extent + + canvas_aspect = compute_aspect_ratio(canvas.axis) + extent_aspect = (extent[1] - extent[0]) / (extent[2] - extent[3]) + + aspect_ratio = extent_aspect * canvas_aspect + points[:, 0] *= aspect_ratio + center = (center[0] * aspect_ratio, center[1]) + x = [np.cos(angle), np.sin(angle)] y = [-np.sin(angle), np.cos(angle)] - verts = np.dot(points - self.center, np.array([x, y])) + self.center + verts = np.dot(points - center, np.array([x, y])) + center + + if canvas.mode == ViewType.polar: + # Reverse the aspect ratio correction + verts[:, 0] /= aspect_ratio + self.shape.set_xy(verts) def on_rotate(self, event): @@ -427,3 +448,10 @@ def on_rotate_release(self, event): self.press = None self.rotate_template(xy, angle) self.redraw() + + +def compute_aspect_ratio(axis): + # Compute the aspect ratio of a matplotlib axis + ll, ur = axis.get_position() * axis.figure.get_size_inches() + width, height = ur - ll + return width / height From d2446e00f8188d21a49e8f3e8944aad68110fbc6 Mon Sep 17 00:00:00 2001 From: Brianna Major Date: Wed, 20 Sep 2023 13:41:47 -0400 Subject: [PATCH 21/25] Fix plot title check We only need to confirm that we are in the correct detector in the raw image mode. Signed-off-by: Brianna Major --- hexrd/ui/mask_regions_dialog.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hexrd/ui/mask_regions_dialog.py b/hexrd/ui/mask_regions_dialog.py index 897195776..e3f14da7a 100644 --- a/hexrd/ui/mask_regions_dialog.py +++ b/hexrd/ui/mask_regions_dialog.py @@ -185,7 +185,8 @@ def check_pick(self, event): (event.xdata, event.ydata)) if (not pick_found and it.template.contains_point(transformed_click) and - event.inaxes.get_title() == it.detector): + (self.image_mode == ViewType.polar or + event.inaxes.get_title() == it.detector)): if self.interactive_template: self.interactive_template.disconnect() self.interactive_template = it From 43f46ca1ccaf4ba91858de7a6e53b047a3ce2461 Mon Sep 17 00:00:00 2001 From: Patrick Avery Date: Wed, 20 Sep 2023 13:07:42 -0500 Subject: [PATCH 22/25] Fix extent aspect ratio correction I accidentally inverted this... Signed-off-by: Patrick Avery --- hexrd/ui/interactive_template.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hexrd/ui/interactive_template.py b/hexrd/ui/interactive_template.py index a65f88c43..1a1de5fa8 100644 --- a/hexrd/ui/interactive_template.py +++ b/hexrd/ui/interactive_template.py @@ -368,7 +368,7 @@ def rotate_template(self, points, angle): extent = canvas.iviewer.pv.extent canvas_aspect = compute_aspect_ratio(canvas.axis) - extent_aspect = (extent[1] - extent[0]) / (extent[2] - extent[3]) + extent_aspect = (extent[2] - extent[3]) / (extent[1] - extent[0]) aspect_ratio = extent_aspect * canvas_aspect points[:, 0] *= aspect_ratio From 3c5bf48e2cc5712ffa070f3604046468efd85012 Mon Sep 17 00:00:00 2001 From: Brianna Major Date: Wed, 20 Sep 2023 15:39:15 -0400 Subject: [PATCH 23/25] Do not interact if in static mode Signed-off-by: Brianna Major --- hexrd/ui/interactive_template.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hexrd/ui/interactive_template.py b/hexrd/ui/interactive_template.py index 1a1de5fa8..a8bf7dcc6 100644 --- a/hexrd/ui/interactive_template.py +++ b/hexrd/ui/interactive_template.py @@ -249,6 +249,9 @@ def scale_template(self, sx=1, sy=1): self.redraw() def on_press(self, event): + if self.static_mode: + return + self.event_key = event.key if event.key is None: self.on_press_translate(event) @@ -262,6 +265,9 @@ def on_release(self, event): self.on_rotate_release(event) def on_key(self, event): + if self.static_mode: + return + if 'shift' in event.key: self.on_key_rotate(event) else: From 85194d0de72ec2818e25a3b15209a5d1f32ea8a4 Mon Sep 17 00:00:00 2001 From: Brianna Major Date: Wed, 20 Sep 2023 15:50:05 -0400 Subject: [PATCH 24/25] Allow the angle of rotation by arrow key to be changed Signed-off-by: Brianna Major --- hexrd/ui/constants.py | 4 ++++ hexrd/ui/interactive_template.py | 17 ++++++++++++++--- hexrd/ui/mask_regions_dialog.py | 3 ++- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/hexrd/ui/constants.py b/hexrd/ui/constants.py index a662a2fa9..d2143b413 100644 --- a/hexrd/ui/constants.py +++ b/hexrd/ui/constants.py @@ -107,3 +107,7 @@ class LLNLTransform: 'IMAGE-PLATE-4', ], } + +KEY_ROTATE_ANGLE_FINE = 0.00175 +KEY_ROTATE_ANGLE_COARSE = 0.01 +KEY_TRANSLATE_DELTA = 0.5 diff --git a/hexrd/ui/interactive_template.py b/hexrd/ui/interactive_template.py index a8bf7dcc6..82e421e62 100644 --- a/hexrd/ui/interactive_template.py +++ b/hexrd/ui/interactive_template.py @@ -6,7 +6,7 @@ from skimage.draw import polygon -from hexrd.ui.constants import ViewType +from hexrd.ui.constants import KEY_ROTATE_ANGLE_FINE, KEY_TRANSLATE_DELTA, ViewType from hexrd.ui.hexrd_config import HexrdConfig from hexrd.ui.utils import has_nan @@ -26,6 +26,7 @@ def __init__(self, canvas, detector, axes=None, instrument=None): self.instrument = instrument self._static = True self.axis_image = axes.get_images()[0] if axes else canvas.axes_images[0] + self._key_angle = KEY_ROTATE_ANGLE_FINE self.button_press_cid = None self.button_release_cid = None @@ -59,6 +60,16 @@ def static_mode(self, mode): self.connect_translate_rotate() self.update_style(color='red') + @property + def key_rotation_angle(self): + return self._key_angle + + @key_rotation_angle.setter + def key_rotation_angle(self, angle=None): + if angle is None: + angle = KEY_ROTATE_ANGLE + self._key_angle = angle + def update_image(self, img): self.img = img @@ -299,7 +310,7 @@ def translate_template(self, dx, dy): def on_key_translate(self, event): dx0, dy0 = self.translation dx1, dy1 = 0, 0 - delta = 0.5 + delta = KEY_TRANSLATE_DELTA if event.key == 'right': dx1 = delta elif event.key == 'left': @@ -403,7 +414,7 @@ def on_rotate(self, event): self.redraw() def on_key_rotate(self, event): - angle = 0.00175 + angle = self.key_rotation_angle # !!! only catch arrow keys if event.key == 'shift+left' or event.key == 'shift+up': angle *= -1. diff --git a/hexrd/ui/mask_regions_dialog.py b/hexrd/ui/mask_regions_dialog.py index e3f14da7a..fa004315a 100644 --- a/hexrd/ui/mask_regions_dialog.py +++ b/hexrd/ui/mask_regions_dialog.py @@ -5,7 +5,7 @@ from hexrd.ui.interactive_template import InteractiveTemplate from hexrd.ui.utils import unique_name from hexrd.ui.hexrd_config import HexrdConfig -from hexrd.ui.constants import ViewType +from hexrd.ui.constants import KEY_ROTATE_ANGLE_COARSE, ViewType from hexrd.ui.ui_loader import UiLoader from hexrd.ui.utils import add_sample_points @@ -87,6 +87,7 @@ def create_interactive_template(self): self.canvas, self.det, axes=self.axes) self.interactive_template.create_polygon([[0,0]], **kwargs) self.interactive_template.update_style(color='red') + self.interactive_template.key_rotation_angle = KEY_ROTATE_ANGLE_COARSE self.added_templates.append(self.det) def update_interactive_template(self, event): From 9c2b7ee2881d66c85daa92fec1f3346c2ae4a9ac Mon Sep 17 00:00:00 2001 From: Brianna Major Date: Wed, 20 Sep 2023 16:23:25 -0400 Subject: [PATCH 25/25] PEP 8 fixes Signed-off-by: Brianna Major --- hexrd/ui/interactive_template.py | 10 +++++++--- hexrd/ui/llnl_import_tool_dialog.py | 7 ++++++- hexrd/ui/mask_regions_dialog.py | 4 ++-- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/hexrd/ui/interactive_template.py b/hexrd/ui/interactive_template.py index 82e421e62..9b49d9665 100644 --- a/hexrd/ui/interactive_template.py +++ b/hexrd/ui/interactive_template.py @@ -6,7 +6,9 @@ from skimage.draw import polygon -from hexrd.ui.constants import KEY_ROTATE_ANGLE_FINE, KEY_TRANSLATE_DELTA, ViewType +from hexrd.ui.constants import ( + KEY_ROTATE_ANGLE_FINE, KEY_TRANSLATE_DELTA, ViewType +) from hexrd.ui.hexrd_config import HexrdConfig from hexrd.ui.utils import has_nan @@ -25,7 +27,8 @@ def __init__(self, canvas, detector, axes=None, instrument=None): self.detector = detector self.instrument = instrument self._static = True - self.axis_image = axes.get_images()[0] if axes else canvas.axes_images[0] + self.axis_image = ( + axes.get_images()[0] if axes else canvas.axes_images[0]) self._key_angle = KEY_ROTATE_ANGLE_FINE self.button_press_cid = None @@ -112,7 +115,8 @@ def update_style(self, style=None, width=None, color=None): def update_position(self): pos = None if self.instrument is not None: - pos = HexrdConfig().boundary_position(self.instrument, self.detector) + pos = HexrdConfig().boundary_position( + self.instrument, self.detector) if pos is None: self.center = self.get_midpoint() else: diff --git a/hexrd/ui/llnl_import_tool_dialog.py b/hexrd/ui/llnl_import_tool_dialog.py index a6bb5ac97..a04abe92b 100644 --- a/hexrd/ui/llnl_import_tool_dialog.py +++ b/hexrd/ui/llnl_import_tool_dialog.py @@ -399,7 +399,12 @@ def swap_bounds_for_cropped(self): module=hexrd_resources, file_name=f'TARDIS_IMAGE-PLATE-3_bnd_cropped.txt' ) - kwargs = {'fill': False, 'lw': width, 'color': color, 'linestyle': '--'} + kwargs = { + 'fill': False, + 'lw': width, + 'color': color, + 'linestyle': '--' + } self.it.create_polygon(verts, **kwargs) self.update_bbox_width(1330) self.update_bbox_height(238) diff --git a/hexrd/ui/mask_regions_dialog.py b/hexrd/ui/mask_regions_dialog.py index fa004315a..04ee239af 100644 --- a/hexrd/ui/mask_regions_dialog.py +++ b/hexrd/ui/mask_regions_dialog.py @@ -85,7 +85,7 @@ def create_interactive_template(self): } self.interactive_template = InteractiveTemplate( self.canvas, self.det, axes=self.axes) - self.interactive_template.create_polygon([[0,0]], **kwargs) + self.interactive_template.create_polygon([[0, 0]], **kwargs) self.interactive_template.update_style(color='red') self.interactive_template.key_rotation_angle = KEY_ROTATE_ANGLE_COARSE self.added_templates.append(self.det) @@ -220,7 +220,7 @@ def button_pressed(self, event): self.create_interactive_template() # For animating the patch - self.canvas.draw() # Force canvas re-draw before caching + self.canvas.draw() # Force canvas re-draw before caching self.bg_cache = self.canvas.copy_from_bbox(self.axes.bbox) self.drawing_axes = self.axes