ome / napari-ome-zarr

A napari plugin for zarr backed OME-NGFF images
https://www.napari-hub.org/plugins/napari-ome-zarr
BSD 3-Clause "New" or "Revised" License
27 stars 21 forks source link

installation page usage error, ValueError: No plugin found capable of reading 'https://s3.embassy.ebi.ac.uk/idr/zarr/v0.1/6001240.zarr/'. #23

Closed mezwick closed 2 years ago

mezwick commented 2 years ago

python = 3.9 conda = 4.10.3 os = windows 10

Hi, I have been playing around with ome-zarr writer and encountered ValueError: No plugin found capable of reading test.zarr This led me to see if I could load the test data. However, when I run

napari "https://s3.embassy.ebi.ac.uk/idr/zarr/v0.1/6001240.zarr/"

from console, this also returns

ValueError: No plugin found capable of reading 'https://s3.embassy.ebi.ac.uk/idr/zarr/v0.1/6001240.zarr/'

I have tested and confirmed error in a new conda environment setup like so...

conda create -n napari_test_3pt9 python=3.9
conda activate napari_test_3pt9 
conda install pip
pip install napari[all]
pip install napari-ome-zarr

I expected to be able to load the test data as per the usage section on the installation page

joshmoore commented 2 years ago

Hi @mezwick, can you try: https://uk1s3.embassy.ebi.ac.uk/idr/zarr/v0.1/6001240.zarr/ (note the addition of uk1. Unfortunately, our provider changed the URL on us. If that doesn't work, we'll dig deeper. ~Josh

mezwick commented 2 years ago

Well that seems to get round part 1, but throws a new error?

