diff --git a/itkwidgets/_initialization_params.py b/itkwidgets/_initialization_params.py index 3ff6272f..7dc571a2 100644 --- a/itkwidgets/_initialization_params.py +++ b/itkwidgets/_initialization_params.py @@ -92,3 +92,8 @@ def build_init_data(input_data): raise RuntimeError(f"Could not process the viewer {input_type}") input_data[render_type.value] = result return input_data + + +def defer_for_data_render(init_data): + deferred_keys = ['image', 'labelImage'] + return any([k in init_data.keys() for k in deferred_keys]) diff --git a/itkwidgets/cell_watcher.py b/itkwidgets/cell_watcher.py index 579f4c4d..7cbbc440 100644 --- a/itkwidgets/cell_watcher.py +++ b/itkwidgets/cell_watcher.py @@ -38,17 +38,22 @@ def viewer_objects(self): return list(self.data.keys()) def add_viewer(self, view): - self._data[view] = {'name': None, 'status': False} + self.data[view] = {'name': None, 'status': False} def set_name(self, view, name): if view not in self.data.keys(): self.add_viewer(view) - self._data[view]['name'] = name + self.data[view]['name'] = name def update_viewer_status(self, view, status): if view not in self.data.keys(): self.add_viewer(view) - self._data[view]['status'] = status + self.data[view]['status'] = status + + def viewer_ready(self, view): + if viewer := self.data.get(view): + return viewer['status'] + return False class CellWatcher(object): @@ -94,6 +99,9 @@ def update_viewer_status(self, view, status): # Might be ready now, try again self.create_task(self.execute_next_request) + def viewer_ready(self, view): + return self.viewers.viewer_ready(view) + def _task_cleanup(self, task): global background_tasks try: diff --git a/itkwidgets/viewer.py b/itkwidgets/viewer.py index 642e4edb..50455733 100644 --- a/itkwidgets/viewer.py +++ b/itkwidgets/viewer.py @@ -12,6 +12,7 @@ build_config, parse_input_data, build_init_data, + defer_for_data_render, ) from .cell_watcher import CellWatcher from .imjoy import register_itkwasm_imjoy_codecs @@ -82,8 +83,12 @@ async def run(self, ctx): if ENVIRONMENT is not Env.JUPYTERLITE: # Create the initial screenshot await self.create_screenshot() - # Once the viewer has been created any queued requests can be run - CellWatcher().update_viewer_status(self.parent, True) + itk_viewer.registerEventListener( + 'renderedImageAssigned', self.update_viewer_status + ) + if not defer_for_data_render(self.init_data): + # Once the viewer has been created any queued requests can be run + CellWatcher().update_viewer_status(self.parent, True) # Wait and then update the screenshot in case rendered level changed await asyncio.sleep(10) @@ -118,6 +123,10 @@ def update_screenshot(self, base64_image): ''') self.img.display(html) + def update_viewer_status(self, name): + if not CellWatcher().viewer_ready(self.parent): + CellWatcher().update_viewer_status(self.parent, True) + class Viewer: """Pythonic Viewer class.""" @@ -201,6 +210,7 @@ def set_image(self, image: Image, name: str = 'Image'): svc.set_label_or_image('image') else: self.viewer_rpc.itk_viewer.setImage(image, name) + CellWatcher().update_viewer_status(self.name, False) elif render_type is RenderType.POINT_SET: image = _get_viewer_point_set(image) self.viewer_rpc.itk_viewer.setPointSets(image) @@ -318,6 +328,7 @@ def compare_images(self, fixed_image: Union[str, Image], moving_image: Union[str if swap_image_order is not None: options['swapImageOrder'] = swap_image_order self.viewer_rpc.itk_viewer.compareImages(fixed_name, moving_name, options) + CellWatcher().update_viewer_status(self.name, False) @fetch_value def set_label_image(self, label_image: Image): @@ -331,6 +342,7 @@ def set_label_image(self, label_image: Image): svc.set_label_or_image('label_image') else: self.viewer_rpc.itk_viewer.setLabelImage(label_image) + CellWatcher().update_viewer_status(self.name, False) elif render_type is RenderType.POINT_SET: label_image = _get_viewer_point_set(label_image) self.viewer_rpc.itk_viewer.setPointSets(label_image)