def _repaint_visible(self, drawing_context, visible_rect): if self.__delegate: canvas_bounds = self.canvas_bounds item_width = int(canvas_bounds.width) item_height = self.__item_height with drawing_context.saver(): items = self.__delegate.items max_index = len(items) top_visible_row = visible_rect.top // item_height bottom_visible_row = visible_rect.bottom // item_height for index in range(top_visible_row, bottom_visible_row + 1): if 0 <= index < max_index: rect = Geometry.IntRect(origin=Geometry.IntPoint(y=index * item_height, x=0), size=Geometry.IntSize(width=item_width, height=item_height)) if rect.intersects_rect(visible_rect): is_selected = self.__selection.contains(index) if is_selected: drawing_context.save() drawing_context.begin_path() drawing_context.rect(rect.left, rect.top, rect.width, rect.height) drawing_context.fill_style = "#3875D6" if self.focused else "#DDD" drawing_context.fill() drawing_context.restore() self.__delegate.paint_item(drawing_context, items[index], rect, is_selected)
def test_eels_data_camera_current_is_consistent(self): instrument = InstrumentDevice.Instrument("usim_stem_controller") # set up the scan context; these are here temporarily until the scan context architecture is fully implemented instrument._update_scan_context(Geometry.IntSize(256, 256), Geometry.FloatPoint(), 10, 0.0) instrument._set_scan_context_probe_position( instrument.scan_context, Geometry.FloatPoint(0.5, 0.5)) # grab scan data instrument.get_scan_data( scan_base.ScanFrameParameters({ "size": (256, 256), "pixel_time_us": 1, "fov_nm": 10 }), 0) instrument.validate_probe_position() camera = instrument._get_camera_simulator("eels") camera_size = camera._camera_shape camera.noise.enabled = False readout_area = Geometry.IntRect(origin=Geometry.IntPoint(), size=camera_size) binning_shape = Geometry.IntSize(1, 1) # get the value at 200eV and ZLP offset of 0 instrument.ZLPoffset = -20 exposure_s = 0.01 d = xd.sum(instrument.get_camera_data("eels", readout_area, binning_shape, exposure_s), axis=0).data # confirm it is a reasonable value camera_current_pA = numpy.sum( d) / exposure_s / instrument.counts_per_electron / 6.242e18 * 1e12 # print(f"current {camera_current_pA :#.2f}pA") self.assertTrue(190 < camera_current_pA < 210)
def test_eels_data_is_consistent_when_energy_offset_changes(self): instrument = InstrumentDevice.Instrument("usim_stem_controller") instrument.get_scan_data( scan_base.ScanFrameParameters({ "size": (256, 256), "pixel_time_us": 1, "fov_nm": 10 }), 0) instrument.validate_probe_position() camera = instrument._get_camera_simulator("eels") camera_size = camera._camera_shape camera.noise.enabled = False readout_area = Geometry.IntRect(origin=Geometry.IntPoint(), size=camera_size) binning_shape = Geometry.IntSize(1, 1) # get the value at 200eV and ZLP offset of 0 instrument.ZLPoffset = 0 d = xd.sum(instrument.get_camera_data("eels", readout_area, binning_shape, 0.01), axis=0) index200_0 = int( d.dimensional_calibrations[-1].convert_from_calibrated_value(200)) value200_0 = d.data[index200_0] # get the value at 200eV and ZLP offset of 100 instrument.ZLPoffset = 100 d = xd.sum(instrument.get_camera_data("eels", readout_area, binning_shape, 0.01), axis=0) index200_100 = int( d.dimensional_calibrations[-1].convert_from_calibrated_value(200)) value200_100 = d.data[index200_100] self.assertEqual(int(value200_0 / 100), int(value200_100 / 100))
def draw_list_item(self, drawing_context: DrawingContext.DrawingContext, rect: Geometry.IntRect) -> None: with drawing_context.saver(): draw_rect = Geometry.IntRect(origin=rect.top_left + Geometry.IntPoint(y=4, x=4), size=Geometry.IntSize(h=72, w=72)) drawing_context.add(self.__create_thumbnail(draw_rect)) drawing_context.fill_style = "#000" drawing_context.font = "11px serif" drawing_context.fill_text(self.title_str, rect.left + 4 + 72 + 4, rect.top + 4 + 12) drawing_context.fill_text(self.format_str, rect.left + 4 + 72 + 4, rect.top + 4 + 12 + 15) drawing_context.fill_text(self.datetime_str, rect.left + 4 + 72 + 4, rect.top + 4 + 12 + 15 + 15) if self.status_str: drawing_context.fill_text(self.status_str, rect.left + 4 + 72 + 4, rect.top + 4 + 12 + 15 + 15 + 15) else: drawing_context.fill_style = "#888" drawing_context.fill_text(self.project_str, rect.left + 4 + 72 + 4, rect.top + 4 + 12 + 15 + 15 + 15)
def test_eels_data_thickness_is_consistent(self): instrument = InstrumentDevice.Instrument("usim_stem_controller") # use the flake sample instrument.sample_index = 0 # set up the scan context; these are here temporarily until the scan context architecture is fully implemented instrument._update_scan_context(Geometry.IntSize(256, 256), Geometry.FloatPoint(), 10, 0.0) instrument._set_scan_context_probe_position( instrument.scan_context, Geometry.FloatPoint(0.5, 0.5)) # grab scan data instrument.get_scan_data( scan_base.ScanFrameParameters({ "size": (256, 256), "pixel_time_us": 1, "fov_nm": 10 }), 0) instrument.validate_probe_position() camera = instrument._get_camera_simulator("eels") camera_size = camera._camera_shape camera.noise.enabled = False readout_area = Geometry.IntRect(origin=Geometry.IntPoint(), size=camera_size) binning_shape = Geometry.IntSize(1, 1) # get the value at 200eV and ZLP offset of 0 instrument.ZLPoffset = -20 d = xd.sum(instrument.get_camera_data("eels", readout_area, binning_shape, 0.01), axis=0).data # confirm it is a reasonable value # print(measure_thickness(d)) self.assertTrue(0.40 < measure_thickness(d) < 1.00)
def __init__(self, instrument: InstrumentDevice.Instrument, camera_type: str, sensor_dimensions: Geometry.IntSize, counts_per_electron: int) -> None: self.__instrument = instrument self._camera_type = camera_type self._sensor_dimensions = sensor_dimensions self._counts_per_electron = counts_per_electron self._needs_recalculation = True self._last_frame_settings = [ Geometry.IntRect((0, 0), (0, 0)), Geometry.IntSize(), 0.0, None ] def property_changed(name: str) -> None: if name in self.depends_on: self._needs_recalculation = True self.__property_changed_event_listener = instrument.property_changed_event.listen( property_changed) # we also need to inform the cameras about changes to the (parked) probe position def probe_state_changed( probe_state: str, probe_position: typing.Optional[Geometry.FloatPoint]) -> None: property_changed("probe_state") property_changed("probe_position") self.__probe_state_changed_event_listener = instrument.probe_state_changed_event.listen( probe_state_changed)
def plot(self, data: numpy.ndarray, offset_m: Geometry.FloatPoint, fov_nm: Geometry.FloatSize, center_nm: Geometry.FloatPoint, shape: Geometry.IntSize) -> int: # TODO: how does center_nm interact with stage position? # TODO: take into account feature angle # TODO: take into account frame parameters angle # TODO: expand features to other shapes than rectangle scan_rect_m = self.get_scan_rect_m(offset_m, fov_nm, center_nm) feature_rect_m = self.get_feature_rect_m() sum = 0 if scan_rect_m.intersects_rect(feature_rect_m): feature_rect_top_px = int(shape[0] * (feature_rect_m.top - scan_rect_m.top) / scan_rect_m.height) feature_rect_left_px = int(shape[1] * (feature_rect_m.left - scan_rect_m.left) / scan_rect_m.width) feature_rect_height_px = int(shape[0] * feature_rect_m.height / scan_rect_m.height) feature_rect_width_px = int(shape[1] * feature_rect_m.width / scan_rect_m.width) if feature_rect_top_px < 0: feature_rect_height_px += feature_rect_top_px feature_rect_top_px = 0 if feature_rect_left_px < 0: feature_rect_width_px += feature_rect_left_px feature_rect_left_px = 0 if feature_rect_top_px + feature_rect_height_px > shape[0]: feature_rect_height_px = shape[0] - feature_rect_top_px if feature_rect_left_px + feature_rect_width_px > shape[1]: feature_rect_width_px = shape[1] - feature_rect_left_px feature_rect_origin_px = Geometry.IntPoint(y=feature_rect_top_px, x=feature_rect_left_px) feature_rect_size_px = Geometry.IntSize(height=feature_rect_height_px, width=feature_rect_width_px) feature_rect_px = Geometry.IntRect(feature_rect_origin_px, feature_rect_size_px) data[feature_rect_px.top:feature_rect_px.bottom, feature_rect_px.left:feature_rect_px.right] += 1.0 sum += (feature_rect_px.bottom - feature_rect_px.top) * (feature_rect_px.right - feature_rect_px.left) return sum
def _repaint_visible(self, drawing_context: DrawingContext.DrawingContext, visible_rect: Geometry.IntRect) -> None: canvas_bounds = self.canvas_bounds if self.__delegate and canvas_bounds: item_width = canvas_bounds.width item_height = self.__item_height with drawing_context.saver(): items = self.__delegate.items max_index = len(items) top_visible_row = visible_rect.top // item_height bottom_visible_row = visible_rect.bottom // item_height for index in range(top_visible_row, bottom_visible_row + 1): if 0 <= index < max_index: rect = Geometry.IntRect(origin=Geometry.IntPoint(y=index * item_height, x=0), size=Geometry.IntSize(width=item_width, height=item_height)) if rect.intersects_rect(visible_rect): is_selected = self.__selection.contains(index) if is_selected: with drawing_context.saver(): drawing_context.begin_path() drawing_context.rect(rect.left, rect.top, rect.width, rect.height) drawing_context.fill_style = "#3875D6" if self.focused else "#DDD" drawing_context.fill() self.__delegate.paint_item(drawing_context, items[index], rect, is_selected) if index == self.__drop_index: with drawing_context.saver(): drop_border_width = 2.5 rect_in = rect.to_float_rect().inset(drop_border_width / 2, drop_border_width / 2).to_int_rect() drawing_context.begin_path() drawing_context.rect(rect_in.left, rect_in.top, rect_in.width, rect_in.height) drawing_context.line_width = drop_border_width drawing_context.stroke_style = "rgba(56, 117, 214, 0.8)" drawing_context.stroke()
def _repaint_visible(self, drawing_context: DrawingContext.DrawingContext, visible_rect: Geometry.IntRect) -> None: canvas_size = self.canvas_size if self.__delegate and canvas_size and canvas_size.height > 0 and canvas_size.width > 0: item_size = self.__calculate_item_size(canvas_size) items = self.__delegate.items if self.__delegate else list() item_count = len(items) items_per_row = max(1, int(canvas_size.width / item_size.width) if self.wrap else item_count) items_per_column = max(1, int(canvas_size.height / item_size.height) if self.wrap else item_count) with drawing_context.saver(): top_visible_row = visible_rect.top // item_size.height bottom_visible_row = visible_rect.bottom // item_size.height left_visible_column = visible_rect.left // item_size.width right_visible_column = visible_rect.right // item_size.width for row in range(top_visible_row, bottom_visible_row + 1): for column in range(left_visible_column, right_visible_column + 1): if self.direction == Direction.Row: index = row * items_per_row + column else: index = row + column * items_per_column if 0 <= index < item_count: rect = Geometry.IntRect(origin=Geometry.IntPoint(y=row * item_size.height, x=column * item_size.width), size=Geometry.IntSize(width=item_size.width, height=item_size.height)) if rect.intersects_rect(visible_rect): is_selected = self.__selection.contains(index) if is_selected: with drawing_context.saver(): drawing_context.begin_path() drawing_context.rect(rect.left, rect.top, rect.width, rect.height) drawing_context.fill_style = "#3875D6" if self.focused else "#BBB" drawing_context.fill() self.__delegate.paint_item(drawing_context, items[index], rect, is_selected)
def __rect_for_index(self, index: int) -> Geometry.IntRect: canvas_bounds = self.canvas_bounds if canvas_bounds: item_width = canvas_bounds.width item_height = self.__item_height return Geometry.IntRect(origin=Geometry.IntPoint(y=index * item_height, x=0), size=Geometry.IntSize(width=item_width, height=item_height)) return Geometry.IntRect.empty_rect()
def __rect_for_index(self, index: int) -> Geometry.IntRect: canvas_size = self.canvas_size if canvas_size: item_size = self.__calculate_item_size(canvas_size) item_count = self.__delegate.item_count if self.__delegate else 0 items_per_row = max(1, int(canvas_size.width / item_size.width) if self.wrap else item_count) items_per_column = max(1, int(canvas_size.height / item_size.height) if self.wrap else item_count) if self.direction == Direction.Row: row = index // items_per_row column = index - row * items_per_row else: column = index // items_per_column row = index - column * items_per_column return Geometry.IntRect(origin=Geometry.IntPoint(y=row * item_size.height, x=column * item_size.width), size=Geometry.IntSize(width=item_size.width, height=item_size.height)) return Geometry.IntRect.empty_rect()
def test_eels_data_is_consistent_when_energy_offset_changes_with_negative_zlp_offset( self): instrument = InstrumentDevice.Instrument("usim_stem_controller") instrument.get_scan_data( scan_base.ScanFrameParameters({ "size": (256, 256), "pixel_time_us": 1, "fov_nm": 10 }), 0) instrument.validate_probe_position() camera = instrument._get_camera_simulator("eels") camera_size = camera._camera_shape camera.noise.enabled = False readout_area = Geometry.IntRect(origin=Geometry.IntPoint(), size=camera_size) binning_shape = Geometry.IntSize(1, 1) # get the value at 200eV and ZLP offset of 0 instrument.ZLPoffset = -20 instrument.get_camera_data("eels", readout_area, binning_shape, 0.01)
def layout(self, canvas_origin, canvas_size, canvas_items, *, immediate=False): r = Geometry.IntRect(origin=canvas_origin, size=canvas_size) if canvas_size.width > canvas_size.height: r = Geometry.fit_to_size( r, Geometry.IntSize(w=canvas_size.height, h=canvas_size.height)) super().layout(canvas_origin, r.size, canvas_items, immediate=immediate) else: r = Geometry.fit_to_size( r, Geometry.IntSize(w=canvas_size.width, h=canvas_size.width)) super().layout(canvas_origin, r.size, canvas_items, immediate=immediate)
def layout(self, canvas_origin: Geometry.IntPoint, canvas_size: Geometry.IntSize, canvas_items: typing.Sequence[CanvasItem.AbstractCanvasItem], *, immediate: bool = False) -> None: r = Geometry.IntRect(origin=canvas_origin, size=canvas_size) if canvas_size.width > canvas_size.height: r = Geometry.fit_to_size( r, Geometry.IntSize(w=canvas_size.height, h=canvas_size.height)).to_int_rect() super().layout(canvas_origin, r.size, canvas_items, immediate=immediate) else: r = Geometry.fit_to_size( r, Geometry.IntSize(w=canvas_size.width, h=canvas_size.width)).to_int_rect() super().layout(canvas_origin, r.size, canvas_items, immediate=immediate)