(napari_test_3pt9) C:\Users\U062951>napari "https://uk1s3.embassy.ebi.ac.uk/idr/zarr/v0.1/6001240.zarr/"
16:37:29 WARNING version mismatch: detected:FormatV01, requested:FormatV03
16:37:30 WARNING version mismatch: detected:FormatV03, requested:FormatV01
16:37:32 WARNING version mismatch: detected:FormatV01, requested:FormatV03
16:37:34 WARNING version mismatch: detected:FormatV03, requested:FormatV01
Traceback (most recent call last):
  File "C:\Users\U062951\Miniconda3\envs\napari_test_3pt9\lib\runpy.py", line 197, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "C:\Users\U062951\Miniconda3\envs\napari_test_3pt9\lib\runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "C:\Users\U062951\Miniconda3\envs\napari_test_3pt9\Scripts\napari.exe\__main__.py", line 7, in <module>
  File "C:\Users\U062951\Miniconda3\envs\napari_test_3pt9\lib\site-packages\napari\__main__.py", line 431, in main
    _run()
  File "C:\Users\U062951\Miniconda3\envs\napari_test_3pt9\lib\site-packages\napari\__main__.py", line 308, in _run
    viewer = view_path(  # noqa: F841
  File "C:\Users\U062951\Miniconda3\envs\napari_test_3pt9\lib\site-packages\napari\view_layers.py", line 167, in view_path
    return _make_viewer_then('open', args, kwargs)
  File "C:\Users\U062951\Miniconda3\envs\napari_test_3pt9\lib\site-packages\napari\view_layers.py", line 117, in _make_viewer_then
    method(*args, **kwargs)
  File "C:\Users\U062951\Miniconda3\envs\napari_test_3pt9\lib\site-packages\napari\components\viewer_model.py", line 885, in open
    self._add_layers_with_plugins(
  File "C:\Users\U062951\Miniconda3\envs\napari_test_3pt9\lib\site-packages\napari\components\viewer_model.py", line 958, in _add_layers_with_plugins
    added.extend(self._add_layer_from_data(*_data))
  File "C:\Users\U062951\Miniconda3\envs\napari_test_3pt9\lib\site-packages\napari\components\viewer_model.py", line 1035, in _add_layer_from_data
    raise exc
  File "C:\Users\U062951\Miniconda3\envs\napari_test_3pt9\lib\site-packages\napari\components\viewer_model.py", line 1032, in _add_layer_from_data
    layer = add_method(data, **(meta or {}))
  File "<string>", line 4, in add_labels
  File "C:\Users\U062951\Miniconda3\envs\napari_test_3pt9\lib\site-packages\napari\layers\labels\labels.py", line 246, in __init__
    data = self._ensure_int_labels(data)
  File "C:\Users\U062951\Miniconda3\envs\napari_test_3pt9\lib\site-packages\napari\layers\labels\labels.py", line 502, in _ensure_int_labels
    raise TypeError(
TypeError: Only integer types are supported for Labels layers, but data contains float64.

(napari_test_3pt9) C:\Users\U062951>
joshmoore commented 2 years ago

Ok. Glad to hear it. So we have you testing against the newer servers, let's also test against newer data. Would you mind trying:

mezwick commented 2 years ago

Same error i'm afraid.

(napari_test_3pt9) C:\Users\U062951>napari "https://uk1s3.embassy.ebi.ac.uk/idr/zarr/v0.3/6001240.zarr/"
Traceback (most recent call last):
  File "C:\Users\U062951\Miniconda3\envs\napari_test_3pt9\lib\runpy.py", line 197, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "C:\Users\U062951\Miniconda3\envs\napari_test_3pt9\lib\runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "C:\Users\U062951\Miniconda3\envs\napari_test_3pt9\Scripts\napari.exe\__main__.py", line 7, in <module>
  File "C:\Users\U062951\Miniconda3\envs\napari_test_3pt9\lib\site-packages\napari\__main__.py", line 431, in main
    _run()
  File "C:\Users\U062951\Miniconda3\envs\napari_test_3pt9\lib\site-packages\napari\__main__.py", line 308, in _run
    viewer = view_path(  # noqa: F841
  File "C:\Users\U062951\Miniconda3\envs\napari_test_3pt9\lib\site-packages\napari\view_layers.py", line 167, in view_path
    return _make_viewer_then('open', args, kwargs)
  File "C:\Users\U062951\Miniconda3\envs\napari_test_3pt9\lib\site-packages\napari\view_layers.py", line 117, in _make_viewer_then
    method(*args, **kwargs)
  File "C:\Users\U062951\Miniconda3\envs\napari_test_3pt9\lib\site-packages\napari\components\viewer_model.py", line 885, in open
    self._add_layers_with_plugins(
  File "C:\Users\U062951\Miniconda3\envs\napari_test_3pt9\lib\site-packages\napari\components\viewer_model.py", line 930, in _add_layers_with_plugins
    layer_data, hookimpl = read_data_with_plugins(
  File "C:\Users\U062951\Miniconda3\envs\napari_test_3pt9\lib\site-packages\napari\plugins\io.py", line 164, in read_data_with_plugins
    raise ValueError(message)
ValueError: No plugin found capable of reading 'https://uk1s3.embassy.ebi.ac.uk/idr/zarr/v0.3/6001240.zarr/'.

(napari_test_3pt9) C:\Users\U062951>
joshmoore commented 2 years ago

Apologies. Looks like I failed to update the image ID:

 napari "https://uk1s3.embassy.ebi.ac.uk/idr/zarr/v0.3/9836842.zarr/"
joshmoore commented 2 years ago

https://github.com/ome/napari-ome-zarr/issues/23#issuecomment-990031547 raises an interesting questions, @sofroniewn / @jni / @tlambert03, of how to detect that a URL doesn't exist and tell the user as much.

mezwick commented 2 years ago

Hot diggity dog it works! I can see the data.

Thanks Josh

joshmoore commented 2 years ago

😄

mezwick commented 2 years ago

do you happen to have a pyramidal .zarr dataset link I could test loading? I'm having trouble reading the pyramidal zarr i wrote out into napari, which I wrote with the write_multiscale function in ome-zarr-py package. I'd like to seperate my incompetence from a real error.

napari happily loads individual arrays when i pull them from the multiscales levels of test.zarr with something like test.zarr[0][:], but gives a peculiar loading (each level as individual layer?) in napari when i try to run something like

import napari
with napari.gui_qt():
    viewer = napari.Viewer()
    viewer.open('test.zarr/')
joshmoore commented 2 years ago

The flower in 9836842.zarr is pyramidal:

(z) ~ $ ome_zarr info "https://uk1s3.embassy.ebi.ac.uk/idr/zarr/v0.3/9836842.zarr/"
https://uk1s3.embassy.ebi.ac.uk/idr/zarr/v0.3/9836842.zarr/ [zgroup]
 - metadata
   - Multiscales
   - OMERO
 - data
   - (4, 1920, 1920)
   - (4, 960, 960)
   - (4, 480, 480)
   - (4, 240, 240)
   - (4, 120, 120)
   - (4, 60, 60)

What does ome_zarr info show for your test.zarr? If not similar, perhaps show a file listing and the .zattrs files.

mezwick commented 2 years ago

Hmm. Ok. It shows me the following...

(psmad_mouse_project) C:\Users\U062951\OneDrive - UCB\Desktop\scratch>ome_zarr info test.zarr
C:\Users\U062951\OneDrive - UCB\Desktop\scratch\test.zarr [zgroup]
 - metadata
   - Multiscales
 - data
   - (3, 41984, 43008)
   - (3, 20992, 21504)
   - (3, 10496, 10752)
   - (3, 5248, 5376)
   - (3, 2624, 2688)
   - (3, 1312, 1344)
   - (3, 656, 672)

but it loads like so... image

mezwick commented 2 years ago

The zarr itself was written with a list of numpy arrays with the following, i suspect this may be where things are going wrong?

import zarr
import pathlib
from ome_zarr import writer

path = pathlib.Path(r'C:\Users\user\Desktop\scratch\test.zarr')
store = zarr.DirectoryStore(path)
g = zarr.group(store=store, overwrite=True)
writer.write_multiscale(pyramid, g, axes='cyx')

pyramid is the list of numpy arrays with the following shape (extracted from a .ndpi whole slide scan file)

[i.shape for i in pyramid]
Out[4]: 
[(3, 41984, 43008),
 (3, 20992, 21504),
 (3, 10496, 10752),
 (3, 5248, 5376),
 (3, 2624, 2688),
 (3, 1312, 1344),
 (3, 656, 672)]
mezwick commented 2 years ago

actually napari just loads 3 layers... perhaps napari interprets the 3 channels (RGB) as 3 layers? image

jni commented 2 years ago

@joshmoore

how to detect that a URL doesn't exist and tell the user as much

Yup, that's already in the issue firehose :joy: as napari/napari#3382.

@mezwick

perhaps napari interprets the 3 channels (RGB) as 3 layers?

Yup, that is the standard way to deal with channels, as RGB is only a small subset of possible colorspaces or even number of channels. I don't know whether you can have an RGB OME-ZARR, @joshmoore? However I do know ome-zarr-py lets you specify the colour and contrast limits of each channel, so you should be able to add that to your file to make sure it loads as red, green, and blue layers.

joshmoore commented 2 years ago

Currently they're agnostic though that's under discussion (https://github.com/ome/omero-cli-render/issues/55). However, in this case, passing rgb=True to napari should fix it, no?

cc: @will-moore

will-moore commented 2 years ago

I think that rgb=True only works if the last dimension is 3. Otherwise I get an error.

@mezwick can you try this, using the ome-zarr-py to create an rgb image and then display in napari:

$ ome_zarr create testAstro --method=astronaut
$ napari testAstro

This uses: https://github.com/ome/ome-zarr-py/blob/5c43ff5c48231d3a39cf8bac951e14cc3f5a118f/ome_zarr/data.py#L101 which does write_multiscale() and then adds additional channel metadata for levels and colours.

Screenshot 2021-12-10 at 10 33 25

I also have a PR for improving the docs on writing OME-Zarr at https://github.com/ome/ome-zarr-py/pull/121/files (not merged yet)

mezwick commented 2 years ago

So certainly I can load the WSI derived pyramid list of rgb arrays into napari with rgb=True. I use the following viewer = napari.view_image(pyramid, rgb=True)

I should say, here the pyramid list has the following order...

In[17]: [i.shape for i in pyramid]
Out[17]: 
[(41984, 43008, 3),
 (20992, 21504, 3),
 (10496, 10752, 3),
 (5248, 5376, 3),
 (2624, 2688, 3),
 (1312, 1344, 3),
 (656, 672, 3)]

I reordered channels from xyc to cyx to write to zarr

In[18]:[i.shape for i in pyramid_zarr_write]
Out[18]: 
[(3, 41984, 43008),
 (3, 20992, 21504),
 (3, 10496, 10752),
 (3, 5248, 5376),
 (3, 2624, 2688),
 (3, 1312, 1344),
 (3, 656, 672)]
mezwick commented 2 years ago

This works.

I think that rgb=True only works if the last dimension is 3. Otherwise I get an error.

@mezwick can you try this, using the ome-zarr-py to create an rgb image and then display in napari:

$ ome_zarr create testAstro --method=astronaut
$ napari testAstro

This uses: https://github.com/ome/ome-zarr-py/blob/5c43ff5c48231d3a39cf8bac951e14cc3f5a118f/ome_zarr/data.py#L101 which does write_multiscale() and then adds additional channel metadata for levels and colours.

Screenshot 2021-12-10 at 10 33 25

I also have a PR for improving the docs on writing OME-Zarr at https://github.com/ome/ome-zarr-py/pull/121/files (not merged yet)

mezwick commented 2 years ago

So this works for the test astro image.

For my own image, i can write the zarr, but it doesn't capture the channel information. Am i running this correctly? Trying to do through python rather than CLI.

Perhaps because i don't have labels?

from ome_zarr import data, writer

path = pathlib.Path(r'my\path\test_createzarr.zarr')
store = zarr.DirectoryStore(path)
g = zarr.group(store=store, overwrite=True)
data.create_zarr(store, writer.write_multiscale(pyramid, g, axes='cyx'))

I get the following traceback if this provides any clues...

Traceback (most recent call last):

  File "\my\path\viewer.py", line 82, in <module>
    data.create_zarr(store, writer.write_multiscale(pyramid, g, axes='cyx'))

  File "C:\Users\U062951\Miniconda3\envs\my_env\lib\site-packages\ome_zarr\data.py", line 109, in create_zarr
    pyramid, labels = method()

TypeError: 'NoneType' object is not callable
will-moore commented 2 years ago

This is because your writer.write_multiscale(pyramid, g, axes='cyx') returns None, which is used as the 2nd argument in create_zarr(). I wouldn't try to use the data.create_zarr() directly.

In the PR above I've simplified the sample code to this, which should get you started:

    import numpy as np
    import zarr
    import os
    from ome_zarr.io import parse_url
    from ome_zarr.writer import write_image

    path = "test_ngff_image"
    os.mkdir(path)

    mean_val=10
    rng = np.random.default_rng(0)
    data = rng.poisson(mean_val, size=(50, 128, 128)).astype(np.uint8)

    # write the image data
    store = parse_url(path, mode="w").store
    root = zarr.group(store=store)
    write_image(image=data, group=root, chunks=(1, 128, 128), axes="zyx")

    # Set colours and initial rendering settings on the channels
    root.attrs["omero"] = {
        "channels": [{
            "color": "00FFFF",
            "window": {"start": 0, "end": 20},
            "label": "random",
            "active": True,
        }]
    }
mezwick commented 2 years ago

Fantastic. Thanks for your help @will-moore @joshmoore . I have got there. Code included in case useful to others looking to package a pyramidal RGB.

pyramid is a list of 3D numpy arrays [cyx]

In[73]:[array.shape for array in pyramid]
Out[73]: 
[(3, 41984, 43008),
 (3, 20992, 21504),
 (3, 10496, 10752),
 (3, 5248, 5376),
 (3, 2624, 2688),
 (3, 1312, 1344),
 (3, 656, 672)]

This is then packaged to a zarr that can be opened directly with the ome-zarr napari plugin, using the following...

#%% write pyramidal RGB image to zarr
import numpy as np
import zarr
from ome_zarr.io import parse_url
from ome_zarr.writer import write_multiscale

path = r'my\path\test_ngff_image'

# write the image data
store = parse_url(path, mode="w").store
root = zarr.group(store=store, overwrite=True)
write_multiscale(pyramid=pyramid, group=root, axes="cyx")

# Set colours and initial rendering settings on the channels
root.attrs["omero"] = {
    "channels": [
        {
            "color": "FF0000",
            "window": {"start": 0, "end": 255},
            "label": "red",
            "active": True,
            },
        {
            "color": "00FF00",
            "window": {"start": 0, "end": 255},
            "label": "green",
            "active": True,
            },
        {
            "color": "0000FF",
            "window": {"start": 0, "end": 255},
            "label": "blue",
            "active": True,
            }
        ]
    }    

with napari.gui_qt():
    viewer = napari.Viewer()
    viewer.open(path)
joshmoore commented 2 years ago

@mezwick : ok to close this?

mezwick commented 2 years ago

yup!

joshmoore commented 2 years ago

:) Thanks. Good luck with your napari+zarr fun.