def test_hit_testing_occurs_same_as_draw_order(self): # draw order occurs from 0 -> n # setup with TestContext.create_memory_context() as test_context: document_controller = test_context.create_document_controller() document_model = document_controller.document_model display_panel = document_controller.selected_display_panel data_item = DataItem.DataItem(numpy.zeros((10, 10))) document_model.append_data_item(data_item) display_item = document_model.get_display_item_for_data_item( data_item) display_panel.set_display_panel_display_item(display_item) header_height = display_panel.header_canvas_item.header_height display_panel.root_container.layout_immediate( (1000 + header_height, 1000)) # run test rect_region1 = Graphics.RectangleGraphic() rect_region1.bounds = (0.2, 0.2), (0.4, 0.4) rect_region2 = Graphics.RectangleGraphic() rect_region2.bounds = (0.4, 0.4), (0.4, 0.4) display_item.add_graphic(rect_region1) display_item.add_graphic(rect_region2) display_item = document_model.get_display_item_for_data_item( data_item) display_panel.display_canvas_item.simulate_click((500, 500)) self.assertEqual(display_item.graphic_selection.indexes, set( (1, )))
def test_specific_parts_take_priority_when_another_selected(self): # setup with TestContext.create_memory_context() as test_context: document_controller = test_context.create_document_controller() document_model = document_controller.document_model display_panel = document_controller.selected_display_panel data_item = DataItem.DataItem(numpy.zeros((10, 10))) document_model.append_data_item(data_item) display_item = document_model.get_display_item_for_data_item( data_item) display_panel.set_display_panel_display_item(display_item) header_height = display_panel.header_canvas_item.header_height display_panel.root_container.layout_immediate( (1000 + header_height, 1000)) # run test rect_region1 = Graphics.RectangleGraphic() rect_region1.bounds = (0.2, 0.2), (0.4, 0.4) rect_region2 = Graphics.RectangleGraphic() rect_region2.bounds = (0.4, 0.4), (0.4, 0.4) display_item.add_graphic(rect_region1) display_item.add_graphic(rect_region2) display_item = document_model.get_display_item_for_data_item( data_item) # clicking on line should select it display_panel.display_canvas_item.simulate_click((700, 700)) self.assertEqual(display_item.graphic_selection.indexes, set( (1, ))) display_panel.display_canvas_item.simulate_click((600, 200)) self.assertEqual(display_item.graphic_selection.indexes, set( (0, )))
def test_target_region_stream_stops_updates_when_region_deselected(self): target_display_item_stream = HistogramPanel.TargetDisplayItemStream( self.document_controller).add_ref() target_region_stream = HistogramPanel.TargetRegionStream( target_display_item_stream).add_ref() try: count = 0 def new_region(graphic: Graphics.Graphic) -> None: nonlocal count count += 1 with contextlib.closing( target_region_stream.value_stream.listen( new_region)) as listener: rect_region = Graphics.RectangleGraphic() rect_region.bounds = (0.2, 0.2), (0.2, 0.2) self.display_item.add_graphic(rect_region) self.display_item.graphic_selection.set(0) # count 1 rect_region.bounds = (0.2, 0.2), (0.2, 0.2) # count 2 self.display_item.graphic_selection.clear() # count 2 count0 = count rect_region.bounds = (0.2, 0.2), (0.2, 0.2) # count 2 rect_region.bounds = (0.2, 0.2), (0.2, 0.2) # count 2 rect_region.bounds = (0.2, 0.2), (0.2, 0.2) # count 2 self.assertEqual(count0, count) finally: target_region_stream.remove_ref() target_display_item_stream.remove_ref()
def test_histogram_updates_when_crop_region_changes(self): data = numpy.zeros((100, 100)) data[20:40, 20:40] = 1 data[40:60, 40:60] = 2 self.display_item.data_item.set_data(data) self.histogram_panel._statistics_widget._statistics_func_value_model._run_until_complete( ) stats1_text = self.histogram_panel._statistics_widget._stats1_property.value stats2_text = self.histogram_panel._statistics_widget._stats2_property.value rect_region = Graphics.RectangleGraphic() rect_region.bounds = (0.2, 0.2), (0.2, 0.2) self.display_item.add_graphic(rect_region) self.display_item.graphic_selection.set(0) self.histogram_panel._statistics_widget._statistics_func_value_model._run_until_complete( ) stats1_new_text = self.histogram_panel._statistics_widget._stats1_property.value stats2_new_text = self.histogram_panel._statistics_widget._stats2_property.value self.assertNotEqual(stats1_text, stats1_new_text) self.assertNotEqual(stats2_text, stats2_new_text) rect_region.bounds = (0.4, 0.4), (0.2, 0.2) self.histogram_panel._statistics_widget._statistics_func_value_model._run_until_complete( ) self.assertNotEqual( stats1_new_text, self.histogram_panel._statistics_widget._stats1_property.value) self.assertNotEqual( stats2_new_text, self.histogram_panel._statistics_widget._stats2_property.value)
async def explore_edges(self, document_controller): document_model = document_controller.document_model model_data_item = self.__model_data_item model_display_item = document_model.get_display_item_for_data_item( model_data_item) pick_region = Graphics.RectangleGraphic() pick_region.size = min(1 / 16, 16 / model_data_item.dimensional_shape[0]), min( 1 / 16, 16 / model_data_item.dimensional_shape[1]) pick_region.label = _("Explore") model_display_item.add_graphic(pick_region) pick_data_item = document_model.get_pick_region_new( model_display_item, model_display_item.data_item, pick_region=pick_region) if pick_data_item: explore_interval = Graphics.IntervalGraphic() explore_interval.interval = 0.4, 0.6 explore_interval.label = _("Explore") explore_interval.graphic_id = "explore" pick_data_item.source = model_data_item pick_display_item = document_model.get_display_item_for_data_item( pick_data_item) pick_display_item.add_graphic(explore_interval) document_controller.show_display_item(pick_display_item) await self.__document_model.compute_immediate( document_controller.event_loop, document_model.get_data_item_computation(pick_data_item) ) # need the data to make connect_explorer_interval work; so do this here. ugh. self.__connect_explorer_interval(document_model, pick_data_item)
def test_specific_parts_take_priority_over_all_part(self): # setup with TestContext.create_memory_context() as test_context: document_controller = test_context.create_document_controller() document_model = document_controller.document_model display_panel = document_controller.selected_display_panel data_item = DataItem.DataItem(numpy.zeros((10, 10))) document_model.append_data_item(data_item) display_item = document_model.get_display_item_for_data_item( data_item) display_panel.set_display_panel_display_item(display_item) header_height = display_panel.header_canvas_item.header_height display_panel.root_container.layout_immediate( (1000 + header_height, 1000)) # run test rect_region = Graphics.RectangleGraphic() rect_region.bounds = (0.25, 0.25), (0.5, 0.5) line_region = Graphics.LineGraphic() line_region.start = (0.5, 0.5) line_region.end = (0.5, 1.0) # draws line, then rect display_item.add_graphic(line_region) display_item.add_graphic(rect_region) display_item = document_model.get_display_item_for_data_item( data_item) # clicking on line should select it display_panel.display_canvas_item.simulate_click((500, 600)) self.assertEqual(display_item.graphic_selection.indexes, set( (0, )))
def test_changing_graphic_does_not_notify_display_values_change(self): with TestContext.create_memory_context() as test_context: document_model = test_context.create_document_model() # this is used to update the inspector data_item = DataItem.DataItem(numpy.zeros((4, 4))) document_model.append_data_item(data_item) display_item = document_model.get_display_item_for_data_item( data_item) graphic = Graphics.RectangleGraphic() display_item.add_graphic(graphic) display_data_channel = display_item.display_data_channels[0] class Observer: def __init__(self) -> None: self.count = 0 def next_calculated_display_values(self): self.count += 1 o = Observer() with contextlib.closing( display_data_channel. add_calculated_display_values_listener( o.next_calculated_display_values)): display_data_channel.get_calculated_display_values() self.assertEqual( 1, o.count) # 1 will be sent when adding the listener with display_item.display_item_changes(): graphic.bounds = ((0, 0), (1, 1)) self.assertEqual( 1, o.count) # 1 will be sent when adding the listener
def test_changing_region_properties_change_drawn_graphic_properties(self): with TestContext.create_memory_context() as test_context: document_model = test_context.create_document_model() data_item = DataItem.DataItem(numpy.zeros((8, 8), numpy.uint32)) document_model.append_data_item(data_item) display_item = document_model.get_display_item_for_data_item(data_item) regions = list() regions.append(Graphics.PointGraphic()) regions.append(Graphics.RectangleGraphic()) regions.append(Graphics.EllipseGraphic()) regions.append(Graphics.LineGraphic()) regions.append(Graphics.IntervalGraphic()) regions.append(Graphics.ChannelGraphic()) for region in regions: region.label = "label" region.is_position_locked = False region.is_shape_locked = False region.is_bounds_constrained = False display_item.add_graphic(region) drawn_graphic = display_item.graphics[-1] self.assertEqual(region.label, drawn_graphic.label) self.assertEqual(region.is_position_locked, drawn_graphic.is_position_locked) self.assertEqual(region.is_shape_locked, drawn_graphic.is_shape_locked) self.assertEqual(region.is_bounds_constrained, drawn_graphic.is_bounds_constrained) region.label = "label2" region.is_position_locked = True region.is_shape_locked = True region.is_bounds_constrained = True self.assertEqual(region.label, drawn_graphic.label) self.assertEqual(region.is_position_locked, drawn_graphic.is_position_locked) self.assertEqual(region.is_shape_locked, drawn_graphic.is_shape_locked) self.assertEqual(region.is_bounds_constrained, drawn_graphic.is_bounds_constrained)
def test_selected_item_takes_priority_over_all_part(self): # setup document_model = DocumentModel.DocumentModel() document_controller = DocumentController.DocumentController( self.app.ui, document_model, workspace_id="library") with contextlib.closing(document_controller): display_panel = document_controller.selected_display_panel data_item = DataItem.DataItem(numpy.zeros((10, 10))) document_model.append_data_item(data_item) display_item = document_model.get_display_item_for_data_item( data_item) display_panel.set_display_panel_display_item(display_item) header_height = display_panel.header_canvas_item.header_height display_panel.root_container.layout_immediate( (1000 + header_height, 1000)) # run test rect_region = Graphics.RectangleGraphic() rect_region.bounds = (0.25, 0.25), (0.5, 0.5) line_region = Graphics.LineGraphic() line_region.start = (0.0, 1.0) line_region.end = (0.75, 0.25) # draws line, then rect display_item.add_graphic(line_region) display_item.add_graphic(rect_region) display_item = document_model.get_display_item_for_data_item( data_item) display_panel.display_canvas_item.simulate_click((50, 950)) self.assertEqual(display_item.graphic_selection.indexes, set( (0, ))) display_panel.display_canvas_item.simulate_click((500, 500)) self.assertEqual(display_item.graphic_selection.indexes, set( (0, )))
def add_line_profile(data_item, document_controller, display_panel_id, midpoint=0.5, integration_width=.25): logging.debug("midpoint: {:.4f}".format(midpoint)) logging.debug("width: {:.4f}".format(integration_width)) # next, line profile through center of crop # please don't copy this bad example code! crop_region = Graphics.RectangleGraphic() crop_region.center = (midpoint, 0.5) crop_region.size = (integration_width, 1) crop_region.is_bounds_constrained = True display_specifier = DataItem.DisplaySpecifier.from_data_item( data_item) display_specifier.display.add_graphic(crop_region) eels_data_item = document_controller.document_model.get_projection_new( data_item, crop_region) if eels_data_item: eels_data_item.title = _("EELS Summed") document_controller.display_data_item( DataItem.DisplaySpecifier.from_data_item(eels_data_item)) document_controller.workspace_controller.display_data_item_in_display_panel( eels_data_item, display_panel_id)
def _create_graphic(self) -> Graphics.RectangleGraphic: subscan_graphic = Graphics.RectangleGraphic() subscan_graphic.graphic_id = "subscan" subscan_graphic.label = _("Subscan") subscan_graphic.bounds = tuple(typing.cast(Geometry.FloatRect, self.__stem_controller.subscan_region)) subscan_graphic.rotation = self.__stem_controller.subscan_rotation subscan_graphic.is_bounds_constrained = True return subscan_graphic
def test_histogram_statistics_with_zero_array(self): self.display_item.data_item.set_data( numpy.ones((10, 10), dtype=numpy.uint32)) rect_region = Graphics.RectangleGraphic() rect_region.bounds = (10000, 10000), (1, 1) self.display_item.add_graphic(rect_region) self.display_item.graphic_selection.set(0) self.histogram_panel._histogram_widget._recompute()
async def __update_subscan_region(self): subscan_region = self.__update_subscan_region_value with self.__last_data_items_lock: scan_data_items = self.__scan_data_items if subscan_region: # create subscan graphics for each scan data item if it doesn't exist if not self.__subscan_graphic_trackers: for scan_data_item in scan_data_items: display_item = self.__document_model.get_display_item_for_data_item( scan_data_item) if display_item: subscan_graphic = Graphics.RectangleGraphic() subscan_graphic.graphic_id = "subscan" subscan_graphic.label = _("Subscan") subscan_graphic.bounds = subscan_region subscan_graphic.is_bounds_constrained = True def subscan_graphic_property_changed( subscan_graphic, name): if name == "bounds": self.__subscan_region_value.value = subscan_graphic.bounds subscan_graphic_property_changed_listener = subscan_graphic.property_changed_event.listen( functools.partial(subscan_graphic_property_changed, subscan_graphic)) def graphic_removed(subscan_graphic): self.__remove_one_subscan_graphic(subscan_graphic) self.__subscan_state_model.value = SubscanState.DISABLED self.__subscan_region_value.value = None def display_removed(subscan_graphic): self.__remove_one_subscan_graphic(subscan_graphic) remove_region_graphic_event_listener = subscan_graphic.about_to_be_removed_event.listen( functools.partial(graphic_removed, subscan_graphic)) display_about_to_be_removed_listener = display_item.about_to_be_removed_event.listen( functools.partial(display_removed, subscan_graphic)) self.__subscan_graphic_trackers.append( (subscan_graphic, subscan_graphic_property_changed_listener, remove_region_graphic_event_listener, display_about_to_be_removed_listener)) display_item.add_graphic(subscan_graphic) # apply new value to any existing subscan graphics for subscan_graphic, l1, l2, l3 in self.__subscan_graphic_trackers: subscan_graphic.bounds = subscan_region else: # remove any graphics for subscan_graphic, subscan_graphic_property_changed_listener, remove_region_graphic_event_listener, display_about_to_be_removed_listener in self.__subscan_graphic_trackers: subscan_graphic_property_changed_listener.close() remove_region_graphic_event_listener.close() display_about_to_be_removed_listener.close() subscan_graphic.container.remove_graphic(subscan_graphic) self.__subscan_graphic_trackers = list()
def test_region_mask_rect(self): rect_graphic = Graphics.RectangleGraphic() rect_graphic.bounds = (0.2, 0.2), (0.1, 0.1) mask = rect_graphic.get_mask((1000, 1000)) self.assertEqual(mask.data[200, 200], 1) # top left self.assertEqual(mask.data[200, 300], 1) # bottom left self.assertEqual(mask.data[300, 300], 1) # bottom right self.assertEqual(mask.data[300, 200], 1) # bottom left self.assertEqual(mask.data[250, 200], 1) # center top self.assertEqual(mask.data[300, 250], 1) # center right self.assertEqual(mask.data[250, 300], 1) # center bottom self.assertEqual(mask.data[200, 250], 1) # center left
def test_region_mask_with_different_types_of_graphics(self): line_graphic = Graphics.LineGraphic() line_graphic.start = (0.25, 0.25) line_graphic.end = (0.75, 0.75) spot_graphic = Graphics.SpotGraphic() spot_graphic.bounds = (0.2, 0.2), (0.1, 0.1) ellipse_graphic = Graphics.EllipseGraphic() ellipse_graphic.bounds = (0.2, 0.2), (0.1, 0.1) rect_graphic = Graphics.RectangleGraphic() rect_graphic.bounds = (0.25, 0.25), (0.5, 0.5) point_graphic = Graphics.PointGraphic() point_graphic.position = (0.25, 0.25) wedge_graphic = Graphics.WedgeGraphic() line_graphic.get_mask((256, 256)) spot_graphic.get_mask((256, 256)) ellipse_graphic.get_mask((256, 256)) rect_graphic.get_mask((256, 256)) point_graphic.get_mask((256, 256))
def __update_drift_region(self) -> None: assert threading.current_thread() == threading.main_thread() if self.__stem_controller.drift_channel_id: drift_data_item = self.__stem_controller.scan_context_channel_map.get( self.__stem_controller.drift_channel_id) else: drift_data_item = None # determine if a new graphic should exist and if it exists already if self.__stem_controller.drift_channel_id and self.__stem_controller.drift_region and drift_data_item: drift_display_item = self.__document_model.get_display_item_for_data_item( drift_data_item) # remove the graphic if it already exists on the wrong display item if self.__graphic and (not drift_display_item or not self.__graphic in drift_display_item.graphics): self.__remove_graphic() # it already exists on the correct display item, update it. if self.__graphic: self.__graphic.bounds = tuple( self.__stem_controller.drift_region) self.__graphic.rotation = self.__stem_controller.drift_rotation # otherwise create it if there is a display item for it elif drift_display_item: drift_graphic = Graphics.RectangleGraphic() drift_graphic.graphic_id = "drift" drift_graphic.label = _("Drift") drift_graphic.bounds = tuple( self.__stem_controller.drift_region) drift_graphic.rotation = self.__stem_controller.drift_rotation drift_graphic.is_bounds_constrained = True drift_graphic.color = "#F0F" # purple drift_display_item.add_graphic(drift_graphic) self.__graphic_display_item = drift_display_item self.__graphic = drift_graphic self.__graphic_property_changed_listener = self.__graphic.property_changed_event.listen( self.__graphic_property_changed) self.__graphic_about_to_be_removed_listener = self.__graphic.about_to_be_removed_event.listen( self.__graphic_about_to_be_removed) # otherwise do nothing, graphic is removed and not tracked. else: # either no drift channel_id or drift region - so remove the graphic if self.__graphic: self.__remove_graphic()
def add_line_profile( data_item: DataItem.DataItem, document_controller: DocumentController.DocumentController, display_panel_id: str, midpoint: float = 0.5, integration_width: float = 0.25) -> None: logging.debug("midpoint: {:.4f}".format(midpoint)) logging.debug("width: {:.4f}".format(integration_width)) # next, line profile through center of crop # please don't copy this bad example code! crop_region = Graphics.RectangleGraphic() crop_region.center = Geometry.FloatPoint(midpoint, 0.5) crop_region.size = Geometry.FloatSize(integration_width, 1) crop_region.is_bounds_constrained = True display_item = document_controller.document_model.get_display_item_for_data_item( data_item) assert display_item display_item.add_graphic(crop_region) display_data_item = display_item.data_item assert display_data_item eels_data_item = document_controller.document_model.get_projection_new( display_item, display_data_item, crop_region) if eels_data_item: eels_data_item.title = _("EELS Summed") eels_display_item = document_controller.document_model.get_display_item_for_data_item( eels_data_item) assert eels_display_item document_controller.show_display_item(eels_display_item) else: eels_display_item = None workspace_controller = document_controller.workspace_controller if workspace_controller and eels_display_item: workspace_controller.display_display_item_in_display_panel( eels_display_item, display_panel_id)
async def pick_new_edge(document_controller, model_data_item, edge) -> None: """Set up a new edge pick from the model data item and the given edge. The library will have the following new components and connections: - a pick region on the model data item - a pick data item with a fit/signal connected to the edge data structure - a background subtraction computation with model data item, and edge intervals as inputs - a background data item, computed by the background subtraction computation - a subtracted data item, computed by the background subtraction computation - a eels line plot with pick, background, and subtracted data items as components - an edge reference, owned by eels line plot, with reference to edge - the edge reference is used to recognize the eels line plot as associated with the referenced edge """ document_model = document_controller.document_model model_display_item = document_model.get_display_item_for_data_item(model_data_item) pick_region = Graphics.RectangleGraphic() pick_region.size = min(1 / 16, 16 / model_data_item.dimensional_shape[0]), min(1 / 16, 16 / model_data_item.dimensional_shape[1]) pick_region.label = "{} {}".format(_("Pick"), str(edge.electron_shell)) model_display_item.add_graphic(pick_region) # set up the computation for this edge. eels_data_item = DataItem.DataItem() document_model.append_data_item(eels_data_item) eels_data_item.title = "{} EELS Data of {}".format(pick_region.label, model_data_item.title) eels_data_item.source = pick_region eels_display_item = document_model.get_display_item_for_data_item(eels_data_item) eels_display_item.display_type = "line_plot" eels_display_item.display_layers = [ {"label": "Signal", "data_index": 0, "data_row": 2, "fill_color": "#0F0"}, {"label": "Background", "data_index": 0, "data_row": 1, "fill_color": "rgba(255, 0, 0, 0.3)"}, {"label": "Data", "data_index": 0, "data_row": 0, "fill_color": "#1E90FF"}, ] eels_display_item.set_display_property("legend_position", "top-right") fit_region = Graphics.IntervalGraphic() fit_region.label = _("Fit") fit_region.graphic_id = "fit" fit_region.interval = edge.fit_interval eels_display_item.add_graphic(fit_region) signal_region = Graphics.IntervalGraphic() signal_region.label = _("Signal") signal_region.graphic_id = "signal" signal_region.interval = edge.signal_interval eels_display_item.add_graphic(signal_region) document_model.append_connection(Connection.PropertyConnection(edge.data_structure, "fit_interval", fit_region, "interval", parent=eels_data_item)) document_model.append_connection(Connection.PropertyConnection(edge.data_structure, "signal_interval", signal_region, "interval", parent=eels_data_item)) computation = document_model.create_computation() computation.create_object("eels_xdata", document_model.get_object_specifier(model_data_item, "xdata")) computation.create_object("region", document_model.get_object_specifier(pick_region)) computation.create_input("fit_interval", document_model.get_object_specifier(edge.data_structure), "fit_interval") computation.create_input("signal_interval", document_model.get_object_specifier(edge.data_structure), "signal_interval") computation.processing_id = "eels.background_subtraction11" computation.create_result("data", document_model.get_object_specifier(eels_data_item)) document_model.append_computation(computation) # the eels item will need the initial computation results to display properly (view to intervals) await document_model.compute_immediate(document_controller.event_loop, computation) # ensure computation is deleted when eels is deleted computation.source = eels_data_item # create an elemental_mapping_edge_ref data structure, owned by the eels data item, with a referenced # object pointing to the edge. used for recognizing the eels data item as such. data_structure = document_model.create_data_structure(structure_type="elemental_mapping_edge_ref", source=eels_data_item) data_structure.set_referenced_object("spectrum_image", model_data_item) data_structure.set_referenced_object("edge", edge.data_structure) data_structure.set_referenced_object("data", eels_data_item) data_structure.set_referenced_object("pick_region", pick_region) document_model.append_data_structure(data_structure) # display it eels_display_item.view_to_intervals(eels_data_item.xdata, [edge.data_structure.fit_interval, edge.data_structure.signal_interval]) document_controller.show_display_item(eels_display_item)