def test_data_item_metadata_methods(self): with create_memory_profile_context() as profile_context: document_controller = profile_context.create_document_controller_with_application( ) document_model = document_controller.document_model data0 = numpy.arange(64).reshape(8, 8) data_item = DataItem.DataItem(data0) data_item.set_intensity_calibration( Calibration.Calibration(0.1, 0.2, "dogs")) data_item.set_dimensional_calibrations([ Calibration.Calibration(0.3, 0.4, "cats"), Calibration.Calibration(0.5, 0.6, "cats") ]) metadata = {"title": "Dogs eat cats."} data_item.metadata = metadata document_model.append_data_item(data_item) api = Facade.get_api("~1.0", "~1.0") library = api.library data_item_ref = library.data_items[0] self.assertEqual(data_item_ref.intensity_calibration.units, "dogs") self.assertEqual(data_item_ref.dimensional_calibrations[1].units, "cats") self.assertEqual(data_item_ref.metadata, metadata) data_item_ref.set_intensity_calibration( api.create_calibration(0.11, 0.22, "cats")) data_item_ref.set_dimensional_calibrations([ api.create_calibration(0.33, 0.44, "mice"), api.create_calibration(0.44, 0.66, "mice") ]) metadata2 = {"title": "Cats eat mice."} data_item_ref.set_metadata(metadata2) self.assertAlmostEqual(data_item.intensity_calibration.offset, 0.11) self.assertAlmostEqual( data_item.dimensional_calibrations[0].offset, 0.33) self.assertEqual(data_item.metadata, metadata2)
def test_register_library_computation_with_variable_and_execute_it(self): with TestContext.create_memory_context() as test_context: document_controller = test_context.create_document_controller_with_application( ) document_model = document_controller.document_model api = Facade.get_api("~1.0") api.register_computation_type("computation2", self.Computation2) data = numpy.random.randn(2, 2) data_item = api.library.create_data_item() data_item.set_data(data) computation = api.library.create_computation( "computation2", inputs={ "src": data_item, "value": "label" }, outputs={"graphic": None}) document_model.recompute_all() self.assertEqual(len(data_item.graphics), 1) self.assertEqual(data_item.graphics[0].label, "label") computation.set_input_value("value", "label2") document_model.recompute_all() self.assertEqual(len(data_item.graphics), 1) self.assertEqual(data_item.graphics[0].label, "label2")
def menu_item_execute(self, window: API.DocumentWindow) -> None: document_controller = window._document_controller display_item = document_controller.selected_display_item data_item = display_item.data_items[0] if display_item and len( display_item.data_items) > 0 else None if not data_item: return api_data_item = Facade.DataItem(data_item) if api_data_item.xdata.is_sequence and api_data_item.xdata.datum_dimension_count == 2: result_data_item = { "output": self.__api.library.create_data_item(title="iDPC of " + data_item.title) } self.__api.library.create_computation("nion.make_idpc", inputs={ "src": api_data_item, "gradient_x_index": 0, "gradient_y_index": 1 }, outputs=result_data_item)
def test_target_display_and_data_item(self): with TestContext.create_memory_context() as test_context: document_controller = test_context.create_document_controller_with_application( ) document_model = document_controller.document_model # configure data items data_item1 = DataItem.DataItem(numpy.zeros((8, 8))) document_model.append_data_item(data_item1) data_item2 = DataItem.DataItem(numpy.zeros((8, 8))) document_model.append_data_item(data_item2) display_item1 = document_model.get_display_item_for_data_item( data_item1) display_item2 = document_model.get_display_item_for_data_item( data_item2) # configure workspace workspace_1x1 = document_controller.project.workspaces[0] document_controller.workspace_controller.change_workspace( workspace_1x1) display_panel = document_controller.selected_display_panel display_panel.set_display_item(display_item1) api = Facade.get_api("~1.0", "~1.0") library = api.library data_item1_ref = library.data_items[0] data_item2_ref = library.data_items[1] display_item1_ref = library.display_items[0] display_item2_ref = library.display_items[1] # first data item gets displayed because there is an empty display panel. self.assertEqual( data_item1_ref, api.application.document_windows[0].target_data_item) self.assertEqual( display_item1, api.application.document_windows[0]. target_display._display_item) self.assertEqual( display_item1_ref, api.application.document_windows[0].target_display)
def test_create_data_item_from_data(self): with create_memory_profile_context() as profile_context: document_controller = profile_context.create_document_controller_with_application() document_model = document_controller.document_model data0 = numpy.arange(64).reshape(8, 8) data_item = DataItem.DataItem(data0) document_model.append_data_item(data_item) api = Facade.get_api("~1.0", "~1.0") library = api.library self.assertEqual(library.data_item_count, 1) self.assertEqual(len(library.data_items), 1) data1 = numpy.arange(128).reshape(16, 8) data2 = numpy.arange(128).reshape(8, 16) data3 = numpy.arange(16).reshape(4, 4) data_item1_ref = library.create_data_item("one") with library.data_ref_for_data_item(data_item1_ref) as data_ref: data_ref.data = data1 data_item2_ref = library.create_data_item_from_data(data2, "two") data_and_metadata = api.create_data_and_metadata(data3) data_item3_ref = library.create_data_item_from_data_and_metadata(data_and_metadata, "three") self.assertEqual(library.data_item_count, 4) self.assertTrue(numpy.array_equal(document_model.data_items[1].data, data1)) self.assertTrue(numpy.array_equal(document_model.data_items[2].data, data2)) self.assertTrue(numpy.array_equal(document_model.data_items[3].data, data3))
def test_display_data_item_returns_none_if_no_panel_available(self): with create_memory_profile_context() as profile_context: document_controller = profile_context.create_document_controller_with_application() document_model = document_controller.document_model # configure data item data_item1 = DataItem.DataItem(numpy.zeros((8, 8))) document_model.append_data_item(data_item1) data_item2 = DataItem.DataItem(numpy.zeros((8, 8))) document_model.append_data_item(data_item2) # configure workspace workspace_1x1 = document_controller.project.workspaces[0] document_controller.workspace_controller.change_workspace(workspace_1x1) display_panel = document_controller.selected_display_panel api = Facade.get_api("~1.0", "~1.0") library = api.library data_item1_ref = library.data_items[0] data_item2_ref = library.data_items[1] # first data item gets displayed because there is an empty display panel. self.assertEqual(api.application.document_windows[0].display_data_item(data_item1_ref)._display_panel, display_panel) # the display is already filled. display panel should be None. self.assertIsNone(api.application.document_windows[0].display_data_item(data_item2_ref)) # redisplay returns existing display panel. self.assertEqual(api.application.document_windows[0].display_data_item(data_item1_ref)._display_panel, display_panel)
# standard libraries import logging import unittest import unittest.mock # third party libraries import numpy # local libraries from nion.swift import Application from nion.swift import Facade from nion.swift.model import DataItem from nion.swift.test import TestContext from nion.ui import TestUI Facade.initialize() def create_memory_profile_context() -> TestContext.MemoryProfileContext: return TestContext.MemoryProfileContext() def press_ok_and_complete(*args, **kwargs): kwargs["completion_fn"]() def press_ok_cancel_and_ok_complete(*args, **kwargs): kwargs["completion_fn"](True) def press_ok_cancel_and_cancel_complete(*args, **kwargs):
def display_data_item( document_controller: DocumentController.DocumentController, data_item: DataItem.DataItem) -> None: Facade.DocumentWindow(document_controller).display_data_item( Facade.DataItem(data_item))
def menu_item_execute(self, window: API.DocumentWindow) -> None: document_controller = window._document_controller selected_display_item = document_controller.selected_display_item data_item = (selected_display_item.data_items[0] if selected_display_item and len(selected_display_item.data_items) > 0 else None) if data_item: api_data_item = Facade.DataItem(data_item) if not api_data_item.xdata.is_data_4d: self.__show_tool_tips('wrong_shape') return map_data_item = self.__api.library.create_data_item( title='Map 4D (RGB) of ' + data_item.title) # the following uses internal API and should not be used as example code. computation = document_controller.document_model.create_computation( ) computation.create_input_item( "src", Symbolic.make_item( selected_display_item. get_display_data_channel_for_data_item(data_item))) computation.create_input_item("map_regions_r", Symbolic.make_item_list([])) computation.create_input_item("map_regions_g", Symbolic.make_item_list([])) computation.create_input_item("map_regions_b", Symbolic.make_item_list([])) computation.create_variable("gamma_r", value_type="real", value=1.0) computation.create_variable("gamma_g", value_type="real", value=1.0) computation.create_variable("gamma_b", value_type="real", value=1.0) computation.create_variable("enabled_r", value_type="boolean", value=True) computation.create_variable("enabled_g", value_type="boolean", value=True) computation.create_variable("enabled_b", value_type="boolean", value=True) computation.processing_id = "nion.map_4d_rgb.2" document_controller.document_model.set_data_item_computation( map_data_item._data_item, computation) map_display_item = document_controller.document_model.get_display_item_for_data_item( map_data_item._data_item) document_controller.show_display_item(map_display_item) graphic = Graphics.PointGraphic() graphic.label = "Pick" graphic.role = "collection_index" map_display_item.add_graphic(graphic) # see note above. self.__computation_data_items.update({ str(data_item.uuid): 'source', str(map_data_item._data_item.uuid): 'map_4d' }) self.__show_tool_tips() self.__display_item_changed_event_listener = ( document_controller.focused_display_item_changed_event.listen( self.__display_item_changed))
def test_lookup_unknown_instrument_or_hardware_source_returns_none(self): api = Facade.get_api("~1.0", "~1.0") self.assertIsNone(api.get_hardware_source_by_id("nonexistent_hardware", "~1.0")) self.assertIsNone(api.get_instrument_by_id("nonexistent_instrument", "~1.0"))
def menu_item_execute(self, window: API.DocumentWindow) -> None: document_controller = window._document_controller selected_display_item = document_controller.selected_display_item data_item = (selected_display_item.data_items[0] if selected_display_item and len(selected_display_item.data_items) > 0 else None) if data_item: api_data_item = Facade.DataItem(data_item) if not api_data_item.xdata.is_data_4d: self.__show_tool_tips('wrong_shape') return average_data_item = self.__api.library.create_data_item( title='Frame average of ' + data_item.title) computation = self.__api.library.create_computation( 'nion.calculate_4d_average', inputs={'src': api_data_item}, outputs={'target': average_data_item}) computation._computation.source = average_data_item._data_item average_display_item = document_controller.document_model.get_display_item_for_data_item( average_data_item._data_item) document_controller.show_display_item(average_display_item) spectrum_graphic = average_data_item.add_rectangle_region( 0.5, 0.5, 0.1, 1.0) spectrum_graphic.label = 'Spectrum' bottom_dark_graphic = average_data_item.add_rectangle_region( 0.7, 0.5, 0.1, 1.0) bottom_dark_graphic.label = 'Bottom dark area' top_dark_graphic = average_data_item.add_rectangle_region( 0.3, 0.5, 0.1, 1.0) top_dark_graphic.label = 'Top dark area' spectrum_graphic._graphic.is_bounds_constrained = True bottom_dark_graphic._graphic.is_bounds_constrained = True top_dark_graphic._graphic.is_bounds_constrained = True dark_corrected_data_item = Facade.DataItem( DataItem.DataItem(large_format=True)) self.__api.library._document_model.append_data_item( dark_corrected_data_item._data_item) dark_corrected_data_item._data_item.session_id = self.__api.library._document_model.session_id dark_corrected_data_item.title = 'Framewise dark correction of ' + data_item.title computation = self.__api.library.create_computation( 'nion.framewise_dark_correction', inputs={ 'src1': api_data_item, 'src2': average_data_item, 'spectrum_region': spectrum_graphic, 'top_dark_region': top_dark_graphic, 'bottom_dark_region': bottom_dark_graphic, 'bin_spectrum': True, 'gain_image': [], 'gain_mode': 'custom' }, outputs={'target': dark_corrected_data_item}) computation._computation.source = dark_corrected_data_item._data_item dark_corrected_display_item = document_controller.document_model.get_display_item_for_data_item( dark_corrected_data_item._data_item) document_controller.show_display_item(dark_corrected_display_item) self.__computation_data_items.update({ data_item: 'source', average_data_item._data_item: 'average', dark_corrected_data_item._data_item: 'corrected' }) self.__show_tool_tips() self.__display_item_changed_event_listener = ( document_controller.focused_display_item_changed_event.listen( self.__display_item_changed))
def test_calibrate_spectrum_for_single_spectrum(self): with TestContext.create_memory_context() as profile_context: document_controller = profile_context.create_document_controller_with_application( ) document_model = document_controller.document_model data = numpy.zeros((100, ), dtype=numpy.float32) data[10] = 1 intensity_calibration = Calibration.Calibration(units="~") dimensional_calibrations = [ Calibration.Calibration(scale=1.0, units="eV") ] data_descriptor = DataAndMetadata.DataDescriptor( is_sequence=False, collection_dimension_count=0, datum_dimension_count=1) xdata = DataAndMetadata.new_data_and_metadata( data, intensity_calibration=intensity_calibration, dimensional_calibrations=dimensional_calibrations, data_descriptor=data_descriptor) data_item = DataItem.new_data_item(xdata) document_model.append_data_item(data_item) display_item = document_model.get_display_item_for_data_item( data_item) document_controller.select_display_items_in_data_panel( [display_item]) document_controller.data_panel_focused() api = Facade.get_api("~1.0", "~1.0") dialog = AlignZLP.calibrate_spectrum( api, api.application.document_windows[0]) self.assertEqual(1, len(document_model.data_items)) self.assertEqual(1, len(document_model.display_items)) self.assertEqual(1, len(api.library.data_items)) # calibrate_spectrum should create two graphics, offset and scale self.assertEqual(2, len(api.library.data_items[0].graphics)) # It should find the peak at 10 and set the calibration offset accordingly self.assertAlmostEqual( data_item.dimensional_calibrations[0].offset, -10.5) # Move the scale graphic and check that the calibration changed accordingly offset_graphic = api.library.data_items[0].graphics[0] scale_graphic = api.library.data_items[0].graphics[1] position_diff = scale_graphic.position - offset_graphic.position scale_graphic.position = offset_graphic.position + 0.5 * position_diff self.assertAlmostEqual(data_item.dimensional_calibrations[0].scale, 2.0) # Move the offset graphic and check that the calibration offset and the scale graphic have moved position_diff = scale_graphic.position - offset_graphic.position offset_graphic.position += 0.1 self.assertAlmostEqual( position_diff, scale_graphic.position - offset_graphic.position) self.assertAlmostEqual( data_item.dimensional_calibrations[0].offset, -41) # Closing the dialog should remove the graphics dialog.request_close() self.assertEqual(0, len(api.library.data_items[0].graphics)) # Test cleanup document_model.remove_data_item(data_item) self.assertEqual(0, len(document_model.data_items)) self.assertEqual(0, len(document_model.display_items)) self.assertEqual(0, len(document_model.data_structures))
def test_acquire_multi_eels_spectrum_image_produces_data_of_correct_shape( self): for sum_frames in [True, False]: for bin_spectra in [True, False]: with self.subTest(sum_frames=sum_frames, bin_spectra=bin_spectra): settings = { 'x_shifter': 'EELS_MagneticShift_Offset', 'blanker': 'C_Blank', 'x_shift_delay': 0.05, 'focus': '', 'focus_delay': 0, 'auto_dark_subtract': False, 'bin_spectra': bin_spectra, 'blanker_delay': 0.05, 'sum_frames': sum_frames, 'camera_hardware_source_id': '' } parameters = [{ 'index': 0, 'offset_x': 0, 'exposure_ms': 5, 'frames': 2 }, { 'index': 1, 'offset_x': 160, 'exposure_ms': 8, 'frames': 1 }] app = Application.Application(TestUI.UserInterface(), set_global=True) document_model = DocumentModel.DocumentModel() document_controller = app.create_document_controller( document_model, None) total_acquisition_time = 0.0 for parms in parameters: # the simulator cant go super fast, so make sure we give it enough time total_acquisition_time += parms['frames'] * max( parms['exposure_ms'], 100) * 1e-3 # add some extra overhead time total_acquisition_time += 0.15 total_acquisition_time += settings['x_shift_delay'] * 2 total_acquisition_time += settings['x_shift_delay'] * 2 api = Facade.get_api('~1.0', '~1.0') si_receiver = MultiAcquirePanel.MultiAcquirePanelDelegate( api) si_receiver._MultiAcquirePanelDelegate__progress_updated_event_listener.close( ) si_receiver._MultiAcquirePanelDelegate__progress_updated_event_listener = None si_receiver._MultiAcquirePanelDelegate__multi_eels_parameters_changed_event_listener.close( ) si_receiver._MultiAcquirePanelDelegate__multi_eels_parameters_changed_event_listener = None si_receiver._MultiAcquirePanelDelegate__acquisition_state_changed_event_listener.close( ) si_receiver._MultiAcquirePanelDelegate__acquisition_state_changed_event_listener = None multi_acquire = self._set_up_multi_acquire( settings, parameters, multi_acquire_instance=si_receiver. multi_acquire_controller) multi_acquire.stem_controller, multi_acquire.camera = self._get_stem_controller_and_camera( is_eels=True) multi_acquire.superscan = self._get_scan_controller( multi_acquire.stem_controller) # enable binning for speed frame_parameters = multi_acquire.camera.get_current_frame_parameters( ) frame_parameters['binning'] = 8 multi_acquire.camera.set_current_frame_parameters( frame_parameters) scan_frame_parameters = multi_acquire.superscan.get_current_frame_parameters( ) scan_frame_parameters['size'] = (10, 10) scan_frame_parameters['fov_size_nm'] = 16 multi_acquire.superscan.set_current_frame_parameters( scan_frame_parameters) progress = 0 def update_progress(minimum, maximum, value): nonlocal progress progress = minimum + value / maximum document_controller.periodic() progress_event_listener = multi_acquire.progress_updated_event.listen( update_progress) new_data_ready_event_listener = multi_acquire.new_data_ready_event.listen( si_receiver.add_to_display_queue) def acquisition_state_changed(info_dict): if info_dict.get('message') in { 'end processing', 'exception' }: si_receiver._data_processed_event.set() acquisition_state_changed_event_listener = multi_acquire.acquisition_state_changed_event.listen( acquisition_state_changed) data_receiver_thread = threading.Thread( target=si_receiver.process_display_queue, daemon=True) data_receiver_thread.start() # starttime = time.time() multi_acquire.camera.start_playing() multi_acquire.acquire_multi_eels_spectrum_image() document_controller.periodic() self.assertTrue(si_receiver._data_processed_event.wait(10)) self.assertGreaterEqual(progress, 1) #self.assertLess(time.time() - starttime, total_acquisition_time) multi_acquire_data_items = list() for data_item in document_model.data_items: if 'MultiAcquire' in data_item.title: multi_acquire_data_items.append(data_item) self.assertEqual(len(multi_acquire_data_items), len(parameters) * 2) for data_item in multi_acquire_data_items: with self.subTest(): camera_dims = multi_acquire.camera.get_expected_dimensions( frame_parameters['binning']) total_shape = tuple(scan_frame_parameters['size']) haadf_shape = tuple(scan_frame_parameters['size']) index = data_item.xdata.metadata[ 'MultiAcquire.parameters']['index'] if parameters[index]['frames'] > 1 and not settings[ 'sum_frames']: total_shape = (parameters[index]['frames'], ) + total_shape haadf_shape = (parameters[index]['frames'], ) + haadf_shape if settings['bin_spectra']: total_shape += camera_dims[1:] else: total_shape += camera_dims if 'HAADF' in data_item.title: self.assertSequenceEqual( data_item.data.shape, haadf_shape) else: self.assertSequenceEqual( data_item.data.shape, total_shape) data_receiver_thread.join(3) self.assertFalse(data_receiver_thread.is_alive()) progress_event_listener.close() new_data_ready_event_listener.close() acquisition_state_changed_event_listener.close() si_receiver.close() app.exit()
def start(self, processing: ScanAcquisitionProcessing) -> None: document_window = self.__document_controller scan_hardware_source = typing.cast(scan_base.ScanHardwareSource, self.__scan_hardware_source._hardware_source) scan_frame_parameters = scan_hardware_source.get_frame_parameters(2) scan_hardware_source.apply_scan_context_subscan(scan_frame_parameters, self.__scan_specifier.size) scan_frame_parameters["scan_id"] = str(uuid.uuid4()) # useful code for testing to exit cleanly at this point. # self.acquisition_state_changed_event.fire(SequenceState.scanning) # self.acquisition_state_changed_event.fire(SequenceState.idle) # return camera_hardware_source = typing.cast(camera_base.CameraHardwareSource, self.__camera_hardware_source._hardware_source) camera_frame_parameters = camera_hardware_source.get_frame_parameters(0) camera_frame_parameters["processing"] = processing.value.processing_id grab_sync_info = scan_hardware_source.grab_synchronized_get_info( scan_frame_parameters=scan_frame_parameters, camera=camera_hardware_source, camera_frame_parameters=camera_frame_parameters) camera_data_channel = CameraDataChannel(self.__document_controller.library._document_model, camera_hardware_source.display_name, grab_sync_info) self.__document_controller.display_data_item(Facade.DataItem(camera_data_channel.data_item)) camera_data_channel.start() drift_correction_behavior : typing.Optional[DriftCorrectionBehavior] = None section_height = None if self.__scan_specifier.drift_interval_lines > 0: drift_correction_behavior = DriftCorrectionBehavior(document_window.library._document_model, scan_hardware_source, scan_frame_parameters) section_height = self.__scan_specifier.drift_interval_lines def grab_synchronized(): self.acquisition_state_changed_event.fire(SequenceState.scanning) try: combined_data = scan_hardware_source.grab_synchronized(scan_frame_parameters=scan_frame_parameters, camera=camera_hardware_source, camera_frame_parameters=camera_frame_parameters, camera_data_channel=camera_data_channel, scan_behavior=drift_correction_behavior, section_height=section_height) if combined_data is not None: scan_data_list, camera_data_list = combined_data def create_and_display_data_item_task(): # this will be executed in UI thread for data_and_metadata in scan_data_list: create_and_display_data_item(document_window, data_and_metadata) # queue the task to be executed in UI thread document_window.queue_task(create_and_display_data_item_task) finally: def stop_channel(): camera_data_channel.stop() document_window.queue_task(stop_channel) self.acquisition_state_changed_event.fire(SequenceState.idle) self.__thread = threading.Thread(target=grab_synchronized) self.__thread.start()
def menu_item_execute(self, window: API.DocumentWindow) -> None: document_controller = window._document_controller selected_display_item = document_controller.selected_display_item data_item = (selected_display_item.data_items[0] if selected_display_item and len(selected_display_item.data_items) > 0 else None) if data_item: api_data_item = Facade.DataItem(data_item) ds = None if not api_data_item.xdata.metadata.get('libertem-io'): executor = Registry.get_component('libertem_executor') if not executor: return ds = LiberTEMAdapter( self.__api, executor).niondata_to_libertemdata(api_data_item) if not api_data_item.xdata.metadata.get('libertem-io'): self.__show_tool_tips('wrong_shape') return map_data_item = self.__api.library.create_data_item( title='Map 4D of ' + data_item.title) display_item = document_controller.document_model.get_display_item_for_data_item( map_data_item._data_item) show_display_item(window, display_item) map_regions = list() for graphic in api_data_item.graphics: if graphic._graphic.role == 'mask': map_regions.append(graphic) computation = self.__api.library.create_computation( 'nion.libertem.map_4d', inputs={ 'src': api_data_item, 'map_regions': map_regions }, outputs={'target': map_data_item}) computation._computation.source = data_item if ds is not None: computation._computation.ds = ds map_display_item = document_controller.document_model.get_display_item_for_data_item( map_data_item) document_controller.show_display_item(map_display_item) pick_graphic = map_data_item.add_point_region(0.5, 0.5) pick_graphic.label = 'Pick' threading.Thread(target=self.__connect_pick_graphic, args=(api_data_item, map_data_item, pick_graphic, computation._computation, 30), daemon=True).start() self.__computation_data_items.update({ str(data_item.uuid): 'source', str(map_data_item._data_item.uuid): 'map_4d' }) self.__api.application.document_controllers[ 0]._document_controller.ui.set_persistent_string( 'libertem_map4d_data_items_0', json.dumps(self.__computation_data_items)) self.__show_tool_tips()
def test_display_data_panel_reuses_existing_display(self): with create_memory_profile_context() as profile_context: document_controller = profile_context.create_document_controller_with_application( ) document_model = document_controller.document_model # configure data item data_item = DataItem.DataItem(numpy.arange(64).reshape(8, 8)) document_model.append_data_item(data_item) # configure workspace d = { "type": "splitter", "orientation": "vertical", "splits": [0.5, 0.5], "children": [{ "type": "image", "uuid": "0569ca31-afd7-48bd-ad54-5e2bb9f21102", "identifier": "a", "selected": True }, { "type": "image", "uuid": "acd77f9f-2f6f-4fbf-af5e-94330b73b997", "identifier": "b" }] } workspace_2x1 = document_controller.workspace_controller.new_workspace( "2x1", d) document_controller.workspace_controller.change_workspace( workspace_2x1) root_canvas_item = document_controller.workspace_controller.image_row.children[ 0]._root_canvas_item() root_canvas_item.layout_immediate( Geometry.IntSize(width=640, height=480)) self.assertIsNone(document_controller.workspace_controller. display_panels[0].data_item) self.assertIsNone(document_controller.workspace_controller. display_panels[1].data_item) # test display_data_item api = Facade.get_api("~1.0", "~1.0") library = api.library document_controller_ref = api.application.document_controllers[0] data_item_ref = library.data_items[0] # display data item and verify it is displayed display_panal_ref = document_controller_ref.display_data_item( data_item_ref) self.assertEqual( document_controller.workspace_controller.display_panels[0]. data_item, data_item_ref._data_item) self.assertIsNone(document_controller.workspace_controller. display_panels[1].data_item) self.assertEqual( document_controller.workspace_controller.display_panels[0], display_panal_ref._display_panel) # display data item again and verify it is displayed only once display_panal_ref = document_controller_ref.display_data_item( data_item_ref) self.assertEqual( document_controller.workspace_controller.display_panels[0]. data_item, data_item_ref._data_item) self.assertIsNone(document_controller.workspace_controller. display_panels[1].data_item) self.assertEqual( document_controller.workspace_controller.display_panels[0], display_panal_ref._display_panel)