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

add crosshairs to orthogonal #73

Merged
merged 1 commit into from
Sep 5, 2024
Merged

add crosshairs to orthogonal #73

merged 1 commit into from
Sep 5, 2024

Conversation

haesleinhuepf
Copy link
Owner

@haesleinhuepf haesleinhuepf commented Sep 5, 2024

image

@haesleinhuepf haesleinhuepf merged commit 1238043 into main Sep 5, 2024
1 check passed
@yiqunma
Copy link
Contributor

yiqunma commented Sep 6, 2024

This is great, but could you make the crosshairs optional? Sometimes I prefer no crosshairs. I simply added an optional argument in _orthogonal.py as follows.

Couple of other suggestions if you have time:

  • a checkbox / toggle in the ipywidgets UI to turn on and off the crosshairs
  • crosshairs that are overlays of constant width thin lines of a different color than white, rather than changing the image pixels (currently, small volumes with higher zoom factor would would have very thick crosshairs)
import warnings

import numpy as np


def orthogonal(
        image,
        display_width : int = None,
        display_height : int = None,
        continuous_update:bool=True,
        zoom_factor:float = 1.0,
        zoom_spline_order:int = 0,
        colormap:str = None,
        display_min:float = None,
        display_max:float = None,
        crosshairs:bool = False,
):
    """Show three viewers slicing the image stack in Z,Y and X.

    Parameters
    ----------
    image : image
        Image to be displayed
    display_width : int, optional
        This parameter is obsolete. Use zoom_factor instead
    display_height : int, optional
        This parameter is obsolete. Use zoom_factor instead
    continuous_update : bool, optional
        Update the image while dragging the mouse, default: False
    zoom_factor: float, optional
        Allows showing the image larger (> 1) or smaller (<1)
    zoom_spline_order: int, optional
        Spline order used for interpolation (default=0, nearest-neighbor)
    colormap: str, optional
        Matplotlib colormap name or "pure_green", "pure_magenta", ...
    display_min: float, optional
        Lower bound of properly shown intensities
    display_max: float, optional
        Upper bound of properly shown intensities
    crosshairs: bool, optional
        Show crosshairs in the image corresponding to the slice position

    Returns
    -------
    An ipywidget with an image display and a slider.

    See Also
    --------
    slice()
    """
    import ipywidgets
    from ._slice import slice

    if 'cupy.ndarray' in str(type(image)):
        image = image.get()

    if len(image.shape) != 3:
        warnings.warn("Orthogonal views are only supported for 3D images. Consider using slice() instead.")

    widgets = [
        slice(image, slider_text="Z", continuous_update=continuous_update, zoom_factor=zoom_factor, zoom_spline_order=zoom_spline_order, colormap=colormap, display_min=display_min, display_max=display_max),
        slice(image.swapaxes(-3,-2).swapaxes(-2,-1), slider_text="Y", continuous_update=continuous_update, zoom_factor=zoom_factor, zoom_spline_order=zoom_spline_order, colormap=colormap, display_min=display_min, display_max=display_max),
        slice(image.swapaxes(-3,-1), slider_text="X", continuous_update=continuous_update, zoom_factor=zoom_factor, zoom_spline_order=zoom_spline_order, colormap=colormap, display_min=display_min, display_max=display_max),
    ]

    def update(event=None):
        for widget in widgets:
            widget.update()


    if crosshairs:
        def redraw0(event=None):
            image = np.copy(widgets[0].viewer.get_view_slice())
            y = widgets[1].viewer.get_slice_index()[-1]
            x = widgets[2].viewer.get_slice_index()[-1]
            image[y,:] = image.max()
            image[:,x] = image.max()
            widgets[0].viewer.view.data = image

        def redraw1(event=None):
            image = np.copy(widgets[1].viewer.get_view_slice())
            y = widgets[2].viewer.get_slice_index()[-1]
            x = widgets[0].viewer.get_slice_index()[-1]
            image[y, :] = image.max()
            image[:, x] = image.max()
            widgets[1].viewer.view.data = image


        def redraw2(event=None):
            image = np.copy(widgets[2].viewer.get_view_slice())
            y = widgets[1].viewer.get_slice_index()[-1]
            x = widgets[0].viewer.get_slice_index()[-1]
            image[y, :] = image.max()
            image[:, x] = image.max()
            widgets[2].viewer.view.data = image
    
        widgets[0].viewer.observe(redraw0)
        widgets[0].viewer.observe(redraw1)
        widgets[0].viewer.observe(redraw2)

        widgets[1].viewer.observe(redraw0)
        widgets[1].viewer.observe(redraw1)
        widgets[1].viewer.observe(redraw2)

        widgets[2].viewer.observe(redraw0)
        widgets[2].viewer.observe(redraw1)
        widgets[2].viewer.observe(redraw2)

        redraw0()
        redraw1()
        redraw2()

    widgets[1].layout=ipywidgets.Layout(margin='0 5px 0 5px')

    result = ipywidgets.HBox(widgets)
    result.update = update
    return result

@haesleinhuepf
Copy link
Owner Author

Hey @yiqunma ,

great idea! If you send it as a pull-request, I'll merge it!

Thanks!

Best,
Robert

@yiqunma
Copy link
Contributor

yiqunma commented Sep 6, 2024

PR created. Feel free to change anything as you see fit! Thanks for your work on this tool.

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.

2 participants