Skip to content

Conversation

@alessandratrapani
Copy link

Add AnatomicalCoordinatesImage class as described in #8

  • Introduced AnatomicalCoordinatesImage class for storing anatomical coordinates as images.
  • Updated ndx_anatomical_localization.py to register the new class.
  • Modified ndx-anatomical-localization.extensions.yaml to include new neurodata type.
  • Added unit tests for AnatomicalCoordinatesImage creation and validation.

Copy link
Collaborator

@h-mayorquin h-mayorquin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Two suggestions.

  1. I think the representation is not obvious at glance. It confused me at the beginning. Something like this could help to clarify and illustrate:

Each pixel stores its complete (x, y, z) atlas coordinate:

            Image with Atlas Coordinates per Pixel

                       j=0             j=1             j=2
                    ──────────────────────────────────────────────
                  │               │               │               │
         i=0      │   x: 2.10     │   x: 2.11     │   x: 2.12     │
                  │   y: -3.40    │   y: -3.40    │   y: -3.40    │
                  │   z: 1.20     │   z: 1.20     │   z: 1.20     │
                  │               │               │               │
                  ├───────────────┼───────────────┼───────────────┤
                  │               │               │               │
         i=1      │   x: 2.10     │   x: 2.11     │   x: 2.12     │
                  │   y: -3.41    │   y: -3.41    │   y: -3.41    │
                  │   z: 1.20     │   z: 1.20     │   z: 1.20     │
                  │               │               │               │
                  ├───────────────┼───────────────┼───────────────┤
                  │               │               │               │
         i=2      │   x: 2.10     │   x: 2.11     │   x: 2.12     │
                  │   y: -3.42    │   y: -3.42    │   y: -3.42    │
                  │   z: 1.20     │   z: 1.20     │   z: 1.20     │
                  │               │               │               │
                   ───────────────────────────────────────────────

    Each pixel stores its atlas coordinates (x, y, z)

    x[i, j], y[i, j], z[i, j] give the atlas location for pixel (i, j)
  1. Also, maybe getting a function that gets you the coordinates per pixel could be useful as a help method on the class:
   def get_atlas_coordinates(self, i=None, j=None):

        import numpy as np

        if i is not None and j is not None:
            return (self.x[i, j], self.y[i, j], self.z[i, j])
        else:
            return np.stack([self.x[:], self.y[:], self.z[:]], axis=-1)

The tests are not running, I am trying to fix that here:
#10

quantity: 1
doc: "The space in which the coordinates are defined"
name: space
- target_type: Image
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the schema does not have either or relationship, right? Or would itm make sense to have both Image and ImagingPlane?

Copy link
Author

@alessandratrapani alessandratrapani Dec 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I don't think there's a way in the schema, but I can implement a check in the init of the class. I am not sure in which case could it be useful to have both Image and ImagingPlane.

name: imaging_plane
attributes:
- name: method
doc: "The method used to determine the coordinates"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How standardized is this? should we really make it required? we should give some examples to illustrate what we intend here in the docs.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was replicating the AnatomicalCoordinatesTable attribute foe consistency, I am not sure what was the intent.

- name: y
dtype: float32
dims:
- - width
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we go the other way around here (height, width) thinking on the future?

Although I think that what they have is the orientation of the image.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exactly, Since it can be confusing in this case, I would keep it as the current NWB schema until we update it

y = kwargs.get("y")
z = kwargs.get("z")
# verify that x, y, z have the same shape as the image data
if x.shape != image.data.shape or y.shape != image.data.shape or z.shape != image.data.shape:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there an image_shape object that can fetch from the ImagingPlane to do a similar check? Maybe the grid?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mmh, no the grid_spacing only gives you the physical dimension of a pixel


def test_create_custom_space():
space = Space(
_ = Space(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was a suggested ruff fix

@alessandratrapani alessandratrapani marked this pull request as ready for review December 4, 2025 15:44
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

Successfully merging this pull request may close these issues.

3 participants