Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support loading pyramids as multiscale layers #81

Open
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

psobolewskiPhD
Copy link
Collaborator

@psobolewskiPhD psobolewskiPhD commented Jan 13, 2025

This is #51 but with the latest changes merged in and conflicts resolved.
I've tested this with:
0.4.18, 0.4.19 -- old napari async implementation

  • very poor performance
  • lots of black screens

0.5.0, 0.5.5 -- new napari async implementation

  • performant with the NAPARI_ASYNC=1 (or setting in Preferences)! some flashing as things are (re)loaded ([async] Figure out flashing/reloading of recent data, perhaps lack of caching? napari/napari#7391) but performance seems on par with napari-ome-zarr (also with ASYNC set on) for a dataset I can access as ome-zarr in s3 or as ndpi in omero.
  • I've also not noticed any memory issues are reported in Pyramid images #51 despite extensive zoom, pan, letting the image sit, whatever.
  • If you do NAPARI_ASYNC=0 everything still works, you just get blocking of the viewer when zooming requires fetching new data.

Note: #51 dates back to napari 0.4.15

@psobolewskiPhD psobolewskiPhD added enhancement New feature or request high priority Something that is important! labels Jan 13, 2025
Copy link

codecov bot commented Jan 13, 2025

Codecov Report

Attention: Patch coverage is 0% with 62 lines in your changes missing coverage. Please review.

Project coverage is 30.90%. Comparing base (1d53966) to head (a697c85).

Files with missing lines Patch % Lines
src/napari_omero/plugins/loaders.py 0.00% 62 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #81      +/-   ##
==========================================
- Coverage   33.13%   30.90%   -2.24%     
==========================================
  Files          13       13              
  Lines         845      906      +61     
==========================================
  Hits          280      280              
- Misses        565      626      +61     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@jo-mueller
Copy link
Collaborator

jo-mueller commented Jan 14, 2025

Hi @psobolewskiPhD , I just wanted to test this, but for lack of being able to upload zarr images to napari in the first place (ome/ZarrReader#95), it's a bit tricky for me.

I tried to see what would happen with "regular" image data and find that I get an error spamed (see below), with the plugin loading the image fine, after all. That's the traceback:

---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
File [c:\Users\Johan\mambaforge\envs\napari-omero\lib\site-packages\napari\_qt\threads\status_checker.py:114](file:///C:/Users/Johan/mambaforge/envs/napari-omero/lib/site-packages/napari/_qt/threads/status_checker.py:114), in StatusChecker.calculate_status(self=<napari._qt.threads.status_checker.StatusChecker object>)
    110     return
    112 try:
    113     # Calculate the status change from cursor's movement
--> 114     res = viewer._calc_status_from_cursor()
        viewer = Viewer(camera=Camera(center=(7.0, 201.5, 325.5), zoom=1.6377300613496932, angles=(0.0, 0.0, 90.00000000000001), perspective=0.0, mouse_pan=True, mouse_zoom=True), cursor=Cursor(position=(0.0, 6.999999999999995, 290.9530861657729, 444.56724217099224), scaled=True, style=<CursorStyle.STANDARD: 'standard'>, size=1.0), dims=Dims(ndim=4, ndisplay=3, order=(0, 1, 2, 3), axis_labels=('0', '1', '2', '3'), rollable=(True, True, True, True), range=(RangeTuple(start=0.0, stop=0.0, step=1.0), RangeTuple(start=0.0, stop=14.0, step=1.0), RangeTuple(start=0.0, stop=403.0, step=1.0), RangeTuple(start=0.0, stop=651.0, step=1.0)), margin_left=(0.0, 0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0, 0.0), point=(0.0, 7.0, 201.0, 325.0), last_used=0), grid=GridCanvas(stride=1, shape=(-1, -1), enabled=False), layers=[<Image layer 'TL Brightfield' at 0x188f571b9d0>], help='use <2> for transform', status='Ready', tooltip=Tooltip(visible=False, text=''), theme='dark', title='napari', mouse_over_canvas=True, mouse_move_callbacks=[], mouse_drag_callbacks=[], mouse_double_click_callbacks=[<function double_click_to_zoom at 0x00000188E0F9AF80>], mouse_wheel_callbacks=[<function dims_scroll at 0x00000188E0F9A5F0>], _persisted_mouse_event={}, _mouse_drag_gen={}, _mouse_wheel_gen={}, _keymap={})
    115 except Exception as e:  # pragma: no cover # noqa: BLE001
    116     # Our codebase is not threadsafe. It is possible that an
    117     # ViewerModel or Layer state is changed while we are trying to
   (...)
    120     # from crashing the thread. The exception is logged
    121     # and a notification is sent.
    122     notification_manager.dispatch(Notification.from_exception(e))

File [c:\Users\Johan\mambaforge\envs\napari-omero\lib\site-packages\napari\components\viewer_model.py:573](file:///C:/Users/Johan/mambaforge/envs/napari-omero/lib/site-packages/napari/components/viewer_model.py:573), in ViewerModel._calc_status_from_cursor(self=Viewer(camera=Camera(center=(7.0, 201.5, 325.5),...use_drag_gen={}, _mouse_wheel_gen={}, _keymap={}))
    571 active = self.layers.selection.active
    572 if active is not None:
--> 573     status = active.get_status(
        active = <Image layer 'TL Brightfield' at 0x188f571b9d0>
        self = Viewer(camera=Camera(center=(7.0, 201.5, 325.5), zoom=1.6377300613496932, angles=(0.0, 0.0, 90.00000000000001), perspective=0.0, mouse_pan=True, mouse_zoom=True), cursor=Cursor(position=(0.0, 6.999999999999995, 290.9530861657729, 444.56724217099224), scaled=True, style=<CursorStyle.STANDARD: 'standard'>, size=1.0), dims=Dims(ndim=4, ndisplay=3, order=(0, 1, 2, 3), axis_labels=('0', '1', '2', '3'), rollable=(True, True, True, True), range=(RangeTuple(start=0.0, stop=0.0, step=1.0), RangeTuple(start=0.0, stop=14.0, step=1.0), RangeTuple(start=0.0, stop=403.0, step=1.0), RangeTuple(start=0.0, stop=651.0, step=1.0)), margin_left=(0.0, 0.0, 0.0, 0.0), margin_right=(0.0, 0.0, 0.0, 0.0), point=(0.0, 7.0, 201.0, 325.0), last_used=0), grid=GridCanvas(stride=1, shape=(-1, -1), enabled=False), layers=[<Image layer 'TL Brightfield' at 0x188f571b9d0>], help='use <2> for transform', status='Ready', tooltip=Tooltip(visible=False, text=''), theme='dark', title='napari', mouse_over_canvas=True, mouse_move_callbacks=[], mouse_drag_callbacks=[], mouse_double_click_callbacks=[<function double_click_to_zoom at 0x00000188E0F9AF80>], mouse_wheel_callbacks=[<function dims_scroll at 0x00000188E0F9A5F0>], _persisted_mouse_event={}, _mouse_drag_gen={}, _mouse_wheel_gen={}, _keymap={})
        self.cursor.position = (0.0, 6.999999999999995, 290.9530861657729, 444.56724217099224)
        self.cursor = Cursor(position=(0.0, 6.999999999999995, 290.9530861657729, 444.56724217099224), scaled=True, style=<CursorStyle.STANDARD: 'standard'>, size=1.0)
        self.cursor._view_direction = array([0.00000e+00, 1.00000e+00, 1.46562e-15, 1.94476e-14])
...
    656     return self._calculate_value_from_ray(values)
    658 return None

IndexError: too many indices for array: array is 2-dimensional, but 3 were indexed

It seems like it has something to do with how some of the viewer/camera parameters are set and the dimensionality of the data itself?

@psobolewskiPhD
Copy link
Collaborator Author

psobolewskiPhD commented Jan 14, 2025

Hi! You don't need a zarr in OMERO just a pyramidal image. We have a lot of slide scans in ours.
If you can upload to your OMERO instance, you could grab an image from e.g. here:
https://qupath.readthedocs.io/en/stable/docs/intro/acknowledgements.html

I think the error you are getting looks like:
#66
Which is upstream issue: napari/napari#7407
Which I fixed 🎉 so should be resolved in 0.5.6

Meanwhile the fix is to not mouse the canvas until the layer is fully loaded.

Importantly, if it's not a pyramidal image, none of the code in this PR should be triggered:
it's gated by if image.requiresPixelsPyramid():

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request high priority Something that is important!
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants