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

Make a decorator for surfaceData / surface-layer conversion #9

Open
haesleinhuepf opened this issue Mar 23, 2022 · 5 comments
Open
Labels
help wanted Extra attention is needed

Comments

@haesleinhuepf
Copy link
Owner

It should be possible to formulate a function decorator that takes functions like this:

@plugin_function
def operation(surface:SurfaceData, points:PointsData)

make appear them like that to the outside:

def operation(surface:SurfaceLayer, points:PointsLayer)

By implementing this plugin_function we could also solve #6 (without if-else blocks in every function) and multiply the surfaceData and pointsData with the layer's scaling. The plugin_function could also convert back pointsData and surfaceData to layers.

There are other examples where similar stuff is done:

Johannes @jo-mueller , if you're interested in implementing this, let me know! Otherwise I can also do it.

@haesleinhuepf haesleinhuepf added the help wanted Extra attention is needed label Mar 23, 2022
@haesleinhuepf haesleinhuepf changed the title Make a declarator for surfaceData / surface-layer conversion Make a decorator for surfaceData / surface-layer conversion Mar 23, 2022
@jo-mueller
Copy link
Collaborator

I'll have my hand at it :)

@jo-mueller
Copy link
Collaborator

Hi @haesleinhuepf ,

I've tried to formulate this similarly as in the linked repos (Thanks for the hints), and the result would look something like this - is this what you had in mind?

from functools import wraps
from toolz import curry
import inspect

from napari.layers import Surface, Points


@curry
def convert_annotation(function) -> callable:

    @wraps(function)
    def wrapper(*args, **kwargs):

        # From https://github.com/haesleinhuepf/napari-simpleitk-image-processing/blob/main/src/napari_simpleitk_image_processing/_simpleitk_image_processing.py
        sig = inspect.signature(function)
        # create mapping from position and keyword arguments to parameters
        # will raise a TypeError if the provided arguments do not match the signature
        # https://docs.python.org/3/library/inspect.html#inspect.Signature.bind
        bound = sig.bind(*args, **kwargs)
        # set default values for missing arguments
        # https://docs.python.org/3/library/inspect.html#inspect.BoundArguments.apply_defaults
        bound.apply_defaults()

        # copy images to napari.types
        for key, value in bound.arguments.items():

            arg = None
            if isinstance(value, Surface):
                arg = (value.data[0], value.data[1])
            if isinstance(value, Points):
                arg = (value.data)

            if arg is not None:
                bound.arguments[key] = arg


        # call the decorated function
        return function(*bound.args, **bound.kwargs)

    return wrapper

@haesleinhuepf
Copy link
Owner Author

Hi Johannes @jo-mueller ,

the code looks interesting. Have you tried to run it? Does it exist as repo/branch somewhere? That would make it easier to discuss about it ;-)

The next challenge might then be to modify the signature of the function to achieve that magicgui works. It should ask the user for a Surface layer, even though the function specifies SurfaceData as type. Hence, I would try to replace SurfaceData annotations with SurfaceLayer annotations.

Best,
Robert

@jo-mueller
Copy link
Collaborator

jo-mueller commented Apr 1, 2022

Hey @haesleinhuepf ,

the code for this lives here. I added the decorator to two functions to test the behavior and it seems to work (e.g., passes a simple test function). I haven't tried it from the viewer, yet.

It should ask the user for a Surface layer, even though the function specifies SurfaceData as type.

So...I would have to add a Surface-annotated argument in the outer function? Or replace the respective argument annotation in the wrapped function?

@haesleinhuepf
Copy link
Owner Author

I think you want to modifiy the signature of wrapper in your code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

2 participants