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

Custom DataWrapper example does not correctly display images in the NDViewer #36

Open
kmdouglass opened this issue Jul 2, 2024 · 0 comments

Comments

@kmdouglass
Copy link

kmdouglass commented Jul 2, 2024

  • ndv version: 0.0.4
  • Python version: 3.11
  • Operating System: Windows

Description

After a discussion with @tlambert03 on image.sc, I tested an example that he provided that demonstrates how to create custom DataWrappers: https://github.com/pyapp-kit/ndv/blob/5fefbd196242474c351587ded75aaff32ed8663c/examples/custom_store.py

Unfortunately, the resulting dataset that is displayed does not show the correct range of pixel values; they tend to be clustered around 109. Additionally, the sliders for navigating through the dataset do not change the displayed image when clicked.

What I Did

As a check, and because I'm ultimately interested in images with low contrast, I modified the example to show images of random integers between 90 and 110 with a dtype of np.uint16.

from typing import Any

import ndv
import numpy as np


if __name__ == "__main__":
    class MyArrayThing:
        def __init__(self, shape: tuple[int, ...]) -> None:
            self.shape = shape
            self._data = np.random.randint(90, 110, shape, dtype=np.uint16)

        def __getitem__(self, item: Any) -> np.ndarray:
            return self._data[item]  # type: ignore [no-any-return]


    class MyWrapper(ndv.DataWrapper[MyArrayThing]):
        @classmethod
        def supports(cls, data: Any) -> bool:
            if isinstance(data, MyArrayThing):
                return True
            return False

        def sizes(self):
            """Return a mapping of {dim: size} for the data"""
            return {f"dim_{k}": v for k, v in enumerate(self.data.shape)}

        def isel(self, indexers) -> Any:
            """Convert mapping of {dim: index} to conventional indexing"""
            idx = tuple(indexers.get(k, slice(None)) for k in range(len(self.data.shape)))
            return self.data[idx]


    data = MyArrayThing((10, 3, 256, 256))

    ndv.imshow(data)

A screenshot of what I see immediately after running the script follows:

image

I performed two sanity checks:

  1. I checked the value of the _data attribute of the MyArrayThing instance and the array contains the correct range of values.
  2. I used a normal numpy array data = np.random.randint(90, 110, (10, 3, 256, 256), dtype=np.uint16) in the call to ndv.imshow(data) and everything worked as expected.

I looked briefly into the code and it looks like the data is ultimately owned by a DataWrapper instance, so any distortion of the underlying values might occur there.

Edits

  • Minor typo in point two of the sanity checks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant