diff --git a/pyproject.toml b/pyproject.toml index 2eb1b60..ef30fc1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "py4D_browser" -version = "1.2.0" +version = "1.2.1" authors = [ { name="Steven Zeltmann", email="steven.zeltmann@lbl.gov" }, ] diff --git a/src/py4D_browser/main_window.py b/src/py4D_browser/main_window.py index 2bbd098..df13f24 100644 --- a/src/py4D_browser/main_window.py +++ b/src/py4D_browser/main_window.py @@ -397,6 +397,18 @@ def setup_menus(self): detector_mode_group.addAction(detector_CoM) self.detector_menu.addAction(detector_CoM) + detector_CoMx = QAction("CoM &X", self) + detector_CoMx.setCheckable(True) + detector_CoMx.triggered.connect(partial(self.update_real_space_view, True)) + detector_mode_group.addAction(detector_CoMx) + self.detector_menu.addAction(detector_CoMx) + + detector_CoMy = QAction("CoM &Y", self) + detector_CoMy.setCheckable(True) + detector_CoMy.triggered.connect(partial(self.update_real_space_view, True)) + detector_mode_group.addAction(detector_CoMy) + self.detector_menu.addAction(detector_CoMy) + detector_iCoM = QAction("i&CoM", self) detector_iCoM.setCheckable(True) detector_iCoM.triggered.connect(partial(self.update_real_space_view, True)) @@ -552,12 +564,7 @@ def setup_views(self): self.diffraction_space_widget.setMouseTracking(True) # Create virtual detector ROI selector - self.virtual_detector_point = pg_point_roi( - self.diffraction_space_widget.getView() - ) - self.virtual_detector_point.sigRegionChanged.connect( - partial(self.update_real_space_view, False) - ) + self.update_diffraction_detector() # Scalebar self.diffraction_scale_bar = ScaleBar(pixel_size=1, units="px", width=10) @@ -574,10 +581,7 @@ def setup_views(self): self.real_space_widget.setImage(np.zeros((512, 512))) # Add point selector connected to displayed diffraction pattern - self.real_space_point_selector = pg_point_roi(self.real_space_widget.getView()) - self.real_space_point_selector.sigRegionChanged.connect( - partial(self.update_diffraction_space_view, False) - ) + self.update_realspace_detector() # Scalebar, None by default self.real_space_scale_bar = ScaleBar(pixel_size=1, units="px", width=10) diff --git a/src/py4D_browser/menu_actions.py b/src/py4D_browser/menu_actions.py index d7e4eaa..74a6ce4 100644 --- a/src/py4D_browser/menu_actions.py +++ b/src/py4D_browser/menu_actions.py @@ -196,7 +196,7 @@ def export_datacube(self, save_format: str): py4DSTEM.save(filename, self.datacube, mode="o") elif save_format == "Plain HDF5": - with h5py.File(filename, "o") as f: + with h5py.File(filename, "w") as f: f["array"] = self.datacube.data diff --git a/src/py4D_browser/update_views.py b/src/py4D_browser/update_views.py index b494434..0dc256a 100644 --- a/src/py4D_browser/update_views.py +++ b/src/py4D_browser/update_views.py @@ -29,6 +29,8 @@ def update_real_space_view(self, reset=False): "Integrating", "Maximum", "CoM", + "CoM X", + "CoM Y", "iCoM", ], detector_mode @@ -50,7 +52,8 @@ def update_real_space_view(self, reset=False): if detector_shape == "Rectangular": # Get slices corresponding to ROI slices, transforms = self.virtual_detector_roi.getArraySlice( - self.datacube.data[0, 0, :, :], self.diffraction_space_widget.getImageItem() + self.datacube.data[0, 0, :, :].T, + self.diffraction_space_widget.getImageItem(), ) slice_y, slice_x = slices @@ -156,6 +159,10 @@ def update_real_space_view(self, reset=False): if detector_mode == "CoM": vimg = CoMx + 1.0j * CoMy + elif detector_mode == "CoM X": + vimg = CoMx + elif detector_mode == "CoM Y": + vimg = CoMy elif detector_mode == "iCoM": dpc = py4DSTEM.process.phase.DPC(verbose=False) dpc.preprocess( @@ -313,7 +320,7 @@ def update_diffraction_space_view(self, reset=False): elif detector_shape == "Rectangular": # Get slices corresponding to ROI slices, _ = self.real_space_rect_selector.getArraySlice( - np.zeros((self.datacube.Rshape)), self.real_space_widget.getImageItem() + np.zeros((self.datacube.Rshape)).T, self.real_space_widget.getImageItem() ) slice_y, slice_x = slices @@ -401,12 +408,18 @@ def update_realspace_detector(self): ) assert detector_shape in ["Point", "Rectangular"], detector_shape - if self.datacube is None: - return + main_pen = {"color": "g", "width": 6} + handle_pen = {"color": "r", "width": 9} + hover_pen = {"color": "c", "width": 6} + hover_handle = {"color": "c", "width": 9} - x, y = self.datacube.data.shape[:2] - x0, y0 = x // 2, y // 2 - xr, yr = x / 10, y / 10 + if self.datacube is None: + x0, y0 = 0, 0 + xr, yr = 4, 4 + else: + x, y = self.datacube.data.shape[2:] + y0, x0 = x // 2, y // 2 + xr, yr = (np.minimum(x, y) / 10,) * 2 # Remove existing detector if hasattr(self, "real_space_point_selector"): @@ -416,19 +429,27 @@ def update_realspace_detector(self): self.real_space_widget.view.scene().removeItem(self.real_space_rect_selector) self.real_space_rect_selector = None - # Rectangular detector + # Point detector if detector_shape == "Point": self.real_space_point_selector = pg_point_roi( self.real_space_widget.getView(), center=(x0 - 0.5, y0 - 0.5), + pen=main_pen, + hoverPen=hover_pen, ) self.real_space_point_selector.sigRegionChanged.connect( partial(self.update_diffraction_space_view, False) ) + # Rectangular detector elif detector_shape == "Rectangular": self.real_space_rect_selector = pg.RectROI( - [int(x0 - xr / 2), int(y0 - yr / 2)], [int(xr), int(yr)], pen=(3, 9) + [int(x0 - xr / 2), int(y0 - yr / 2)], + [int(xr), int(yr)], + pen=main_pen, + handlePen=handle_pen, + hoverPen=hover_pen, + handleHoverPen=hover_handle, ) self.real_space_widget.getView().addItem(self.real_space_rect_selector) self.real_space_rect_selector.sigRegionChangeFinished.connect( @@ -447,12 +468,18 @@ def update_diffraction_detector(self): detector_shape = self.detector_shape_group.checkedAction().text().strip("&") assert detector_shape in ["Point", "Rectangular", "Circle", "Annulus"] - if self.datacube is None: - return + main_pen = {"color": "g", "width": 6} + handle_pen = {"color": "r", "width": 9} + hover_pen = {"color": "c", "width": 6} + hover_handle = {"color": "c", "width": 9} - x, y = self.datacube.data.shape[2:] - x0, y0 = x // 2, y // 2 - xr, yr = x / 10, y / 10 + if self.datacube is None: + x0, y0 = 0, 0 + xr, yr = 4, 4 + else: + x, y = self.datacube.data.shape[2:] + y0, x0 = x // 2, y // 2 + xr, yr = (np.minimum(x, y) / 10,) * 2 # Remove existing detector if hasattr(self, "virtual_detector_point"): @@ -479,6 +506,8 @@ def update_diffraction_detector(self): self.virtual_detector_point = pg_point_roi( self.diffraction_space_widget.getView(), center=(x0 - 0.5, y0 - 0.5), + pen=main_pen, + hoverPen=hover_pen, ) self.virtual_detector_point.sigRegionChanged.connect( partial(self.update_real_space_view, False) @@ -487,7 +516,12 @@ def update_diffraction_detector(self): # Rectangular detector elif detector_shape == "Rectangular": self.virtual_detector_roi = pg.RectROI( - [int(x0 - xr / 2), int(y0 - yr / 2)], [int(xr), int(yr)], pen=(3, 9) + [int(x0 - xr / 2), int(y0 - yr / 2)], + [int(xr), int(yr)], + pen=main_pen, + handlePen=handle_pen, + hoverPen=hover_pen, + handleHoverPen=hover_handle, ) self.diffraction_space_widget.getView().addItem(self.virtual_detector_roi) self.virtual_detector_roi.sigRegionChangeFinished.connect( @@ -497,7 +531,12 @@ def update_diffraction_detector(self): # Circular detector elif detector_shape == "Circle": self.virtual_detector_roi = pg.CircleROI( - [int(x0 - xr / 2), int(y0 - yr / 2)], [int(xr), int(yr)], pen=(3, 9) + [int(x0 - xr / 2), int(y0 - yr / 2)], + [int(xr), int(yr)], + pen=main_pen, + handlePen=handle_pen, + hoverPen=hover_pen, + handleHoverPen=hover_handle, ) self.diffraction_space_widget.getView().addItem(self.virtual_detector_roi) self.virtual_detector_roi.sigRegionChangeFinished.connect( @@ -508,7 +547,12 @@ def update_diffraction_detector(self): elif detector_shape == "Annulus": # Make outer detector self.virtual_detector_roi_outer = pg.CircleROI( - [int(x0 - xr), int(y0 - yr)], [int(2 * xr), int(2 * yr)], pen=(3, 9) + [int(x0 - xr), int(y0 - yr)], + [int(2 * xr), int(2 * yr)], + pen=main_pen, + handlePen=handle_pen, + hoverPen=hover_pen, + handleHoverPen=hover_handle, ) self.diffraction_space_widget.getView().addItem(self.virtual_detector_roi_outer) @@ -516,7 +560,10 @@ def update_diffraction_detector(self): self.virtual_detector_roi_inner = pg.CircleROI( [int(x0 - xr / 2), int(y0 - yr / 2)], [int(xr), int(yr)], - pen=(4, 9), + pen=main_pen, + hoverPen=hover_pen, + handlePen=handle_pen, + handleHoverPen=hover_handle, movable=False, ) self.diffraction_space_widget.getView().addItem(self.virtual_detector_roi_inner) @@ -623,8 +670,8 @@ def update_tooltip(self): if scene.getView().rect().contains(pos_in_scene): pos_in_data = scene.view.mapSceneToView(pos_in_scene) - y = int(np.clip(np.floor(pos_in_data.x()), 0, data.shape[0] - 1)) - x = int(np.clip(np.floor(pos_in_data.y()), 0, data.shape[1] - 1)) + y = int(np.clip(np.floor(pos_in_data.x()), 0, data.shape[1] - 1)) + x = int(np.clip(np.floor(pos_in_data.y()), 0, data.shape[0] - 1)) if np.isrealobj(data): display_text = f"[{x},{y}]: {data[x,y]:.5g}" diff --git a/src/py4D_browser/utils.py b/src/py4D_browser/utils.py index 5ac1058..b27ad7f 100644 --- a/src/py4D_browser/utils.py +++ b/src/py4D_browser/utils.py @@ -66,12 +66,12 @@ def on_click(self, *args): self.status_bar.showMessage("Shift+click to keep on", 5_000) -def pg_point_roi(view_box, center=(-0.5, -0.5)): +def pg_point_roi(view_box, center=(-0.5, -0.5), pen=(0, 9), hoverPen=None): """ Point selection. Based in pyqtgraph, and returns a pyqtgraph CircleROI object. This object has a sigRegionChanged.connect() signal method to connect to other functions. """ - circ_roi = pg.CircleROI(center, (2, 2), movable=True, pen=(0, 9)) + circ_roi = pg.CircleROI(center, (2, 2), movable=True, pen=pen, hoverPen=hoverPen) h = circ_roi.addTranslateHandle((0.5, 0.5)) h.pen = pg.mkPen("r") h.update()